On 10.06.2015 21:50, Michael Niedermayer wrote:
> On Wed, Jun 10, 2015 at 09:10:31PM +0200, Andreas Cadhalpun wrote:
>> On 10.06.2015 12:01, Michael Niedermayer wrote:
>>>> also avctx->pix_fmt would then still potentially not match the last
>>>> output frame, also pix_fmt has the same problem as above
>>
>> Yes, pix_fmt should also be updated. Attached patch does this, but
> 
>> this caused changes in some h264 reinit fate tests. Is that a problem?
> 
> looking at the testfile with ffplay shows heavy artifacts after the
> patch and no artifacts before

Yes, that's bad...

>>>> ive fixed one use of width/height not to depend on the AVCodecContext
>>>> value but a 2nd remains
>>>
>>> actually theres more code that uses it
>>> ff_h264_draw_horiz_band() and its callers use h->avctx->height too
>>
>> Could these be fixed to use a new H264Context field instead?
> 
> i think it might be possible for them to use the AVFrame height
> but the code should be tested

I tried a few things, but couldn't get it to work that way.
In the end I decided to work around the differing expectations of the h264
decoder and the API users by backing up and restoring the internally
used values. See attached patch.
I tested this extensively and it fixes the problem without introducing
another one as far as I can tell.
One can see the effect, when using -loglevel debug, e.g. for the
reinit-small_422_9-to-small_420_9.h264 sample:
 * Without the patch:
[...]
[h264 @ 0x196e320] Reinit context to 240x208, pix_fmt: yuv420p9le
Frame parameters mismatch context 240,196,80 != 240,196,70
    Last message repeated 1 times
Input stream #0:0 frame changed from size:240x196 fmt:yuv422p9le to 
size:240x196 fmt:yuv420p9le
[...]

 * With the patch:
[...]
[h264 @ 0x2707320] Reinit context to 240x208, pix_fmt: yuv420p9le
Input stream #0:0 frame changed from size:240x196 fmt:yuv422p9le to 
size:240x196 fmt:yuv420p9le
[...]

The messages about the parameter mismatch for the two frames disappear.

> especially with a file that uses croping and some application that
> uses these codepathes
> iam not sure this codepath works currently with files using croping
> and using the AVFrame height and if needed an adjusted pointer
> offset might fix that or might break it depending on what applications
> expect

I don't know, whether or not this currently works, but it shouldn't
be affected by attached patch.

Best regards,
Andreas
>From 61f8aad99f05173a15ec28802ee8c92439bb2b0c Mon Sep 17 00:00:00 2001
From: Andreas Cadhalpun <andreas.cadhal...@googlemail.com>
Date: Tue, 9 Jun 2015 23:38:26 +0200
Subject: [PATCH] h264: update avctx width/height/pix_fmt when returning frame

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.

Signed-off-by: Andreas Cadhalpun <andreas.cadhal...@googlemail.com>
---
 libavcodec/h264.c       | 24 ++++++++++++++++++++++++
 libavcodec/h264.h       |  8 ++++++++
 libavcodec/h264_slice.c |  3 +++
 3 files changed, 35 insertions(+)

diff --git a/libavcodec/h264.c b/libavcodec/h264.c
index 9a00214..9be317c 100644
--- a/libavcodec/h264.c
+++ b/libavcodec/h264.c
@@ -591,6 +591,9 @@ static int h264_init_context(AVCodecContext *avctx, H264Context *h)
     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;
@@ -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);
 
+    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)
@@ -1726,6 +1737,19 @@ static int h264_decode_frame(AVCodecContext *avctx, void *data,
 
     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 */
diff --git a/libavcodec/h264.h b/libavcodec/h264.h
index 95db912..548510d 100644
--- a/libavcodec/h264.h
+++ b/libavcodec/h264.h
@@ -519,6 +519,14 @@ typedef struct H264Context {
     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;
diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
index 9c4d613..0c0812f 100644
--- a/libavcodec/h264_slice.c
+++ b/libavcodec/h264_slice.c
@@ -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->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]);
-- 
2.1.4

_______________________________________________
libav-devel mailing list
libav-devel@libav.org
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to