]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/ffv1dec.c
lavc: support extracting audio service type from side data
[ffmpeg] / libavcodec / ffv1dec.c
index b1dec7de3f93b55ef66ed4dea7b04940ac7e297c..4349af571a5f9e64997b1209fecdd8810fd710b7 100644 (file)
 #include "libavutil/crc.h"
 #include "libavutil/opt.h"
 #include "libavutil/imgutils.h"
+#include "libavutil/timer.h"
 #include "avcodec.h"
 #include "internal.h"
 #include "get_bits.h"
 #include "put_bits.h"
-#include "dsputil.h"
 #include "rangecoder.h"
 #include "golomb.h"
 #include "mathops.h"
@@ -317,16 +317,24 @@ static int decode_slice_header(FFV1Context *f, FFV1Context *fs)
 
     ps = get_symbol(c, state, 0);
     if (ps == 1) {
-        f->picture.interlaced_frame = 1;
-        f->picture.top_field_first  = 1;
+        f->cur->interlaced_frame = 1;
+        f->cur->top_field_first  = 1;
     } else if (ps == 2) {
-        f->picture.interlaced_frame = 1;
-        f->picture.top_field_first  = 0;
+        f->cur->interlaced_frame = 1;
+        f->cur->top_field_first  = 0;
     } else if (ps == 3) {
-        f->picture.interlaced_frame = 0;
+        f->cur->interlaced_frame = 0;
+    }
+    f->cur->sample_aspect_ratio.num = get_symbol(c, state, 0);
+    f->cur->sample_aspect_ratio.den = get_symbol(c, state, 0);
+
+    if (av_image_check_sar(f->width, f->height,
+                           f->cur->sample_aspect_ratio) < 0) {
+        av_log(f->avctx, AV_LOG_WARNING, "ignoring invalid SAR: %u/%u\n",
+               f->cur->sample_aspect_ratio.num,
+               f->cur->sample_aspect_ratio.den);
+        f->cur->sample_aspect_ratio = (AVRational){ 0, 1 };
     }
-    f->picture.sample_aspect_ratio.num = get_symbol(c, state, 0);
-    f->picture.sample_aspect_ratio.den = get_symbol(c, state, 0);
 
     return 0;
 }
@@ -336,10 +344,10 @@ static int decode_slice(AVCodecContext *c, void *arg)
     FFV1Context *fs = *(void **)arg;
     FFV1Context *f  = fs->avctx->priv_data;
     int width, height, x, y, ret;
-    const int ps = (av_pix_fmt_desc_get(c->pix_fmt)->flags & PIX_FMT_PLANAR)
+    const int ps = (av_pix_fmt_desc_get(c->pix_fmt)->flags & AV_PIX_FMT_FLAG_PLANAR)
                    ? (c->bits_per_raw_sample > 8) + 1
                    : 4;
