[FFmpeg-devel] [PATCH 6/6 v2] avcodec/hevcdec: export global side data in AVCodecContext
James Almer
jamrial at gmail.com
Mon Mar 25 22:06:02 EET 2024
Signed-off-by: James Almer <jamrial at gmail.com>
---
libavcodec/avcodec.h | 2 +-
libavcodec/h2645_sei.c | 217 ++++++++++++++++++++++---------------
libavcodec/h2645_sei.h | 2 +
libavcodec/hevcdec.c | 4 +
libavcodec/pthread_frame.c | 10 ++
5 files changed, 146 insertions(+), 89 deletions(-)
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 83dc487251..968009a192 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -2071,7 +2071,7 @@ typedef struct AVCodecContext {
* - encoding: may be set by user before calling avcodec_open2() for
* encoder configuration. Afterwards owned and freed by the
* encoder.
- * - decoding: unused
+ * - decoding: may be set by libavcodec in avcodec_open2().
*/
AVFrameSideData **decoded_side_data;
int nb_decoded_side_data;
diff --git a/libavcodec/h2645_sei.c b/libavcodec/h2645_sei.c
index a9f4e01de8..7c11d7e449 100644
--- a/libavcodec/h2645_sei.c
+++ b/libavcodec/h2645_sei.c
@@ -529,6 +529,124 @@ static int is_frame_packing_type_valid(SEIFpaType type, enum AVCodecID codec_id)
type >= SEI_FPA_TYPE_SIDE_BY_SIDE;
}
+static int h2645_sei_to_side_data(AVCodecContext *avctx, H2645SEI *sei,
+ AVFrameSideData ***sd, int *nb_sd)
+{
+ int ret;
+
+ for (unsigned i = 0; i < sei->unregistered.nb_buf_ref; i++) {
+ H2645SEIUnregistered *unreg = &sei->unregistered;
+ AVBufferRef *buf;
+
+ if (!unreg->buf_ref[i])
+ continue;
+
+ buf = av_buffer_ref(unreg->buf_ref[i]);
+ if (!buf)
+ return AVERROR(ENOMEM);
+
+ if (!av_frame_side_data_add(sd, nb_sd, AV_FRAME_DATA_SEI_UNREGISTERED, &buf, 0)) {
+ av_buffer_unref(&buf);
+ return AVERROR(ENOMEM);
+ }
+ }
+
+ if (sei->ambient_viewing_environment.present) {
+ H2645SEIAmbientViewingEnvironment *env =
+ &sei->ambient_viewing_environment;
+ AVBufferRef *buf;
+ size_t size;
+
+ AVAmbientViewingEnvironment *dst_env =
+ av_ambient_viewing_environment_alloc(&size);
+ if (!dst_env)
+ return AVERROR(ENOMEM);
+
+ buf = av_buffer_create((uint8_t *)dst_env, size, NULL, NULL, 0);
+ if (!buf) {
+ av_free(dst_env);
+ return AVERROR(ENOMEM);
+ }
+
+ ret = ff_frame_new_side_data_from_buf(avctx, sd, nb_sd,
+ AV_FRAME_DATA_AMBIENT_VIEWING_ENVIRONMENT, &buf);
+
+ if (ret < 0)
+ return ret;
+
+ dst_env->ambient_illuminance = av_make_q(env->ambient_illuminance, 10000);
+ dst_env->ambient_light_x = av_make_q(env->ambient_light_x, 50000);
+ dst_env->ambient_light_y = av_make_q(env->ambient_light_y, 50000);
+ }
+
+ if (sei->mastering_display.present) {
+ // HEVC uses a g,b,r ordering, which we convert to a more natural r,g,b
+ const int mapping[3] = {2, 0, 1};
+ const int chroma_den = 50000;
+ const int luma_den = 10000;
+ int i;
+ AVMasteringDisplayMetadata *metadata;
+
+ ret = ff_decode_mastering_display_new(avctx, sd, nb_sd, &metadata);
+ if (ret < 0)
+ return ret;
+
+ if (metadata) {
+ for (i = 0; i < 3; i++) {
+ const int j = mapping[i];
+ metadata->display_primaries[i][0].num = sei->mastering_display.display_primaries[j][0];
+ metadata->display_primaries[i][0].den = chroma_den;
+ metadata->display_primaries[i][1].num = sei->mastering_display.display_primaries[j][1];
+ metadata->display_primaries[i][1].den = chroma_den;
+ }
+ metadata->white_point[0].num = sei->mastering_display.white_point[0];
+ metadata->white_point[0].den = chroma_den;
+ metadata->white_point[1].num = sei->mastering_display.white_point[1];
+ metadata->white_point[1].den = chroma_den;
+
+ metadata->max_luminance.num = sei->mastering_display.max_luminance;
+ metadata->max_luminance.den = luma_den;
+ metadata->min_luminance.num = sei->mastering_display.min_luminance;
+ metadata->min_luminance.den = luma_den;
+ metadata->has_luminance = 1;
+ metadata->has_primaries = 1;
+
+ av_log(avctx, AV_LOG_DEBUG, "Mastering Display Metadata:\n");
+ av_log(avctx, AV_LOG_DEBUG,
+ "r(%5.4f,%5.4f) g(%5.4f,%5.4f) b(%5.4f %5.4f) wp(%5.4f, %5.4f)\n",
+ av_q2d(metadata->display_primaries[0][0]),
+ av_q2d(metadata->display_primaries[0][1]),
+ av_q2d(metadata->display_primaries[1][0]),
+ av_q2d(metadata->display_primaries[1][1]),
+ av_q2d(metadata->display_primaries[2][0]),
+ av_q2d(metadata->display_primaries[2][1]),
+ av_q2d(metadata->white_point[0]), av_q2d(metadata->white_point[1]));
+ av_log(avctx, AV_LOG_DEBUG,
+ "min_luminance=%f, max_luminance=%f\n",
+ av_q2d(metadata->min_luminance), av_q2d(metadata->max_luminance));
+ }
+ }
+
+ if (sei->content_light.present) {
+ AVContentLightMetadata *metadata;
+
+ ret = ff_decode_content_light_new(avctx, sd, nb_sd, &metadata);
+ if (ret < 0)
+ return ret;
+
+ if (metadata) {
+ metadata->MaxCLL = sei->content_light.max_content_light_level;
+ metadata->MaxFALL = sei->content_light.max_pic_average_light_level;
+
+ av_log(avctx, AV_LOG_DEBUG, "Content Light Level Metadata:\n");
+ av_log(avctx, AV_LOG_DEBUG, "MaxCLL=%d, MaxFALL=%d\n",
+ metadata->MaxCLL, metadata->MaxFALL);
+ }
+ }
+
+ return 0;
+}
+
int ff_h2645_sei_to_frame(AVFrame *frame, H2645SEI *sei,
enum AVCodecID codec_id,
AVCodecContext *avctx, const H2645VUI *vui,
@@ -625,17 +743,13 @@ int ff_h2645_sei_to_frame(AVFrame *frame, H2645SEI *sei,
avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS;
}
+ ret = h2645_sei_to_side_data(avctx, sei, &frame->side_data, &frame->nb_side_data);
+ if (ret < 0)
+ return ret;
+
for (unsigned i = 0; i < sei->unregistered.nb_buf_ref; i++) {
H2645SEIUnregistered *unreg = &sei->unregistered;
-
- if (unreg->buf_ref[i]) {
- AVFrameSideData *sd = av_frame_new_side_data_from_buf(frame,
- AV_FRAME_DATA_SEI_UNREGISTERED,
- unreg->buf_ref[i]);
- if (!sd)
- av_buffer_unref(&unreg->buf_ref[i]);
- unreg->buf_ref[i] = NULL;
- }
+ av_buffer_unref(&unreg->buf_ref[i]);
}
sei->unregistered.nb_buf_ref = 0;
@@ -728,88 +842,15 @@ FF_ENABLE_DEPRECATION_WARNINGS
return ret;
#endif
- if (sei->ambient_viewing_environment.present) {
- H2645SEIAmbientViewingEnvironment *env =
- &sei->ambient_viewing_environment;
-
- AVAmbientViewingEnvironment *dst_env =
- av_ambient_viewing_environment_create_side_data(frame);
- if (!dst_env)
- return AVERROR(ENOMEM);
-
- dst_env->ambient_illuminance = av_make_q(env->ambient_illuminance, 10000);
- dst_env->ambient_light_x = av_make_q(env->ambient_light_x, 50000);
- dst_env->ambient_light_y = av_make_q(env->ambient_light_y, 50000);
- }
-
- if (sei->mastering_display.present) {
- // HEVC uses a g,b,r ordering, which we convert to a more natural r,g,b
- const int mapping[3] = {2, 0, 1};
- const int chroma_den = 50000;
- const int luma_den = 10000;
- int i;
- AVMasteringDisplayMetadata *metadata;
-
- ret = ff_decode_mastering_display_new(avctx, &frame->side_data, &frame->nb_side_data, &metadata);
- if (ret < 0)
- return ret;
-
- if (metadata) {
- for (i = 0; i < 3; i++) {
- const int j = mapping[i];
- metadata->display_primaries[i][0].num = sei->mastering_display.display_primaries[j][0];
- metadata->display_primaries[i][0].den = chroma_den;
- metadata->display_primaries[i][1].num = sei->mastering_display.display_primaries[j][1];
- metadata->display_primaries[i][1].den = chroma_den;
- }
- metadata->white_point[0].num = sei->mastering_display.white_point[0];
- metadata->white_point[0].den = chroma_den;
- metadata->white_point[1].num = sei->mastering_display.white_point[1];
- metadata->white_point[1].den = chroma_den;
-
- metadata->max_luminance.num = sei->mastering_display.max_luminance;
- metadata->max_luminance.den = luma_den;
- metadata->min_luminance.num = sei->mastering_display.min_luminance;
- metadata->min_luminance.den = luma_den;
- metadata->has_luminance = 1;
- metadata->has_primaries = 1;
-
- av_log(avctx, AV_LOG_DEBUG, "Mastering Display Metadata:\n");
- av_log(avctx, AV_LOG_DEBUG,
- "r(%5.4f,%5.4f) g(%5.4f,%5.4f) b(%5.4f %5.4f) wp(%5.4f, %5.4f)\n",
- av_q2d(metadata->display_primaries[0][0]),
- av_q2d(metadata->display_primaries[0][1]),
- av_q2d(metadata->display_primaries[1][0]),
- av_q2d(metadata->display_primaries[1][1]),
- av_q2d(metadata->display_primaries[2][0]),
- av_q2d(metadata->display_primaries[2][1]),
- av_q2d(metadata->white_point[0]), av_q2d(metadata->white_point[1]));
- av_log(avctx, AV_LOG_DEBUG,
- "min_luminance=%f, max_luminance=%f\n",
- av_q2d(metadata->min_luminance), av_q2d(metadata->max_luminance));
- }
- }
-
- if (sei->content_light.present) {
- AVContentLightMetadata *metadata;
-
- ret = ff_decode_content_light_new(avctx, &frame->side_data, &frame->nb_side_data, &metadata);
- if (ret < 0)
- return ret;
-
- if (metadata) {
- metadata->MaxCLL = sei->content_light.max_content_light_level;
- metadata->MaxFALL = sei->content_light.max_pic_average_light_level;
-
- av_log(avctx, AV_LOG_DEBUG, "Content Light Level Metadata:\n");
- av_log(avctx, AV_LOG_DEBUG, "MaxCLL=%d, MaxFALL=%d\n",
- metadata->MaxCLL, metadata->MaxFALL);
- }
- }
-
return 0;
}
+int ff_h2645_sei_to_context(AVCodecContext *avctx, H2645SEI *sei)
+{
+ return h2645_sei_to_side_data(avctx, sei, &avctx->decoded_side_data,
+ &avctx->nb_decoded_side_data);
+}
+
void ff_h2645_sei_reset(H2645SEI *s)
{
av_buffer_unref(&s->a53_caption.buf_ref);
diff --git a/libavcodec/h2645_sei.h b/libavcodec/h2645_sei.h
index b9a6c7587b..488dbcad7e 100644
--- a/libavcodec/h2645_sei.h
+++ b/libavcodec/h2645_sei.h
@@ -168,4 +168,6 @@ int ff_h2645_sei_to_frame(AVFrame *frame, H2645SEI *sei,
unsigned bit_depth_luma, unsigned bit_depth_chroma,
int seed);
+int ff_h2645_sei_to_context(AVCodecContext *avctx, H2645SEI *sei);
+
#endif /* AVCODEC_H2645_SEI_H */
diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c
index d744e6f598..70d22e5976 100644
--- a/libavcodec/hevcdec.c
+++ b/libavcodec/hevcdec.c
@@ -3658,6 +3658,10 @@ static av_cold int hevc_decode_init(AVCodecContext *avctx)
if (ret < 0) {
return ret;
}
+
+ ret = ff_h2645_sei_to_context(avctx, &s->sei.common);
+ if (ret < 0)
+ return ret;
}
sd = ff_get_coded_side_data(avctx, AV_PKT_DATA_DOVI_CONF);
diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
index fd356bd190..bbf8a546dc 100644
--- a/libavcodec/pthread_frame.c
+++ b/libavcodec/pthread_frame.c
@@ -334,6 +334,14 @@ FF_ENABLE_DEPRECATION_WARNINGS
if (for_user) {
if (codec->update_thread_context_for_user)
err = codec->update_thread_context_for_user(dst, src);
+
+ av_frame_side_data_free(&dst->decoded_side_data, &dst->nb_decoded_side_data);
+ for (int i = 0; i < src->nb_decoded_side_data; i++) {
+ int ret = av_frame_side_data_clone(&dst->decoded_side_data, &dst->nb_decoded_side_data,
+ src->decoded_side_data[i], AV_FRAME_SIDE_DATA_FLAG_UNIQUE);
+ if (ret < 0)
+ return ret;
+ }
} else {
const PerThreadContext *p_src = src->internal->thread_ctx;
PerThreadContext *p_dst = dst->internal->thread_ctx;
@@ -767,6 +775,8 @@ static av_cold int init_thread(PerThreadContext *p, int *threads_to_free,
if (!copy)
return AVERROR(ENOMEM);
copy->priv_data = NULL;
+ copy->decoded_side_data = NULL;
+ copy->nb_decoded_side_data = 0;
/* From now on, this PerThreadContext will be cleaned up by
* ff_frame_thread_free in case of errors. */
--
2.44.0
More information about the ffmpeg-devel
mailing list