From 02fda253e165a733b03dba263b5043fdf11566b5 Mon Sep 17 00:00:00 2001 From: Zhao Zhili Date: Sat, 7 May 2022 10:54:57 +0800 Subject: [PATCH 1/2] dav1d: extract update format as a function --- modules/codec/dav1d.c | 47 ++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/modules/codec/dav1d.c b/modules/codec/dav1d.c index 12aebc36300..b3cd8eed02b 100644 --- a/modules/codec/dav1d.c +++ b/modules/codec/dav1d.c @@ -149,10 +149,8 @@ static void UpdateDecoderOutput(decoder_t *dec, const Dav1dSequenceHeader *seq_h } } -static int NewPicture(Dav1dPicture *img, void *cookie) +static int UpdateFormat(decoder_t *dec, Dav1dPicture *img) { - decoder_t *dec = cookie; - video_format_t *v = &dec->fmt_out.video; v->i_visible_width = img->p.w; @@ -195,24 +193,31 @@ static int NewPicture(Dav1dPicture *img, void *cookie) v->i_height = (img->p.h + 0x7F) & ~0x7F; v->i_chroma = dec->fmt_out.i_codec; - if (decoder_UpdateVideoFormat(dec) == 0) - { - picture_t *pic; - pic = decoder_NewPicture(dec); - if (unlikely(pic == NULL)) - return -1; - - img->data[0] = pic->p[0].p_pixels; - img->stride[0] = pic->p[0].i_pitch; - img->data[1] = pic->p[1].p_pixels; - img->data[2] = pic->p[2].p_pixels; - assert(pic->p[1].i_pitch == pic->p[2].i_pitch); - img->stride[1] = pic->p[1].i_pitch; - - img->allocator_data = pic; - return 0; - } - return -1; + return decoder_UpdateVideoFormat(dec); +} + +static int NewPicture(Dav1dPicture *img, void *cookie) +{ + decoder_t *dec = cookie; + + + if (UpdateFormat(dec, img)) + return -1; + + picture_t *pic; + pic = decoder_NewPicture(dec); + if (unlikely(pic == NULL)) + return -1; + + img->data[0] = pic->p[0].p_pixels; + img->stride[0] = pic->p[0].i_pitch; + img->data[1] = pic->p[1].p_pixels; + img->data[2] = pic->p[2].p_pixels; + assert(pic->p[1].i_pitch == pic->p[2].i_pitch); + img->stride[1] = pic->p[1].i_pitch; + + img->allocator_data = pic; + return 0; } static void ExtractCaptions(decoder_t *dec, const Dav1dPicture *img) -- GitLab From c0b7fbdb13dd2c66192fb48e5c076533100a4d1d Mon Sep 17 00:00:00 2001 From: Zhao Zhili Date: Sat, 7 May 2022 13:06:35 +0800 Subject: [PATCH 2/2] dav1d: fix decoder failed after seek decoder_NewPicture() can return NULL due to picture_pool_Cancel, which can happen when seek. With alloc_picture_callback, decoder_NewPicture() error leads to decoder failure. Let dav1d do picture buffer allocate, then we wrap Dav1dPicture inside picture_t. Fix #26915 --- modules/codec/dav1d.c | 84 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/modules/codec/dav1d.c b/modules/codec/dav1d.c index b3cd8eed02b..e13cebccc12 100644 --- a/modules/codec/dav1d.c +++ b/modules/codec/dav1d.c @@ -41,6 +41,11 @@ #include "../packetizer/av1_obu.h" #include "cc.h" +/* decoder_NewPicture() can return NULL due to picture_pool_Cancel. It leads + * to decoder error with alloc_picture_callback. + */ +#define USE_ALLOC_PICTURE_CALLBACK 0 + /**************************************************************************** * Local prototypes ****************************************************************************/ @@ -196,6 +201,7 @@ static int UpdateFormat(decoder_t *dec, Dav1dPicture *img) return decoder_UpdateVideoFormat(dec); } +#if USE_ALLOC_PICTURE_CALLBACK static int NewPicture(Dav1dPicture *img, void *cookie) { decoder_t *dec = cookie; @@ -220,6 +226,46 @@ static int NewPicture(Dav1dPicture *img, void *cookie) return 0; } +#else // USE_ALLOC_PICTURE_CALLBACK == 0 + +static void FreeDav1dPictureWrap(picture_t *pic) +{ + Dav1dPicture *img = pic->p_sys; + dav1d_picture_unref(img); + free(img); +} + +static picture_t *WrapDav1dPicture(decoder_t *dec, Dav1dPicture *img) +{ + picture_resource_t res = { + .p_sys = img, + .pf_destroy = FreeDav1dPictureWrap, + }; + + const video_format_t *fmt = &dec->fmt_out.video; + const vlc_chroma_description_t *des = + vlc_fourcc_GetChromaDescription(fmt->i_chroma); + + for (unsigned i = 0; i < des->plane_count; i++) + { + const vlc_rational_t *h = &des->p[i].h; + res.p[i].p_pixels = img->data[i]; + res.p[i].i_pitch = i ? img->stride[1] : img->stride[0]; + res.p[i].i_lines = fmt->i_height * h->num / h->den; + } + + picture_t *pic = picture_NewFromResource(fmt, &res); + if (pic == NULL) + { + dav1d_picture_unref(img); + return NULL; + } + pic->date = img->m.timestamp; + return pic; +} + +#endif + static void ExtractCaptions(decoder_t *dec, const Dav1dPicture *img) { decoder_sys_t *p_sys = dec->p_sys; @@ -252,6 +298,7 @@ static void ExtractCaptions(decoder_t *dec, const Dav1dPicture *img) } } +#if USE_ALLOC_PICTURE_CALLBACK static void FreePicture(Dav1dPicture *data, void *cookie) { picture_t *pic = data->allocator_data; @@ -259,6 +306,7 @@ static void FreePicture(Dav1dPicture *data, void *cookie) VLC_UNUSED(dec); picture_Release(pic); } +#endif /**************************************************************************** * Flush: clears decoder between seeks @@ -353,6 +401,7 @@ static int Decode(decoder_t *dec, block_t *block) do { Dav1dPicture img = { 0 }; +#if USE_ALLOC_PICTURE_CALLBACK res = dav1d_get_picture(p_sys->c, &img); if (res == 0) { @@ -370,6 +419,39 @@ static int Decode(decoder_t *dec, block_t *block) decoder_QueueVideo(dec, pic); ExtractCaptions(dec, &img); dav1d_picture_unref(&img); +#else + Dav1dPicture *p_img = malloc(sizeof(*p_img)); + if (unlikely(p_img == NULL)) + { + i_ret = VLC_ENOMEM; + b_output_error = true; + break; + } + *p_img = img; + res = dav1d_get_picture(p_sys->c, p_img); + if (res == 0) + { + if (UpdateFormat(dec, p_img)) + { + i_ret = VLC_EGENERIC; + b_output_error = true; + break; + } + + picture_t *pic = WrapDav1dPicture(dec, p_img); + if (unlikely(pic == NULL)) + { + i_ret = VLC_EGENERIC; + b_output_error = true; + break; + } + /* Prevent img being released by decoder_QueueVideo + * before ExtractCaptions. */ + picture_Hold(pic); + decoder_QueueVideo(dec, pic); + ExtractCaptions(dec, p_img); + picture_Release(pic); +#endif } else if (res != DAV1D_ERR(EAGAIN)) { @@ -445,9 +527,11 @@ static int OpenDecoder(vlc_object_t *p_this) if (p_sys->s.n_frame_threads == 0) p_sys->s.n_frame_threads = __MAX(1, vlc_GetCPUCount()); #endif +#if USE_ALLOC_PICTURE_CALLBACK p_sys->s.allocator.cookie = dec; p_sys->s.allocator.alloc_picture_callback = NewPicture; p_sys->s.allocator.release_picture_callback = FreePicture; +#endif av1_OBU_sequence_header_t *sequence_hdr = NULL; if (dec->fmt_in.i_extra > 4) -- GitLab