libavcodec/escape130.c
7d643914
 /*
350914fc
  * Escape 130 video decoder
7d643914
  * Copyright (C) 2008 Eli Friedman (eli.friedman <at> gmail.com)
  *
  * This file is part of FFmpeg.
  *
  * FFmpeg is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
  * FFmpeg is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with FFmpeg; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
350914fc
 #include "libavutil/attributes.h"
 #include "libavutil/mem.h"
b6686629
 
d1c28e35
 #define BITSTREAM_READER_LE
b6686629
 #include "avcodec.h"
06029fbb
 #include "get_bits.h"
874c5b02
 #include "internal.h"
 
7d643914
 typedef struct Escape130Context {
350914fc
     uint8_t *old_y_avg;
 
     uint8_t *new_y, *old_y;
     uint8_t *new_u, *old_u;
     uint8_t *new_v, *old_v;
 
     uint8_t *buf1, *buf2;
     int     linesize[3];
7d643914
 } Escape130Context;
 
350914fc
 static const uint8_t offset_table[] = { 2, 4, 10, 20 };
 static const int8_t sign_table[64][4] = {
     {  0,  0,  0,  0 },
     { -1,  1,  0,  0 },
     {  1, -1,  0,  0 },
     { -1,  0,  1,  0 },
     { -1,  1,  1,  0 },
     {  0, -1,  1,  0 },
     {  1, -1,  1,  0 },
     { -1, -1,  1,  0 },
     {  1,  0, -1,  0 },
     {  0,  1, -1,  0 },
     {  1,  1, -1,  0 },
     { -1,  1, -1,  0 },
     {  1, -1, -1,  0 },
     { -1,  0,  0,  1 },
     { -1,  1,  0,  1 },
     {  0, -1,  0,  1 },
 
     {  0,  0,  0,  0 },
     {  1, -1,  0,  1 },
     { -1, -1,  0,  1 },
     { -1,  0,  1,  1 },
     { -1,  1,  1,  1 },
     {  0, -1,  1,  1 },
     {  1, -1,  1,  1 },
     { -1, -1,  1,  1 },
     {  0,  0, -1,  1 },
     {  1,  0, -1,  1 },
     { -1,  0, -1,  1 },
     {  0,  1, -1,  1 },
     {  1,  1, -1,  1 },
     { -1,  1, -1,  1 },
     {  0, -1, -1,  1 },
     {  1, -1, -1,  1 },
 
     {  0,  0,  0,  0 },
     { -1, -1, -1,  1 },
     {  1,  0,  0, -1 },
     {  0,  1,  0, -1 },
     {  1,  1,  0, -1 },
     { -1,  1,  0, -1 },
     {  1, -1,  0, -1 },
     {  0,  0,  1, -1 },
     {  1,  0,  1, -1 },
     { -1,  0,  1, -1 },
     {  0,  1,  1, -1 },
     {  1,  1,  1, -1 },
     { -1,  1,  1, -1 },
     {  0, -1,  1, -1 },
     {  1, -1,  1, -1 },
     { -1, -1,  1, -1 },
 
     {  0,  0,  0,  0 },
     {  1,  0, -1, -1 },
     {  0,  1, -1, -1 },
     {  1,  1, -1, -1 },
     { -1,  1, -1, -1 },
     {  1, -1, -1, -1 }
 };
 
 static const int8_t luma_adjust[] = { -4, -3, -2, -1, 1, 2, 3, 4 };
 
 static const int8_t chroma_adjust[2][8] = {
     { 1, 1, 0, -1, -1, -1,  0,  1 },
     { 0, 1, 1,  1,  0, -1, -1, -1 }
 };
 
3ea5d01a
 static const uint8_t chroma_vals[] = {
350914fc
      20,  28,  36,  44,  52,  60,  68,  76,
      84,  92, 100, 106, 112, 116, 120, 124,
     128, 132, 136, 140, 144, 150, 156, 164,
     172, 180, 188, 196, 204, 212, 220, 228
 };
 
7d643914
 static av_cold int escape130_decode_init(AVCodecContext *avctx)
 {
06798c6e
     Escape130Context *s = avctx->priv_data;
ac627b3d
     avctx->pix_fmt = AV_PIX_FMT_YUV420P;
7d643914
 
350914fc
     if ((avctx->width & 1) || (avctx->height & 1)) {
         av_log(avctx, AV_LOG_ERROR,
                "Dimensions should be a multiple of two.\n");
         return AVERROR_INVALIDDATA;
     }
 
     s->old_y_avg = av_malloc(avctx->width * avctx->height / 4);
     s->buf1      = av_malloc(avctx->width * avctx->height * 3 / 2);
     s->buf2      = av_malloc(avctx->width * avctx->height * 3 / 2);
     if (!s->old_y_avg || !s->buf1 || !s->buf2) {
         av_freep(&s->old_y_avg);
         av_freep(&s->buf1);
         av_freep(&s->buf2);
         av_log(avctx, AV_LOG_ERROR, "Could not allocate buffer.\n");
         return AVERROR(ENOMEM);
59d3656f
     }
 
350914fc
     s->linesize[0] = avctx->width;
     s->linesize[1] =
     s->linesize[2] = avctx->width / 2;
 
     s->new_y = s->buf1;
     s->new_u = s->new_y + avctx->width * avctx->height;
     s->new_v = s->new_u + avctx->width * avctx->height / 4;
     s->old_y = s->buf2;
     s->old_u = s->old_y + avctx->width * avctx->height;
     s->old_v = s->old_u + avctx->width * avctx->height / 4;
     memset(s->old_y, 0,    avctx->width * avctx->height);
     memset(s->old_u, 0x10, avctx->width * avctx->height / 4);
     memset(s->old_v, 0x10, avctx->width * avctx->height / 4);
06798c6e
 
7d643914
     return 0;
 }
 
 static av_cold int escape130_decode_close(AVCodecContext *avctx)
 {
     Escape130Context *s = avctx->priv_data;
 
350914fc
     av_freep(&s->old_y_avg);
     av_freep(&s->buf1);
     av_freep(&s->buf2);
06798c6e
 
7d643914
     return 0;
 }
 
350914fc
 static int decode_skip_count(GetBitContext* gb)
 {
     int value;
 
bef8dfa0
     if (get_bits_left(gb) < 1+3)
7d643914
         return -1;
 
     value = get_bits1(gb);
     if (value)
         return 0;
 
     value = get_bits(gb, 3);
     if (value)
         return value;
 
     value = get_bits(gb, 8);
     if (value)
         return value + 7;
 
     value = get_bits(gb, 15);
     if (value)
         return value + 262;
 
     return -1;
 }
 
350914fc
 static int escape130_decode_frame(AVCodecContext *avctx, void *data,
                                   int *got_frame, AVPacket *avpkt)
7d643914
 {
350914fc
     int buf_size        = avpkt->size;
7d643914
     Escape130Context *s = avctx->priv_data;
350914fc
     AVFrame *pic        = data;
7d643914
     GetBitContext gb;
80e9e63c
     int ret;
7d643914
 
1e8f7732
     uint8_t *old_y, *old_cb, *old_cr,
7d643914
             *new_y, *new_cb, *new_cr;
350914fc
     uint8_t *dstY, *dstU, *dstV;
7d643914
     unsigned old_y_stride, old_cb_stride, old_cr_stride,
              new_y_stride, new_cb_stride, new_cr_stride;
     unsigned total_blocks = avctx->width * avctx->height / 4,
350914fc
              block_index, block_x = 0;
     unsigned y[4] = { 0 }, cb = 0x10, cr = 0x10;
     int skip = -1, y_avg = 0, i, j;
     uint8_t *ya = s->old_y_avg;
 
     // first 16 bytes are header; no useful information in here
     if (buf_size <= 16) {
         av_log(avctx, AV_LOG_ERROR, "Insufficient frame data\n");
         return AVERROR_INVALIDDATA;
     }
7d643914
 
350914fc
     if ((ret = ff_get_buffer(avctx, pic, 0)) < 0)
1ec94b0f
         return ret;
1e8f7732
 
fbd0f91a
     if ((ret = init_get_bits8(&gb, avpkt->data, avpkt->size)) < 0)
         return ret;
     skip_bits_long(&gb, 16 * 8);
350914fc
 
     new_y  = s->new_y;
     new_cb = s->new_u;
     new_cr = s->new_v;
     new_y_stride  = s->linesize[0];
     new_cb_stride = s->linesize[1];
     new_cr_stride = s->linesize[2];
     old_y  = s->old_y;
     old_cb = s->old_u;
     old_cr = s->old_v;
     old_y_stride  = s->linesize[0];
     old_cb_stride = s->linesize[1];
     old_cr_stride = s->linesize[2];
7d643914
 
     for (block_index = 0; block_index < total_blocks; block_index++) {
         // Note that this call will make us skip the rest of the blocks
350914fc
         // if the frame ends prematurely.
7d643914
         if (skip == -1)
             skip = decode_skip_count(&gb);
350914fc
         if (skip == -1) {
             av_log(avctx, AV_LOG_ERROR, "Error decoding skip value\n");
             return AVERROR_INVALIDDATA;
         }
7d643914
 
         if (skip) {
350914fc
             y[0] = old_y[0];
             y[1] = old_y[1];
             y[2] = old_y[old_y_stride];
             y[3] = old_y[old_y_stride + 1];
             y_avg = ya[0];
             cb = old_cb[0];
             cr = old_cr[0];
7d643914
         } else {
             if (get_bits1(&gb)) {
350914fc
                 unsigned sign_selector       = get_bits(&gb, 6);
8ac64695
                 unsigned difference_selector = get_bits(&gb, 2);
350914fc
                 y_avg = 2 * get_bits(&gb, 5);
7d643914
                 for (i = 0; i < 4; i++) {
350914fc
                     y[i] = av_clip(y_avg + offset_table[difference_selector] *
                                    sign_table[sign_selector][i], 0, 63);
7d643914
                 }
             } else if (get_bits1(&gb)) {
                 if (get_bits1(&gb)) {
350914fc
                     y_avg = get_bits(&gb, 6);
7d643914
                 } else {
                     unsigned adjust_index = get_bits(&gb, 3);
350914fc
                     y_avg = (y_avg + luma_adjust[adjust_index]) & 63;
7d643914
                 }
06798c6e
                 for (i = 0; i < 4; i++)
350914fc
                     y[i] = y_avg;
7d643914
             }
 
             if (get_bits1(&gb)) {
                 if (get_bits1(&gb)) {
                     cb = get_bits(&gb, 5);
                     cr = get_bits(&gb, 5);
                 } else {
                     unsigned adjust_index = get_bits(&gb, 3);
350914fc
                     cb = (cb + chroma_adjust[0][adjust_index]) & 31;
                     cr = (cr + chroma_adjust[1][adjust_index]) & 31;
7d643914
                 }
             }
         }
350914fc
         *ya++ = y_avg;
 
         new_y[0]                = y[0];
         new_y[1]                = y[1];
         new_y[new_y_stride]     = y[2];
         new_y[new_y_stride + 1] = y[3];
         *new_cb = cb;
         *new_cr = cr;
 
         old_y += 2;
         old_cb++;
         old_cr++;
         new_y += 2;
         new_cb++;
         new_cr++;
         block_x++;
         if (block_x * 2 == avctx->width) {
             block_x = 0;
             old_y  += old_y_stride * 2  - avctx->width;
             old_cb += old_cb_stride     - avctx->width / 2;
             old_cr += old_cr_stride     - avctx->width / 2;
7d643914
             new_y  += new_y_stride * 2  - avctx->width;
350914fc
             new_cb += new_cb_stride     - avctx->width / 2;
             new_cr += new_cr_stride     - avctx->width / 2;
7d643914
         }
 
         skip--;
     }
 
350914fc
     new_y  = s->new_y;
     new_cb = s->new_u;
     new_cr = s->new_v;
     dstY   = pic->data[0];
     dstU   = pic->data[1];
     dstV   = pic->data[2];
     for (j = 0; j < avctx->height; j++) {
         for (i = 0; i < avctx->width; i++)
             dstY[i] = new_y[i] << 2;
         dstY  += pic->linesize[0];
         new_y += new_y_stride;
     }
     for (j = 0; j < avctx->height / 2; j++) {
         for (i = 0; i < avctx->width / 2; i++) {
             dstU[i] = chroma_vals[new_cb[i]];
             dstV[i] = chroma_vals[new_cr[i]];
         }
         dstU   += pic->linesize[1];
         dstV   += pic->linesize[2];
         new_cb += new_cb_stride;
         new_cr += new_cr_stride;
     }
 
6a85dfc8
     ff_dlog(avctx, "Frame data: provided %d bytes, used %d bytes\n",
350914fc
             buf_size, get_bits_count(&gb) >> 3);
7d643914
 
350914fc
     FFSWAP(uint8_t*, s->old_y, s->new_y);
     FFSWAP(uint8_t*, s->old_u, s->new_u);
     FFSWAP(uint8_t*, s->old_v, s->new_v);
7d643914
 
4012cd6c
     *got_frame = 1;
7d643914
 
     return buf_size;
 }
 
06029fbb
 AVCodec ff_escape130_decoder = {
     .name           = "escape130",
b2bed932
     .long_name      = NULL_IF_CONFIG_SMALL("Escape 130"),
06029fbb
     .type           = AVMEDIA_TYPE_VIDEO,
7a72695c
     .id             = AV_CODEC_ID_ESCAPE130,
06029fbb
     .priv_data_size = sizeof(Escape130Context),
     .init           = escape130_decode_init,
     .close          = escape130_decode_close,
     .decode         = escape130_decode_frame,
def97856
     .capabilities   = AV_CODEC_CAP_DR1,
7d643914
 };