]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/bink.c
aacsbr: Make the previous value of bs_num_env local to read_sbr_data().
[ffmpeg] / libavcodec / bink.c
index 661f75fec3ca275ac578c4c5c171ad42876a70e6..7465d215c29b693c5311adf8f87a2e322c7a9a2d 100644 (file)
@@ -27,6 +27,9 @@
 #define ALT_BITSTREAM_READER_LE
 #include "get_bits.h"
 
+#define BINK_FLAG_ALPHA 0x00100000
+#define BINK_FLAG_GRAY  0x00020000
+
 static VLC bink_trees[16];
 
 /**
@@ -77,6 +80,7 @@ typedef struct BinkContext {
     DSPContext     dsp;
     AVFrame        pic, last;
     int            version;              ///< internal Bink file version
+    int            has_alpha;
     int            swap_planes;
     ScanTable      scantable;            ///< permutated scantable for DCT coeffs decoding
 
@@ -668,239 +672,260 @@ static int read_residue(GetBitContext *gb, DCTELEM block[64], int masks_count)
     return 0;
 }
 
-static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPacket *pkt)
+static int bink_decode_plane(BinkContext *c, GetBitContext *gb, int plane_idx,
+                             int is_chroma)
 {
-    BinkContext * const c = avctx->priv_data;
-    GetBitContext gb;
     int blk;
-    int i, j, plane, plane_idx, bx, by;
+    int i, j, bx, by;
     uint8_t *dst, *prev, *ref, *ref_start, *ref_end;
     int v, col[2];
     const uint8_t *scan;
     int xoff, yoff;
-    DECLARE_ALIGNED_16(DCTELEM, block[64]);
-    DECLARE_ALIGNED_16(uint8_t, ublock[64]);
+    DECLARE_ALIGNED(16, DCTELEM, block[64]);
+    DECLARE_ALIGNED(16, uint8_t, ublock[64]);
     int coordmap[64];
 
-    if(c->pic.data[0])
-        avctx->release_buffer(avctx, &c->pic);
+    const int stride = c->pic.linesize[plane_idx];
+    int bw = is_chroma ? (c->avctx->width  + 15) >> 4 : (c->avctx->width  + 7) >> 3;
+    int bh = is_chroma ? (c->avctx->height + 15) >> 4 : (c->avctx->height + 7) >> 3;
+    int width = c->avctx->width >> is_chroma;
 
-    if(avctx->get_buffer(avctx, &c->pic) < 0){
-        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
-        return -1;
-    }
-
-    init_get_bits(&gb, pkt->data, pkt->size*8);
-    if (c->version >= 'i')
-        skip_bits_long(&gb, 32);
-
-    for (plane = 0; plane < 3; plane++) {
-        const int stride = c->pic.linesize[plane];
-        int bw = plane ? (avctx->width  + 15) >> 4 : (avctx->width  + 7) >> 3;
-        int bh = plane ? (avctx->height + 15) >> 4 : (avctx->height + 7) >> 3;
-        int width = avctx->width >> !!plane;
-
-        init_lengths(c, FFMAX(width, 8), bw);
-        for (i = 0; i < BINK_NB_SRC; i++)
-            read_bundle(&gb, c, i);
-
-        plane_idx = (!plane || !c->swap_planes) ? plane : (plane ^ 3);
-        ref_start = c->last.data[plane_idx];
-        ref_end   = c->last.data[plane_idx]
-                    + (bw - 1 + c->last.linesize[plane_idx] * (bh - 1)) * 8;
-
-        for (i = 0; i < 64; i++)
-            coordmap[i] = (i & 7) + (i >> 3) * stride;
-
-        for (by = 0; by < bh; by++) {
-            if (read_block_types(avctx, &gb, &c->bundle[BINK_SRC_BLOCK_TYPES]) < 0)
-                return -1;
-            if (read_block_types(avctx, &gb, &c->bundle[BINK_SRC_SUB_BLOCK_TYPES]) < 0)
-                return -1;
-            if (read_colors(&gb, &c->bundle[BINK_SRC_COLORS], c) < 0)
-                return -1;
-            if (read_patterns(avctx, &gb, &c->bundle[BINK_SRC_PATTERN]) < 0)
-                return -1;
-            if (read_motion_values(avctx, &gb, &c->bundle[BINK_SRC_X_OFF]) < 0)
-                return -1;
-            if (read_motion_values(avctx, &gb, &c->bundle[BINK_SRC_Y_OFF]) < 0)
-                return -1;
-            if (read_dcs(avctx, &gb, &c->bundle[BINK_SRC_INTRA_DC], DC_START_BITS, 0) < 0)
-                return -1;
-            if (read_dcs(avctx, &gb, &c->bundle[BINK_SRC_INTER_DC], DC_START_BITS, 1) < 0)
-                return -1;
-            if (read_runs(avctx, &gb, &c->bundle[BINK_SRC_RUN]) < 0)
-                return -1;
-
-            if (by == bh)
+    init_lengths(c, FFMAX(width, 8), bw);
+    for (i = 0; i < BINK_NB_SRC; i++)
+        read_bundle(gb, c, i);
+
+    ref_start = c->last.data[plane_idx];
+    ref_end   = c->last.data[plane_idx]
+                + (bw - 1 + c->last.linesize[plane_idx] * (bh - 1)) * 8;
+
+    for (i = 0; i < 64; i++)
+        coordmap[i] = (i & 7) + (i >> 3) * stride;
+
+    for (by = 0; by < bh; by++) {
+        if (read_block_types(c->avctx, gb, &c->bundle[BINK_SRC_BLOCK_TYPES]) < 0)
+            return -1;
+        if (read_block_types(c->avctx, gb, &c->bundle[BINK_SRC_SUB_BLOCK_TYPES]) < 0)
+            return -1;
+        if (read_colors(gb, &c->bundle[BINK_SRC_COLORS], c) < 0)
+            return -1;
+        if (read_patterns(c->avctx, gb, &c->bundle[BINK_SRC_PATTERN]) < 0)
+            return -1;
+        if (read_motion_values(c->avctx, gb, &c->bundle[BINK_SRC_X_OFF]) < 0)
+            return -1;
+        if (read_motion_values(c->avctx, gb, &c->bundle[BINK_SRC_Y_OFF]) < 0)
+            return -1;
+        if (read_dcs(c->avctx, gb, &c->bundle[BINK_SRC_INTRA_DC], DC_START_BITS, 0) < 0)
+            return -1;
+        if (read_dcs(c->avctx, gb, &c->bundle[BINK_SRC_INTER_DC], DC_START_BITS, 1) < 0)
+            return -1;
+        if (read_runs(c->avctx, gb, &c->bundle[BINK_SRC_RUN]) < 0)
+            return -1;
+
+        if (by == bh)
+            break;
+        dst  = c->pic.data[plane_idx]  + 8*by*stride;
+        prev = c->last.data[plane_idx] + 8*by*stride;
+        for (bx = 0; bx < bw; bx++, dst += 8, prev += 8) {
+            blk = get_value(c, BINK_SRC_BLOCK_TYPES);
+            // 16x16 block type on odd line means part of the already decoded block, so skip it
+            if ((by & 1) && blk == SCALED_BLOCK) {
+                bx++;
+                dst  += 8;
+                prev += 8;
+                continue;
+            }
+            switch (blk) {
+            case SKIP_BLOCK:
+                c->dsp.put_pixels_tab[1][0](dst, prev, stride, 8);
                 break;
-            dst  = c->pic.data[plane_idx]  + 8*by*stride;
-            prev = c->last.data[plane_idx] + 8*by*stride;
-            for (bx = 0; bx < bw; bx++, dst += 8, prev += 8) {
-                blk = get_value(c, BINK_SRC_BLOCK_TYPES);
-                // 16x16 block type on odd line means part of the already decoded block, so skip it
-                if ((by & 1) && blk == SCALED_BLOCK) {
-                    bx++;
-                    dst  += 8;
-                    prev += 8;
-                    continue;
-                }
+            case SCALED_BLOCK:
+                blk = get_value(c, BINK_SRC_SUB_BLOCK_TYPES);
                 switch (blk) {
-                case SKIP_BLOCK:
-                    c->dsp.put_pixels_tab[1][0](dst, prev, stride, 8);
-                    break;
-                case SCALED_BLOCK:
-                    blk = get_value(c, BINK_SRC_SUB_BLOCK_TYPES);
-                    switch (blk) {
-                    case RUN_BLOCK:
-                        scan = bink_patterns[get_bits(&gb, 4)];
-                        i = 0;
-                        do {
-                            int run = get_value(c, BINK_SRC_RUN) + 1;
-
-                            i += run;
-                            if (i > 64) {
-                                av_log(avctx, AV_LOG_ERROR, "Run went out of bounds\n");
-                                return -1;
-                            }
-                            if (get_bits1(&gb)) {
-                                v = get_value(c, BINK_SRC_COLORS);
-                                for (j = 0; j < run; j++)
-                                    ublock[*scan++] = v;
-                            } else {
-                                for (j = 0; j < run; j++)
-                                    ublock[*scan++] = get_value(c, BINK_SRC_COLORS);
-                            }
-                        } while (i < 63);
-                        if (i == 63)
-                            ublock[*scan++] = get_value(c, BINK_SRC_COLORS);
-                        break;
-                    case INTRA_BLOCK:
-                        c->dsp.clear_block(block);
-                        block[0] = get_value(c, BINK_SRC_INTRA_DC);
-                        read_dct_coeffs(&gb, block, c->scantable.permutated, 1);
-                        c->dsp.idct(block);
-                        c->dsp.put_pixels_nonclamped(block, ublock, 8);
-                        break;
-                    case FILL_BLOCK:
-                        v = get_value(c, BINK_SRC_COLORS);
-                        c->dsp.fill_block_tab[0](dst, v, stride, 16);
-                        break;
-                    case PATTERN_BLOCK:
-                        for (i = 0; i < 2; i++)
-                            col[i] = get_value(c, BINK_SRC_COLORS);
-                        for (j = 0; j < 8; j++) {
-                            v = get_value(c, BINK_SRC_PATTERN);
-                            for (i = 0; i < 8; i++, v >>= 1)
-                                ublock[i + j*8] = col[v & 1];
-                        }
-                        break;
-                    case RAW_BLOCK:
-                        for (j = 0; j < 8; j++)
-                            for (i = 0; i < 8; i++)
-                                ublock[i + j*8] = get_value(c, BINK_SRC_COLORS);
-                        break;
-                    default:
-                        av_log(avctx, AV_LOG_ERROR, "Incorrect 16x16 block type %d\n", blk);
-                        return -1;
-                    }
-                    if (blk != FILL_BLOCK)
-                        c->dsp.scale_block(ublock, dst, stride);
-                    bx++;
-                    dst  += 8;
-                    prev += 8;
-                    break;
-                case MOTION_BLOCK:
-                    xoff = get_value(c, BINK_SRC_X_OFF);
-                    yoff = get_value(c, BINK_SRC_Y_OFF);
-                    ref = prev + xoff + yoff * stride;
-                    if (ref < ref_start || ref > ref_end) {
-                        av_log(avctx, AV_LOG_ERROR, "Copy out of bounds @%d, %d\n",
-                               bx*8 + xoff, by*8 + yoff);
-                        return -1;
-                    }
-                    c->dsp.put_pixels_tab[1][0](dst, ref, stride, 8);
-                    break;
                 case RUN_BLOCK:
-                    scan = bink_patterns[get_bits(&gb, 4)];
+                    scan = bink_patterns[get_bits(gb, 4)];
                     i = 0;
                     do {
                         int run = get_value(c, BINK_SRC_RUN) + 1;
 
                         i += run;
                         if (i > 64) {
-                            av_log(avctx, AV_LOG_ERROR, "Run went out of bounds\n");
+                            av_log(c->avctx, AV_LOG_ERROR, "Run went out of bounds\n");
                             return -1;
                         }
-                        if (get_bits1(&gb)) {
+                        if (get_bits1(gb)) {
                             v = get_value(c, BINK_SRC_COLORS);
                             for (j = 0; j < run; j++)
-                                dst[coordmap[*scan++]] = v;
+                                ublock[*scan++] = v;
                         } else {
                             for (j = 0; j < run; j++)
-                                dst[coordmap[*scan++]] = get_value(c, BINK_SRC_COLORS);
+                                ublock[*scan++] = get_value(c, BINK_SRC_COLORS);
                         }
                     } while (i < 63);
                     if (i == 63)
-                        dst[coordmap[*scan++]] = get_value(c, BINK_SRC_COLORS);
-                    break;
-                case RESIDUE_BLOCK:
-                    xoff = get_value(c, BINK_SRC_X_OFF);
-                    yoff = get_value(c, BINK_SRC_Y_OFF);
-                    ref = prev + xoff + yoff * stride;
-                    if (ref < ref_start || ref > ref_end) {
-                        av_log(avctx, AV_LOG_ERROR, "Copy out of bounds @%d, %d\n",
-                               bx*8 + xoff, by*8 + yoff);
-                        return -1;
-                    }
-                    c->dsp.put_pixels_tab[1][0](dst, ref, stride, 8);
-                    c->dsp.clear_block(block);
-                    v = get_bits(&gb, 7);
-                    read_residue(&gb, block, v);
-                    c->dsp.add_pixels8(dst, block, stride);
+                        ublock[*scan++] = get_value(c, BINK_SRC_COLORS);
                     break;
                 case INTRA_BLOCK:
                     c->dsp.clear_block(block);
                     block[0] = get_value(c, BINK_SRC_INTRA_DC);
-                    read_dct_coeffs(&gb, block, c->scantable.permutated, 1);
-                    c->dsp.idct_put(dst, stride, block);
+                    read_dct_coeffs(gb, block, c->scantable.permutated, 1);
+                    c->dsp.idct(block);
+                    c->dsp.put_pixels_nonclamped(block, ublock, 8);
                     break;
                 case FILL_BLOCK:
                     v = get_value(c, BINK_SRC_COLORS);
-                    c->dsp.fill_block_tab[1](dst, v, stride, 8);
-                    break;
-                case INTER_BLOCK:
-                    xoff = get_value(c, BINK_SRC_X_OFF);
-                    yoff = get_value(c, BINK_SRC_Y_OFF);
-                    ref = prev + xoff + yoff * stride;
-                    c->dsp.put_pixels_tab[1][0](dst, ref, stride, 8);
-                    c->dsp.clear_block(block);
-                    block[0] = get_value(c, BINK_SRC_INTER_DC);
-                    read_dct_coeffs(&gb, block, c->scantable.permutated, 0);
-                    c->dsp.idct_add(dst, stride, block);
+                    c->dsp.fill_block_tab[0](dst, v, stride, 16);
                     break;
                 case PATTERN_BLOCK:
                     for (i = 0; i < 2; i++)
                         col[i] = get_value(c, BINK_SRC_COLORS);
-                    for (i = 0; i < 8; i++) {
+                    for (j = 0; j < 8; j++) {
                         v = get_value(c, BINK_SRC_PATTERN);
-                        for (j = 0; j < 8; j++, v >>= 1)
-                            dst[i*stride + j] = col[v & 1];
+                        for (i = 0; i < 8; i++, v >>= 1)
+                            ublock[i + j*8] = col[v & 1];
                     }
                     break;
                 case RAW_BLOCK:
-                    for (i = 0; i < 8; i++)
-                        memcpy(dst + i*stride, c->bundle[BINK_SRC_COLORS].cur_ptr + i*8, 8);
-                    c->bundle[BINK_SRC_COLORS].cur_ptr += 64;
+                    for (j = 0; j < 8; j++)
+                        for (i = 0; i < 8; i++)
+                            ublock[i + j*8] = get_value(c, BINK_SRC_COLORS);
                     break;
                 default:
-                    av_log(avctx, AV_LOG_ERROR, "Unknown block type %d\n", blk);
+                    av_log(c->avctx, AV_LOG_ERROR, "Incorrect 16x16 block type %d\n", blk);
                     return -1;
                 }
+                if (blk != FILL_BLOCK)
+                c->dsp.scale_block(ublock, dst, stride);
+                bx++;
+                dst  += 8;
+                prev += 8;
+                break;
+            case MOTION_BLOCK:
+                xoff = get_value(c, BINK_SRC_X_OFF);
+                yoff = get_value(c, BINK_SRC_Y_OFF);
+                ref = prev + xoff + yoff * stride;
+                if (ref < ref_start || ref > ref_end) {
+                    av_log(c->avctx, AV_LOG_ERROR, "Copy out of bounds @%d, %d\n",
+                           bx*8 + xoff, by*8 + yoff);
+                    return -1;
+                }
+                c->dsp.put_pixels_tab[1][0](dst, ref, stride, 8);
+                break;
+            case RUN_BLOCK:
+                scan = bink_patterns[get_bits(gb, 4)];
+                i = 0;
+                do {
+                    int run = get_value(c, BINK_SRC_RUN) + 1;
+
+                    i += run;
+                    if (i > 64) {
+                        av_log(c->avctx, AV_LOG_ERROR, "Run went out of bounds\n");
+                        return -1;
+                    }
+                    if (get_bits1(gb)) {
+                        v = get_value(c, BINK_SRC_COLORS);
+                        for (j = 0; j < run; j++)
+                            dst[coordmap[*scan++]] = v;
+                    } else {
+                        for (j = 0; j < run; j++)
+                            dst[coordmap[*scan++]] = get_value(c, BINK_SRC_COLORS);
+                    }
+                } while (i < 63);
+                if (i == 63)
+                    dst[coordmap[*scan++]] = get_value(c, BINK_SRC_COLORS);
+                break;
+            case RESIDUE_BLOCK:
+                xoff = get_value(c, BINK_SRC_X_OFF);
+                yoff = get_value(c, BINK_SRC_Y_OFF);
+                ref = prev + xoff + yoff * stride;
+                if (ref < ref_start || ref > ref_end) {
+                    av_log(c->avctx, AV_LOG_ERROR, "Copy out of bounds @%d, %d\n",
+                           bx*8 + xoff, by*8 + yoff);
+                    return -1;
+                }
+                c->dsp.put_pixels_tab[1][0](dst, ref, stride, 8);
+                c->dsp.clear_block(block);
+                v = get_bits(gb, 7);
+                read_residue(gb, block, v);
+                c->dsp.add_pixels8(dst, block, stride);
+                break;
+            case INTRA_BLOCK:
+                c->dsp.clear_block(block);
+                block[0] = get_value(c, BINK_SRC_INTRA_DC);
+                read_dct_coeffs(gb, block, c->scantable.permutated, 1);
+                c->dsp.idct_put(dst, stride, block);
+                break;
+            case FILL_BLOCK:
+                v = get_value(c, BINK_SRC_COLORS);
+                c->dsp.fill_block_tab[1](dst, v, stride, 8);
+                break;
+            case INTER_BLOCK:
+                xoff = get_value(c, BINK_SRC_X_OFF);
+                yoff = get_value(c, BINK_SRC_Y_OFF);
+                ref = prev + xoff + yoff * stride;
+                c->dsp.put_pixels_tab[1][0](dst, ref, stride, 8);
+                c->dsp.clear_block(block);
+                block[0] = get_value(c, BINK_SRC_INTER_DC);
+                read_dct_coeffs(gb, block, c->scantable.permutated, 0);
+                c->dsp.idct_add(dst, stride, block);
+                break;
+            case PATTERN_BLOCK:
+                for (i = 0; i < 2; i++)
+                    col[i] = get_value(c, BINK_SRC_COLORS);
+                for (i = 0; i < 8; i++) {
+                    v = get_value(c, BINK_SRC_PATTERN);
+                    for (j = 0; j < 8; j++, v >>= 1)
+                        dst[i*stride + j] = col[v & 1];
+                }
+                break;
+            case RAW_BLOCK:
+                for (i = 0; i < 8; i++)
+                    memcpy(dst + i*stride, c->bundle[BINK_SRC_COLORS].cur_ptr + i*8, 8);
+                c->bundle[BINK_SRC_COLORS].cur_ptr += 64;
+                break;
+            default:
+                av_log(c->avctx, AV_LOG_ERROR, "Unknown block type %d\n", blk);
+                return -1;
             }
         }
-        if (get_bits_count(&gb) & 0x1F) //next plane data starts at 32-bit boundary
-            skip_bits_long(&gb, 32 - (get_bits_count(&gb) & 0x1F));
+    }
+    if (get_bits_count(gb) & 0x1F) //next plane data starts at 32-bit boundary
+        skip_bits_long(gb, 32 - (get_bits_count(gb) & 0x1F));
+
+    return 0;
+}
+
+static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPacket *pkt)
+{
+    BinkContext * const c = avctx->priv_data;
+    GetBitContext gb;
+    int plane, plane_idx;
+    int bits_count = pkt->size << 3;
+
+    if(c->pic.data[0])
+        avctx->release_buffer(avctx, &c->pic);
+
+    if(avctx->get_buffer(avctx, &c->pic) < 0){
+        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+        return -1;
+    }
+
+    init_get_bits(&gb, pkt->data, bits_count);
+    if (c->has_alpha) {
+        if (c->version >= 'i')
+            skip_bits_long(&gb, 32);
+        if (bink_decode_plane(c, &gb, 3, 0) < 0)
+            return -1;
+    }
+    if (c->version >= 'i')
+        skip_bits_long(&gb, 32);
+
+    for (plane = 0; plane < 3; plane++) {
+        plane_idx = (!plane || !c->swap_planes) ? plane : (plane ^ 3);
+
+        if (bink_decode_plane(c, &gb, plane_idx, !!plane) < 0)
+            return -1;
+        if (get_bits_count(&gb) >= bits_count)
+            break;
     }
     emms_c();
 
@@ -918,13 +943,20 @@ static av_cold int decode_init(AVCodecContext *avctx)
     BinkContext * const c = avctx->priv_data;
     static VLC_TYPE table[16 * 128][2];
     int i;
+    int flags;
 
     c->version = avctx->codec_tag >> 24;
     if (c->version < 'c') {
         av_log(avctx, AV_LOG_ERROR, "Too old version '%c'\n", c->version);
         return -1;
     }
-    c->swap_planes = c->version >= 'i';
+    if (avctx->extradata_size < 4) {
+        av_log(avctx, AV_LOG_ERROR, "Extradata missing or too short\n");
+        return -1;
+    }
+    flags = AV_RL32(avctx->extradata);
+    c->has_alpha = flags & BINK_FLAG_ALPHA;
+    c->swap_planes = c->version >= 'h';
     if (!bink_trees[15].table) {
         for (i = 0; i < 16; i++) {
             const int maxbits = bink_tree_lens[i][15];
@@ -943,7 +975,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
         return 1;
     }
 
-    avctx->pix_fmt = PIX_FMT_YUV420P;
+    avctx->pix_fmt = c->has_alpha ? PIX_FMT_YUVA420P : PIX_FMT_YUV420P;
 
     avctx->idct_algo = FF_IDCT_BINK;
     dsputil_init(&c->dsp, avctx);