-    AVFrame *const p = &f->picture;
+    AVFrame *const p = f->cur;
 
     if (f->version > 2) {
         if (decode_slice_header(f, fs) < 0) {
@@ -349,7 +357,7 @@ static int decode_slice(AVCodecContext *c, void *arg)
     }
     if ((ret = ffv1_init_slice_state(f, fs)) < 0)
         return ret;
-    if (f->picture.key_frame)
+    if (f->cur->key_frame)
         ffv1_clear_slice_state(f, fs);
     width  = fs->slice_width;
     height = fs->slice_height;
@@ -542,6 +550,7 @@ static int read_header(FFV1Context *f)
     memset(state, 128, sizeof(state));
 
     if (f->version < 2) {
+        int chroma_planes, chroma_h_shift, chroma_v_shift, transparency, colorspace, bits_per_raw_sample;
         unsigned v = get_symbol(c, state, 0);
         if (v > 1) {
             av_log(f->avctx, AV_LOG_ERROR,
@@ -558,15 +567,32 @@ static int read_header(FFV1Context *f)
                     get_symbol(c, state, 1) + c->one_state[i];
         }
 
-        f->colorspace = get_symbol(c, state, 0); //YUV cs type
+        colorspace          = get_symbol(c, state, 0); //YUV cs type
+        bits_per_raw_sample = f->version > 0 ? get_symbol(c, state, 0) : f->avctx->bits_per_raw_sample;
+        chroma_planes       = get_rac(c, state);
+        chroma_h_shift      = get_symbol(c, state, 0);
+        chroma_v_shift      = get_symbol(c, state, 0);
+        transparency        = get_rac(c, state);
+
+        if (f->plane_count) {
+            if (colorspace          != f->colorspace                 ||
+                bits_per_raw_sample != f->avctx->bits_per_raw_sample ||
+                chroma_planes       != f->chroma_planes              ||
+                chroma_h_shift      != f->chroma_h_shift             ||
+                chroma_v_shift      != f->chroma_v_shift             ||
+                transparency        != f->transparency) {
+                av_log(f->avctx, AV_LOG_ERROR, "Invalid change of global parameters\n");
+                return AVERROR_INVALIDDATA;
+            }
+        }
 
-        if (f->version > 0)
-            f->avctx->bits_per_raw_sample = get_symbol(c, state, 0);
+        f->colorspace                 = colorspace;
+        f->avctx->bits_per_raw_sample = bits_per_raw_sample;
+        f->chroma_planes              = chroma_planes;
+        f->chroma_h_shift             = chroma_h_shift;
+        f->chroma_v_shift             = chroma_v_shift;
+        f->transparency               = transparency;
 
-        f->chroma_planes  = get_rac(c, state);
-        f->chroma_h_shift = get_symbol(c, state, 0);
-        f->chroma_v_shift = get_symbol(c, state, 0);
-        f->transparency   = get_rac(c, state);
         f->plane_count    = 2 + f->transparency;
     }
 
@@ -670,6 +696,7 @@ static int read_header(FFV1Context *f)
             return AVERROR(ENOSYS);
         }
         switch (f->avctx->bits_per_raw_sample) {
+        case 0:
         case 8:
             f->avctx->pix_fmt = AV_PIX_FMT_RGB32;
             break;
@@ -735,8 +762,8 @@ static int read_header(FFV1Context *f)
 
             fs->slice_x      /= f->num_h_slices;
             fs->slice_y      /= f->num_v_slices;
-            fs->slice_width  /= f->num_h_slices - fs->slice_x;
-            fs->slice_height /= f->num_v_slices - fs->slice_y;
+            fs->slice_width  = fs->slice_width  / f->num_h_slices - fs->slice_x;
+            fs->slice_height = fs->slice_height / f->num_v_slices - fs->slice_y;
             if ((unsigned)fs->slice_width > f->width ||
                 (unsigned)fs->slice_height > f->height)
                 return AVERROR_INVALIDDATA;
@@ -784,6 +811,10 @@ static av_cold int ffv1_decode_init(AVCodecContext *avctx)
 
     ffv1_common_init(avctx);
 
+    f->last_picture = av_frame_alloc();
+    if (!f->last_picture)
+        return AVERROR(ENOMEM);
+
     if (avctx->extradata && (ret = read_extra_header(f)) < 0)
         return ret;
 
@@ -796,20 +827,16 @@ static av_cold int ffv1_decode_init(AVCodecContext *avctx)
 static int ffv1_decode_frame(AVCodecContext *avctx, void *data,
                              int *got_frame, AVPacket *avpkt)
 {
-    const uint8_t *buf  = avpkt->data;
+    uint8_t *buf        = avpkt->data;
     int buf_size        = avpkt->size;
     FFV1Context *f      = avctx->priv_data;
     RangeCoder *const c = &f->slice_context[0]->c;
-    AVFrame *const p    = &f->picture;
     int i, ret;
     uint8_t keystate = 128;
-    const uint8_t *buf_p;
+    uint8_t *buf_p;
+    AVFrame *const p    = data;
 
-    AVFrame *picture = data;
-
-    /* release previously stored data */
-    if (p->data[0])
-        avctx->release_buffer(avctx, p);
+    f->cur = p;
 
     ff_init_range_decoder(c, buf, buf_size);
     ff_build_rac_states(c, 0.05 * (1LL << 32), 256 - 8);
@@ -824,14 +851,13 @@ static int ffv1_decode_frame(AVCodecContext *avctx, void *data,
     } else {
         if (!f->key_frame_ok) {
             av_log(avctx, AV_LOG_ERROR,
-                   "Cant decode non keyframe without valid keyframe\n");
+                   "Cannot decode non-keyframe without valid keyframe\n");
             return AVERROR_INVALIDDATA;
         }
         p->key_frame = 0;
     }
 
-    p->reference = 3; //for error concealment
-    if ((ret = ff_get_buffer(avctx, p)) < 0) {
+    if ((ret = ff_get_buffer(avctx, p, AV_GET_BUFFER_FLAG_REF)) < 0) {
         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
         return ret;
     }
@@ -869,7 +895,9 @@ static int ffv1_decode_frame(AVCodecContext *avctx, void *data,
         if (i) {
             ff_init_range_decoder(&fs->c, buf_p, v);
         } else
-            fs->c.bytestream_end = (uint8_t *)(buf_p + v);
+            fs->c.bytestream_end = buf_p + v;
+
+        fs->cur = p;
     }
 
     avctx->execute(avctx, decode_slice, &f->slice_context[0], NULL,
@@ -879,20 +907,20 @@ static int ffv1_decode_frame(AVCodecContext *avctx, void *data,
     for (i = f->slice_count - 1; i >= 0; i--) {
         FFV1Context *fs = f->slice_context[i];
         int j;
-        if (fs->slice_damaged && f->last_picture.data[0]) {
+        if (fs->slice_damaged && f->last_picture->data[0]) {
             const uint8_t *src[4];
             uint8_t *dst[4];
             for (j = 0; j < 4; j++) {
                 int sh = (j == 1 || j == 2) ? f->chroma_h_shift : 0;
                 int sv = (j == 1 || j == 2) ? f->chroma_v_shift : 0;
-                dst[j] = f->picture.data[j] + f->picture.linesize[j] *
+                dst[j] = p->data[j] + p->linesize[j] *
                          (fs->slice_y >> sv) + (fs->slice_x >> sh);
-                src[j] = f->last_picture.data[j] +
-                         f->last_picture.linesize[j] *
+                src[j] = f->last_picture->data[j] +
+                         f->last_picture->linesize[j] *
                          (fs->slice_y >> sv) + (fs->slice_x >> sh);
             }
-            av_image_copy(dst, f->picture.linesize, (const uint8_t **)src,
-                          f->last_picture.linesize,
+            av_image_copy(dst, p->linesize, src,
+                          f->last_picture->linesize,
                           avctx->pix_fmt, fs->slice_width,
                           fs->slice_height);
         }
@@ -900,23 +928,36 @@ static int ffv1_decode_frame(AVCodecContext *avctx, void *data,
 
     f->picture_number++;
 
-    *picture   = *p;
-    *got_frame = 1;
+    av_frame_unref(f->last_picture);
+    if ((ret = av_frame_ref(f->last_picture, p)) < 0)
+        return ret;
+    f->cur = NULL;
 
-    FFSWAP(AVFrame, f->picture, f->last_picture);
+    *got_frame = 1;
 
     return buf_size;
 }
 
+static av_cold int ffv1_decode_close(AVCodecContext *avctx)
+{
+    FFV1Context *s = avctx->priv_data;;
+
+    av_frame_free(&s->last_picture);
+
+    ffv1_close(avctx);
+
+    return 0;
+}
+
 AVCodec ff_ffv1_decoder = {
     .name           = "ffv1",
+    .long_name      = NULL_IF_CONFIG_SMALL("FFmpeg video codec #1"),
     .type           = AVMEDIA_TYPE_VIDEO,
     .id             = AV_CODEC_ID_FFV1,
     .priv_data_size = sizeof(FFV1Context),
     .init           = ffv1_decode_init,
-    .close          = ffv1_close,
+    .close          = ffv1_decode_close,
     .decode         = ffv1_decode_frame,
     .capabilities   = CODEC_CAP_DR1 /*| CODEC_CAP_DRAW_HORIZ_BAND*/ |
                       CODEC_CAP_SLICE_THREADS,
-    .long_name      = NULL_IF_CONFIG_SMALL("FFmpeg video codec #1"),
 };