diff mbox series

[FFmpeg-devel,1/2] avcodec/libdav1d: try to set decoder context parameters during init()

Message ID 20200511142756.1868-1-jamrial@gmail.com
State New
Headers show
Series [FFmpeg-devel,1/2] avcodec/libdav1d: try to set decoder context parameters during init()
Related show

Checks

Context Check Description
andriy/default pending
andriy/make success Make finished
andriy/make_fate success Make fate finished

Commit Message

James Almer May 11, 2020, 2:27 p.m. UTC
If extradata is available, use it to initialize the AVCodecContext before
packet data is seen. Also, don't constantly overwrite it after it's set.

Signed-off-by: James Almer <jamrial@gmail.com>
---
The main benefit from this is using ff_decode_frame_props() to fill frame
props, which includes copying any relevant side data that may be present in
packets, like for example container mastering metadata propagated by a demuxer.

 libavcodec/libdav1d.c | 102 +++++++++++++++++++++++++++++-------------
 1 file changed, 71 insertions(+), 31 deletions(-)

Comments

Anton Khirnov May 18, 2020, 2:43 p.m. UTC | #1
Quoting James Almer (2020-05-11 16:27:55)
> If extradata is available, use it to initialize the AVCodecContext before
> packet data is seen. Also, don't constantly overwrite it after it's set.
> 
> Signed-off-by: James Almer <jamrial@gmail.com>
> ---
> The main benefit from this is using ff_decode_frame_props() to fill frame
> props, which includes copying any relevant side data that may be present in
> packets, like for example container mastering metadata propagated by a demuxer.
> 
>  libavcodec/libdav1d.c | 102 +++++++++++++++++++++++++++++-------------
>  1 file changed, 71 insertions(+), 31 deletions(-)
> 
> diff --git a/libavcodec/libdav1d.c b/libavcodec/libdav1d.c
> index 5248e3f9f5..72f06c550e 100644
> --- a/libavcodec/libdav1d.c
> +++ b/libavcodec/libdav1d.c
> @@ -42,6 +42,8 @@ typedef struct Libdav1dContext {
>      int apply_grain;
>      int operating_point;
>      int all_layers;
> +
> +    int inited;
>  } Libdav1dContext;
>  
>  static const enum AVPixelFormat pix_fmt[][3] = {
> @@ -117,9 +119,59 @@ static void libdav1d_picture_release(Dav1dPicture *p, void *cookie)
>      av_buffer_unref(&buf);
>  }
>  
> +static int libdav1d_init_params(AVCodecContext *c, Dav1dSequenceHeader *seq)
> +{
> +    Libdav1dContext *dav1d = c->priv_data;
> +    int res;
> +
> +    if (dav1d->inited)
> +        return 0;

Changing parameters mid-stream is not supported?
James Almer May 18, 2020, 2:58 p.m. UTC | #2
On 5/18/2020 11:43 AM, Anton Khirnov wrote:
> Quoting James Almer (2020-05-11 16:27:55)
>> If extradata is available, use it to initialize the AVCodecContext before
>> packet data is seen. Also, don't constantly overwrite it after it's set.
>>
>> Signed-off-by: James Almer <jamrial@gmail.com>
>> ---
>> The main benefit from this is using ff_decode_frame_props() to fill frame
>> props, which includes copying any relevant side data that may be present in
>> packets, like for example container mastering metadata propagated by a demuxer.
>>
>>  libavcodec/libdav1d.c | 102 +++++++++++++++++++++++++++++-------------
>>  1 file changed, 71 insertions(+), 31 deletions(-)
>>
>> diff --git a/libavcodec/libdav1d.c b/libavcodec/libdav1d.c
>> index 5248e3f9f5..72f06c550e 100644
>> --- a/libavcodec/libdav1d.c
>> +++ b/libavcodec/libdav1d.c
>> @@ -42,6 +42,8 @@ typedef struct Libdav1dContext {
>>      int apply_grain;
>>      int operating_point;
>>      int all_layers;
>> +
>> +    int inited;
>>  } Libdav1dContext;
>>  
>>  static const enum AVPixelFormat pix_fmt[][3] = {
>> @@ -117,9 +119,59 @@ static void libdav1d_picture_release(Dav1dPicture *p, void *cookie)
>>      av_buffer_unref(&buf);
>>  }
>>  
>> +static int libdav1d_init_params(AVCodecContext *c, Dav1dSequenceHeader *seq)
>> +{
>> +    Libdav1dContext *dav1d = c->priv_data;
>> +    int res;
>> +
>> +    if (dav1d->inited)
>> +        return 0;
> 
> Changing parameters mid-stream is not supported?

Sequence Headers are not meant to change within a video sequence. Afaik,
the only params that can change between frames are its dimensions, and
that's already handled by looking at the values on a given Dav1dPicture.
But libdav1d does seem to gracefully handle changes in seq headers by
assuming it's a new sequence and resetting its internal state, so i
guess I'll remove it.
diff mbox series

Patch

diff --git a/libavcodec/libdav1d.c b/libavcodec/libdav1d.c
index 5248e3f9f5..72f06c550e 100644
--- a/libavcodec/libdav1d.c
+++ b/libavcodec/libdav1d.c
@@ -42,6 +42,8 @@  typedef struct Libdav1dContext {
     int apply_grain;
     int operating_point;
     int all_layers;
+
+    int inited;
 } Libdav1dContext;
 
 static const enum AVPixelFormat pix_fmt[][3] = {
@@ -117,9 +119,59 @@  static void libdav1d_picture_release(Dav1dPicture *p, void *cookie)
     av_buffer_unref(&buf);
 }
 
+static int libdav1d_init_params(AVCodecContext *c, Dav1dSequenceHeader *seq)
+{
+    Libdav1dContext *dav1d = c->priv_data;
+    int res;
+
+    if (dav1d->inited)
+        return 0;
+
+    c->profile = seq->profile;
+    c->level = ((seq->operating_points[0].major_level - 2) << 2)
+               | seq->operating_points[0].minor_level;
+
+    res = ff_set_dimensions(c, seq->max_width, seq->max_height);
+    if (res < 0)
+        return res;
+
+    switch (seq->chr) {
+    case DAV1D_CHR_VERTICAL:
+        c->chroma_sample_location = AVCHROMA_LOC_LEFT;
+        break;
+    case DAV1D_CHR_COLOCATED:
+        c->chroma_sample_location = AVCHROMA_LOC_TOPLEFT;
+        break;
+    }
+    c->colorspace = (enum AVColorSpace) seq->mtrx;
+    c->color_primaries = (enum AVColorPrimaries) seq->pri;
+    c->color_trc = (enum AVColorTransferCharacteristic) seq->trc;
+    c->color_range = seq->color_range ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG;
+
+    if (seq->layout == DAV1D_PIXEL_LAYOUT_I444 &&
+        seq->mtrx == DAV1D_MC_IDENTITY &&
+        seq->pri  == DAV1D_COLOR_PRI_BT709 &&
+        seq->trc  == DAV1D_TRC_SRGB)
+        c->pix_fmt = pix_fmt_rgb[seq->hbd];
+    else
+        c->pix_fmt = pix_fmt[seq->layout][seq->hbd];
+
+    if (seq->num_units_in_tick && seq->time_scale) {
+        av_reduce(&c->framerate.den, &c->framerate.num,
+                  seq->num_units_in_tick, seq->time_scale, INT_MAX);
+        if (seq->equal_picture_interval)
+            c->ticks_per_frame = seq->num_ticks_per_picture;
+    }
+
+    dav1d->inited = 1;
+
+    return 0;
+}
+
 static av_cold int libdav1d_init(AVCodecContext *c)
 {
     Libdav1dContext *dav1d = c->priv_data;
+    Dav1dSequenceHeader seq;
     Dav1dSettings s;
     int threads = (c->thread_count ? c->thread_count : av_cpu_count()) * 3 / 2;
     int res;
@@ -153,6 +205,16 @@  static av_cold int libdav1d_init(AVCodecContext *c)
     if (res < 0)
         return AVERROR(ENOMEM);
 
+    if (c->extradata && c->extradata_size) {
+        res = dav1d_parse_sequence_header(&seq, c->extradata, c->extradata_size);
+        if (res < 0)
+            return AVERROR_INVALIDDATA;
+
+        res = libdav1d_init_params(c, &seq);
+        if (res < 0)
+            return res;
+    }
+
     return 0;
 }
 
@@ -162,6 +224,7 @@  static void libdav1d_flush(AVCodecContext *c)
 
     dav1d_data_unref(&dav1d->data);
     dav1d_flush(dav1d->c);
+    dav1d->inited = 0;
 }
 
 static void libdav1d_data_free(const uint8_t *data, void *opaque) {
@@ -256,9 +319,14 @@  static int libdav1d_receive_frame(AVCodecContext *c, AVFrame *frame)
     frame->linesize[1] = p->stride[1];
     frame->linesize[2] = p->stride[1];
 
-    c->profile = p->seq_hdr->profile;
-    c->level = ((p->seq_hdr->operating_points[0].major_level - 2) << 2)
-               | p->seq_hdr->operating_points[0].minor_level;
+    res = libdav1d_init_params(c, p->seq_hdr);
+    if (res < 0)
+        return res;
+
+    res = ff_decode_frame_props(c, frame);
+    if (res < 0)
+        return res;
+
     frame->width = p->p.w;
     frame->height = p->p.h;
     if (c->width != p->p.w || c->height != p->p.h) {
@@ -267,39 +335,11 @@  static int libdav1d_receive_frame(AVCodecContext *c, AVFrame *frame)
             goto fail;
     }
 
-    switch (p->seq_hdr->chr) {
-    case DAV1D_CHR_VERTICAL:
-        frame->chroma_location = c->chroma_sample_location = AVCHROMA_LOC_LEFT;
-        break;
-    case DAV1D_CHR_COLOCATED:
-        frame->chroma_location = c->chroma_sample_location = AVCHROMA_LOC_TOPLEFT;
-        break;
-    }
-    frame->colorspace = c->colorspace = (enum AVColorSpace) p->seq_hdr->mtrx;
-    frame->color_primaries = c->color_primaries = (enum AVColorPrimaries) p->seq_hdr->pri;
-    frame->color_trc = c->color_trc = (enum AVColorTransferCharacteristic) p->seq_hdr->trc;
-    frame->color_range = c->color_range = p->seq_hdr->color_range ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG;
-
-    if (p->p.layout == DAV1D_PIXEL_LAYOUT_I444 &&
-        p->seq_hdr->mtrx == DAV1D_MC_IDENTITY &&
-        p->seq_hdr->pri  == DAV1D_COLOR_PRI_BT709 &&
-        p->seq_hdr->trc  == DAV1D_TRC_SRGB)
-        frame->format = c->pix_fmt = pix_fmt_rgb[p->seq_hdr->hbd];
-    else
-        frame->format = c->pix_fmt = pix_fmt[p->p.layout][p->seq_hdr->hbd];
-
     if (p->m.user_data.data)
         memcpy(&frame->reordered_opaque, p->m.user_data.data, sizeof(frame->reordered_opaque));
     else
         frame->reordered_opaque = AV_NOPTS_VALUE;
 
-    if (p->seq_hdr->num_units_in_tick && p->seq_hdr->time_scale) {
-        av_reduce(&c->framerate.den, &c->framerate.num,
-                  p->seq_hdr->num_units_in_tick, p->seq_hdr->time_scale, INT_MAX);
-        if (p->seq_hdr->equal_picture_interval)
-            c->ticks_per_frame = p->seq_hdr->num_ticks_per_picture;
-    }
-
     // match timestamps and packet size
     frame->pts = frame->best_effort_timestamp = p->m.timestamp;
 #if FF_API_PKT_PTS