mp_image: add Dolby Vision metadata mapping

Remove side-loading metadata in vo_gpu_next.c and remove unneded
side-data duplication.
This commit is contained in:
Kacper Michajłow 2024-02-11 00:52:49 +01:00 committed by Dudemanguy
parent 05c8d5a93a
commit d9c1e9bc5c
6 changed files with 50 additions and 42 deletions

View File

@ -23,6 +23,8 @@
#include <libavutil/rational.h>
#include <libavutil/buffer.h>
#include <libavutil/frame.h>
#include <libplacebo/utils/libav.h>
#include "common/msg.h"
#include "common/common.h"
@ -109,6 +111,16 @@ static void set_params(struct vf_format_opts *p, struct mp_image_params *out,
mp_image_params_set_dsize(out, dsize.num, dsize.den);
}
static inline void *get_side_data(const struct mp_image *mpi,
enum AVFrameSideDataType type)
{
for (int i = 0; i < mpi->num_ff_side_data; i++) {
if (mpi->ff_side_data[i].type == type)
return (void *)mpi->ff_side_data[i].buf->data;
}
return NULL;
}
static void vf_format_process(struct mp_filter *f)
{
struct priv *priv = f->priv;
@ -155,8 +167,15 @@ static void vf_format_process(struct mp_filter *f)
}
if (!priv->opts->dovi) {
av_buffer_unref(&img->dovi);
av_buffer_unref(&img->dovi_buf);
if (img->params.repr.sys == PL_COLOR_SYSTEM_DOLBYVISION)
img->params.repr.sys = PL_COLOR_SYSTEM_BT_2020_NC;
// Map again to strip any DV metadata set to common fields.
img->params.color.hdr = (struct pl_hdr_metadata){0};
pl_map_hdr_metadata(&img->params.color.hdr, &(struct pl_av_hdr_metadata) {
.mdm = get_side_data(img, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA),
.clm = get_side_data(img, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL),
.dhp = get_side_data(img, AV_FRAME_DATA_DYNAMIC_HDR_PLUS),
});
}
if (!priv->opts->film_grain)

View File

@ -209,7 +209,6 @@ static void mp_image_destructor(void *ptr)
av_buffer_unref(&mpi->a53_cc);
av_buffer_unref(&mpi->dovi);
av_buffer_unref(&mpi->film_grain);
av_buffer_unref(&mpi->dovi_buf);
for (int n = 0; n < mpi->num_ff_side_data; n++)
av_buffer_unref(&mpi->ff_side_data[n].buf);
talloc_free(mpi->ff_side_data);
@ -344,7 +343,6 @@ struct mp_image *mp_image_new_ref(struct mp_image *img)
ref_buffer(&new->a53_cc);
ref_buffer(&new->dovi);
ref_buffer(&new->film_grain);
ref_buffer(&new->dovi_buf);
new->ff_side_data = talloc_memdup(NULL, new->ff_side_data,
new->num_ff_side_data * sizeof(new->ff_side_data[0]));
@ -382,7 +380,6 @@ struct mp_image *mp_image_new_dummy_ref(struct mp_image *img)
new->a53_cc = NULL;
new->dovi = NULL;
new->film_grain = NULL;
new->dovi_buf = NULL;
new->num_ff_side_data = 0;
new->ff_side_data = NULL;
return new;
@ -542,7 +539,6 @@ void mp_image_copy_attributes(struct mp_image *dst, struct mp_image *src)
}
assign_bufref(&dst->icc_profile, src->icc_profile);
assign_bufref(&dst->dovi, src->dovi);
assign_bufref(&dst->dovi_buf, src->dovi_buf);
assign_bufref(&dst->film_grain, src->film_grain);
assign_bufref(&dst->a53_cc, src->a53_cc);
@ -1093,14 +1089,38 @@ struct mp_image *mp_image_from_av_frame(struct AVFrame *src)
if (sd)
dst->a53_cc = sd->buf;
AVBufferRef *dovi = NULL;
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 16, 100)
sd = av_frame_get_side_data(src, AV_FRAME_DATA_DOVI_METADATA);
if (sd)
dst->dovi = sd->buf;
if (sd) {
#ifdef PL_HAVE_LAV_DOLBY_VISION
const AVDOVIMetadata *metadata = (const AVDOVIMetadata *)sd->buf->data;
const AVDOVIRpuDataHeader *header = av_dovi_get_header(metadata);
if (header->disable_residual_flag) {
dst->dovi = dovi = av_buffer_alloc(sizeof(struct pl_dovi_metadata));
MP_HANDLE_OOM(dovi);
#if PL_API_VER >= 343
pl_map_avdovi_metadata(&dst->params.color, &dst->params.repr,
(void *)dst->dovi->data, metadata);
#else
struct pl_frame frame;
frame.repr = dst->params.repr;
frame.color = dst->params.color;
pl_frame_map_avdovi_metadata(&frame, (void *)dst->dovi->data, metadata);
dst->params.repr = frame.repr;
dst->params.color = frame.color;
#endif
}
#endif
}
sd = av_frame_get_side_data(src, AV_FRAME_DATA_DOVI_RPU_BUFFER);
if (sd)
dst->dovi_buf = sd->buf;
if (sd) {
#ifdef PL_HAVE_LIBDOVI
pl_hdr_metadata_from_dovi_rpu(&dst->params.color.hdr, sd->buf->data,
sd->buf->size);
#endif
}
#endif
sd = av_frame_get_side_data(src, AV_FRAME_DATA_FILM_GRAIN_PARAMS);
@ -1125,6 +1145,7 @@ struct mp_image *mp_image_from_av_frame(struct AVFrame *src)
// Allocated, but non-refcounted data.
talloc_free(dst->ff_side_data);
av_buffer_unref(&dovi);
return res;
}

