* [FFmpeg-devel] [PATCH 02/10] avcodec/dovi_rpu: store entire config record
2024-04-03 15:43 [FFmpeg-devel] [PATCH 01/10] avcodec: add dolbyvision option Niklas Haas
@ 2024-04-03 15:43 ` Niklas Haas
2024-04-03 15:43 ` [FFmpeg-devel] [PATCH 03/10] avcodec/dovi_rpu: properly replace context header Niklas Haas
` (9 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Niklas Haas @ 2024-04-03 15:43 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Niklas Haas
From: Niklas Haas <git@haasn.dev>
And make it public.
For encoding, users may also be interested in the configured level and
compatibility ID. So generalize the dv_profile field and just expose the
whole configuration record.
This makes the already rather reductive ff_dovi_update_cfg() function
almost wholly redundant, since users can just directly assign
DOVIContext.cfg.
---
libavcodec/av1dec.c | 6 +++---
libavcodec/dovi_rpu.c | 16 ++++------------
libavcodec/dovi_rpu.h | 21 ++++++++++++---------
libavcodec/hevcdec.c | 13 ++++++-------
libavcodec/libdav1d.c | 6 +++---
5 files changed, 28 insertions(+), 34 deletions(-)
diff --git a/libavcodec/av1dec.c b/libavcodec/av1dec.c
index 824725c031f..4c1405df779 100644
--- a/libavcodec/av1dec.c
+++ b/libavcodec/av1dec.c
@@ -888,10 +888,10 @@ static av_cold int av1_decode_init(AVCodecContext *avctx)
}
s->dovi.logctx = avctx;
- s->dovi.dv_profile = 10; // default for AV1
+ s->dovi.cfg.dv_profile = 10; // default for AV1
sd = ff_get_coded_side_data(avctx, AV_PKT_DATA_DOVI_CONF);
- if (sd && sd->size > 0)
- ff_dovi_update_cfg(&s->dovi, (AVDOVIDecoderConfigurationRecord *) sd->data);
+ if (sd && sd->size >= sizeof(s->dovi.cfg))
+ s->dovi.cfg = *(AVDOVIDecoderConfigurationRecord *) sd->data;
return ret;
}
diff --git a/libavcodec/dovi_rpu.c b/libavcodec/dovi_rpu.c
index 9f7a6b00664..d95c7e03af9 100644
--- a/libavcodec/dovi_rpu.c
+++ b/libavcodec/dovi_rpu.c
@@ -64,7 +64,7 @@ void ff_dovi_ctx_flush(DOVIContext *s)
*s = (DOVIContext) {
.logctx = s->logctx,
- .dv_profile = s->dv_profile,
+ .cfg = s->cfg,
/* preserve temporary buffer */
.rpu_buf = s->rpu_buf,
.rpu_buf_sz = s->rpu_buf_sz,
@@ -74,22 +74,14 @@ void ff_dovi_ctx_flush(DOVIContext *s)
void ff_dovi_ctx_replace(DOVIContext *s, const DOVIContext *s0)
{
s->logctx = s0->logctx;
+ s->cfg = s0->cfg;
s->mapping = s0->mapping;
s->color = s0->color;
- s->dv_profile = s0->dv_profile;
for (int i = 0; i <= DOVI_MAX_DM_ID; i++)
ff_refstruct_replace(&s->vdr[i], s0->vdr[i]);
ff_refstruct_replace(&s->ext_blocks, s0->ext_blocks);
}
-void ff_dovi_update_cfg(DOVIContext *s, const AVDOVIDecoderConfigurationRecord *cfg)
-{
- if (!cfg)
- return;
-
- s->dv_profile = cfg->dv_profile;
-}
-
int ff_dovi_attach_side_data(DOVIContext *s, AVFrame *frame)
{
AVFrameSideData *sd;
@@ -392,7 +384,7 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size,
goto fail;
/* Container */
- if (s->dv_profile == 10 /* dav1.10 */) {
+ if (s->cfg.dv_profile == 10 /* dav1.10 */) {
/* DV inside AV1 re-uses an EMDF container skeleton, but with fixed
* values - so we can effectively treat this as a magic byte sequence.
*
@@ -517,7 +509,7 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size,
use_prev_vdr_rpu = get_bits1(gb);
use_nlq = (hdr->rpu_format & 0x700) == 0 && !hdr->disable_residual_flag;
- profile = s->dv_profile ? s->dv_profile : guess_profile(hdr);
+ profile = s->cfg.dv_profile ? s->cfg.dv_profile : guess_profile(hdr);
if (profile == 5 && use_nlq) {
av_log(s->logctx, AV_LOG_ERROR, "Profile 5 RPUs should not use NLQ\n");
goto fail;
diff --git a/libavcodec/dovi_rpu.h b/libavcodec/dovi_rpu.h
index 9f26f332ceb..9a68e45bf1b 100644
--- a/libavcodec/dovi_rpu.h
+++ b/libavcodec/dovi_rpu.h
@@ -31,6 +31,16 @@
typedef struct DOVIContext {
void *logctx;
+ /**
+ * Currently active dolby vision configuration, or {0} for none.
+ * Set by the user when decoding.
+ *
+ * Note: sizeof(cfg) is not part of the libavutil ABI, so users should
+ * never pass &cfg to any other library calls. This is included merely as
+ * a way to look up the values of fields known at compile time.
+ */
+ AVDOVIDecoderConfigurationRecord cfg;
+
/**
* Currently active RPU data header, updates on every dovi_rpu_parse().
*/
@@ -56,7 +66,6 @@ typedef struct DOVIContext {
struct DOVIVdr *vdr[DOVI_MAX_DM_ID+1]; ///< RefStruct references
uint8_t *rpu_buf; ///< temporary buffer
unsigned rpu_buf_sz;
- uint8_t dv_profile;
} DOVIContext;
@@ -68,17 +77,11 @@ void ff_dovi_ctx_replace(DOVIContext *s, const DOVIContext *s0);
void ff_dovi_ctx_unref(DOVIContext *s);
/**
- * Partially reset the internal state. Resets per-frame state while preserving
- * fields parsed from the configuration record.
+ * Partially reset the internal state. Resets per-frame state, but preserves
+ * the stream-wide configuration record.
*/
void ff_dovi_ctx_flush(DOVIContext *s);
-/**
- * Read the contents of an AVDOVIDecoderConfigurationRecord (usually provided
- * by stream side data) and update internal state accordingly.
- */
-void ff_dovi_update_cfg(DOVIContext *s, const AVDOVIDecoderConfigurationRecord *cfg);
-
/**
* Parse the contents of a Dovi RPU NAL and update the parsed values in the
* DOVIContext struct.
diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c
index 727b02f0f40..4bc9e2afc1d 100644
--- a/libavcodec/hevcdec.c
+++ b/libavcodec/hevcdec.c
@@ -3364,14 +3364,13 @@ static int hevc_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
}
sd = av_packet_get_side_data(avpkt, AV_PKT_DATA_DOVI_CONF, &sd_size);
- if (sd && sd_size > 0) {
- int old = s->dovi_ctx.dv_profile;
-
- ff_dovi_update_cfg(&s->dovi_ctx, (AVDOVIDecoderConfigurationRecord *) sd);
+ if (sd && sd_size >= sizeof(s->dovi_ctx.cfg)) {
+ int old = s->dovi_ctx.cfg.dv_profile;
+ s->dovi_ctx.cfg = *(AVDOVIDecoderConfigurationRecord *) sd;
if (old)
av_log(avctx, AV_LOG_DEBUG,
"New DOVI configuration record from input packet (profile %d -> %u).\n",
- old, s->dovi_ctx.dv_profile);
+ old, s->dovi_ctx.cfg.dv_profile);
}
s->ref = s->collocated_ref = NULL;
@@ -3661,8 +3660,8 @@ static av_cold int hevc_decode_init(AVCodecContext *avctx)
}
sd = ff_get_coded_side_data(avctx, AV_PKT_DATA_DOVI_CONF);
- if (sd && sd->size > 0)
- ff_dovi_update_cfg(&s->dovi_ctx, (AVDOVIDecoderConfigurationRecord *) sd->data);
+ if (sd && sd->size >= sizeof(s->dovi_ctx.cfg))
+ s->dovi_ctx.cfg = *(AVDOVIDecoderConfigurationRecord *) sd->data;
}
return 0;
diff --git a/libavcodec/libdav1d.c b/libavcodec/libdav1d.c
index f022a4ad05c..a2f44c65e34 100644
--- a/libavcodec/libdav1d.c
+++ b/libavcodec/libdav1d.c
@@ -290,10 +290,10 @@ static av_cold int libdav1d_init(AVCodecContext *c)
#endif
dav1d->dovi.logctx = c;
- dav1d->dovi.dv_profile = 10; // default for AV1
+ dav1d->dovi.cfg.dv_profile = 10; // default for AV1
sd = ff_get_coded_side_data(c, AV_PKT_DATA_DOVI_CONF);
- if (sd && sd->size > 0)
- ff_dovi_update_cfg(&dav1d->dovi, (AVDOVIDecoderConfigurationRecord *) sd->data);
+ if (sd && sd->size >= sizeof(dav1d->dovi.cfg))
+ dav1d->dovi.cfg = *(AVDOVIDecoderConfigurationRecord *) sd->data;
return 0;
}
--
2.44.0
_______________________________________________
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".
^ permalink raw reply [flat|nested] 12+ messages in thread
* [FFmpeg-devel] [PATCH 03/10] avcodec/dovi_rpu: properly replace context header
2024-04-03 15:43 [FFmpeg-devel] [PATCH 01/10] avcodec: add dolbyvision option Niklas Haas
2024-04-03 15:43 ` [FFmpeg-devel] [PATCH 02/10] avcodec/dovi_rpu: store entire config record Niklas Haas
@ 2024-04-03 15:43 ` Niklas Haas
2024-04-03 15:43 ` [FFmpeg-devel] [PATCH 04/10] avcodec/dovi_rpu: clarify error on missing RPU VDR Niklas Haas
` (8 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Niklas Haas @ 2024-04-03 15:43 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Niklas Haas
From: Niklas Haas <git@haasn.dev>
This was never set in ff_dovi_ctx_replace(), leading to possibly
out-of-date when copying from a sub-thread to the main thread.
---
libavcodec/dovi_rpu.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/libavcodec/dovi_rpu.c b/libavcodec/dovi_rpu.c
index d95c7e03af9..bfb7b9fe661 100644
--- a/libavcodec/dovi_rpu.c
+++ b/libavcodec/dovi_rpu.c
@@ -75,6 +75,7 @@ void ff_dovi_ctx_replace(DOVIContext *s, const DOVIContext *s0)
{
s->logctx = s0->logctx;
s->cfg = s0->cfg;
+ s->header = s0->header;
s->mapping = s0->mapping;
s->color = s0->color;
for (int i = 0; i <= DOVI_MAX_DM_ID; i++)
--
2.44.0
_______________________________________________
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".
^ permalink raw reply [flat|nested] 12+ messages in thread
* [FFmpeg-devel] [PATCH 04/10] avcodec/dovi_rpu: clarify error on missing RPU VDR
2024-04-03 15:43 [FFmpeg-devel] [PATCH 01/10] avcodec: add dolbyvision option Niklas Haas
2024-04-03 15:43 ` [FFmpeg-devel] [PATCH 02/10] avcodec/dovi_rpu: store entire config record Niklas Haas
2024-04-03 15:43 ` [FFmpeg-devel] [PATCH 03/10] avcodec/dovi_rpu: properly replace context header Niklas Haas
@ 2024-04-03 15:43 ` Niklas Haas
2024-04-03 15:43 ` [FFmpeg-devel] [PATCH 05/10] avcodec/dovi_rpu: clarify semantics of guess_profile() Niklas Haas
` (7 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Niklas Haas @ 2024-04-03 15:43 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Niklas Haas
From: Niklas Haas <git@haasn.dev>
The code was written under the misguided assumption that these fields
would only be present when the value changes, however this does not
match the actual patent specification, which says that streams are
required to either always signal this metadata, or never signal it.
That said, the specification does not really clarify what the defaults
of these fields should be in the event that this metadata is missing, so
without any sample file or other reference I don't wish to hazard
a guess at how to interpret these fields.
Fix the current behavior by making sure we always throw this error, even
for files that have the vdr sequence info in one frame but are missing
it in the next frame.
---
libavcodec/dovi_rpu.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/libavcodec/dovi_rpu.c b/libavcodec/dovi_rpu.c
index bfb7b9fe661..267e52ceb66 100644
--- a/libavcodec/dovi_rpu.c
+++ b/libavcodec/dovi_rpu.c
@@ -499,11 +499,11 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size,
hdr->el_spatial_resampling_filter_flag = get_bits1(gb);
hdr->disable_residual_flag = get_bits1(gb);
}
- }
-
- if (!hdr->bl_bit_depth) {
- av_log(s->logctx, AV_LOG_ERROR, "Missing RPU VDR sequence info?\n");
- goto fail;
+ } else {
+ /* lack of documentation/samples */
+ avpriv_request_sample(s->logctx, "Missing RPU VDR sequence info\n");
+ ff_dovi_ctx_unref(s);
+ return AVERROR_PATCHWELCOME;
}
vdr_dm_metadata_present = get_bits1(gb);
--
2.44.0
_______________________________________________
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".
^ permalink raw reply [flat|nested] 12+ messages in thread
* [FFmpeg-devel] [PATCH 05/10] avcodec/dovi_rpu: clarify semantics of guess_profile()
2024-04-03 15:43 [FFmpeg-devel] [PATCH 01/10] avcodec: add dolbyvision option Niklas Haas
` (2 preceding siblings ...)
2024-04-03 15:43 ` [FFmpeg-devel] [PATCH 04/10] avcodec/dovi_rpu: clarify error on missing RPU VDR Niklas Haas
@ 2024-04-03 15:43 ` Niklas Haas
2024-04-03 15:43 ` [FFmpeg-devel] [PATCH 06/10] avcodec/dovi_rpu: add ff_dovi_configure() Niklas Haas
` (6 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Niklas Haas @ 2024-04-03 15:43 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Niklas Haas
From: Niklas Haas <git@haasn.dev>
This is based on HEVC only, H.264/AV1 use their own (hopefully correctly
signalled) profiles.
---
libavcodec/dovi_rpu.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/libavcodec/dovi_rpu.c b/libavcodec/dovi_rpu.c
index 267e52ceb66..4da711d763e 100644
--- a/libavcodec/dovi_rpu.c
+++ b/libavcodec/dovi_rpu.c
@@ -121,7 +121,8 @@ int ff_dovi_attach_side_data(DOVIContext *s, AVFrame *frame)
return 0;
}
-static int guess_profile(const AVDOVIRpuDataHeader *hdr)
+/* Note: Only works for HEVC */
+static int guess_hevc_profile(const AVDOVIRpuDataHeader *hdr)
{
switch (hdr->vdr_rpu_profile) {
case 0:
@@ -510,7 +511,7 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size,
use_prev_vdr_rpu = get_bits1(gb);
use_nlq = (hdr->rpu_format & 0x700) == 0 && !hdr->disable_residual_flag;
- profile = s->cfg.dv_profile ? s->cfg.dv_profile : guess_profile(hdr);
+ profile = s->cfg.dv_profile ? s->cfg.dv_profile : guess_hevc_profile(hdr);
if (profile == 5 && use_nlq) {
av_log(s->logctx, AV_LOG_ERROR, "Profile 5 RPUs should not use NLQ\n");
goto fail;
--
2.44.0
_______________________________________________
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".
^ permalink raw reply [flat|nested] 12+ messages in thread
* [FFmpeg-devel] [PATCH 06/10] avcodec/dovi_rpu: add ff_dovi_configure()
2024-04-03 15:43 [FFmpeg-devel] [PATCH 01/10] avcodec: add dolbyvision option Niklas Haas
` (3 preceding siblings ...)
2024-04-03 15:43 ` [FFmpeg-devel] [PATCH 05/10] avcodec/dovi_rpu: clarify semantics of guess_profile() Niklas Haas
@ 2024-04-03 15:43 ` Niklas Haas
2024-04-03 15:43 ` [FFmpeg-devel] [PATCH 07/10] avcodec/dovi_rpu: add ff_dovi_rpu_generate() Niklas Haas
` (5 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Niklas Haas @ 2024-04-03 15:43 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Niklas Haas
From: Niklas Haas <git@haasn.dev>
We need to set up the configuration struct appropriately based on the
codec type, colorspace metadata, and presence/absence of an EL (though,
we currently don't support an EL).
When present, we use the signalled RPU data header to help infer (and
validate) the right values.
---
libavcodec/dovi_rpu.c | 176 ++++++++++++++++++++++++++++++++++++++++++
libavcodec/dovi_rpu.h | 14 +++-
2 files changed, 189 insertions(+), 1 deletion(-)
diff --git a/libavcodec/dovi_rpu.c b/libavcodec/dovi_rpu.c
index 4da711d763e..b4e8d0cdea4 100644
--- a/libavcodec/dovi_rpu.c
+++ b/libavcodec/dovi_rpu.c
@@ -144,6 +144,182 @@ static int guess_hevc_profile(const AVDOVIRpuDataHeader *hdr)
return 0; /* unknown */
}
+static struct {
+ uint64_t pps; // maximum pixels per second
+ int width; // maximum width
+ int main; // maximum bitrate in main tier
+ int high; // maximum bitrate in high tier
+} dv_levels[] = {
+ [1] = {1280*720*24, 1280, 20, 50},
+ [2] = {1280*720*30, 1280, 20, 50},
+ [3] = {1920*1080*24, 1920, 20, 70},
+ [4] = {1920*1080*30, 2560, 20, 70},
+ [5] = {1920*1080*60, 3840, 20, 70},
+ [6] = {3840*2160*24, 3840, 25, 130},
+ [7] = {3840*2160*30, 3840, 25, 130},
+ [8] = {3840*2160*48, 3840, 40, 130},
+ [9] = {3840*2160*60, 3840, 40, 130},
+ [10] = {3840*2160*120, 3840, 60, 240},
+ [11] = {3840*2160*120, 7680, 60, 240},
+ [12] = {7680*4320*60, 7680, 120, 450},
+ [13] = {7680*4320*120u, 7680, 240, 800},
+};
+
+int ff_dovi_configure(DOVIContext *s, AVCodecContext *avctx)
+{
+ AVDOVIDecoderConfigurationRecord *cfg;
+ const AVDOVIRpuDataHeader *hdr = NULL;
+ const AVFrameSideData *sd;
+ int dv_profile, dv_level, bl_compat_id;
+ size_t cfg_size;
+ uint64_t pps;
+
+ if (!avctx->dolbyvision)
+ goto skip;
+
+ sd = av_frame_side_data_get(avctx->decoded_side_data,
+ avctx->nb_decoded_side_data, AV_FRAME_DATA_DOVI_METADATA);
+
+ if (sd)
+ hdr = av_dovi_get_header((const AVDOVIMetadata *) sd->data);
+
+ if (avctx->dolbyvision == FF_DOLBYVISION_AUTO && !hdr)
+ goto skip;
+
+ switch (avctx->codec_id) {
+ case AV_CODEC_ID_AV1: dv_profile = 10; break;
+ case AV_CODEC_ID_H264: dv_profile = 9; break;
+ case AV_CODEC_ID_HEVC: dv_profile = hdr ? guess_hevc_profile(hdr) : 8; break;
+ default:
+ /* No other encoder should be calling this! */
+ av_assert0(0);
+ return AVERROR_BUG;
+ }
+
+ if (avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
+ if (dv_profile == 9) {
+ if (avctx->pix_fmt != AV_PIX_FMT_YUV420P)
+ dv_profile = 0;
+ } else {
+ if (avctx->pix_fmt != AV_PIX_FMT_YUV420P10)
+ dv_profile = 0;
+ }
+ }
+
+ switch (dv_profile) {
+ case 0: /* None */
+ bl_compat_id = -1;
+ break;
+ case 4: /* HEVC with enhancement layer */
+ case 7:
+ if (avctx->dolbyvision > 0) {
+ av_log(s->logctx, AV_LOG_ERROR, "Coding of Dolby Vision enhancement "
+ "layers is currently unsupported.");
+ return AVERROR_PATCHWELCOME;
+ } else {
+ goto skip;
+ }
+ case 5: /* HEVC with proprietary IPTPQc2 */
+ bl_compat_id = 0;
+ break;
+ case 10:
+ /* FIXME: check for proper H.273 tags once those are added */
+ if (hdr && hdr->bl_video_full_range_flag) {
+ /* AV1 with proprietary IPTPQc2 */
+ bl_compat_id = 0;
+ break;
+ }
+ /* fall through */
+ case 8: /* HEVC (or AV1) with BL compatibility */
+ if (avctx->colorspace == AVCOL_SPC_BT2020_NCL &&
+ avctx->color_primaries == AVCOL_PRI_BT2020 &&
+ avctx->color_trc == AVCOL_TRC_SMPTE2084) {
+ bl_compat_id = 1;
+ } else if (avctx->colorspace == AVCOL_SPC_BT2020_NCL &&
+ avctx->color_primaries == AVCOL_PRI_BT2020 &&
+ avctx->color_trc == AVCOL_TRC_ARIB_STD_B67) {
+ bl_compat_id = 4;
+ } else if (avctx->colorspace == AVCOL_SPC_BT709 &&
+ avctx->color_primaries == AVCOL_PRI_BT709 &&
+ avctx->color_trc == AVCOL_TRC_BT709) {
+ bl_compat_id = 2;
+ } else {
+ /* Not a valid colorspace combination */
+ bl_compat_id = -1;
+ }
+ }
+
+ if (!dv_profile || bl_compat_id < 0) {
+ if (avctx->dolbyvision > 0) {
+ av_log(s->logctx, AV_LOG_ERROR, "Dolby Vision enabled, but could "
+ "not determine profile and compaatibility mode. Double-check "
+ "colorspace and format settings for compatibility?\n");
+ return AVERROR(EINVAL);
+ }
+ goto skip;
+ }
+
+ pps = avctx->width * avctx->height;
+ if (avctx->framerate.num) {
+ pps = pps * avctx->framerate.num / avctx->framerate.den;
+ } else {
+ pps *= 25; /* sanity fallback */
+ }
+
+ dv_level = 0;
+ for (int i = 1; i < FF_ARRAY_ELEMS(dv_levels); i++) {
+ if (pps > dv_levels[i].pps)
+ continue;
+ if (avctx->width > dv_levels[i].width)
+ continue;
+ /* In theory, we should also test the bitrate when known, and
+ * distinguish between main and high tier. In practice, just ignore
+ * the bitrate constraints and hope they work out. This would ideally
+ * be handled by either the encoder or muxer directly. */
+ dv_level = i;
+ break;
+ }
+
+ if (!dv_level) {
+ if (avctx->strict_std_compliance >= FF_COMPLIANCE_STRICT) {
+ av_log(s->logctx, AV_LOG_ERROR, "Coded PPS (%"PRIu64") and width (%d) "
+ "exceed Dolby Vision limitations\n", pps, avctx->width);
+ return AVERROR(EINVAL);
+ } else {
+ av_log(s->logctx, AV_LOG_WARNING, "Coded PPS (%"PRIu64") and width (%d) "
+ "exceed Dolby Vision limitations. Ignoring, resulting file "
+ "may be non-conforming.\n", pps, avctx->width);
+ dv_level = FF_ARRAY_ELEMS(dv_levels) - 1;
+ }
+ }
+
+ cfg = av_dovi_alloc(&cfg_size);
+ if (!cfg)
+ return AVERROR(ENOMEM);
+
+ if (!av_packet_side_data_add(&avctx->coded_side_data, &avctx->nb_coded_side_data,
+ AV_PKT_DATA_DOVI_CONF, cfg, cfg_size, 0)) {
+ av_free(cfg);
+ return AVERROR(ENOMEM);
+ }
+
+ cfg->dv_version_major = 1;
+ cfg->dv_version_minor = 0;
+ cfg->dv_profile = dv_profile;
+ cfg->dv_level = dv_level;
+ cfg->rpu_present_flag = 1;
+ cfg->el_present_flag = 0;
+ cfg->bl_present_flag = 1;
+ cfg->dv_bl_signal_compatibility_id = bl_compat_id;
+
+ s->cfg = *cfg;
+ return 0;
+
+skip:
+ s->cfg = (AVDOVIDecoderConfigurationRecord) {0};
+ return 0;
+}
+
static inline uint64_t get_ue_coef(GetBitContext *gb, const AVDOVIRpuDataHeader *hdr)
{
uint64_t ipart;
diff --git a/libavcodec/dovi_rpu.h b/libavcodec/dovi_rpu.h
index 9a68e45bf1b..33e19dd037c 100644
--- a/libavcodec/dovi_rpu.h
+++ b/libavcodec/dovi_rpu.h
@@ -26,6 +26,7 @@
#include "libavutil/dovi_meta.h"
#include "libavutil/frame.h"
+#include "avcodec.h"
#define DOVI_MAX_DM_ID 15
typedef struct DOVIContext {
@@ -33,7 +34,8 @@ typedef struct DOVIContext {
/**
* Currently active dolby vision configuration, or {0} for none.
- * Set by the user when decoding.
+ * Set by the user when decoding. Generated by ff_dovi_configure()
+ * when encoding.
*
* Note: sizeof(cfg) is not part of the libavutil ABI, so users should
* never pass &cfg to any other library calls. This is included merely as
@@ -96,4 +98,14 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size,
*/
int ff_dovi_attach_side_data(DOVIContext *s, AVFrame *frame);
+/**
+ * Configure the encoder for Dolby Vision encoding. Generates a configuration
+ * record in s->cfg, and attaches it to avctx->coded_side_data. Sets the correct
+ * profile and compatibility ID based on the tagged AVCodecContext colorspace
+ * metadata, and the correct level based on the resolution and tagged framerate.
+ *
+ * Returns 0 or a negative error code.
+ */
+int ff_dovi_configure(DOVIContext *s, AVCodecContext *avctx);
+
#endif /* AVCODEC_DOVI_RPU_H */
--
2.44.0
_______________________________________________
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".
^ permalink raw reply [flat|nested] 12+ messages in thread
* [FFmpeg-devel] [PATCH 07/10] avcodec/dovi_rpu: add ff_dovi_rpu_generate()
2024-04-03 15:43 [FFmpeg-devel] [PATCH 01/10] avcodec: add dolbyvision option Niklas Haas
` (4 preceding siblings ...)
2024-04-03 15:43 ` [FFmpeg-devel] [PATCH 06/10] avcodec/dovi_rpu: add ff_dovi_configure() Niklas Haas
@ 2024-04-03 15:43 ` Niklas Haas
2024-04-03 15:43 ` [FFmpeg-devel] [PATCH 08/10] avcodec/libaomenc: implement dolby vision coding Niklas Haas
` (4 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Niklas Haas @ 2024-04-03 15:43 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Niklas Haas
From: Niklas Haas <git@haasn.dev>
This function takes a decoded AVDOVIMetadata struct and turns it back
into a binary RPU. Verified using existing tools, and matches the
bitstream in official reference files.
I decided to just roll the EMDF and NAL encapsulation into this function
because the end user will need to do it otherwise anyways.
---
libavcodec/dovi_rpu.c | 542 ++++++++++++++++++++++++++++++++++++++++++
libavcodec/dovi_rpu.h | 20 +-
2 files changed, 560 insertions(+), 2 deletions(-)
diff --git a/libavcodec/dovi_rpu.c b/libavcodec/dovi_rpu.c
index b4e8d0cdea4..89353ccd1e4 100644
--- a/libavcodec/dovi_rpu.c
+++ b/libavcodec/dovi_rpu.c
@@ -29,6 +29,9 @@
#include "dovi_rpu.h"
#include "golomb.h"
#include "get_bits.h"
+#include "itut35.h"
+#include "put_bits.h"
+#include "put_golomb.h"
#include "refstruct.h"
enum {
@@ -358,6 +361,42 @@ static inline int64_t get_se_coef(GetBitContext *gb, const AVDOVIRpuDataHeader *
return 0; /* unreachable */
}
+static inline void put_ue_coef(PutBitContext *pb, const AVDOVIRpuDataHeader *hdr,
+ uint64_t coef)
+{
+ union { uint32_t u32; float f32; } fpart;
+
+ switch (hdr->coef_data_type) {
+ case RPU_COEFF_FIXED:
+ set_ue_golomb(pb, coef >> hdr->coef_log2_denom);
+ put_bits64(pb, hdr->coef_log2_denom,
+ coef & ((1LL << hdr->coef_log2_denom) - 1));
+ break;
+ case RPU_COEFF_FLOAT:
+ fpart.f32 = coef / (float) (1LL << hdr->coef_log2_denom);
+ put_bits64(pb, hdr->coef_log2_denom, fpart.u32);
+ break;
+ }
+}
+
+static inline void put_se_coef(PutBitContext *pb, const AVDOVIRpuDataHeader *hdr,
+ uint64_t coef)
+{
+ union { uint32_t u32; float f32; } fpart;
+
+ switch (hdr->coef_data_type) {
+ case RPU_COEFF_FIXED:
+ set_se_golomb(pb, coef >> hdr->coef_log2_denom);
+ put_bits64(pb, hdr->coef_log2_denom,
+ coef & ((1LL << hdr->coef_log2_denom) - 1));
+ break;
+ case RPU_COEFF_FLOAT:
+ fpart.f32 = coef / (float) (1LL << hdr->coef_log2_denom);
+ put_bits64(pb, hdr->coef_log2_denom, fpart.u32);
+ break;
+ }
+}
+
static inline unsigned get_variable_bits(GetBitContext *gb, int n)
{
unsigned int value = get_bits(gb, n);
@@ -885,3 +924,506 @@ fail:
ff_dovi_ctx_unref(s); /* don't leak potentially invalid state */
return AVERROR_INVALIDDATA;
}
+
+static int av_q2den(AVRational q, int den)
+{
+ if (q.den == den)
+ return q.num;
+ q = av_mul_q(q, av_make_q(den, 1));
+ return (q.num + (q.den >> 1)) / q.den;
+}
+
+static void generate_ext_v1(PutBitContext *pb, const AVDOVIDmData *dm)
+{
+ int ext_block_length, start_pos, pad_bits;
+
+ switch (dm->level) {
+ case 1: ext_block_length = 5; break;
+ case 2: ext_block_length = 11; break;
+ case 4: ext_block_length = 3; break;
+ case 5: ext_block_length = 7; break;
+ case 6: ext_block_length = 8; break;
+ case 255: ext_block_length = 6; break;
+ default: return;
+ }
+
+ set_ue_golomb(pb, ext_block_length);
+ put_bits(pb, 8, dm->level);
+ start_pos = put_bits_count(pb);
+
+ switch (dm->level) {
+ case 1:
+ put_bits(pb, 12, dm->l1.min_pq);
+ put_bits(pb, 12, dm->l1.max_pq);
+ put_bits(pb, 12, dm->l1.avg_pq);
+ break;
+ case 2:
+ put_bits(pb, 12, dm->l2.target_max_pq);
+ put_bits(pb, 12, dm->l2.trim_slope);
+ put_bits(pb, 12, dm->l2.trim_offset);
+ put_bits(pb, 12, dm->l2.trim_power);
+ put_bits(pb, 12, dm->l2.trim_chroma_weight);
+ put_bits(pb, 12, dm->l2.trim_saturation_gain);
+ put_bits(pb, 13, dm->l2.ms_weight + 8192);
+ break;
+ case 4:
+ put_bits(pb, 12, dm->l4.anchor_pq);
+ put_bits(pb, 12, dm->l4.anchor_power);
+ break;
+ case 5:
+ put_bits(pb, 13, dm->l5.left_offset);
+ put_bits(pb, 13, dm->l5.right_offset);
+ put_bits(pb, 13, dm->l5.top_offset);
+ put_bits(pb, 13, dm->l5.bottom_offset);
+ break;
+ case 6:
+ put_bits(pb, 16, dm->l6.max_luminance);
+ put_bits(pb, 16, dm->l6.min_luminance);
+ put_bits(pb, 16, dm->l6.max_cll);
+ put_bits(pb, 16, dm->l6.max_fall);
+ break;
+ case 255:
+ put_bits(pb, 8, dm->l255.dm_run_mode);
+ put_bits(pb, 8, dm->l255.dm_run_version);
+ for (int i = 0; i < 4; i++)
+ put_bits(pb, 8, dm->l255.dm_debug[i]);
+ break;
+ }
+
+ pad_bits = ext_block_length * 8 - (put_bits_count(pb) - start_pos);
+ av_assert1(pad_bits >= 0);
+ put_bits(pb, pad_bits, 0);
+}
+
+static void put_cie_xy(PutBitContext *pb, AVCIExy xy)
+{
+ const int denom = 32767;
+ put_sbits(pb, 16, av_q2den(xy.x, denom));
+ put_sbits(pb, 16, av_q2den(xy.y, denom));
+}
+
+#define ANY6(arr) (arr[0] || arr[1] || arr[2] || arr[3] || arr[4] || arr[5])
+#define ANY_XY(xy) (xy.x.num || xy.y.num)
+#define ANY_CSP(csp) (ANY_XY(csp.prim.r) || ANY_XY(csp.prim.g) || \
+ ANY_XY(csp.prim.b) || ANY_XY(csp.wp))
+
+static void generate_ext_v2(PutBitContext *pb, const AVDOVIDmData *dm)
+{
+ int ext_block_length, start_pos, pad_bits;
+
+ switch (dm->level) {
+ case 3: ext_block_length = 5; break;
+ case 8:
+ if (ANY6(dm->l8.hue_vector_field)) {
+ ext_block_length = 25;
+ } else if (ANY6(dm->l8.saturation_vector_field)) {
+ ext_block_length = 19;
+ } else if (dm->l8.clip_trim) {
+ ext_block_length = 13;
+ } else if (dm->l8.target_mid_contrast) {
+ ext_block_length = 12;
+ } else {
+ ext_block_length = 10;
+ }
+ break;
+ case 9:
+ if (ANY_CSP(dm->l9.source_display_primaries)) {
+ ext_block_length = 17;
+ } else {
+ ext_block_length = 1;
+ }
+ break;
+ case 10:
+ if (ANY_CSP(dm->l10.target_display_primaries)) {
+ ext_block_length = 21;
+ } else {
+ ext_block_length = 5;
+ }
+ break;
+ case 11: ext_block_length = 5; break;
+ case 254: ext_block_length = 2; break;
+ default: return;
+ }
+
+ set_ue_golomb(pb, ext_block_length);
+ put_bits(pb, 8, dm->level);
+ start_pos = put_bits_count(pb);
+
+ switch (dm->level) {
+ case 3:
+ put_bits(pb, 12, dm->l3.min_pq_offset);
+ put_bits(pb, 12, dm->l3.max_pq_offset);
+ put_bits(pb, 12, dm->l3.avg_pq_offset);
+ break;
+ case 8:
+ put_bits(pb, 8, dm->l8.target_display_index);
+ put_bits(pb, 12, dm->l8.trim_slope);
+ put_bits(pb, 12, dm->l8.trim_offset);
+ put_bits(pb, 12, dm->l8.trim_power);
+ put_bits(pb, 12, dm->l8.trim_chroma_weight);
+ put_bits(pb, 12, dm->l8.trim_saturation_gain);
+ put_bits(pb, 12, dm->l8.ms_weight + 8192);
+ if (ext_block_length < 12)
+ break;
+ put_bits(pb, 12, dm->l8.target_mid_contrast);
+ if (ext_block_length < 13)
+ break;
+ put_bits(pb, 12, dm->l8.clip_trim);
+ if (ext_block_length < 19)
+ break;
+ for (int i = 0; i < 6; i++)
+ put_bits(pb, 8, dm->l8.saturation_vector_field[i]);
+ if (ext_block_length < 25)
+ break;
+ for (int i = 0; i < 6; i++)
+ put_bits(pb, 8, dm->l8.hue_vector_field[i]);
+ break;
+ case 9:
+ put_bits(pb, 8, dm->l9.source_primary_index);
+ if (ext_block_length < 17)
+ break;
+ put_cie_xy(pb, dm->l9.source_display_primaries.prim.r);
+ put_cie_xy(pb, dm->l9.source_display_primaries.prim.g);
+ put_cie_xy(pb, dm->l9.source_display_primaries.prim.b);
+ put_cie_xy(pb, dm->l9.source_display_primaries.wp);
+ break;
+ case 10:
+ put_bits(pb, 8, dm->l10.target_display_index);
+ put_bits(pb, 12, dm->l10.target_max_pq);
+ put_bits(pb, 12, dm->l10.target_min_pq);
+ put_bits(pb, 8, dm->l10.target_primary_index);
+ if (ext_block_length < 21)
+ break;
+ put_cie_xy(pb, dm->l10.target_display_primaries.prim.r);
+ put_cie_xy(pb, dm->l10.target_display_primaries.prim.g);
+ put_cie_xy(pb, dm->l10.target_display_primaries.prim.b);
+ put_cie_xy(pb, dm->l10.target_display_primaries.wp);
+ break;
+ case 11:
+ put_bits(pb, 8, dm->l11.content_type);
+ put_bits(pb, 4, dm->l11.whitepoint);
+ put_bits(pb, 1, dm->l11.reference_mode_flag);
+ put_bits(pb, 3, 0); /* reserved */
+ put_bits(pb, 2, dm->l11.sharpness);
+ put_bits(pb, 2, dm->l11.noise_reduction);
+ put_bits(pb, 2, dm->l11.mpeg_noise_reduction);
+ put_bits(pb, 2, dm->l11.frame_rate_conversion);
+ put_bits(pb, 2, dm->l11.brightness);
+ put_bits(pb, 2, dm->l11.color);
+ break;
+ case 254:
+ put_bits(pb, 8, dm->l254.dm_mode);
+ put_bits(pb, 8, dm->l254.dm_version_index);
+ break;
+ }
+
+ pad_bits = ext_block_length * 8 - (put_bits_count(pb) - start_pos);
+ av_assert1(pad_bits >= 0);
+ put_bits(pb, pad_bits, 0);
+}
+
+int ff_dovi_rpu_generate(DOVIContext *s, const AVDOVIMetadata *metadata,
+ uint8_t **out_rpu, int *out_size)
+{
+ PutBitContext *pb = &(PutBitContext){0};
+ const AVDOVIRpuDataHeader *hdr;
+ const AVDOVIDataMapping *mapping;
+ const AVDOVIColorMetadata *color;
+ int vdr_dm_metadata_changed, vdr_rpu_id, use_prev_vdr_rpu, profile,
+ buffer_size, rpu_size, pad, zero_run;
+ int num_ext_blocks_v1, num_ext_blocks_v2;
+ uint32_t crc;
+ uint8_t *dst;
+ if (!metadata) {
+ *out_rpu = NULL;
+ *out_size = 0;
+ return 0;
+ }
+
+ hdr = av_dovi_get_header(metadata);
+ mapping = av_dovi_get_mapping(metadata);
+ color = av_dovi_get_color(metadata);
+ av_assert0(s->cfg.dv_profile);
+
+ if (hdr->rpu_type != 2) {
+ av_log(s->logctx, AV_LOG_ERROR, "Unhandled RPU type %"PRIu8"\n",
+ hdr->rpu_type);
+ return AVERROR_INVALIDDATA;
+ }
+
+ vdr_rpu_id = -1;
+ for (int i = 0; i <= DOVI_MAX_DM_ID; i++) {
+ if (s->vdr[i] && !memcmp(&s->vdr[i]->mapping, mapping, sizeof(*mapping))) {
+ vdr_rpu_id = i;
+ break;
+ } else if (vdr_rpu_id < 0 && (!s->vdr[i] || i == DOVI_MAX_DM_ID)) {
+ vdr_rpu_id = i;
+ }
+ }
+
+ if (!s->vdr[vdr_rpu_id]) {
+ s->vdr[vdr_rpu_id] = ff_refstruct_allocz(sizeof(DOVIVdr));
+ if (!s->vdr[vdr_rpu_id])
+ return AVERROR(ENOMEM);
+ }
+
+ if (!s->vdr[color->dm_metadata_id]) {
+ s->vdr[color->dm_metadata_id] = ff_refstruct_allocz(sizeof(DOVIVdr));
+ if (!s->vdr[color->dm_metadata_id])
+ return AVERROR(ENOMEM);
+ }
+
+ num_ext_blocks_v1 = num_ext_blocks_v2 = 0;
+ for (int i = 0; i < metadata->num_ext_blocks; i++) {
+ const AVDOVIDmData *dm = av_dovi_get_ext(metadata, i);
+ switch (dm->level) {
+ case 1:
+ case 2:
+ case 4:
+ case 5:
+ case 6:
+ case 255:
+ num_ext_blocks_v1++;
+ break;
+ case 3:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 254:
+ num_ext_blocks_v2++;
+ break;
+ default:
+ av_log(s->logctx, AV_LOG_ERROR, "Invalid ext block level %d\n",
+ dm->level);
+ return AVERROR_INVALIDDATA;
+ }
+ }
+
+ vdr_dm_metadata_changed = !s->color || memcmp(s->color, color, sizeof(*color));
+ use_prev_vdr_rpu = !memcmp(&s->vdr[vdr_rpu_id]->mapping, mapping, sizeof(*mapping));
+
+ buffer_size = 12 /* vdr seq info */ + 5 /* CRC32 + terminator */;
+ buffer_size += num_ext_blocks_v1 * 13;
+ buffer_size += num_ext_blocks_v2 * 28;
+ if (!use_prev_vdr_rpu) {
+ buffer_size += 160;
+ for (int c = 0; c < 3; c++) {
+ for (int i = 0; i < mapping->curves[c].num_pivots - 1; i++) {
+ switch (mapping->curves[c].mapping_idc[i]) {
+ case AV_DOVI_MAPPING_POLYNOMIAL: buffer_size += 26; break;
+ case AV_DOVI_MAPPING_MMR: buffer_size += 177; break;
+ }
+ }
+ }
+ }
+ if (vdr_dm_metadata_changed)
+ buffer_size += 67;
+
+ av_fast_padded_malloc(&s->rpu_buf, &s->rpu_buf_sz, buffer_size);
+ if (!s->rpu_buf)
+ return AVERROR(ENOMEM);
+ init_put_bits(pb, s->rpu_buf, s->rpu_buf_sz);
+
+ /* RPU header */
+ put_bits(pb, 6, hdr->rpu_type);
+ put_bits(pb, 11, hdr->rpu_format);
+ put_bits(pb, 4, hdr->vdr_rpu_profile);
+ put_bits(pb, 4, hdr->vdr_rpu_level);
+ put_bits(pb, 1, 1); /* vdr_seq_info_present */
+ put_bits(pb, 1, hdr->chroma_resampling_explicit_filter_flag);
+ put_bits(pb, 2, hdr->coef_data_type);
+ if (hdr->coef_data_type == RPU_COEFF_FIXED)
+ set_ue_golomb(pb, hdr->coef_log2_denom);
+ put_bits(pb, 2, hdr->vdr_rpu_normalized_idc);
+ put_bits(pb, 1, hdr->bl_video_full_range_flag);
+ if ((hdr->rpu_format & 0x700) == 0) {
+ set_ue_golomb(pb, hdr->bl_bit_depth - 8);
+ set_ue_golomb(pb, hdr->el_bit_depth - 8);
+ set_ue_golomb(pb, hdr->vdr_bit_depth - 8);
+ put_bits(pb, 1, hdr->spatial_resampling_filter_flag);
+ put_bits(pb, 3, 0); /* reserved_zero_3bits */
+ put_bits(pb, 1, hdr->el_spatial_resampling_filter_flag);
+ put_bits(pb, 1, hdr->disable_residual_flag);
+ }
+ s->header = *hdr;
+
+ put_bits(pb, 1, vdr_dm_metadata_changed);
+ put_bits(pb, 1, use_prev_vdr_rpu);
+ set_ue_golomb(pb, vdr_rpu_id);
+ s->mapping = &s->vdr[vdr_rpu_id]->mapping;
+
+ if (!use_prev_vdr_rpu) {
+ set_ue_golomb(pb, mapping->mapping_color_space);
+ set_ue_golomb(pb, mapping->mapping_chroma_format_idc);
+ for (int c = 0; c < 3; c++) {
+ const AVDOVIReshapingCurve *curve = &mapping->curves[c];
+ int prev = 0;
+ set_ue_golomb(pb, curve->num_pivots - 2);
+ for (int i = 0; i < curve->num_pivots; i++) {
+ put_bits(pb, hdr->bl_bit_depth, curve->pivots[i] - prev);
+ prev = curve->pivots[i];
+ }
+ }
+
+ if (mapping->nlq_method_idc != AV_DOVI_NLQ_NONE) {
+ put_bits(pb, 3, mapping->nlq_method_idc);
+ put_bits(pb, hdr->bl_bit_depth, mapping->nlq_pivots[0]);
+ put_bits(pb, hdr->bl_bit_depth, mapping->nlq_pivots[1] - mapping->nlq_pivots[0]);
+ }
+
+ set_ue_golomb(pb, mapping->num_x_partitions - 1);
+ set_ue_golomb(pb, mapping->num_y_partitions - 1);
+
+ for (int c = 0; c < 3; c++) {
+ const AVDOVIReshapingCurve *curve = &mapping->curves[c];
+ for (int i = 0; i < curve->num_pivots - 1; i++) {
+ set_ue_golomb(pb, curve->mapping_idc[i]);
+ switch (curve->mapping_idc[i]) {
+ case AV_DOVI_MAPPING_POLYNOMIAL: {
+ set_ue_golomb(pb, curve->poly_order[i] - 1);
+ if (curve->poly_order[i] == 1)
+ put_bits(pb, 1, 0); /* linear_interp_flag */
+ for (int k = 0; k <= curve->poly_order[i]; k++)
+ put_se_coef(pb, hdr, curve->poly_coef[i][k]);
+ break;
+ }
+ case AV_DOVI_MAPPING_MMR: {
+ put_bits(pb, 2, curve->mmr_order[i] - 1);
+ put_se_coef(pb, hdr, curve->mmr_constant[i]);
+ for (int j = 0; j < curve->mmr_order[i]; j++) {
+ for (int k = 0; k < 7; k++)
+ put_se_coef(pb, hdr, curve->mmr_coef[i][j][k]);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ if (mapping->nlq_method_idc != AV_DOVI_NLQ_NONE) {
+ for (int c = 0; c < 3; c++) {
+ const AVDOVINLQParams *nlq = &mapping->nlq[c];
+ put_bits(pb, hdr->el_bit_depth, nlq->nlq_offset);
+ put_ue_coef(pb, hdr, nlq->vdr_in_max);
+ switch (mapping->nlq_method_idc) {
+ case AV_DOVI_NLQ_LINEAR_DZ:
+ put_ue_coef(pb, hdr, nlq->linear_deadzone_slope);
+ put_ue_coef(pb, hdr, nlq->linear_deadzone_threshold);
+ break;
+ }
+ }
+ }
+
+ memcpy(&s->vdr[vdr_rpu_id]->mapping, mapping, sizeof(*mapping));
+ }
+
+ if (vdr_dm_metadata_changed) {
+ const int denom = profile == 4 ? (1 << 30) : (1 << 28);
+ set_ue_golomb(pb, color->dm_metadata_id); /* affected_dm_id */
+ set_ue_golomb(pb, color->dm_metadata_id); /* current_dm_id */
+ set_ue_golomb(pb, color->scene_refresh_flag);
+ for (int i = 0; i < 9; i++)
+ put_sbits(pb, 16, av_q2den(color->ycc_to_rgb_matrix[i], 1 << 13));
+ for (int i = 0; i < 3; i++)
+ put_bits32(pb, av_q2den(color->ycc_to_rgb_offset[i], denom));
+ for (int i = 0; i < 9; i++)
+ put_sbits(pb, 16, av_q2den(color->rgb_to_lms_matrix[i], 1 << 14));
+ put_bits(pb, 16, color->signal_eotf);
+ put_bits(pb, 16, color->signal_eotf_param0);
+ put_bits(pb, 16, color->signal_eotf_param1);
+ put_bits32(pb, color->signal_eotf_param2);
+ put_bits(pb, 5, color->signal_bit_depth);
+ put_bits(pb, 2, color->signal_color_space);
+ put_bits(pb, 2, color->signal_chroma_format);
+ put_bits(pb, 2, color->signal_full_range_flag);
+ put_bits(pb, 12, color->source_min_pq);
+ put_bits(pb, 12, color->source_max_pq);
+ put_bits(pb, 10, color->source_diagonal);
+
+ memcpy(&s->vdr[color->dm_metadata_id]->color, color, sizeof(*color));
+ s->color = &s->vdr[color->dm_metadata_id]->color;
+ }
+
+ set_ue_golomb(pb, num_ext_blocks_v1);
+ align_put_bits(pb);
+ for (int i = 0; i < metadata->num_ext_blocks; i++)
+ generate_ext_v1(pb, av_dovi_get_ext(metadata, i));
+
+ if (num_ext_blocks_v2) {
+ set_ue_golomb(pb, num_ext_blocks_v2);
+ align_put_bits(pb);
+ for (int i = 0; i < metadata->num_ext_blocks; i++)
+ generate_ext_v2(pb, av_dovi_get_ext(metadata, i));
+ }
+
+ flush_put_bits(pb);
+ crc = av_bswap32(av_crc(av_crc_get_table(AV_CRC_32_IEEE), -1,
+ s->rpu_buf, put_bytes_output(pb)));
+ put_bits32(pb, crc);
+ put_bits(pb, 8, 0x80); /* terminator */
+ flush_put_bits(pb);
+
+ rpu_size = put_bytes_output(pb);
+ switch (s->cfg.dv_profile) {
+ case 10:
+ /* AV1 uses T.35 OBU with EMDF header */
+ *out_rpu = av_malloc(rpu_size + 15);
+ if (!*out_rpu)
+ return AVERROR(ENOMEM);
+ init_put_bits(pb, *out_rpu, rpu_size + 15);
+ put_bits(pb, 8, ITU_T_T35_COUNTRY_CODE_US);
+ put_bits(pb, 16, ITU_T_T35_PROVIDER_CODE_DOLBY);
+ put_bits32(pb, 0x800); /* provider_oriented_code */
+ put_bits(pb, 27, 0x01be6841u); /* fixed EMDF header, see above */
+ if (rpu_size > 0xFF) {
+ av_assert2(rpu_size <= 0x10000);
+ put_bits(pb, 8, (rpu_size >> 8) - 1);
+ put_bits(pb, 1, 1); /* read_more */
+ put_bits(pb, 8, rpu_size & 0xFF);
+ put_bits(pb, 1, 0);
+ } else {
+ put_bits(pb, 8, rpu_size);
+ put_bits(pb, 1, 0);
+ }
+ ff_copy_bits(pb, s->rpu_buf, rpu_size * 8);
+ put_bits(pb, 17, 0x400); /* emdf payload id + emdf_protection */
+
+ pad = pb->bit_left & 7;
+ put_bits(pb, pad, (1 << pad) - 1); /* pad to next byte with 1 bits */
+ flush_put_bits(pb);
+ *out_size = put_bytes_output(pb);
+ return 0;
+
+ case 5:
+ case 8:
+ *out_rpu = dst = av_malloc(1 + rpu_size * 3 / 2); /* worst case */
+ if (!*out_rpu)
+ return AVERROR(ENOMEM);
+ *dst++ = 25; /* NAL prefix */
+ zero_run = 0;
+ for (int i = 0; i < rpu_size; i++) {
+ if (zero_run < 2) {
+ if (s->rpu_buf[i] == 0) {
+ zero_run++;
+ } else {
+ zero_run = 0;
+ }
+ } else {
+ if ((s->rpu_buf[i] & ~3) == 0) {
+ /* emulation prevention */
+ *dst++ = 3;
+ }
+ zero_run = s->rpu_buf[i] == 0;
+ }
+ *dst++ = s->rpu_buf[i];
+ }
+ *out_size = dst - *out_rpu;
+ return 0;
+
+ default:
+ /* Should be unreachable */
+ av_assert0(0);
+ return AVERROR_BUG;
+ }
+}
diff --git a/libavcodec/dovi_rpu.h b/libavcodec/dovi_rpu.h
index 33e19dd037c..64433b73e65 100644
--- a/libavcodec/dovi_rpu.h
+++ b/libavcodec/dovi_rpu.h
@@ -44,20 +44,22 @@ typedef struct DOVIContext {
AVDOVIDecoderConfigurationRecord cfg;
/**
- * Currently active RPU data header, updates on every dovi_rpu_parse().
+ * Currently active RPU data header, updates on every ff_dovi_rpu_parse()
+ * or ff_dovi_rpu_generate().
*/
AVDOVIRpuDataHeader header;
/**
* Currently active data mappings, or NULL. Points into memory owned by the
* corresponding rpu/vdr_ref, which becomes invalid on the next call to
- * dovi_rpu_parse.
+ * ff_dovi_rpu_parse() or ff_dovi_rpu_generate().
*/
const AVDOVIDataMapping *mapping;
const AVDOVIColorMetadata *color;
/**
* Currently active extension blocks, updates on every ff_dovi_rpu_parse()
+ * or ff_dovi_rpu_generate().
*/
AVDOVIDmData *ext_blocks;
int num_ext_blocks;
@@ -108,4 +110,18 @@ int ff_dovi_attach_side_data(DOVIContext *s, AVFrame *frame);
*/
int ff_dovi_configure(DOVIContext *s, AVCodecContext *avctx);
+/**
+ * Synthesize a Dolby Vision RPU reflecting the current state. Note that this
+ * assumes all previous calls to `ff_dovi_rpu_generate` have been appropriately
+ * signalled, i.e. it will not re-send already transmitted redundant data.
+ *
+ * Mutates the internal state of DOVIContext to reflect the change.
+ * Returns 0 or a negative error code.
+ *
+ * This generates a fully formed RPU ready for inclusion in the bitstream,
+ * including the EMDF header (profile 10) or NAL encapsulation (otherwise).
+ */
+int ff_dovi_rpu_generate(DOVIContext *s, const AVDOVIMetadata *metadata,
+ uint8_t **out_rpu, int *out_size);
+
#endif /* AVCODEC_DOVI_RPU_H */
--
2.44.0
_______________________________________________
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".
^ permalink raw reply [flat|nested] 12+ messages in thread
* [FFmpeg-devel] [PATCH 08/10] avcodec/libaomenc: implement dolby vision coding
2024-04-03 15:43 [FFmpeg-devel] [PATCH 01/10] avcodec: add dolbyvision option Niklas Haas
` (5 preceding siblings ...)
2024-04-03 15:43 ` [FFmpeg-devel] [PATCH 07/10] avcodec/dovi_rpu: add ff_dovi_rpu_generate() Niklas Haas
@ 2024-04-03 15:43 ` Niklas Haas
2024-04-03 15:43 ` [FFmpeg-devel] [PATCH 09/10] avcodec/libx265: " Niklas Haas
` (3 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Niklas Haas @ 2024-04-03 15:43 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Niklas Haas
From: Niklas Haas <git@haasn.dev>
---
libavcodec/libaomenc.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/libavcodec/libaomenc.c b/libavcodec/libaomenc.c
index d660afab4ec..6bc46ec6e28 100644
--- a/libavcodec/libaomenc.c
+++ b/libavcodec/libaomenc.c
@@ -43,6 +43,7 @@
#include "avcodec.h"
#include "bsf.h"
#include "codec_internal.h"
+#include "dovi_rpu.h"
#include "encode.h"
#include "internal.h"
#include "libaom.h"
@@ -70,6 +71,7 @@ struct FrameListData {
typedef struct AOMEncoderContext {
AVClass *class;
AVBSFContext *bsf;
+ DOVIContext dovi;
struct aom_codec_ctx encoder;
struct aom_image rawimg;
struct aom_fixed_buf twopass_stats;
@@ -437,6 +439,7 @@ static av_cold int aom_free(AVCodecContext *avctx)
av_freep(&avctx->stats_out);
free_frame_list(ctx->coded_frame_list);
av_bsf_free(&ctx->bsf);
+ ff_dovi_ctx_unref(&ctx->dovi);
return 0;
}
@@ -1023,6 +1026,10 @@ static av_cold int aom_init(AVCodecContext *avctx,
if (!cpb_props)
return AVERROR(ENOMEM);
+ ctx->dovi.logctx = avctx;
+ if ((res = ff_dovi_configure(&ctx->dovi, avctx)) < 0)
+ return res;
+
if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
const AVBitStreamFilter *filter = av_bsf_get_by_name("extract_extradata");
int ret;
@@ -1282,6 +1289,7 @@ static int aom_encode(AVCodecContext *avctx, AVPacket *pkt,
unsigned long duration = 0;
int res, coded_size;
aom_enc_frame_flags_t flags = 0;
+ AVFrameSideData *sd;
if (frame) {
rawimg = &ctx->rawimg;
@@ -1319,6 +1327,24 @@ FF_ENABLE_DEPRECATION_WARNINGS
break;
}
+ sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DOVI_METADATA);
+ if (ctx->dovi.cfg.dv_profile && sd) {
+ const AVDOVIMetadata *metadata = (const AVDOVIMetadata *)sd->data;
+ uint8_t *t35;
+ int size;
+ if ((res = ff_dovi_rpu_generate(&ctx->dovi, metadata, &t35, &size)) < 0)
+ return res;
+ res = aom_img_add_metadata(rawimg, OBU_METADATA_TYPE_ITUT_T35,
+ t35, size, AOM_MIF_ANY_FRAME);
+ av_free(t35);
+ if (res != AOM_CODEC_OK)
+ return AVERROR(ENOMEM);
+ } else if (ctx->dovi.cfg.dv_profile) {
+ av_log(avctx, AV_LOG_ERROR, "Dolby Vision enabled, but received frame "
+ "without AV_FRAME_DATA_DOVI_METADATA");
+ return AVERROR_INVALIDDATA;
+ }
+
if (frame->pict_type == AV_PICTURE_TYPE_I)
flags |= AOM_EFLAG_FORCE_KF;
}
--
2.44.0
_______________________________________________
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".
^ permalink raw reply [flat|nested] 12+ messages in thread
* [FFmpeg-devel] [PATCH 09/10] avcodec/libx265: implement dolby vision coding
2024-04-03 15:43 [FFmpeg-devel] [PATCH 01/10] avcodec: add dolbyvision option Niklas Haas
` (6 preceding siblings ...)
2024-04-03 15:43 ` [FFmpeg-devel] [PATCH 08/10] avcodec/libaomenc: implement dolby vision coding Niklas Haas
@ 2024-04-03 15:43 ` Niklas Haas
2024-04-03 15:43 ` [FFmpeg-devel] [PATCH 10/10] avformat/movenc: warn if dovi cfg ignored Niklas Haas
` (2 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Niklas Haas @ 2024-04-03 15:43 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Niklas Haas
From: Niklas Haas <git@haasn.dev>
libx265 supports these natively, we just need to attach the generated
NALs to the x265picture, as well as setting the appropriate DV profile.
---
libavcodec/libx265.c | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/libavcodec/libx265.c b/libavcodec/libx265.c
index 40ddce60306..b525b4ed59f 100644
--- a/libavcodec/libx265.c
+++ b/libavcodec/libx265.c
@@ -36,6 +36,7 @@
#include "libavutil/pixdesc.h"
#include "avcodec.h"
#include "codec_internal.h"
+#include "dovi_rpu.h"
#include "encode.h"
#include "packet_internal.h"
#include "atsc_a53.h"
@@ -78,6 +79,8 @@ typedef struct libx265Context {
* encounter a frame with ROI side data.
*/
int roi_warned;
+
+ DOVIContext dovi;
} libx265Context;
static int is_keyframe(NalUnitType naltype)
@@ -143,6 +146,8 @@ static av_cold int libx265_encode_close(AVCodecContext *avctx)
if (ctx->encoder)
ctx->api->encoder_close(ctx->encoder);
+ ff_dovi_ctx_unref(&ctx->dovi);
+
return 0;
}
@@ -529,6 +534,14 @@ FF_ENABLE_DEPRECATION_WARNINGS
}
}
+#if X265_BUILD >= 167
+ ctx->dovi.logctx = avctx;
+ if ((ret = ff_dovi_configure(&ctx->dovi, avctx)) < 0)
+ return ret;
+ ctx->params->dolbyProfile = ctx->dovi.cfg.dv_profile * 10 +
+ ctx->dovi.cfg.dv_bl_signal_compatibility_id;
+#endif
+
ctx->encoder = ctx->api->encoder_open(ctx->params);
if (!ctx->encoder) {
av_log(avctx, AV_LOG_ERROR, "Cannot open libx265 encoder.\n");
@@ -632,6 +645,10 @@ static void free_picture(libx265Context *ctx, x265_picture *pic)
for (int i = 0; i < sei->numPayloads; i++)
av_free(sei->payloads[i].payload);
+#if X265_BUILD >= 167
+ av_free(pic->rpu.payload);
+#endif
+
if (pic->userData) {
int idx = (int)(intptr_t)pic->userData - 1;
rd_release(ctx, idx);
@@ -663,6 +680,7 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
sei->numPayloads = 0;
if (pic) {
+ AVFrameSideData *sd;
ReorderedData *rd;
int rd_idx;
@@ -763,6 +781,24 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
sei->numPayloads++;
}
}
+
+#if X265_BUILD >= 167
+ sd = av_frame_get_side_data(pic, AV_FRAME_DATA_DOVI_METADATA);
+ if (ctx->dovi.cfg.dv_profile && sd) {
+ const AVDOVIMetadata *metadata = (const AVDOVIMetadata *)sd->data;
+ ret = ff_dovi_rpu_generate(&ctx->dovi, metadata, &x265pic.rpu.payload,
+ &x265pic.rpu.payloadSize);
+ if (ret < 0) {
+ free_picture(ctx, &x265pic);
+ return ret;
+ }
+ } else if (ctx->dovi.cfg.dv_profile) {
+ av_log(avctx, AV_LOG_ERROR, "Dolby Vision enabled, but received frame "
+ "without AV_FRAME_DATA_DOVI_METADATA");
+ free_picture(ctx, &x265pic);
+ return AVERROR_INVALIDDATA;
+ }
+#endif
}
ret = ctx->api->encoder_encode(ctx->encoder, &nal, &nnal,
--
2.44.0
_______________________________________________
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".
^ permalink raw reply [flat|nested] 12+ messages in thread
* [FFmpeg-devel] [PATCH 10/10] avformat/movenc: warn if dovi cfg ignored
2024-04-03 15:43 [FFmpeg-devel] [PATCH 01/10] avcodec: add dolbyvision option Niklas Haas
` (7 preceding siblings ...)
2024-04-03 15:43 ` [FFmpeg-devel] [PATCH 09/10] avcodec/libx265: " Niklas Haas
@ 2024-04-03 15:43 ` Niklas Haas
2024-04-03 16:29 ` [FFmpeg-devel] [PATCH 01/10] avcodec: add dolbyvision option Andreas Rheinhardt
2024-04-03 18:32 ` James Almer
10 siblings, 0 replies; 12+ messages in thread
From: Niklas Haas @ 2024-04-03 15:43 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Niklas Haas
From: Niklas Haas <git@haasn.dev>
Since this is guarded behind strict unofficial, we should warn if the
user feeds a dolby vision stream to this muxer, as it will otherwise
result in a broken file.
---
libavformat/movenc.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index 15b65dcf96d..0f819214be9 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -2528,16 +2528,21 @@ static int mov_write_video_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContex
const AVPacketSideData *spherical_mapping = av_packet_side_data_get(track->st->codecpar->coded_side_data,
track->st->codecpar->nb_coded_side_data,
AV_PKT_DATA_SPHERICAL);
- const AVPacketSideData *dovi = av_packet_side_data_get(track->st->codecpar->coded_side_data,
- track->st->codecpar->nb_coded_side_data,
- AV_PKT_DATA_DOVI_CONF);
-
if (stereo_3d)
mov_write_st3d_tag(s, pb, (AVStereo3D*)stereo_3d->data);
if (spherical_mapping)
mov_write_sv3d_tag(mov->fc, pb, (AVSphericalMapping*)spherical_mapping->data);
- if (dovi)
+ }
+
+ if (track->mode == MODE_MP4) {
+ const AVPacketSideData *dovi = av_packet_side_data_get(track->st->codecpar->coded_side_data,
+ track->st->codecpar->nb_coded_side_data,
+ AV_PKT_DATA_DOVI_CONF);
+ if (dovi && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
mov_write_dvcc_dvvc_tag(s, pb, (AVDOVIDecoderConfigurationRecord *)dovi->data);
+ } else if (dovi) {
+ av_log(mov->fc, AV_LOG_WARNING, "Not writing 'dvcC'/'dvvC' box. Requires -strict unofficial.\n");
+ }
}
if (track->par->sample_aspect_ratio.den && track->par->sample_aspect_ratio.num) {
--
2.44.0
_______________________________________________
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".
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [FFmpeg-devel] [PATCH 01/10] avcodec: add dolbyvision option
2024-04-03 15:43 [FFmpeg-devel] [PATCH 01/10] avcodec: add dolbyvision option Niklas Haas
` (8 preceding siblings ...)
2024-04-03 15:43 ` [FFmpeg-devel] [PATCH 10/10] avformat/movenc: warn if dovi cfg ignored Niklas Haas
@ 2024-04-03 16:29 ` Andreas Rheinhardt
2024-04-03 18:32 ` James Almer
10 siblings, 0 replies; 12+ messages in thread
From: Andreas Rheinhardt @ 2024-04-03 16:29 UTC (permalink / raw)
To: ffmpeg-devel
Niklas Haas:
> From: Niklas Haas <git@haasn.dev>
>
> Tri-state yes/no/auto option. Allows users to set `dolbyvision` to `no`
> to suppress coding dolby vision even when supported by the target codec.
> ---
> doc/APIchanges | 3 +++
> doc/codecs.texi | 12 ++++++++++++
> libavcodec/avcodec.h | 11 +++++++++++
> libavcodec/options_table.h | 2 ++
> libavcodec/version.h | 2 +-
> 5 files changed, 29 insertions(+), 1 deletion(-)
>
> diff --git a/doc/APIchanges b/doc/APIchanges
> index 7eda1321cb0..a4484ceb670 100644
> --- a/doc/APIchanges
> +++ b/doc/APIchanges
> @@ -2,6 +2,9 @@ The last version increases of all libraries were on 2024-03-07
>
> API changes, most recent first:
>
> +2024-03-23 - f17e18d2922 - lavc 61.6.100 - avcodec.h
> + Add AVCodecContext.dolbyvision option.
> +
> 2024-04-xx - xxxxxxxxxx - lavu 59.12.100 - dovi_meta.h
> Add AVDOVIMetadata.ext_block_{offset,size}, AVDOVIMetadata.num_ext_blocks,
> AVDOVIDmData and AVDOVIDmLevel{1..6,8..11,254..255}, av_dovi_get_ext()
> diff --git a/doc/codecs.texi b/doc/codecs.texi
> index 6bdeb664e72..7203adc0489 100644
> --- a/doc/codecs.texi
> +++ b/doc/codecs.texi
> @@ -1018,6 +1018,18 @@ Note: The required alignment depends on if @code{AV_CODEC_FLAG_UNALIGNED} is set
> CPU. @code{AV_CODEC_FLAG_UNALIGNED} cannot be changed from the command line. Also hardware
> decoders will not apply left/top Cropping.
>
> +@item dolbyvision @var{integer} (@emph{encoding,video})
> +Whether to encode Dolby Vision metadata when transcoding.
> +Possible values:
> +@table @samp
> +@item auto
> +Enable when coded frames contain Dolby Vision side data (default)
> +@item yes/on
> +Enable always, error out when frames do not contain metadata
> +@item no/off
> +Disable always, strip any tagged metadata
> +@end table
> +
>
> @end table
>
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index 83dc487251c..f54f758608d 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -2075,6 +2075,17 @@ typedef struct AVCodecContext {
> */
> AVFrameSideData **decoded_side_data;
> int nb_decoded_side_data;
> +
> + /**
> + * Video encoding only. Whether to mark the coded stream as Dolby Vision.
> + * If set to FF_DOLBYVISION_AUTO, this will be enabled only if
> + * decoded_side_data contains a valid RPU.
> + *
> + * If enabled, sending frames without AV_FRAME_DATA_DOVI_METADATA is
> + * considered an error.
> + */
> + int dolbyvision;
> +#define FF_DOLBYVISION_AUTO -1
> } AVCodecContext;
>
> /**
> diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h
> index 7a2ef3474e7..d92269d2ff7 100644
> --- a/libavcodec/options_table.h
> +++ b/libavcodec/options_table.h
> @@ -407,6 +407,8 @@ static const AVOption avcodec_options[] = {
> {"mastering_display_metadata", .default_val.i64 = AV_PKT_DATA_MASTERING_DISPLAY_METADATA, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
> {"content_light_level", .default_val.i64 = AV_PKT_DATA_CONTENT_LIGHT_LEVEL, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
> {"icc_profile", .default_val.i64 = AV_PKT_DATA_ICC_PROFILE, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
> +{"dolbyvision", "flag stream as Dolby Vision", OFFSET(dolbyvision), AV_OPT_TYPE_INT, {.i64 = FF_DOLBYVISION_AUTO }, -1, 1, V|E, .unit = "dolbyvision" },
> +{"auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DOLBYVISION_AUTO }, .flags = V|E, .unit = "dolbyvision" },
> {NULL},
> };
>
> diff --git a/libavcodec/version.h b/libavcodec/version.h
> index 7aa95fc3f1c..da54f878874 100644
> --- a/libavcodec/version.h
> +++ b/libavcodec/version.h
> @@ -29,7 +29,7 @@
>
> #include "version_major.h"
>
> -#define LIBAVCODEC_VERSION_MINOR 5
> +#define LIBAVCODEC_VERSION_MINOR 6
> #define LIBAVCODEC_VERSION_MICRO 100
>
> #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
Why is this a global option when only a handful of encoders support it?
Apart from that, adding an option is not an APIChange.
- Andreas
_______________________________________________
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".
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [FFmpeg-devel] [PATCH 01/10] avcodec: add dolbyvision option
2024-04-03 15:43 [FFmpeg-devel] [PATCH 01/10] avcodec: add dolbyvision option Niklas Haas
` (9 preceding siblings ...)
2024-04-03 16:29 ` [FFmpeg-devel] [PATCH 01/10] avcodec: add dolbyvision option Andreas Rheinhardt
@ 2024-04-03 18:32 ` James Almer
10 siblings, 0 replies; 12+ messages in thread
From: James Almer @ 2024-04-03 18:32 UTC (permalink / raw)
To: ffmpeg-devel
On 4/3/2024 12:43 PM, Niklas Haas wrote:
> From: Niklas Haas <git@haasn.dev>
>
> Tri-state yes/no/auto option. Allows users to set `dolbyvision` to `no`
> to suppress coding dolby vision even when supported by the target codec.
> ---
> doc/APIchanges | 3 +++
> doc/codecs.texi | 12 ++++++++++++
> libavcodec/avcodec.h | 11 +++++++++++
> libavcodec/options_table.h | 2 ++
> libavcodec/version.h | 2 +-
> 5 files changed, 29 insertions(+), 1 deletion(-)
>
> diff --git a/doc/APIchanges b/doc/APIchanges
> index 7eda1321cb0..a4484ceb670 100644
> --- a/doc/APIchanges
> +++ b/doc/APIchanges
> @@ -2,6 +2,9 @@ The last version increases of all libraries were on 2024-03-07
>
> API changes, most recent first:
>
> +2024-03-23 - f17e18d2922 - lavc 61.6.100 - avcodec.h
> + Add AVCodecContext.dolbyvision option.
> +
> 2024-04-xx - xxxxxxxxxx - lavu 59.12.100 - dovi_meta.h
> Add AVDOVIMetadata.ext_block_{offset,size}, AVDOVIMetadata.num_ext_blocks,
> AVDOVIDmData and AVDOVIDmLevel{1..6,8..11,254..255}, av_dovi_get_ext()
> diff --git a/doc/codecs.texi b/doc/codecs.texi
> index 6bdeb664e72..7203adc0489 100644
> --- a/doc/codecs.texi
> +++ b/doc/codecs.texi
> @@ -1018,6 +1018,18 @@ Note: The required alignment depends on if @code{AV_CODEC_FLAG_UNALIGNED} is set
> CPU. @code{AV_CODEC_FLAG_UNALIGNED} cannot be changed from the command line. Also hardware
> decoders will not apply left/top Cropping.
>
> +@item dolbyvision @var{integer} (@emph{encoding,video})
> +Whether to encode Dolby Vision metadata when transcoding.
> +Possible values:
> +@table @samp
> +@item auto
> +Enable when coded frames contain Dolby Vision side data (default)
> +@item yes/on
> +Enable always, error out when frames do not contain metadata
> +@item no/off
> +Disable always, strip any tagged metadata
> +@end table
> +
>
> @end table
>
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index 83dc487251c..f54f758608d 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -2075,6 +2075,17 @@ typedef struct AVCodecContext {
> */
> AVFrameSideData **decoded_side_data;
> int nb_decoded_side_data;
> +
> + /**
> + * Video encoding only. Whether to mark the coded stream as Dolby Vision.
> + * If set to FF_DOLBYVISION_AUTO, this will be enabled only if
> + * decoded_side_data contains a valid RPU.
> + *
> + * If enabled, sending frames without AV_FRAME_DATA_DOVI_METADATA is
> + * considered an error.
> + */
> + int dolbyvision;
This should be encoder specific options, not a global one. Only three
encoders care about it at the end of this set.
> +#define FF_DOLBYVISION_AUTO -1
> } AVCodecContext;
>
> /**
> diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h
> index 7a2ef3474e7..d92269d2ff7 100644
> --- a/libavcodec/options_table.h
> +++ b/libavcodec/options_table.h
> @@ -407,6 +407,8 @@ static const AVOption avcodec_options[] = {
> {"mastering_display_metadata", .default_val.i64 = AV_PKT_DATA_MASTERING_DISPLAY_METADATA, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
> {"content_light_level", .default_val.i64 = AV_PKT_DATA_CONTENT_LIGHT_LEVEL, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
> {"icc_profile", .default_val.i64 = AV_PKT_DATA_ICC_PROFILE, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
> +{"dolbyvision", "flag stream as Dolby Vision", OFFSET(dolbyvision), AV_OPT_TYPE_INT, {.i64 = FF_DOLBYVISION_AUTO }, -1, 1, V|E, .unit = "dolbyvision" },
You can make it AV_OPT_TYPE_BOOL and still support -1 for auto. It's
done in many places.
> +{"auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DOLBYVISION_AUTO }, .flags = V|E, .unit = "dolbyvision" },
> {NULL},
> };
>
> diff --git a/libavcodec/version.h b/libavcodec/version.h
> index 7aa95fc3f1c..da54f878874 100644
> --- a/libavcodec/version.h
> +++ b/libavcodec/version.h
> @@ -29,7 +29,7 @@
>
> #include "version_major.h"
>
> -#define LIBAVCODEC_VERSION_MINOR 5
> +#define LIBAVCODEC_VERSION_MINOR 6
> #define LIBAVCODEC_VERSION_MICRO 100
>
> #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
_______________________________________________
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".
^ permalink raw reply [flat|nested] 12+ messages in thread