h264: update avctx width/height/pix_fmt when returning frame
authorAndreas Cadhalpun <Andreas.Cadhalpun@googlemail.com>
Tue, 9 Jun 2015 21:38:26 +0000 (23:38 +0200)
committerAndreas Cadhalpun <Andreas.Cadhalpun@googlemail.com>
Fri, 12 Jun 2015 19:22:00 +0000 (21:22 +0200)
Inconsistencies between the dimensions/pixel format of avctx and the
frame can confuse API users.
For example this can crash the demuxing_decoding example.

Back up the previous values and restore them, when decoding the next
frame. This is necessary, because these can be different between the
returned frame and the last decoded frame.

Reviewed-by: Michael Niedermayer <michaelni@gmx.at>
Signed-off-by: Andreas Cadhalpun <Andreas.Cadhalpun@googlemail.com>
libavcodec/h264.c
libavcodec/h264.h
libavcodec/h264_slice.c

index 9a002142ccf4942cfd8c9f76761fda9a82749d27..9be317c55fda7bc50cccc8993c5d0862fec5d721 100644 (file)
@@ -591,6 +591,9 @@ static int h264_init_context(AVCodecContext *avctx, H264Context *h)
     int i;
 
     h->avctx                 = avctx;
     int i;
 
     h->avctx                 = avctx;
+    h->backup_width          = -1;
+    h->backup_height         = -1;
+    h->backup_pix_fmt        = AV_PIX_FMT_NONE;
     h->dequant_coeff_pps     = -1;
     h->current_sps_id        = -1;
     h->cur_chroma_format_idc = -1;
     h->dequant_coeff_pps     = -1;
     h->current_sps_id        = -1;
     h->cur_chroma_format_idc = -1;
@@ -1675,6 +1678,14 @@ static int output_frame(H264Context *h, AVFrame *dst, H264Picture *srcp)
 
     av_dict_set(&dst->metadata, "stereo_mode", ff_h264_sei_stereo_mode(h), 0);
 
 
     av_dict_set(&dst->metadata, "stereo_mode", ff_h264_sei_stereo_mode(h), 0);
 
+    h->backup_width   = h->avctx->width;
+    h->backup_height  = h->avctx->height;
+    h->backup_pix_fmt = h->avctx->pix_fmt;
+
+    h->avctx->width   = dst->width;
+    h->avctx->height  = dst->height;
+    h->avctx->pix_fmt = dst->format;
+
     if (srcp->sei_recovery_frame_cnt == 0)
         dst->key_frame = 1;
     if (!srcp->crop)
     if (srcp->sei_recovery_frame_cnt == 0)
         dst->key_frame = 1;
     if (!srcp->crop)
@@ -1726,6 +1737,19 @@ static int h264_decode_frame(AVCodecContext *avctx, void *data,
 
     h->flags = avctx->flags;
 
 
     h->flags = avctx->flags;
 
+    if (h->backup_width != -1) {
+        avctx->width    = h->backup_width;
+        h->backup_width = -1;
+    }
+    if (h->backup_height != -1) {
+        avctx->height    = h->backup_height;
+        h->backup_height = -1;
+    }
+    if (h->backup_pix_fmt != AV_PIX_FMT_NONE) {
+        avctx->pix_fmt    = h->backup_pix_fmt;
+        h->backup_pix_fmt = AV_PIX_FMT_NONE;
+    }
+
     ff_h264_unref_picture(h, &h->last_pic_for_ec);
 
     /* end of stream, output what is still in the buffers */
     ff_h264_unref_picture(h, &h->last_pic_for_ec);
 
     /* end of stream, output what is still in the buffers */
index 95db912465b893dfa2299f0861a357308147c56f..548510d793016ea8939cbd058a54345cc4877c60 100644 (file)
@@ -519,6 +519,14 @@ typedef struct H264Context {
     int width, height;
     int chroma_x_shift, chroma_y_shift;
 
     int width, height;
     int chroma_x_shift, chroma_y_shift;
 
+    /**
+     * Backup frame properties: needed, because they can be different
+     * between returned frame and last decoded frame.
+     **/
+    int backup_width;
+    int backup_height;
+    enum AVPixelFormat backup_pix_fmt;
+
     int droppable;
     int coded_picture_number;
     int low_delay;
     int droppable;
     int coded_picture_number;
     int low_delay;
index 9c4d613195c4b4e6c259e5dd98281b01750e8c7f..0c0812f472ad69ee467e8d0d16c552ee19de49f2 100644 (file)
@@ -497,6 +497,9 @@ int ff_h264_update_thread_context(AVCodecContext *dst,
     h->picture_structure    = h1->picture_structure;
     h->droppable            = h1->droppable;
     h->low_delay            = h1->low_delay;
     h->picture_structure    = h1->picture_structure;
     h->droppable            = h1->droppable;
     h->low_delay            = h1->low_delay;
+    h->backup_width         = h1->backup_width;
+    h->backup_height        = h1->backup_height;
+    h->backup_pix_fmt       = h1->backup_pix_fmt;
 
     for (i = 0; i < H264_MAX_PICTURE_COUNT; i++) {
         ff_h264_unref_picture(h, &h->DPB[i]);
 
     for (i = 0; i < H264_MAX_PICTURE_COUNT; i++) {
         ff_h264_unref_picture(h, &h->DPB[i]);