View File

@ -116,8 +116,6 @@ typedef struct mp_image {
struct AVBufferRef *dovi;
// Film grain data, if any
struct AVBufferRef *film_grain;
// Dolby Vision RPU buffer, if any
struct AVBufferRef *dovi_buf;
// Other side data we don't care about.
struct mp_ff_side_data *ff_side_data;
int num_ff_side_data;

View File

@ -71,27 +71,3 @@ void mppl_log_set_probing(pl_log log, bool probing)
params.log_cb = probing ? log_cb_probing : log_cb;
pl_log_update(log, &params);
}
void mp_map_dovi_metadata_to_pl(struct mp_image *mpi,
struct pl_frame *frame)
{
#ifdef PL_HAVE_LAV_DOLBY_VISION
if (mpi->dovi) {
const AVDOVIMetadata *metadata = (AVDOVIMetadata *) mpi->dovi->data;
const AVDOVIRpuDataHeader *header = av_dovi_get_header(metadata);
if (header->disable_residual_flag) {
// Only automatically map DoVi RPUs that don't require an EL
struct pl_dovi_metadata *dovi = talloc_ptrtype(mpi, dovi);
pl_frame_map_avdovi_metadata(frame, dovi, metadata);
}
}
#if defined(PL_HAVE_LIBDOVI)
if (mpi->dovi_buf)
pl_hdr_metadata_from_dovi_rpu(&frame->color.hdr, mpi->dovi_buf->data,
mpi->dovi_buf->size);
#endif
#endif // PL_HAVE_LAV_DOLBY_VISION
}

View File

@ -26,6 +26,3 @@ static inline struct pl_rect2d mp_rect2d_to_pl(struct mp_rect rc)
.y1 = rc.y1,
};
}
void mp_map_dovi_metadata_to_pl(struct mp_image *mpi,
struct pl_frame *frame);

View File

@ -705,9 +705,6 @@ static bool map_frame(pl_gpu gpu, pl_tex *tex, const struct pl_source_frame *src
// Update chroma location, must be done after initializing planes
pl_frame_set_chroma_location(frame, par->chroma_location);
// Set the frame DOVI metadata
mp_map_dovi_metadata_to_pl(mpi, frame);
if (mpi->film_grain)
pl_film_grain_from_av(&frame->film_grain, (AVFilmGrainParams *) mpi->film_grain->data);