diff mbox series

[FFmpeg-devel] avcodec/libdav1d: parse sequence headers in extradata if available

Message ID 20210709145301.3715-1-jamrial@gmail.com
State Accepted
Headers show
Series [FFmpeg-devel] avcodec/libdav1d: parse sequence headers in extradata if available | expand

Checks

Context Check Description
andriy/x86_make success Make finished
andriy/x86_make_fate success Make fate finished
andriy/PPC64_make success Make finished
andriy/PPC64_make_fate success Make fate finished

Commit Message

James Almer July 9, 2021, 2:53 p.m. UTC
This allows the decoder context to be initialized with all stream parameters
before a packet is parsed.

Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavcodec/libdav1d.c | 45 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

Comments

Derek Buitenhuis July 11, 2021, 11:40 a.m. UTC | #1
On 7/9/2021 3:53 PM, James Almer wrote:
> +    res = dav1d_parse_sequence_header(&seq, c->extradata + offset,
> +                                      c->extradata_size  - offset);
> +    if (res < 0) {
> +        av_log(c, explode ? AV_LOG_ERROR : AV_LOG_INFO,
> +               "Error decoding extradata\n");
> +        return explode ? AVERROR_INVALIDDATA : 0;
> +    }
> +

I don't think it is a good idea to fail like this, even in explode
mode.

Both the AV1-in-ISOBMFF and AV1-in-Matroska specs do specify that
the sequence header OBU must be first if there is one in the
configOBUs, however, they do not require on actually be present.

For example, configOBUs may contain a single metadata OBU, and
nothing else - and it would be entirely valid - so failing here
would actually be wrong, even in explode mode. This can happen,
if, for example, you have a file with HDR metadata in the av1c box,
but in-band sequence headers.

- Derek
James Almer July 11, 2021, 1:07 p.m. UTC | #2
On 7/11/2021 8:40 AM, Derek Buitenhuis wrote:
> On 7/9/2021 3:53 PM, James Almer wrote:
>> +    res = dav1d_parse_sequence_header(&seq, c->extradata + offset,
>> +                                      c->extradata_size  - offset);
>> +    if (res < 0) {
>> +        av_log(c, explode ? AV_LOG_ERROR : AV_LOG_INFO,
>> +               "Error decoding extradata\n");
>> +        return explode ? AVERROR_INVALIDDATA : 0;
>> +    }
>> +
> 
> I don't think it is a good idea to fail like this, even in explode
> mode.
> 
> Both the AV1-in-ISOBMFF and AV1-in-Matroska specs do specify that
> the sequence header OBU must be first if there is one in the
> configOBUs, however, they do not require on actually be present.
> 
> For example, configOBUs may contain a single metadata OBU, and
> nothing else - and it would be entirely valid - so failing here
> would actually be wrong, even in explode mode. This can happen,
> if, for example, you have a file with HDR metadata in the av1c box,
> but in-band sequence headers.

I can amend this patch locally to check for DAV1D_ERR(ENOENT), which was 
implemented to signal "No seqhdr is present", and return 0 in that case, 
but it's a very recent addition, so older libdav1d builds will never 
emit that error code.

Guess just returning 0 on all scenarios here until we increase the 
minimum required library version is better, so I'll do that.

> 
> - Derek
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
>
diff mbox series

Patch

diff --git a/libavcodec/libdav1d.c b/libavcodec/libdav1d.c
index c39df418d5..8132ff1593 100644
--- a/libavcodec/libdav1d.c
+++ b/libavcodec/libdav1d.c
@@ -158,6 +158,47 @@  static void libdav1d_init_params(AVCodecContext *c, const Dav1dSequenceHeader *s
     }
 }
 
+static av_cold int libdav1d_parse_extradata(AVCodecContext *c)
+{
+    Dav1dSequenceHeader seq;
+    size_t offset = 0;
+    int res, explode = !!(c->err_recognition & AV_EF_EXPLODE);
+
+    if (!c->extradata || c->extradata_size <= 0)
+        return 0;
+
+    if (c->extradata[0] & 0x80) {
+        int version = c->extradata[0] & 0x7F;
+
+        if (version != 1 || c->extradata_size < 4) {
+            av_log(c, explode ? AV_LOG_ERROR : AV_LOG_INFO,
+                   "Error decoding extradata\n");
+            return explode ? AVERROR_INVALIDDATA : 0;
+        }
+
+        // Do nothing if there are no configOBUs to parse
+        if (c->extradata_size == 4)
+            return 0;
+
+        offset = 4;
+    }
+
+    res = dav1d_parse_sequence_header(&seq, c->extradata + offset,
+                                      c->extradata_size  - offset);
+    if (res < 0) {
+        av_log(c, explode ? AV_LOG_ERROR : AV_LOG_INFO,
+               "Error decoding extradata\n");
+        return explode ? AVERROR_INVALIDDATA : 0;
+    }
+
+    libdav1d_init_params(c, &seq);
+    res = ff_set_dimensions(c, seq.max_width, seq.max_height);
+    if (res < 0)
+        return res;
+
+    return 0;
+}
+
 static av_cold int libdav1d_init(AVCodecContext *c)
 {
     Libdav1dContext *dav1d = c->priv_data;
@@ -192,6 +233,10 @@  static av_cold int libdav1d_init(AVCodecContext *c)
     av_log(c, AV_LOG_DEBUG, "Using %d frame threads, %d tile threads\n",
            s.n_frame_threads, s.n_tile_threads);
 
+    res = libdav1d_parse_extradata(c);
+    if (res < 0)
+        return res;
+
     res = dav1d_open(&dav1d->c, &s);
     if (res < 0)
         return AVERROR(ENOMEM);