diff mbox

[FFmpeg-devel,2/4] avcodec/qtrle: return last frame even if unchanged

Message ID 20190530140400.6205-2-michael@niedermayer.cc
State New
Headers show

Commit Message

Michael Niedermayer May 30, 2019, 2:03 p.m. UTC
Fixes: Ticket7880

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
---
 libavcodec/qtrle.c        | 42 +++++++++++++++++++++++++++++++++++----
 tests/ref/fate/qtrle-8bit |  1 +
 2 files changed, 39 insertions(+), 4 deletions(-)

Comments

Marton Balint May 31, 2019, 8:28 p.m. UTC | #1
On Thu, 30 May 2019, Michael Niedermayer wrote:

> Fixes: Ticket7880
>
> Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
> ---
> libavcodec/qtrle.c        | 42 +++++++++++++++++++++++++++++++++++----
> tests/ref/fate/qtrle-8bit |  1 +
> 2 files changed, 39 insertions(+), 4 deletions(-)
>
> diff --git a/libavcodec/qtrle.c b/libavcodec/qtrle.c
> index 2c29547e5a..4add1aded6 100644
> --- a/libavcodec/qtrle.c
> +++ b/libavcodec/qtrle.c
> @@ -45,6 +45,8 @@ typedef struct QtrleContext {
>
>     GetByteContext g;
>     uint32_t pal[256];
> +    int need_flush;
> +    AVPacket flush_pkt;
> } QtrleContext;
> 
> #define CHECK_PIXEL_PTR(n)                                                            \
> @@ -444,6 +446,12 @@ static av_cold int qtrle_decode_init(AVCodecContext *avctx)
>     return 0;
> }
> 
> +static void qtrle_flush(AVCodecContext *avctx){
> +    QtrleContext *s = avctx->priv_data;
> +
> +    s->need_flush = 0;
> +}
> +
> static int qtrle_decode_frame(AVCodecContext *avctx,
>                               void *data, int *got_frame,
>                               AVPacket *avpkt)
> @@ -454,11 +462,32 @@ static int qtrle_decode_frame(AVCodecContext *avctx,
>     int has_palette = 0;
>     int ret, size;
> 
> +    if (!avpkt->data) {
> +        if (s->need_flush) {
> +            s->need_flush = 0;
> +            if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
> +                return ret;
> +            s->frame->pkt_pos      = s->flush_pkt.pos;
> +            s->frame->pkt_duration = s->flush_pkt.duration;
> +            s->frame->pkt_dts      = s->flush_pkt.dts;
> +            s->frame->pkt_pts      =
> +            s->frame->pts          = s->flush_pkt.pts;

This does not seem to work, because the magic in decode_simple_internal in 
decode.c will overwrite these fields. Alternative approach which seems to 
work is assigning the AVPacket fields instead:

             avpkt->pos      = s->flush_pkt.pos;
             avpkt->duration = s->flush_pkt.duration;
             avpkt->dts      = s->flush_pkt.dts;
             avpkt->pts      = s->flush_pkt.pts;

Looks a bit ugly, but as far as I see we are using an internal packet, 
and not the one provided by the user, so it might be OK.

Regards,
Marton
Michael Niedermayer Aug. 12, 2019, 7:12 p.m. UTC | #2
On Fri, May 31, 2019 at 10:28:15PM +0200, Marton Balint wrote:
> 
> 
> On Thu, 30 May 2019, Michael Niedermayer wrote:
> 
> >Fixes: Ticket7880
> >
> >Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
> >---
> >libavcodec/qtrle.c        | 42 +++++++++++++++++++++++++++++++++++----
> >tests/ref/fate/qtrle-8bit |  1 +
> >2 files changed, 39 insertions(+), 4 deletions(-)
> >
> >diff --git a/libavcodec/qtrle.c b/libavcodec/qtrle.c
> >index 2c29547e5a..4add1aded6 100644
> >--- a/libavcodec/qtrle.c
> >+++ b/libavcodec/qtrle.c
> >@@ -45,6 +45,8 @@ typedef struct QtrleContext {
> >
> >    GetByteContext g;
> >    uint32_t pal[256];
> >+    int need_flush;
> >+    AVPacket flush_pkt;
> >} QtrleContext;
> >
> >#define CHECK_PIXEL_PTR(n)                                                            \
> >@@ -444,6 +446,12 @@ static av_cold int qtrle_decode_init(AVCodecContext *avctx)
> >    return 0;
> >}
> >
> >+static void qtrle_flush(AVCodecContext *avctx){
> >+    QtrleContext *s = avctx->priv_data;
> >+
> >+    s->need_flush = 0;
> >+}
> >+
> >static int qtrle_decode_frame(AVCodecContext *avctx,
> >                              void *data, int *got_frame,
> >                              AVPacket *avpkt)
> >@@ -454,11 +462,32 @@ static int qtrle_decode_frame(AVCodecContext *avctx,
> >    int has_palette = 0;
> >    int ret, size;
> >
> >+    if (!avpkt->data) {
> >+        if (s->need_flush) {
> >+            s->need_flush = 0;
> >+            if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
> >+                return ret;
> >+            s->frame->pkt_pos      = s->flush_pkt.pos;
> >+            s->frame->pkt_duration = s->flush_pkt.duration;
> >+            s->frame->pkt_dts      = s->flush_pkt.dts;
> >+            s->frame->pkt_pts      =
> >+            s->frame->pts          = s->flush_pkt.pts;
> 
> This does not seem to work, because the magic in decode_simple_internal in
> decode.c will overwrite these fields. Alternative approach which seems to
> work is assigning the AVPacket fields instead:
> 
>             avpkt->pos      = s->flush_pkt.pos;
>             avpkt->duration = s->flush_pkt.duration;
>             avpkt->dts      = s->flush_pkt.dts;
>             avpkt->pts      = s->flush_pkt.pts;
> 
> Looks a bit ugly, but as far as I see we are using an internal packet, and
> not the one provided by the user, so it might be OK.

ill repost this with a different, less ugly variant. 

Please recheck if that works!

[...]
Marton Balint Aug. 12, 2019, 8:43 p.m. UTC | #3
On Mon, 12 Aug 2019, Michael Niedermayer wrote:

> On Fri, May 31, 2019 at 10:28:15PM +0200, Marton Balint wrote:
>>
>>
>> On Thu, 30 May 2019, Michael Niedermayer wrote:
>>
>>> Fixes: Ticket7880
>>>
>>> Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
>>> ---
>>> libavcodec/qtrle.c        | 42 +++++++++++++++++++++++++++++++++++----
>>> tests/ref/fate/qtrle-8bit |  1 +
>>> 2 files changed, 39 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/libavcodec/qtrle.c b/libavcodec/qtrle.c
>>> index 2c29547e5a..4add1aded6 100644
>>> --- a/libavcodec/qtrle.c
>>> +++ b/libavcodec/qtrle.c
>>> @@ -45,6 +45,8 @@ typedef struct QtrleContext {
>>>
>>>    GetByteContext g;
>>>    uint32_t pal[256];
>>> +    int need_flush;
>>> +    AVPacket flush_pkt;
>>> } QtrleContext;
>>>
>>> #define CHECK_PIXEL_PTR(n)                                                            \
>>> @@ -444,6 +446,12 @@ static av_cold int qtrle_decode_init(AVCodecContext *avctx)
>>>    return 0;
>>> }
>>>
>>> +static void qtrle_flush(AVCodecContext *avctx){
>>> +    QtrleContext *s = avctx->priv_data;
>>> +
>>> +    s->need_flush = 0;
>>> +}
>>> +
>>> static int qtrle_decode_frame(AVCodecContext *avctx,
>>>                              void *data, int *got_frame,
>>>                              AVPacket *avpkt)
>>> @@ -454,11 +462,32 @@ static int qtrle_decode_frame(AVCodecContext *avctx,
>>>    int has_palette = 0;
>>>    int ret, size;
>>>
>>> +    if (!avpkt->data) {
>>> +        if (s->need_flush) {
>>> +            s->need_flush = 0;
>>> +            if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
>>> +                return ret;
>>> +            s->frame->pkt_pos      = s->flush_pkt.pos;
>>> +            s->frame->pkt_duration = s->flush_pkt.duration;
>>> +            s->frame->pkt_dts      = s->flush_pkt.dts;
>>> +            s->frame->pkt_pts      =
>>> +            s->frame->pts          = s->flush_pkt.pts;
>>
>> This does not seem to work, because the magic in decode_simple_internal in
>> decode.c will overwrite these fields. Alternative approach which seems to
>> work is assigning the AVPacket fields instead:
>>
>>             avpkt->pos      = s->flush_pkt.pos;
>>             avpkt->duration = s->flush_pkt.duration;
>>             avpkt->dts      = s->flush_pkt.dts;
>>             avpkt->pts      = s->flush_pkt.pts;
>>
>> Looks a bit ugly, but as far as I see we are using an internal packet, and
>> not the one provided by the user, so it might be OK.
>
> ill repost this with a different, less ugly variant.
>
> Please recheck if that works!

Seems fine now, thanks.

Regards,
Marton
diff mbox

Patch

diff --git a/libavcodec/qtrle.c b/libavcodec/qtrle.c
index 2c29547e5a..4add1aded6 100644
--- a/libavcodec/qtrle.c
+++ b/libavcodec/qtrle.c
@@ -45,6 +45,8 @@  typedef struct QtrleContext {
 
     GetByteContext g;
     uint32_t pal[256];
+    int need_flush;
+    AVPacket flush_pkt;
 } QtrleContext;
 
 #define CHECK_PIXEL_PTR(n)                                                            \
@@ -444,6 +446,12 @@  static av_cold int qtrle_decode_init(AVCodecContext *avctx)
     return 0;
 }
 
+static void qtrle_flush(AVCodecContext *avctx){
+    QtrleContext *s = avctx->priv_data;
+
+    s->need_flush = 0;
+}
+
 static int qtrle_decode_frame(AVCodecContext *avctx,
                               void *data, int *got_frame,
                               AVPacket *avpkt)
@@ -454,11 +462,32 @@  static int qtrle_decode_frame(AVCodecContext *avctx,
     int has_palette = 0;
     int ret, size;
 
+    if (!avpkt->data) {
+        if (s->need_flush) {
+            s->need_flush = 0;
+            if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
+                return ret;
+            s->frame->pkt_pos      = s->flush_pkt.pos;
+            s->frame->pkt_duration = s->flush_pkt.duration;
+            s->frame->pkt_dts      = s->flush_pkt.dts;
+            s->frame->pkt_pts      =
+            s->frame->pts          = s->flush_pkt.pts;
+            if ((ret = av_frame_ref(data, s->frame)) < 0)
+                return ret;
+            *got_frame = 1;
+        }
+        return 0;
+    }
+    s->flush_pkt = *avpkt;
+
     bytestream2_init(&s->g, avpkt->data, avpkt->size);
 
     /* check if this frame is even supposed to change */
-    if (avpkt->size < 8)
+    if (avpkt->size < 8) {
+        s->need_flush = 1;
         return avpkt->size;
+    }
+    s->need_flush = 0;
 
     /* start after the chunk size */
     size = bytestream2_get_be32(&s->g) & 0x3FFFFFFF;
@@ -471,14 +500,18 @@  static int qtrle_decode_frame(AVCodecContext *avctx,
 
     /* if a header is present, fetch additional decoding parameters */
     if (header & 0x0008) {
-        if (avpkt->size < 14)
+        if (avpkt->size < 14) {
+            s->need_flush = 1;
             return avpkt->size;
+        }
         start_line = bytestream2_get_be16(&s->g);
         bytestream2_skip(&s->g, 2);
         height     = bytestream2_get_be16(&s->g);
         bytestream2_skip(&s->g, 2);
-        if (height > s->avctx->height - start_line)
+        if (height > s->avctx->height - start_line) {
+            s->need_flush = 1;
             return avpkt->size;
+        }
     } else {
         start_line = 0;
         height     = s->avctx->height;
@@ -572,5 +605,6 @@  AVCodec ff_qtrle_decoder = {
     .init           = qtrle_decode_init,
     .close          = qtrle_decode_end,
     .decode         = qtrle_decode_frame,
-    .capabilities   = AV_CODEC_CAP_DR1,
+    .flush          = qtrle_flush,
+    .capabilities   = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY,
 };
diff --git a/tests/ref/fate/qtrle-8bit b/tests/ref/fate/qtrle-8bit
index 27bb8aad71..39a03b7b6c 100644
--- a/tests/ref/fate/qtrle-8bit
+++ b/tests/ref/fate/qtrle-8bit
@@ -61,3 +61,4 @@ 
 0,        160,        160,        1,   921600, 0xcfd6ad2b
 0,        163,        163,        1,   921600, 0x3b372379
 0,        165,        165,        1,   921600, 0x36f245f5
+0,        166,        166,        1,   921600, 0x36f245f5