* [FFmpeg-devel] [PATCH 1/2] avcodec/cbs_av1: also store a pointer to the start of the tile group data
@ 2025-03-20 17:01 James Almer
2025-03-20 17:01 ` [FFmpeg-devel] [PATCH 2/2] avformat/movenccenc: add support for CENC AV1 encryption James Almer
0 siblings, 1 reply; 9+ messages in thread
From: James Almer @ 2025-03-20 17:01 UTC (permalink / raw)
To: ffmpeg-devel
This will be useful a following commit, where the offset of the Tile Group
inside a Frame OBU needs to be known.
Signed-off-by: James Almer <jamrial@gmail.com>
---
libavcodec/cbs_av1.c | 91 ++++++++++++++++++----------
libavcodec/cbs_av1.h | 4 ++
libavcodec/cbs_av1_syntax_template.c | 2 -
3 files changed, 62 insertions(+), 35 deletions(-)
diff --git a/libavcodec/cbs_av1.c b/libavcodec/cbs_av1.c
index fea079379b..54589a4065 100644
--- a/libavcodec/cbs_av1.c
+++ b/libavcodec/cbs_av1.c
@@ -782,7 +782,8 @@ fail:
static int cbs_av1_ref_tile_data(CodedBitstreamContext *ctx,
CodedBitstreamUnit *unit,
GetBitContext *gbc,
- AV1RawTileData *td)
+ AVBufferRef **data_ref,
+ uint8_t **data, size_t *data_size)
{
int pos;
@@ -795,12 +796,12 @@ static int cbs_av1_ref_tile_data(CodedBitstreamContext *ctx,
// Must be byte-aligned at this point.
av_assert0(pos % 8 == 0);
- td->data_ref = av_buffer_ref(unit->data_ref);
- if (!td->data_ref)
+ *data_ref = av_buffer_ref(unit->data_ref);
+ if (!*data_ref)
return AVERROR(ENOMEM);
- td->data = unit->data + pos / 8;
- td->data_size = unit->data_size - pos / 8;
+ *data = unit->data + pos / 8;
+ *data_size = unit->data_size - pos / 8;
return 0;
}
@@ -901,28 +902,31 @@ static int cbs_av1_read_unit(CodedBitstreamContext *ctx,
return err;
}
break;
- case AV1_OBU_TILE_GROUP:
- {
- err = cbs_av1_read_tile_group_obu(ctx, &gbc,
- &obu->obu.tile_group);
+ case AV1_OBU_FRAME:
+ err = cbs_av1_read_frame_obu(ctx, &gbc, &obu->obu.frame,
+ unit->data_ref);
if (err < 0)
return err;
-
+ // fall-through
+ case AV1_OBU_TILE_GROUP:
+ {
+ AV1RawTileGroup *tile_group = obu->header.obu_type == AV1_OBU_FRAME ? &obu->obu.frame.tile_group
+ : &obu->obu.tile_group;
err = cbs_av1_ref_tile_data(ctx, unit, &gbc,
- &obu->obu.tile_group.tile_data);
+ &tile_group->data_ref,
+ &tile_group->data,
+ &tile_group->data_size);
if (err < 0)
return err;
- }
- break;
- case AV1_OBU_FRAME:
- {
- err = cbs_av1_read_frame_obu(ctx, &gbc, &obu->obu.frame,
- unit->data_ref);
+
+ err = cbs_av1_read_tile_group_obu(ctx, &gbc, tile_group);
if (err < 0)
return err;
err = cbs_av1_ref_tile_data(ctx, unit, &gbc,
- &obu->obu.frame.tile_group.tile_data);
+ &tile_group->tile_data.data_ref,
+ &tile_group->tile_data.data,
+ &tile_group->tile_data.data_size);
if (err < 0)
return err;
}
@@ -935,7 +939,9 @@ static int cbs_av1_read_unit(CodedBitstreamContext *ctx,
return err;
err = cbs_av1_ref_tile_data(ctx, unit, &gbc,
- &obu->obu.tile_list.tile_data);
+ &obu->obu.tile_list.tile_data.data_ref,
+ &obu->obu.tile_list.tile_data.data,
+ &obu->obu.tile_list.tile_data.data_size);
if (err < 0)
return err;
}
@@ -1065,23 +1071,20 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx,
goto error;
}
break;
- case AV1_OBU_TILE_GROUP:
- {
- err = cbs_av1_write_tile_group_obu(ctx, pbc,
- &obu->obu.tile_group);
+ case AV1_OBU_FRAME:
+ err = cbs_av1_write_frame_obu(ctx, pbc, &obu->obu.frame, NULL);
if (err < 0)
goto error;
-
- td = &obu->obu.tile_group.tile_data;
- }
- break;
- case AV1_OBU_FRAME:
+ // fall-through
+ case AV1_OBU_TILE_GROUP:
{
- err = cbs_av1_write_frame_obu(ctx, pbc, &obu->obu.frame, NULL);
+ AV1RawTileGroup *tile_group = obu->header.obu_type == AV1_OBU_FRAME ? &obu->obu.frame.tile_group
+ : &obu->obu.tile_group;
+ err = cbs_av1_write_tile_group_obu(ctx, pbc, tile_group);
if (err < 0)
goto error;
- td = &obu->obu.frame.tile_group.tile_data;
+ td = &tile_group->tile_data;
}
break;
case AV1_OBU_TILE_LIST:
@@ -1258,11 +1261,33 @@ static const CodedBitstreamUnitTypeDescriptor cbs_av1_unit_types[] = {
CBS_UNIT_TYPE_POD(AV1_OBU_TEMPORAL_DELIMITER, AV1RawOBU),
CBS_UNIT_TYPE_POD(AV1_OBU_FRAME_HEADER, AV1RawOBU),
CBS_UNIT_TYPE_POD(AV1_OBU_REDUNDANT_FRAME_HEADER, AV1RawOBU),
-
- CBS_UNIT_TYPE_INTERNAL_REF(AV1_OBU_TILE_GROUP, AV1RawOBU,
+ {
+ .nb_unit_types = 1,
+ .unit_type.list[0] = AV1_OBU_TILE_GROUP,
+ .content_type = CBS_CONTENT_TYPE_INTERNAL_REFS,
+ .content_size = sizeof(AV1RawOBU),
+ .type.ref = {
+ .nb_offsets = 2,
+ .offsets = { offsetof(AV1RawOBU, obu.tile_group.data),
+ offsetof(AV1RawOBU, obu.tile_group.tile_data.data) }
+ },
+ },
+
+ {
+ .nb_unit_types = 1,
+ .unit_type.list[0] = AV1_OBU_FRAME,
+ .content_type = CBS_CONTENT_TYPE_INTERNAL_REFS,
+ .content_size = sizeof(AV1RawOBU),
+ .type.ref = {
+ .nb_offsets = 2,
+ .offsets = { offsetof(AV1RawOBU, obu.frame.tile_group.data),
+ offsetof(AV1RawOBU, obu.frame.tile_group.tile_data.data) }
+ },
+ },
+ /*CBS_UNIT_TYPE_INTERNAL_REF(AV1_OBU_TILE_GROUP, AV1RawOBU,
obu.tile_group.tile_data.data),
CBS_UNIT_TYPE_INTERNAL_REF(AV1_OBU_FRAME, AV1RawOBU,
- obu.frame.tile_group.tile_data.data),
+ obu.frame.tile_group.tile_data.data),*/
CBS_UNIT_TYPE_INTERNAL_REF(AV1_OBU_TILE_LIST, AV1RawOBU,
obu.tile_list.tile_data.data),
CBS_UNIT_TYPE_INTERNAL_REF(AV1_OBU_PADDING, AV1RawOBU,
diff --git a/libavcodec/cbs_av1.h b/libavcodec/cbs_av1.h
index 8586f2bf4a..62c7720142 100644
--- a/libavcodec/cbs_av1.h
+++ b/libavcodec/cbs_av1.h
@@ -295,6 +295,10 @@ typedef struct AV1RawTileData {
} AV1RawTileData;
typedef struct AV1RawTileGroup {
+ uint8_t *data;
+ AVBufferRef *data_ref;
+ size_t data_size;
+
uint8_t tile_start_and_end_present_flag;
uint16_t tg_start;
uint16_t tg_end;
diff --git a/libavcodec/cbs_av1_syntax_template.c b/libavcodec/cbs_av1_syntax_template.c
index a4a912482c..62a83945ec 100644
--- a/libavcodec/cbs_av1_syntax_template.c
+++ b/libavcodec/cbs_av1_syntax_template.c
@@ -1865,8 +1865,6 @@ static int FUNC(frame_obu)(CodedBitstreamContext *ctx, RWContext *rw,
CHECK(FUNC(byte_alignment)(ctx, rw));
- CHECK(FUNC(tile_group_obu)(ctx, rw, ¤t->tile_group));
-
return 0;
}
--
2.48.1
_______________________________________________
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] 9+ messages in thread
* [FFmpeg-devel] [PATCH 2/2] avformat/movenccenc: add support for CENC AV1 encryption
2025-03-20 17:01 [FFmpeg-devel] [PATCH 1/2] avcodec/cbs_av1: also store a pointer to the start of the tile group data James Almer
@ 2025-03-20 17:01 ` James Almer
2025-03-21 2:55 ` Andreas Rheinhardt
0 siblings, 1 reply; 9+ messages in thread
From: James Almer @ 2025-03-20 17:01 UTC (permalink / raw)
To: ffmpeg-devel
Signed-off-by: James Almer <jamrial@gmail.com>
---
configure | 2 +-
libavformat/Makefile | 1 +
libavformat/cbs.c | 1 +
libavformat/cbs_av1.c | 1 +
libavformat/movenc.c | 13 ++-
libavformat/movenccenc.c | 223 ++++++++++++++++++++++++++++++++++++++-
libavformat/movenccenc.h | 20 +++-
7 files changed, 255 insertions(+), 6 deletions(-)
create mode 100644 libavformat/cbs.c
create mode 100644 libavformat/cbs_av1.c
diff --git a/configure b/configure
index 14f7bcde0e..0f6b6c20fb 100755
--- a/configure
+++ b/configure
@@ -3689,7 +3689,7 @@ mlp_demuxer_select="mlp_parser"
mmf_muxer_select="riffenc"
mov_demuxer_select="iso_media riffdec"
mov_demuxer_suggest="iamfdec zlib"
-mov_muxer_select="iso_media iso_writer riffenc rtpenc_chain vp9_superframe_bsf aac_adtstoasc_bsf ac3_parser"
+mov_muxer_select="iso_media iso_writer riffenc rtpenc_chain vp9_superframe_bsf aac_adtstoasc_bsf ac3_parser cbs_av1"
mov_muxer_suggest="iamfenc"
mp3_demuxer_select="mpegaudio_parser"
mp3_muxer_select="mpegaudioheader"
diff --git a/libavformat/Makefile b/libavformat/Makefile
index 7730e7c4e6..1e57ae7d8a 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -740,6 +740,7 @@ SHLIBOBJS-$(CONFIG_JNI) += ffjni.o
SHLIBOBJS-$(CONFIG_JPEGXL_ANIM_DEMUXER) += jpegxl_parse.o
SHLIBOBJS-$(CONFIG_MATROSKA_DEMUXER) += mpeg4audio_sample_rates.o
SHLIBOBJS-$(CONFIG_MOV_DEMUXER) += ac3_channel_layout_tab.o
+SHLIBOBJS-$(CONFIG_MOV_MUXER) += cbs.o cbs_av1.o
SHLIBOBJS-$(CONFIG_MP3_MUXER) += mpegaudiotabs.o
SHLIBOBJS-$(CONFIG_MXF_MUXER) += golomb_tab.o \
rangecoder_dec.o
diff --git a/libavformat/cbs.c b/libavformat/cbs.c
new file mode 100644
index 0000000000..8f1235da8d
--- /dev/null
+++ b/libavformat/cbs.c
@@ -0,0 +1 @@
+#include "libavcodec/cbs.c"
diff --git a/libavformat/cbs_av1.c b/libavformat/cbs_av1.c
new file mode 100644
index 0000000000..32b9e72c57
--- /dev/null
+++ b/libavformat/cbs_av1.c
@@ -0,0 +1 @@
+#include "libavcodec/cbs_av1.c"
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index af013e1fc6..c60c46012f 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -6767,7 +6767,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
} else {
size = ff_vvc_annexb2mp4(pb, pkt->data, pkt->size, 0, NULL);
}
- } else if (par->codec_id == AV_CODEC_ID_AV1) {
+ } else if (par->codec_id == AV_CODEC_ID_AV1 && !trk->cenc.aes_ctr) {
if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
ret = ff_av1_filter_obus_buf(pkt->data, &reformatted_data,
&size, &offset);
@@ -6815,6 +6815,13 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
} else if(par->codec_id == AV_CODEC_ID_VVC) {
ret = AVERROR_PATCHWELCOME;
+ } else if(par->codec_id == AV_CODEC_ID_AV1) {
+ av_assert0(size == pkt->size);
+ ret = ff_mov_cenc_av1_write_obus(s, &trk->cenc, pb, pkt);
+ if (ret > 0) {
+ size = ret;
+ ret = 0;
+ }
} else {
ret = ff_mov_cenc_write_packet(&trk->cenc, pb, pkt->data, size);
}
@@ -8135,8 +8142,8 @@ static int mov_init(AVFormatContext *s)
if (mov->encryption_scheme == MOV_ENC_CENC_AES_CTR) {
ret = ff_mov_cenc_init(&track->cenc, mov->encryption_key,
(track->par->codec_id == AV_CODEC_ID_H264 || track->par->codec_id == AV_CODEC_ID_HEVC ||
- track->par->codec_id == AV_CODEC_ID_VVC),
- s->flags & AVFMT_FLAG_BITEXACT);
+ track->par->codec_id == AV_CODEC_ID_VVC || track->par->codec_id == AV_CODEC_ID_AV1),
+ track->par->codec_id, s->flags & AVFMT_FLAG_BITEXACT);
if (ret)
return ret;
}
diff --git a/libavformat/movenccenc.c b/libavformat/movenccenc.c
index f54d3bcbca..af801eb3a0 100644
--- a/libavformat/movenccenc.c
+++ b/libavformat/movenccenc.c
@@ -19,6 +19,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "movenccenc.h"
+#include "libavcodec/av1_parse.h"
+#include "libavcodec/bytestream.h"
+#include "libavcodec/cbs_av1.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/mem.h"
#include "avio_internal.h"
@@ -280,6 +283,203 @@ int ff_mov_cenc_avc_write_nal_units(AVFormatContext *s, MOVMuxCencContext* ctx,
return 0;
}
+static int write_tiles(AVFormatContext *s, MOVMuxCencContext *ctx, AVIOContext *pb, AV1_OBU_Type type,
+ const AV1RawFrameHeader *frame_header, const uint8_t *fh_data, size_t fh_data_size,
+ const AV1RawTileGroup *tile_group)
+{
+ GetByteContext gb;
+ size_t tgh_data_size = tile_group->data_size;
+ int cur_tile_num = frame_header->tile_cols * frame_header->tile_rows;
+ int total = 0;
+
+ // Get the Frame Header size
+ if (type == AV1_OBU_FRAME)
+ fh_data_size -= tgh_data_size;
+ // Get the Tile Group Header size
+ tgh_data_size -= tile_group->tile_data.data_size;
+
+ if (ctx->tile_num < cur_tile_num) {
+ int ret = av_reallocp_array(&ctx->tile_group_sizes, cur_tile_num,
+ sizeof(*ctx->tile_group_sizes));
+ if (ret < 0) {
+ ctx->tile_num = 0;
+ return ret;
+ }
+ }
+ ctx->tile_num = cur_tile_num;
+
+ total = fh_data_size + tgh_data_size;
+ ctx->clear_bytes += total;
+
+ bytestream2_init(&gb, tile_group->tile_data.data, tile_group->tile_data.data_size);
+
+ // Build a table with block sizes for encrypted bytes and clear bytes
+ for (unsigned tile_num = tile_group->tg_start; tile_num <= tile_group->tg_end; tile_num++) {
+ uint32_t encrypted_bytes, tile_size_bytes, tile_size = 0;
+
+ if (tile_num == tile_group->tg_end) {
+ tile_size = bytestream2_get_bytes_left(&gb);
+ encrypted_bytes = tile_size & ~0xFU;
+ ctx->clear_bytes += tile_size & 0xFU;
+
+ ctx->tile_group_sizes[tile_num].encrypted_bytes = encrypted_bytes;
+ ctx->tile_group_sizes[tile_num].aux_clear_bytes = encrypted_bytes ? ctx->clear_bytes : 0;
+ ctx->tile_group_sizes[tile_num].write_clear_bytes = tile_size & 0xFU;
+
+ if (encrypted_bytes)
+ ctx->clear_bytes = 0;
+ total += tile_size;
+
+ break;
+ }
+
+ tile_size_bytes = frame_header->tile_size_bytes_minus1 + 1;
+ if (bytestream2_get_bytes_left(&gb) < tile_size_bytes)
+ return AVERROR_INVALIDDATA;
+
+ for (int i = 0; i < tile_size_bytes; i++)
+ tile_size |= bytestream2_get_byteu(&gb) << 8 * i;
+ if (bytestream2_get_bytes_left(&gb) <= tile_size)
+ return AVERROR_INVALIDDATA;
+ tile_size++;
+
+ // The spec requires encrypted bytes to be in blocks multiple of 16
+ encrypted_bytes = tile_size & ~0xFU;
+ ctx->clear_bytes += (tile_size & 0xFU) + tile_size_bytes;
+
+ ctx->tile_group_sizes[tile_num].encrypted_bytes = encrypted_bytes;
+ ctx->tile_group_sizes[tile_num].aux_clear_bytes = encrypted_bytes ? ctx->clear_bytes : 0;
+ ctx->tile_group_sizes[tile_num].write_clear_bytes = (tile_size & 0xFU) + tile_size_bytes;
+
+ if (encrypted_bytes)
+ ctx->clear_bytes = 0;
+
+ total += tile_size + tile_size_bytes;
+ bytestream2_skipu(&gb, tile_size);
+ }
+
+ bytestream2_init(&gb, tile_group->tile_data.data, tile_group->tile_data.data_size);
+
+ avio_write(pb, fh_data, fh_data_size);
+ avio_write(pb, tile_group->data, tgh_data_size);
+
+ for (unsigned tile_num = tile_group->tg_start; tile_num <= tile_group->tg_end; tile_num++) {
+ const struct MOVMuxCencAV1TGInfo *sizes = &ctx->tile_group_sizes[tile_num];
+
+ avio_write(pb, gb.buffer, sizes->write_clear_bytes);
+ bytestream2_skipu(&gb, sizes->write_clear_bytes);
+ mov_cenc_write_encrypted(ctx, pb, gb.buffer, sizes->encrypted_bytes);
+ bytestream2_skipu(&gb, sizes->encrypted_bytes);
+ if (sizes->encrypted_bytes) {
+ unsigned clear_bytes = sizes->aux_clear_bytes;
+ if (clear_bytes > UINT16_MAX) {
+ auxiliary_info_add_subsample(ctx, UINT16_MAX, 0);
+ clear_bytes -= UINT16_MAX;
+ }
+ auxiliary_info_add_subsample(ctx, clear_bytes, sizes->encrypted_bytes);
+ }
+ }
+
+ return total;
+}
+
+int ff_mov_cenc_av1_write_obus(AVFormatContext *s, MOVMuxCencContext* ctx,
+ AVIOContext *pb, const AVPacket *pkt)
+{
+ CodedBitstreamFragment *td = &ctx->temporal_unit;
+ const CodedBitstreamAV1Context *av1 = ctx->cbc->priv_data;
+ const AV1RawFrameHeader *frame_header = NULL;
+ const uint8_t *fh_data = NULL;
+ size_t fh_data_size;
+ int out_size = 0, ret;
+
+ ret = mov_cenc_start_packet(ctx);
+ if (ret) {
+ return ret;
+ }
+
+ ret = ff_cbs_read_packet(ctx->cbc, td, pkt);
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "CENC-AV1: Failed to parse temporal unit.\n");
+ return ret;
+ }
+
+ if (!av1->sequence_header) {
+ av_log(s, AV_LOG_ERROR, "CENC-AV1: No sequence header available\n");
+ ret = AVERROR_INVALIDDATA;
+ goto end;
+ }
+
+ for (int i = 0; i < td->nb_units; i++) {
+ const CodedBitstreamUnit *unit = &td->units[i];
+ const AV1RawOBU *obu = unit->content;
+
+ switch (unit->type) {
+ case AV1_OBU_FRAME_HEADER:
+ if (!obu->obu.frame_header.show_existing_frame) {
+ frame_header = &obu->obu.frame_header;
+ fh_data = unit->data;
+ fh_data_size = unit->data_size;
+ break;
+ }
+ // fall-through
+ case AV1_OBU_SEQUENCE_HEADER:
+ case AV1_OBU_METADATA:
+ avio_write(pb, unit->data, unit->data_size);
+ ctx->clear_bytes += unit->data_size;
+ out_size += unit->data_size;
+ break;
+ case AV1_OBU_FRAME:
+ frame_header = &obu->obu.frame.header;
+ fh_data = unit->data;
+ fh_data_size = unit->data_size;
+ // fall-through
+ case AV1_OBU_TILE_GROUP:
+ {
+ const AV1RawTileGroup *tile_group;
+
+ if (!frame_header){
+ ret = AVERROR_INVALIDDATA;
+ goto end;
+ }
+
+ if (unit->type == AV1_OBU_FRAME)
+ tile_group = &obu->obu.frame.tile_group;
+ else
+ tile_group = &obu->obu.tile_group;
+
+ ret = write_tiles(s, ctx, pb, unit->type,
+ frame_header, fh_data, fh_data_size, tile_group);
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "CENC-AV1: Failed to write tiles\n");
+ goto end;
+ }
+ av_assert0(ret == unit->data_size);
+ out_size += unit->data_size;
+ frame_header = NULL;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (ctx->clear_bytes)
+ auxiliary_info_add_subsample(ctx, ctx->clear_bytes, 0);
+ ctx->clear_bytes = 0;
+
+ ret = mov_cenc_end_packet(ctx);
+ if (ret) {
+ ret = AVERROR_INVALIDDATA;
+ goto end;
+ }
+
+ ret = out_size;
+end:
+ ff_cbs_fragment_reset(td);
+ return ret;
+}
+
/* TODO: reuse this function from movenc.c */
static int64_t update_size(AVIOContext *pb, int64_t pos)
{
@@ -388,8 +588,16 @@ int ff_mov_cenc_write_sinf_tag(MOVTrack* track, AVIOContext *pb, uint8_t* kid)
return update_size(pb, pos);
}
+static const CodedBitstreamUnitType decompose_unit_types[] = {
+ AV1_OBU_TEMPORAL_DELIMITER,
+ AV1_OBU_SEQUENCE_HEADER,
+ AV1_OBU_FRAME_HEADER,
+ AV1_OBU_TILE_GROUP,
+ AV1_OBU_FRAME,
+};
+
int ff_mov_cenc_init(MOVMuxCencContext* ctx, uint8_t* encryption_key,
- int use_subsamples, int bitexact)
+ int use_subsamples, enum AVCodecID codec_id, int bitexact)
{
int ret;
@@ -409,6 +617,15 @@ int ff_mov_cenc_init(MOVMuxCencContext* ctx, uint8_t* encryption_key,
ctx->use_subsamples = use_subsamples;
+ if (codec_id == AV_CODEC_ID_AV1) {
+ ret = ff_cbs_init(&ctx->cbc, codec_id, NULL);
+ if (ret < 0)
+ return ret;
+
+ ctx->cbc->decompose_unit_types = decompose_unit_types;
+ ctx->cbc->nb_decompose_unit_types = FF_ARRAY_ELEMS(decompose_unit_types);
+ }
+
return 0;
}
@@ -417,4 +634,8 @@ void ff_mov_cenc_free(MOVMuxCencContext* ctx)
av_aes_ctr_free(ctx->aes_ctr);
av_freep(&ctx->auxiliary_info);
av_freep(&ctx->auxiliary_info_sizes);
+
+ av_freep(&ctx->tile_group_sizes);
+ ff_cbs_fragment_free(&ctx->temporal_unit);
+ ff_cbs_close(&ctx->cbc);
}
diff --git a/libavformat/movenccenc.h b/libavformat/movenccenc.h
index 7da5268090..722914dc1c 100644
--- a/libavformat/movenccenc.h
+++ b/libavformat/movenccenc.h
@@ -23,6 +23,7 @@
#define AVFORMAT_MOVENCCENC_H
#include "libavutil/aes_ctr.h"
+#include "libavcodec/cbs.h"
#include "avformat.h"
#include "avio.h"
@@ -30,6 +31,12 @@
struct MOVTrack;
+struct MOVMuxCencAV1TGInfo {
+ uint32_t encrypted_bytes;
+ uint32_t write_clear_bytes;
+ uint32_t aux_clear_bytes;
+};
+
typedef struct {
struct AVAESCTR* aes_ctr;
uint8_t* auxiliary_info;
@@ -43,6 +50,14 @@ typedef struct {
size_t auxiliary_info_subsample_start;
uint8_t* auxiliary_info_sizes;
size_t auxiliary_info_sizes_alloc_size;
+
+ /* AV1 */
+ struct MOVMuxCencAV1TGInfo *tile_group_sizes;
+ uint32_t clear_bytes;
+ int tile_num;
+ /* CBS */
+ CodedBitstreamContext *cbc;
+ CodedBitstreamFragment temporal_unit;
} MOVMuxCencContext;
/**
@@ -50,7 +65,8 @@ typedef struct {
* @param key encryption key, must have a length of AES_CTR_KEY_SIZE
* @param use_subsamples when enabled parts of a packet can be encrypted, otherwise the whole packet is encrypted
*/
-int ff_mov_cenc_init(MOVMuxCencContext* ctx, uint8_t* encryption_key, int use_subsamples, int bitexact);
+int ff_mov_cenc_init(MOVMuxCencContext* ctx, uint8_t* encryption_key, int use_subsamples,
+ enum AVCodecID codec_id, int bitexact);
/**
* Free a CENC context
@@ -73,6 +89,8 @@ int ff_mov_cenc_avc_parse_nal_units(MOVMuxCencContext* ctx, AVIOContext *pb, con
int ff_mov_cenc_avc_write_nal_units(AVFormatContext *s, MOVMuxCencContext* ctx, int nal_length_size,
AVIOContext *pb, const uint8_t *buf_in, int size);
+int ff_mov_cenc_av1_write_obus(AVFormatContext *s, MOVMuxCencContext* ctx,
+ AVIOContext *pb, const AVPacket *pkt);
/**
* Write the cenc atoms that should reside inside stbl
*/
--
2.48.1
_______________________________________________
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] 9+ messages in thread
* Re: [FFmpeg-devel] [PATCH 2/2] avformat/movenccenc: add support for CENC AV1 encryption
2025-03-20 17:01 ` [FFmpeg-devel] [PATCH 2/2] avformat/movenccenc: add support for CENC AV1 encryption James Almer
@ 2025-03-21 2:55 ` Andreas Rheinhardt
2025-03-21 3:30 ` James Almer
0 siblings, 1 reply; 9+ messages in thread
From: Andreas Rheinhardt @ 2025-03-21 2:55 UTC (permalink / raw)
To: ffmpeg-devel
James Almer:
> Signed-off-by: James Almer <jamrial@gmail.com>
> ---
> configure | 2 +-
> libavformat/Makefile | 1 +
> libavformat/cbs.c | 1 +
> libavformat/cbs_av1.c | 1 +
> libavformat/movenc.c | 13 ++-
> libavformat/movenccenc.c | 223 ++++++++++++++++++++++++++++++++++++++-
> libavformat/movenccenc.h | 20 +++-
> 7 files changed, 255 insertions(+), 6 deletions(-)
> create mode 100644 libavformat/cbs.c
> create mode 100644 libavformat/cbs_av1.c
>
> diff --git a/configure b/configure
> index 14f7bcde0e..0f6b6c20fb 100755
> --- a/configure
> +++ b/configure
> @@ -3689,7 +3689,7 @@ mlp_demuxer_select="mlp_parser"
> mmf_muxer_select="riffenc"
> mov_demuxer_select="iso_media riffdec"
> mov_demuxer_suggest="iamfdec zlib"
> -mov_muxer_select="iso_media iso_writer riffenc rtpenc_chain vp9_superframe_bsf aac_adtstoasc_bsf ac3_parser"
> +mov_muxer_select="iso_media iso_writer riffenc rtpenc_chain vp9_superframe_bsf aac_adtstoasc_bsf ac3_parser cbs_av1"
> mov_muxer_suggest="iamfenc"
> mp3_demuxer_select="mpegaudio_parser"
> mp3_muxer_select="mpegaudioheader"
> diff --git a/libavformat/Makefile b/libavformat/Makefile
> index 7730e7c4e6..1e57ae7d8a 100644
> --- a/libavformat/Makefile
> +++ b/libavformat/Makefile
> @@ -740,6 +740,7 @@ SHLIBOBJS-$(CONFIG_JNI) += ffjni.o
> SHLIBOBJS-$(CONFIG_JPEGXL_ANIM_DEMUXER) += jpegxl_parse.o
> SHLIBOBJS-$(CONFIG_MATROSKA_DEMUXER) += mpeg4audio_sample_rates.o
> SHLIBOBJS-$(CONFIG_MOV_DEMUXER) += ac3_channel_layout_tab.o
> +SHLIBOBJS-$(CONFIG_MOV_MUXER) += cbs.o cbs_av1.o
> SHLIBOBJS-$(CONFIG_MP3_MUXER) += mpegaudiotabs.o
> SHLIBOBJS-$(CONFIG_MXF_MUXER) += golomb_tab.o \
> rangecoder_dec.o
> diff --git a/libavformat/cbs.c b/libavformat/cbs.c
> new file mode 100644
> index 0000000000..8f1235da8d
> --- /dev/null
> +++ b/libavformat/cbs.c
> @@ -0,0 +1 @@
> +#include "libavcodec/cbs.c"
> diff --git a/libavformat/cbs_av1.c b/libavformat/cbs_av1.c
> new file mode 100644
> index 0000000000..32b9e72c57
> --- /dev/null
> +++ b/libavformat/cbs_av1.c
> @@ -0,0 +1 @@
> +#include "libavcodec/cbs_av1.c"
> diff --git a/libavformat/movenc.c b/libavformat/movenc.c
> index af013e1fc6..c60c46012f 100644
> --- a/libavformat/movenc.c
> +++ b/libavformat/movenc.c
> @@ -6767,7 +6767,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
> } else {
> size = ff_vvc_annexb2mp4(pb, pkt->data, pkt->size, 0, NULL);
> }
> - } else if (par->codec_id == AV_CODEC_ID_AV1) {
> + } else if (par->codec_id == AV_CODEC_ID_AV1 && !trk->cenc.aes_ctr) {
> if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
> ret = ff_av1_filter_obus_buf(pkt->data, &reformatted_data,
> &size, &offset);
> @@ -6815,6 +6815,13 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
> ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
> } else if(par->codec_id == AV_CODEC_ID_VVC) {
> ret = AVERROR_PATCHWELCOME;
> + } else if(par->codec_id == AV_CODEC_ID_AV1) {
> + av_assert0(size == pkt->size);
> + ret = ff_mov_cenc_av1_write_obus(s, &trk->cenc, pb, pkt);
> + if (ret > 0) {
> + size = ret;
> + ret = 0;
> + }
> } else {
> ret = ff_mov_cenc_write_packet(&trk->cenc, pb, pkt->data, size);
> }
> @@ -8135,8 +8142,8 @@ static int mov_init(AVFormatContext *s)
> if (mov->encryption_scheme == MOV_ENC_CENC_AES_CTR) {
> ret = ff_mov_cenc_init(&track->cenc, mov->encryption_key,
> (track->par->codec_id == AV_CODEC_ID_H264 || track->par->codec_id == AV_CODEC_ID_HEVC ||
> - track->par->codec_id == AV_CODEC_ID_VVC),
> - s->flags & AVFMT_FLAG_BITEXACT);
> + track->par->codec_id == AV_CODEC_ID_VVC || track->par->codec_id == AV_CODEC_ID_AV1),
> + track->par->codec_id, s->flags & AVFMT_FLAG_BITEXACT);
> if (ret)
> return ret;
> }
> diff --git a/libavformat/movenccenc.c b/libavformat/movenccenc.c
> index f54d3bcbca..af801eb3a0 100644
> --- a/libavformat/movenccenc.c
> +++ b/libavformat/movenccenc.c
> @@ -19,6 +19,9 @@
> * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> */
> #include "movenccenc.h"
> +#include "libavcodec/av1_parse.h"
> +#include "libavcodec/bytestream.h"
> +#include "libavcodec/cbs_av1.h"
> #include "libavutil/intreadwrite.h"
> #include "libavutil/mem.h"
> #include "avio_internal.h"
> @@ -280,6 +283,203 @@ int ff_mov_cenc_avc_write_nal_units(AVFormatContext *s, MOVMuxCencContext* ctx,
> return 0;
> }
>
> +static int write_tiles(AVFormatContext *s, MOVMuxCencContext *ctx, AVIOContext *pb, AV1_OBU_Type type,
> + const AV1RawFrameHeader *frame_header, const uint8_t *fh_data, size_t fh_data_size,
> + const AV1RawTileGroup *tile_group)
> +{
> + GetByteContext gb;
> + size_t tgh_data_size = tile_group->data_size;
> + int cur_tile_num = frame_header->tile_cols * frame_header->tile_rows;
> + int total = 0;
> +
> + // Get the Frame Header size
> + if (type == AV1_OBU_FRAME)
> + fh_data_size -= tgh_data_size;
> + // Get the Tile Group Header size
> + tgh_data_size -= tile_group->tile_data.data_size;
> +
> + if (ctx->tile_num < cur_tile_num) {
> + int ret = av_reallocp_array(&ctx->tile_group_sizes, cur_tile_num,
> + sizeof(*ctx->tile_group_sizes));
> + if (ret < 0) {
> + ctx->tile_num = 0;
> + return ret;
> + }
> + }
> + ctx->tile_num = cur_tile_num;
> +
> + total = fh_data_size + tgh_data_size;
> + ctx->clear_bytes += total;
> +
> + bytestream2_init(&gb, tile_group->tile_data.data, tile_group->tile_data.data_size);
> +
> + // Build a table with block sizes for encrypted bytes and clear bytes
> + for (unsigned tile_num = tile_group->tg_start; tile_num <= tile_group->tg_end; tile_num++) {
> + uint32_t encrypted_bytes, tile_size_bytes, tile_size = 0;
> +
> + if (tile_num == tile_group->tg_end) {
> + tile_size = bytestream2_get_bytes_left(&gb);
> + encrypted_bytes = tile_size & ~0xFU;
> + ctx->clear_bytes += tile_size & 0xFU;
> +
> + ctx->tile_group_sizes[tile_num].encrypted_bytes = encrypted_bytes;
> + ctx->tile_group_sizes[tile_num].aux_clear_bytes = encrypted_bytes ? ctx->clear_bytes : 0;
> + ctx->tile_group_sizes[tile_num].write_clear_bytes = tile_size & 0xFU;
> +
> + if (encrypted_bytes)
> + ctx->clear_bytes = 0;
> + total += tile_size;
> +
> + break;
> + }
> +
> + tile_size_bytes = frame_header->tile_size_bytes_minus1 + 1;
> + if (bytestream2_get_bytes_left(&gb) < tile_size_bytes)
> + return AVERROR_INVALIDDATA;
> +
> + for (int i = 0; i < tile_size_bytes; i++)
> + tile_size |= bytestream2_get_byteu(&gb) << 8 * i;
> + if (bytestream2_get_bytes_left(&gb) <= tile_size)
> + return AVERROR_INVALIDDATA;
> + tile_size++;
> +
> + // The spec requires encrypted bytes to be in blocks multiple of 16
> + encrypted_bytes = tile_size & ~0xFU;
> + ctx->clear_bytes += (tile_size & 0xFU) + tile_size_bytes;
> +
> + ctx->tile_group_sizes[tile_num].encrypted_bytes = encrypted_bytes;
> + ctx->tile_group_sizes[tile_num].aux_clear_bytes = encrypted_bytes ? ctx->clear_bytes : 0;
> + ctx->tile_group_sizes[tile_num].write_clear_bytes = (tile_size & 0xFU) + tile_size_bytes;
> +
> + if (encrypted_bytes)
> + ctx->clear_bytes = 0;
> +
> + total += tile_size + tile_size_bytes;
> + bytestream2_skipu(&gb, tile_size);
> + }
> +
> + bytestream2_init(&gb, tile_group->tile_data.data, tile_group->tile_data.data_size);
> +
> + avio_write(pb, fh_data, fh_data_size);
> + avio_write(pb, tile_group->data, tgh_data_size);
> +
> + for (unsigned tile_num = tile_group->tg_start; tile_num <= tile_group->tg_end; tile_num++) {
> + const struct MOVMuxCencAV1TGInfo *sizes = &ctx->tile_group_sizes[tile_num];
> +
> + avio_write(pb, gb.buffer, sizes->write_clear_bytes);
> + bytestream2_skipu(&gb, sizes->write_clear_bytes);
> + mov_cenc_write_encrypted(ctx, pb, gb.buffer, sizes->encrypted_bytes);
> + bytestream2_skipu(&gb, sizes->encrypted_bytes);
> + if (sizes->encrypted_bytes) {
> + unsigned clear_bytes = sizes->aux_clear_bytes;
> + if (clear_bytes > UINT16_MAX) {
> + auxiliary_info_add_subsample(ctx, UINT16_MAX, 0);
> + clear_bytes -= UINT16_MAX;
> + }
> + auxiliary_info_add_subsample(ctx, clear_bytes, sizes->encrypted_bytes);
> + }
> + }
> +
> + return total;
> +}
> +
> +int ff_mov_cenc_av1_write_obus(AVFormatContext *s, MOVMuxCencContext* ctx,
> + AVIOContext *pb, const AVPacket *pkt)
> +{
> + CodedBitstreamFragment *td = &ctx->temporal_unit;
> + const CodedBitstreamAV1Context *av1 = ctx->cbc->priv_data;
> + const AV1RawFrameHeader *frame_header = NULL;
> + const uint8_t *fh_data = NULL;
> + size_t fh_data_size;
> + int out_size = 0, ret;
> +
> + ret = mov_cenc_start_packet(ctx);
> + if (ret) {
> + return ret;
> + }
> +
> + ret = ff_cbs_read_packet(ctx->cbc, td, pkt);
> + if (ret < 0) {
> + av_log(s, AV_LOG_ERROR, "CENC-AV1: Failed to parse temporal unit.\n");
> + return ret;
> + }
> +
> + if (!av1->sequence_header) {
> + av_log(s, AV_LOG_ERROR, "CENC-AV1: No sequence header available\n");
> + ret = AVERROR_INVALIDDATA;
> + goto end;
> + }
> +
> + for (int i = 0; i < td->nb_units; i++) {
> + const CodedBitstreamUnit *unit = &td->units[i];
> + const AV1RawOBU *obu = unit->content;
> +
> + switch (unit->type) {
> + case AV1_OBU_FRAME_HEADER:
> + if (!obu->obu.frame_header.show_existing_frame) {
> + frame_header = &obu->obu.frame_header;
> + fh_data = unit->data;
> + fh_data_size = unit->data_size;
> + break;
> + }
> + // fall-through
> + case AV1_OBU_SEQUENCE_HEADER:
> + case AV1_OBU_METADATA:
> + avio_write(pb, unit->data, unit->data_size);
> + ctx->clear_bytes += unit->data_size;
> + out_size += unit->data_size;
> + break;
> + case AV1_OBU_FRAME:
> + frame_header = &obu->obu.frame.header;
> + fh_data = unit->data;
> + fh_data_size = unit->data_size;
> + // fall-through
> + case AV1_OBU_TILE_GROUP:
> + {
> + const AV1RawTileGroup *tile_group;
> +
> + if (!frame_header){
> + ret = AVERROR_INVALIDDATA;
> + goto end;
> + }
> +
> + if (unit->type == AV1_OBU_FRAME)
> + tile_group = &obu->obu.frame.tile_group;
> + else
> + tile_group = &obu->obu.tile_group;
> +
> + ret = write_tiles(s, ctx, pb, unit->type,
> + frame_header, fh_data, fh_data_size, tile_group);
> + if (ret < 0) {
> + av_log(s, AV_LOG_ERROR, "CENC-AV1: Failed to write tiles\n");
> + goto end;
> + }
> + av_assert0(ret == unit->data_size);
> + out_size += unit->data_size;
> + frame_header = NULL;
> + }
> + break;
> + default:
> + break;
> + }
> + }
> +
> + if (ctx->clear_bytes)
> + auxiliary_info_add_subsample(ctx, ctx->clear_bytes, 0);
> + ctx->clear_bytes = 0;
> +
> + ret = mov_cenc_end_packet(ctx);
> + if (ret) {
> + ret = AVERROR_INVALIDDATA;
> + goto end;
> + }
> +
> + ret = out_size;
> +end:
> + ff_cbs_fragment_reset(td);
> + return ret;
> +}
> +
> /* TODO: reuse this function from movenc.c */
> static int64_t update_size(AVIOContext *pb, int64_t pos)
> {
> @@ -388,8 +588,16 @@ int ff_mov_cenc_write_sinf_tag(MOVTrack* track, AVIOContext *pb, uint8_t* kid)
> return update_size(pb, pos);
> }
>
> +static const CodedBitstreamUnitType decompose_unit_types[] = {
> + AV1_OBU_TEMPORAL_DELIMITER,
> + AV1_OBU_SEQUENCE_HEADER,
> + AV1_OBU_FRAME_HEADER,
> + AV1_OBU_TILE_GROUP,
> + AV1_OBU_FRAME,
> +};
> +
> int ff_mov_cenc_init(MOVMuxCencContext* ctx, uint8_t* encryption_key,
> - int use_subsamples, int bitexact)
> + int use_subsamples, enum AVCodecID codec_id, int bitexact)
> {
> int ret;
>
> @@ -409,6 +617,15 @@ int ff_mov_cenc_init(MOVMuxCencContext* ctx, uint8_t* encryption_key,
>
> ctx->use_subsamples = use_subsamples;
>
> + if (codec_id == AV_CODEC_ID_AV1) {
> + ret = ff_cbs_init(&ctx->cbc, codec_id, NULL);
> + if (ret < 0)
> + return ret;
> +
> + ctx->cbc->decompose_unit_types = decompose_unit_types;
> + ctx->cbc->nb_decompose_unit_types = FF_ARRAY_ELEMS(decompose_unit_types);
> + }
> +
> return 0;
> }
>
> @@ -417,4 +634,8 @@ void ff_mov_cenc_free(MOVMuxCencContext* ctx)
> av_aes_ctr_free(ctx->aes_ctr);
> av_freep(&ctx->auxiliary_info);
> av_freep(&ctx->auxiliary_info_sizes);
> +
> + av_freep(&ctx->tile_group_sizes);
> + ff_cbs_fragment_free(&ctx->temporal_unit);
> + ff_cbs_close(&ctx->cbc);
> }
> diff --git a/libavformat/movenccenc.h b/libavformat/movenccenc.h
> index 7da5268090..722914dc1c 100644
> --- a/libavformat/movenccenc.h
> +++ b/libavformat/movenccenc.h
> @@ -23,6 +23,7 @@
> #define AVFORMAT_MOVENCCENC_H
>
> #include "libavutil/aes_ctr.h"
> +#include "libavcodec/cbs.h"
> #include "avformat.h"
> #include "avio.h"
>
> @@ -30,6 +31,12 @@
>
> struct MOVTrack;
>
> +struct MOVMuxCencAV1TGInfo {
> + uint32_t encrypted_bytes;
> + uint32_t write_clear_bytes;
> + uint32_t aux_clear_bytes;
> +};
> +
> typedef struct {
> struct AVAESCTR* aes_ctr;
> uint8_t* auxiliary_info;
> @@ -43,6 +50,14 @@ typedef struct {
> size_t auxiliary_info_subsample_start;
> uint8_t* auxiliary_info_sizes;
> size_t auxiliary_info_sizes_alloc_size;
> +
> + /* AV1 */
> + struct MOVMuxCencAV1TGInfo *tile_group_sizes;
> + uint32_t clear_bytes;
> + int tile_num;
> + /* CBS */
> + CodedBitstreamContext *cbc;
> + CodedBitstreamFragment temporal_unit;
> } MOVMuxCencContext;
>
> /**
> @@ -50,7 +65,8 @@ typedef struct {
> * @param key encryption key, must have a length of AES_CTR_KEY_SIZE
> * @param use_subsamples when enabled parts of a packet can be encrypted, otherwise the whole packet is encrypted
> */
> -int ff_mov_cenc_init(MOVMuxCencContext* ctx, uint8_t* encryption_key, int use_subsamples, int bitexact);
> +int ff_mov_cenc_init(MOVMuxCencContext* ctx, uint8_t* encryption_key, int use_subsamples,
> + enum AVCodecID codec_id, int bitexact);
>
> /**
> * Free a CENC context
> @@ -73,6 +89,8 @@ int ff_mov_cenc_avc_parse_nal_units(MOVMuxCencContext* ctx, AVIOContext *pb, con
> int ff_mov_cenc_avc_write_nal_units(AVFormatContext *s, MOVMuxCencContext* ctx, int nal_length_size,
> AVIOContext *pb, const uint8_t *buf_in, int size);
>
> +int ff_mov_cenc_av1_write_obus(AVFormatContext *s, MOVMuxCencContext* ctx,
> + AVIOContext *pb, const AVPacket *pkt);
> /**
> * Write the cenc atoms that should reside inside stbl
> */
Duplicating .o files is meant for small stuff, not for gigantic things
like cbs_av1.o (whose .text is 86519B here).
- 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] 9+ messages in thread
* Re: [FFmpeg-devel] [PATCH 2/2] avformat/movenccenc: add support for CENC AV1 encryption
2025-03-21 2:55 ` Andreas Rheinhardt
@ 2025-03-21 3:30 ` James Almer
2025-03-21 3:52 ` Andreas Rheinhardt
0 siblings, 1 reply; 9+ messages in thread
From: James Almer @ 2025-03-21 3:30 UTC (permalink / raw)
To: ffmpeg-devel
[-- Attachment #1.1.1: Type: text/plain, Size: 418 bytes --]
On 3/20/2025 11:55 PM, Andreas Rheinhardt wrote:
> Duplicating .o files is meant for small stuff, not for gigantic things
> like cbs_av1.o (whose .text is 86519B here).
This feature requires complete frame and tile group parsing, which in
turn requires complete sequence header parsing. The amount of work to
get that much parsing code in lavf will be huge for little (if any) gain
in total object size.
[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]
[-- Attachment #2: Type: text/plain, Size: 251 bytes --]
_______________________________________________
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] 9+ messages in thread
* Re: [FFmpeg-devel] [PATCH 2/2] avformat/movenccenc: add support for CENC AV1 encryption
2025-03-21 3:30 ` James Almer
@ 2025-03-21 3:52 ` Andreas Rheinhardt
2025-03-21 12:50 ` James Almer
2025-03-21 19:42 ` [FFmpeg-devel] [PATCH 2/3] avcodec/cbs: allow fine tunning selection of features James Almer
0 siblings, 2 replies; 9+ messages in thread
From: Andreas Rheinhardt @ 2025-03-21 3:52 UTC (permalink / raw)
To: ffmpeg-devel
James Almer:
> On 3/20/2025 11:55 PM, Andreas Rheinhardt wrote:
>> Duplicating .o files is meant for small stuff, not for gigantic things
>> like cbs_av1.o (whose .text is 86519B here).
>
> This feature requires complete frame and tile group parsing, which in
> turn requires complete sequence header parsing. The amount of work to
> get that much parsing code in lavf will be huge for little (if any) gain
> in total object size.
>
a) Completely wrong: Approximately half of cbs_av1.o is code for writing
which lavf doesn't use.
b) Even the reading code is littered with CBS's tracing stuff which lavf
won't use.
c) There is also parsing stuff that won't be used.
d) Btw: Your patch shouldn't even compile in shared builds if the other
CBS modules are enabled as your lavf/cbs.o will try to pull in the other
ff_cbs_type_*.
- 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] 9+ messages in thread
* Re: [FFmpeg-devel] [PATCH 2/2] avformat/movenccenc: add support for CENC AV1 encryption
2025-03-21 3:52 ` Andreas Rheinhardt
@ 2025-03-21 12:50 ` James Almer
2025-03-21 19:42 ` [FFmpeg-devel] [PATCH 2/3] avcodec/cbs: allow fine tunning selection of features James Almer
1 sibling, 0 replies; 9+ messages in thread
From: James Almer @ 2025-03-21 12:50 UTC (permalink / raw)
To: ffmpeg-devel
[-- Attachment #1.1.1: Type: text/plain, Size: 1005 bytes --]
On 3/21/2025 12:52 AM, Andreas Rheinhardt wrote:
> James Almer:
>> On 3/20/2025 11:55 PM, Andreas Rheinhardt wrote:
>>> Duplicating .o files is meant for small stuff, not for gigantic things
>>> like cbs_av1.o (whose .text is 86519B here).
>>
>> This feature requires complete frame and tile group parsing, which in
>> turn requires complete sequence header parsing. The amount of work to
>> get that much parsing code in lavf will be huge for little (if any) gain
>> in total object size.
>>
>
> a) Completely wrong: Approximately half of cbs_av1.o is code for writing
> which lavf doesn't use.
> b) Even the reading code is littered with CBS's tracing stuff which lavf
> won't use.
> c) There is also parsing stuff that won't be used.
I could make it so i selectively enable portions of the module.
> d) Btw: Your patch shouldn't even compile in shared builds if the other
> CBS modules are enabled as your lavf/cbs.o will try to pull in the other
> ff_cbs_type_*.
Ditto.
[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]
[-- Attachment #2: Type: text/plain, Size: 251 bytes --]
_______________________________________________
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] 9+ messages in thread
* [FFmpeg-devel] [PATCH 2/3] avcodec/cbs: allow fine tunning selection of features
2025-03-21 3:52 ` Andreas Rheinhardt
2025-03-21 12:50 ` James Almer
@ 2025-03-21 19:42 ` James Almer
2025-03-21 19:42 ` [FFmpeg-devel] [PATCH v2 3/3] avformat/movenccenc: add support for CENC AV1 encryption James Almer
2025-03-22 14:25 ` [FFmpeg-devel] [PATCH 2/3] avcodec/cbs: allow fine tunning selection of features Andreas Rheinhardt
1 sibling, 2 replies; 9+ messages in thread
From: James Almer @ 2025-03-21 19:42 UTC (permalink / raw)
To: ffmpeg-devel
This will be useful in an upcoming commit, where CBS will be utilized by
a module outside libavcodec.
Signed-off-by: James Almer <jamrial@gmail.com>
---
libavcodec/cbs.c | 100 ++++++++++++++++++++++-----
libavcodec/cbs_av1.c | 64 ++++++++++++++++-
libavcodec/cbs_av1.h | 15 ++++
libavcodec/cbs_av1_syntax_template.c | 6 ++
libavcodec/cbs_internal.h | 48 +++++++++++++
5 files changed, 212 insertions(+), 21 deletions(-)
diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c
index 01dd916d81..94bf174700 100644
--- a/libavcodec/cbs.c
+++ b/libavcodec/cbs.c
@@ -18,8 +18,6 @@
#include <string.h>
-#include "config.h"
-
#include "libavutil/avassert.h"
#include "libavutil/buffer.h"
#include "libavutil/common.h"
@@ -33,55 +31,55 @@
static const CodedBitstreamType *const cbs_type_table[] = {
-#if CONFIG_CBS_AV1
+#if CBS_AV1
&ff_cbs_type_av1,
#endif
-#if CONFIG_CBS_H264
+#if CBS_H264
&ff_cbs_type_h264,
#endif
-#if CONFIG_CBS_H265
+#if CBS_H265
&ff_cbs_type_h265,
#endif
-#if CONFIG_CBS_H266
+#if CBS_H266
&ff_cbs_type_h266,
#endif
-#if CONFIG_CBS_JPEG
+#if CBS_JPEG
&ff_cbs_type_jpeg,
#endif
-#if CONFIG_CBS_MPEG2
+#if CBS_MPEG2
&ff_cbs_type_mpeg2,
#endif
-#if CONFIG_CBS_VP8
+#if CBS_VP8
&ff_cbs_type_vp8,
#endif
-#if CONFIG_CBS_VP9
+#if CBS_VP9
&ff_cbs_type_vp9,
#endif
};
const enum AVCodecID ff_cbs_all_codec_ids[] = {
-#if CONFIG_CBS_AV1
+#if CBS_AV1
AV_CODEC_ID_AV1,
#endif
-#if CONFIG_CBS_H264
+#if CBS_H264
AV_CODEC_ID_H264,
#endif
-#if CONFIG_CBS_H265
+#if CBS_H265
AV_CODEC_ID_H265,
#endif
-#if CONFIG_CBS_H266
+#if CBS_H266
AV_CODEC_ID_H266,
#endif
-#if CONFIG_CBS_JPEG
+#if CBS_JPEG
AV_CODEC_ID_MJPEG,
#endif
-#if CONFIG_CBS_MPEG2
+#if CBS_MPEG2
AV_CODEC_ID_MPEG2VIDEO,
#endif
-#if CONFIG_CBS_VP8
+#if CBS_VP8
AV_CODEC_ID_VP8,
#endif
-#if CONFIG_CBS_VP9
+#if CBS_VP9
AV_CODEC_ID_VP9,
#endif
AV_CODEC_ID_NONE
@@ -234,6 +232,7 @@ static int cbs_read_fragment_content(CodedBitstreamContext *ctx,
return 0;
}
+#if CBS_READ
static int cbs_fill_fragment_data(CodedBitstreamFragment *frag,
const uint8_t *data, size_t size)
{
@@ -282,37 +281,51 @@ static int cbs_read_data(CodedBitstreamContext *ctx,
return cbs_read_fragment_content(ctx, frag);
}
+#endif
int ff_cbs_read_extradata(CodedBitstreamContext *ctx,
CodedBitstreamFragment *frag,
const AVCodecParameters *par)
{
+#if CBS_READ
return cbs_read_data(ctx, frag, NULL,
par->extradata,
par->extradata_size, 1);
+#else
+ return AVERROR(ENOSYS);
+#endif
}
int ff_cbs_read_extradata_from_codec(CodedBitstreamContext *ctx,
CodedBitstreamFragment *frag,
const AVCodecContext *avctx)
{
+#if CBS_READ
return cbs_read_data(ctx, frag, NULL,
avctx->extradata,
avctx->extradata_size, 1);
+#else
+ return AVERROR(ENOSYS);
+#endif
}
int ff_cbs_read_packet(CodedBitstreamContext *ctx,
CodedBitstreamFragment *frag,
const AVPacket *pkt)
{
+#if CBS_READ
return cbs_read_data(ctx, frag, pkt->buf,
pkt->data, pkt->size, 0);
+#else
+ return AVERROR(ENOSYS);
+#endif
}
int ff_cbs_read_packet_side_data(CodedBitstreamContext *ctx,
CodedBitstreamFragment *frag,
const AVPacket *pkt)
{
+#if CBS_READ
size_t side_data_size;
const uint8_t *side_data =
av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,
@@ -320,16 +333,24 @@ int ff_cbs_read_packet_side_data(CodedBitstreamContext *ctx,
return cbs_read_data(ctx, frag, NULL,
side_data, side_data_size, 1);
+#else
+ return AVERROR(ENOSYS);
+#endif
}
int ff_cbs_read(CodedBitstreamContext *ctx,
CodedBitstreamFragment *frag,
const uint8_t *data, size_t size)
{
+#if CBS_READ
return cbs_read_data(ctx, frag, NULL,
data, size, 0);
+#else
+ return AVERROR(ENOSYS);
+#endif
}
+#if CBS_WRITE
/**
* Allocate a new internal data buffer of the given size in the unit.
*
@@ -405,10 +426,12 @@ static int cbs_write_unit_data(CodedBitstreamContext *ctx,
return 0;
}
+#endif
int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx,
CodedBitstreamFragment *frag)
{
+#if CBS_WRITE
int err, i;
for (i = 0; i < frag->nb_units; i++) {
@@ -440,12 +463,16 @@ int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx,
av_assert0(frag->data && frag->data_ref);
return 0;
+#else
+ return AVERROR(ENOSYS);
+#endif
}
int ff_cbs_write_extradata(CodedBitstreamContext *ctx,
AVCodecParameters *par,
CodedBitstreamFragment *frag)
{
+#if CBS_WRITE
int err;
err = ff_cbs_write_fragment_data(ctx, frag);
@@ -469,12 +496,16 @@ int ff_cbs_write_extradata(CodedBitstreamContext *ctx,
par->extradata_size = frag->data_size;
return 0;
+#else
+ return AVERROR(ENOSYS);
+#endif
}
int ff_cbs_write_packet(CodedBitstreamContext *ctx,
AVPacket *pkt,
CodedBitstreamFragment *frag)
{
+#if CBS_WRITE
AVBufferRef *buf;
int err;
@@ -493,16 +524,21 @@ int ff_cbs_write_packet(CodedBitstreamContext *ctx,
pkt->size = frag->data_size;
return 0;
+#else
+ return AVERROR(ENOSYS);
+#endif
}
void ff_cbs_trace_header(CodedBitstreamContext *ctx,
const char *name)
{
+#if CBS_TRACE
if (!ctx->trace_enable)
return;
av_log(ctx->log_ctx, ctx->trace_level, "%s\n", name);
+#endif
}
void ff_cbs_trace_read_log(void *trace_context,
@@ -510,6 +546,7 @@ void ff_cbs_trace_read_log(void *trace_context,
const char *str, const int *subscripts,
int64_t value)
{
+#if CBS_TRACE
CodedBitstreamContext *ctx = trace_context;
char name[256];
char bits[256];
@@ -561,6 +598,7 @@ void ff_cbs_trace_read_log(void *trace_context,
av_log(ctx->log_ctx, ctx->trace_level, "%-10d %s%*s = %"PRId64"\n",
position, name, pad, bits, value);
+#endif
}
void ff_cbs_trace_write_log(void *trace_context,
@@ -568,6 +606,7 @@ void ff_cbs_trace_write_log(void *trace_context,
const char *str, const int *subscripts,
int64_t value)
{
+#if CBS_TRACE
CodedBitstreamContext *ctx = trace_context;
// Ensure that the syntax element is written to the output buffer,
@@ -591,6 +630,7 @@ void ff_cbs_trace_write_log(void *trace_context,
skip_bits_long(&gbc, position - length);
ff_cbs_trace_read_log(ctx, &gbc, length, str, subscripts, value);
+#endif
}
static av_always_inline int cbs_read_unsigned(CodedBitstreamContext *ctx,
@@ -633,15 +673,23 @@ int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc,
const int *subscripts, uint32_t *write_to,
uint32_t range_min, uint32_t range_max)
{
+#if CBS_READ
return cbs_read_unsigned(ctx, gbc, width, name, subscripts,
write_to, range_min, range_max);
+#else
+ return AVERROR(ENOSYS);
+#endif
}
int ff_cbs_read_simple_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc,
int width, const char *name, uint32_t *write_to)
{
+#if CBS_READ
return cbs_read_unsigned(ctx, gbc, width, name, NULL,
write_to, 0, UINT32_MAX);
+#else
+ return AVERROR(ENOSYS);
+#endif
}
int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc,
@@ -649,6 +697,7 @@ int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc,
const int *subscripts, uint32_t value,
uint32_t range_min, uint32_t range_max)
{
+#if CBS_WRITE
CBS_TRACE_WRITE_START();
av_assert0(width > 0 && width <= 32);
@@ -671,13 +720,20 @@ int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc,
CBS_TRACE_WRITE_END();
return 0;
+#else
+ return AVERROR(ENOSYS);
+#endif
}
int ff_cbs_write_simple_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc,
int width, const char *name, uint32_t value)
{
+#if CBS_WRITE
return ff_cbs_write_unsigned(ctx, pbc, width, name, NULL,
value, 0, MAX_UINT_BITS(width));
+#else
+ return AVERROR(ENOSYS);
+#endif
}
int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc,
@@ -685,6 +741,7 @@ int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc,
const int *subscripts, int32_t *write_to,
int32_t range_min, int32_t range_max)
{
+#if CBS_READ
int32_t value;
CBS_TRACE_READ_START();
@@ -710,6 +767,9 @@ int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc,
*write_to = value;
return 0;
+#else
+ return AVERROR(ENOSYS);
+#endif
}
int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc,
@@ -717,6 +777,7 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc,
const int *subscripts, int32_t value,
int32_t range_min, int32_t range_max)
{
+#if CBS_WRITE
CBS_TRACE_WRITE_START();
av_assert0(width > 0 && width <= 32);
@@ -739,6 +800,9 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc,
CBS_TRACE_WRITE_END();
return 0;
+#else
+ return AVERROR(ENOSYS);
+#endif
}
diff --git a/libavcodec/cbs_av1.c b/libavcodec/cbs_av1.c
index d7862a2e48..e0a4eba20f 100644
--- a/libavcodec/cbs_av1.c
+++ b/libavcodec/cbs_av1.c
@@ -27,6 +27,7 @@
#include "libavutil/refstruct.h"
+#if CBS_READ
static int cbs_av1_read_uvlc(CodedBitstreamContext *ctx, GetBitContext *gbc,
const char *name, uint32_t *write_to,
uint32_t range_min, uint32_t range_max)
@@ -84,7 +85,9 @@ static int cbs_av1_read_uvlc(CodedBitstreamContext *ctx, GetBitContext *gbc,
*write_to = value;
return 0;
}
+#endif
+#if CBS_WRITE
static int cbs_av1_write_uvlc(CodedBitstreamContext *ctx, PutBitContext *pbc,
const char *name, uint32_t value,
uint32_t range_min, uint32_t range_max)
@@ -115,7 +118,9 @@ static int cbs_av1_write_uvlc(CodedBitstreamContext *ctx, PutBitContext *pbc,
return 0;
}
+#endif
+#if CBS_READ
static int cbs_av1_read_leb128(CodedBitstreamContext *ctx, GetBitContext *gbc,
const char *name, uint64_t *write_to)
{
@@ -146,7 +151,9 @@ static int cbs_av1_read_leb128(CodedBitstreamContext *ctx, GetBitContext *gbc,
*write_to = value;
return 0;
}
+#endif
+#if CBS_WRITE
static int cbs_av1_write_leb128(CodedBitstreamContext *ctx, PutBitContext *pbc,
const char *name, uint64_t value, int fixed_length)
{
@@ -182,7 +189,9 @@ static int cbs_av1_write_leb128(CodedBitstreamContext *ctx, PutBitContext *pbc,
return 0;
}
+#endif
+#if CBS_READ
static int cbs_av1_read_ns(CodedBitstreamContext *ctx, GetBitContext *gbc,
uint32_t n, const char *name,
const int *subscripts, uint32_t *write_to)
@@ -220,7 +229,9 @@ static int cbs_av1_read_ns(CodedBitstreamContext *ctx, GetBitContext *gbc,
*write_to = value;
return 0;
}
+#endif
+#if CBS_WRITE
static int cbs_av1_write_ns(CodedBitstreamContext *ctx, PutBitContext *pbc,
uint32_t n, const char *name,
const int *subscripts, uint32_t value)
@@ -256,7 +267,9 @@ static int cbs_av1_write_ns(CodedBitstreamContext *ctx, PutBitContext *pbc,
return 0;
}
+#endif
+#if CBS_READ
static int cbs_av1_read_increment(CodedBitstreamContext *ctx, GetBitContext *gbc,
uint32_t range_min, uint32_t range_max,
const char *name, uint32_t *write_to)
@@ -284,7 +297,9 @@ static int cbs_av1_read_increment(CodedBitstreamContext *ctx, GetBitContext *gbc
*write_to = value;
return 0;
}
+#endif
+#if CBS_WRITE
static int cbs_av1_write_increment(CodedBitstreamContext *ctx, PutBitContext *pbc,
uint32_t range_min, uint32_t range_max,
const char *name, uint32_t value)
@@ -315,7 +330,9 @@ static int cbs_av1_write_increment(CodedBitstreamContext *ctx, PutBitContext *pb
return 0;
}
+#endif
+#if CBS_READ
static int cbs_av1_read_subexp(CodedBitstreamContext *ctx, GetBitContext *gbc,
uint32_t range_max, const char *name,
const int *subscripts, uint32_t *write_to)
@@ -360,7 +377,9 @@ static int cbs_av1_read_subexp(CodedBitstreamContext *ctx, GetBitContext *gbc,
*write_to = value;
return err;
}
+#endif
+#if CBS_WRITE
static int cbs_av1_write_subexp(CodedBitstreamContext *ctx, PutBitContext *pbc,
uint32_t range_max, const char *name,
const int *subscripts, uint32_t value)
@@ -420,6 +439,7 @@ static int cbs_av1_write_subexp(CodedBitstreamContext *ctx, PutBitContext *pbc,
return err;
}
+#endif
static int cbs_av1_tile_log2(int blksize, int target)
@@ -441,7 +461,7 @@ static int cbs_av1_get_relative_dist(const AV1RawSequenceHeader *seq,
return diff;
}
-static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc)
+static av_unused size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc)
{
GetBitContext tmp = *gbc;
size_t size = 0;
@@ -469,6 +489,7 @@ static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc)
#define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL)
+#if CBS_READ
#define fc(width, name, range_min, range_max) \
xf(width, name, current->name, range_min, range_max, 0, )
#define flag(name) fb(1, name)
@@ -584,8 +605,9 @@ static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc)
#undef leb128
#undef infer
#undef byte_alignment
+#endif // CBS_READ
-
+#if CBS_WRITE
#define WRITE
#define READWRITE write
#define RWContext PutBitContext
@@ -668,12 +690,13 @@ static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc)
#undef leb128
#undef infer
#undef byte_alignment
-
+#endif // CBS_WRITE
static int cbs_av1_split_fragment(CodedBitstreamContext *ctx,
CodedBitstreamFragment *frag,
int header)
{
+#if CBS_READ
GetBitContext gbc;
uint8_t *data;
size_t size;
@@ -777,6 +800,9 @@ success:
fail:
ctx->trace_enable = trace;
return err;
+#else
+ return AVERROR(ENOSYS);
+#endif
}
static int cbs_av1_ref_tile_data(CodedBitstreamContext *ctx,
@@ -809,6 +835,7 @@ static int cbs_av1_ref_tile_data(CodedBitstreamContext *ctx,
static int cbs_av1_read_unit(CodedBitstreamContext *ctx,
CodedBitstreamUnit *unit)
{
+#if CBS_READ
CodedBitstreamAV1Context *priv = ctx->priv_data;
AV1RawOBU *obu;
GetBitContext gbc;
@@ -931,6 +958,7 @@ static int cbs_av1_read_unit(CodedBitstreamContext *ctx,
return err;
}
break;
+#if CBS_OBU_TILE_LIST
case AV1_OBU_TILE_LIST:
{
err = cbs_av1_read_tile_list_obu(ctx, &gbc,
@@ -946,6 +974,8 @@ static int cbs_av1_read_unit(CodedBitstreamContext *ctx,
return err;
}
break;
+#endif
+#if CBS_OBU_METADATA
case AV1_OBU_METADATA:
{
err = cbs_av1_read_metadata_obu(ctx, &gbc, &obu->obu.metadata);
@@ -953,6 +983,8 @@ static int cbs_av1_read_unit(CodedBitstreamContext *ctx,
return err;
}
break;
+#endif
+#if CBS_OBU_PADDING
case AV1_OBU_PADDING:
{
err = cbs_av1_read_padding_obu(ctx, &gbc, &obu->obu.padding);
@@ -960,6 +992,7 @@ static int cbs_av1_read_unit(CodedBitstreamContext *ctx,
return err;
}
break;
+#endif
default:
return AVERROR(ENOSYS);
}
@@ -982,12 +1015,16 @@ static int cbs_av1_read_unit(CodedBitstreamContext *ctx,
}
return 0;
+#else
+ return AVERROR(ENOSYS);
+#endif
}
static int cbs_av1_write_obu(CodedBitstreamContext *ctx,
CodedBitstreamUnit *unit,
PutBitContext *pbc)
{
+#if CBS_WRITE
CodedBitstreamAV1Context *priv = ctx->priv_data;
AV1RawOBU *obu = unit->content;
PutBitContext pbc_tmp;
@@ -1087,6 +1124,7 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx,
td = &tile_group->tile_data;
}
break;
+#if CBS_OBU_TILE_LIST
case AV1_OBU_TILE_LIST:
{
err = cbs_av1_write_tile_list_obu(ctx, pbc, &obu->obu.tile_list);
@@ -1096,6 +1134,8 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx,
td = &obu->obu.tile_list.tile_data;
}
break;
+#endif
+#if CBS_OBU_METADATA
case AV1_OBU_METADATA:
{
err = cbs_av1_write_metadata_obu(ctx, pbc, &obu->obu.metadata);
@@ -1103,6 +1143,8 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx,
goto error;
}
break;
+#endif
+#if CBS_OBU_PADDING
case AV1_OBU_PADDING:
{
err = cbs_av1_write_padding_obu(ctx, pbc, &obu->obu.padding);
@@ -1110,6 +1152,7 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx,
goto error;
}
break;
+#endif
default:
err = AVERROR(ENOSYS);
goto error;
@@ -1182,11 +1225,15 @@ error:
av_buffer_unref(&av1ctx.frame_header_ref);
return err;
+#else
+ return AVERROR(ENOSYS);
+#endif
}
static int cbs_av1_assemble_fragment(CodedBitstreamContext *ctx,
CodedBitstreamFragment *frag)
{
+#if CBS_WRITE
size_t size, pos;
int i;
@@ -1210,6 +1257,9 @@ static int cbs_av1_assemble_fragment(CodedBitstreamContext *ctx,
frag->data_size = size;
return 0;
+#else
+ return AVERROR(ENOSYS);
+#endif
}
static void cbs_av1_flush(CodedBitstreamContext *ctx)
@@ -1234,6 +1284,7 @@ static void cbs_av1_close(CodedBitstreamContext *ctx)
av_buffer_unref(&priv->frame_header_ref);
}
+#if CBS_OBU_METADATA
static void cbs_av1_free_metadata(AVRefStructOpaque unused, void *content)
{
AV1RawOBU *obu = content;
@@ -1255,6 +1306,7 @@ static void cbs_av1_free_metadata(AVRefStructOpaque unused, void *content)
av_buffer_unref(&md->metadata.unknown.payload_ref);
}
}
+#endif
static const CodedBitstreamUnitTypeDescriptor cbs_av1_unit_types[] = {
CBS_UNIT_TYPE_POD(AV1_OBU_SEQUENCE_HEADER, AV1RawOBU),
@@ -1284,13 +1336,19 @@ static const CodedBitstreamUnitTypeDescriptor cbs_av1_unit_types[] = {
offsetof(AV1RawOBU, obu.frame.tile_group.tile_data.data) }
},
},
+#if CBS_OBU_TILE_LIST
CBS_UNIT_TYPE_INTERNAL_REF(AV1_OBU_TILE_LIST, AV1RawOBU,
obu.tile_list.tile_data.data),
+#endif
+#if CBS_OBU_PADDING
CBS_UNIT_TYPE_INTERNAL_REF(AV1_OBU_PADDING, AV1RawOBU,
obu.padding.payload),
+#endif
+#if CBS_OBU_METADATA
CBS_UNIT_TYPE_COMPLEX(AV1_OBU_METADATA, AV1RawOBU,
&cbs_av1_free_metadata),
+#endif
CBS_UNIT_TYPE_END_OF_LIST
};
diff --git a/libavcodec/cbs_av1.h b/libavcodec/cbs_av1.h
index 62c7720142..0c73e12c84 100644
--- a/libavcodec/cbs_av1.h
+++ b/libavcodec/cbs_av1.h
@@ -25,6 +25,15 @@
#include "av1.h"
#include "cbs.h"
+#ifndef CBS_OBU_METADATA
+#define CBS_OBU_METADATA 1
+#endif
+#ifndef CBS_OBU_TILE_LIST
+#define CBS_OBU_TILE_LIST 1
+#endif
+#ifndef CBS_OBU_PADDING
+#define CBS_OBU_PADDING 1
+#endif
typedef struct AV1RawOBUHeader {
uint8_t obu_forbidden_bit;
@@ -411,9 +420,15 @@ typedef struct AV1RawOBU {
AV1RawFrameHeader frame_header;
AV1RawFrame frame;
AV1RawTileGroup tile_group;
+#if CBS_OBU_TILE_LIST
AV1RawTileList tile_list;
+#endif
+#if CBS_OBU_METADATA
AV1RawMetadata metadata;
+#endif
+#if CBS_OBU_PADDING
AV1RawPadding padding;
+#endif
} obu;
} AV1RawOBU;
diff --git a/libavcodec/cbs_av1_syntax_template.c b/libavcodec/cbs_av1_syntax_template.c
index 62a83945ec..b594bfd22b 100644
--- a/libavcodec/cbs_av1_syntax_template.c
+++ b/libavcodec/cbs_av1_syntax_template.c
@@ -1868,6 +1868,7 @@ static int FUNC(frame_obu)(CodedBitstreamContext *ctx, RWContext *rw,
return 0;
}
+#if CBS_OBU_TILE_LIST
static int FUNC(tile_list_obu)(CodedBitstreamContext *ctx, RWContext *rw,
AV1RawTileList *current)
{
@@ -1882,7 +1883,9 @@ static int FUNC(tile_list_obu)(CodedBitstreamContext *ctx, RWContext *rw,
return 0;
}
+#endif
+#if CBS_OBU_METADATA
static int FUNC(metadata_hdr_cll)(CodedBitstreamContext *ctx, RWContext *rw,
AV1RawMetadataHDRCLL *current)
{
@@ -2101,7 +2104,9 @@ static int FUNC(metadata_obu)(CodedBitstreamContext *ctx, RWContext *rw,
return 0;
}
+#endif
+#if CBS_OBU_PADDING
static int FUNC(padding_obu)(CodedBitstreamContext *ctx, RWContext *rw,
AV1RawPadding *current)
{
@@ -2125,3 +2130,4 @@ static int FUNC(padding_obu)(CodedBitstreamContext *ctx, RWContext *rw,
return 0;
}
+#endif
diff --git a/libavcodec/cbs_internal.h b/libavcodec/cbs_internal.h
index 80cad2b162..f15ba1ab90 100644
--- a/libavcodec/cbs_internal.h
+++ b/libavcodec/cbs_internal.h
@@ -22,6 +22,8 @@
#include <stddef.h>
#include <stdint.h>
+#include "config.h"
+
#include "libavutil/log.h"
#include "cbs.h"
@@ -30,6 +32,40 @@
#include "put_bits.h"
#include "libavutil/refstruct.h"
+#ifndef CBS_READ
+#define CBS_READ 1
+#endif
+#ifndef CBS_WRITE
+#define CBS_WRITE 1
+#endif
+#ifndef CBS_TRACE
+#define CBS_TRACE 1
+#endif
+
+#ifndef CBS_AV1
+#define CBS_AV1 CONFIG_CBS_AV1
+#endif
+#ifndef CBS_H264
+#define CBS_H264 CONFIG_CBS_H264
+#endif
+#ifndef CBS_H265
+#define CBS_H265 CONFIG_CBS_H265
+#endif
+#ifndef CBS_H266
+#define CBS_H266 CONFIG_CBS_H266
+#endif
+#ifndef CBS_JPEG
+#define CBS_JPEG CONFIG_CBS_JPEG
+#endif
+#ifndef CBS_MPEG2
+#define CBS_MPEG2 CONFIG_CBS_MPEG2
+#endif
+#ifndef CBS_VP8
+#define CBS_VP8 CONFIG_CBS_VP8
+#endif
+#ifndef CBS_VP9
+#define CBS_VP9 CONFIG_CBS_VP9
+#endif
enum CBSContentType {
// Unit content may contain some references to other structures, but all
@@ -204,6 +240,7 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc,
#define MIN_INT_BITS(length) (-(INT64_C(1) << ((length) - 1)))
+#if CBS_TRACE
// Start of a syntax element during read tracing.
#define CBS_TRACE_READ_START() \
GetBitContext trace_start; \
@@ -284,6 +321,17 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc,
} \
} while (0)
+#else // CBS_TRACE
+#define CBS_TRACE_READ_START() do { } while (0)
+#define CBS_TRACE_READ_END() do { } while (0)
+#define CBS_TRACE_READ_END_NO_SUBSCRIPTS() do { } while (0)
+#define CBS_TRACE_READ_END_VALUE_ONLY() do { } while (0)
+#define CBS_TRACE_WRITE_START() do { } while (0)
+#define CBS_TRACE_WRITE_END() do { } while (0)
+#define CBS_TRACE_WRITE_END_NO_SUBSCRIPTS() do { } while (0)
+#define CBS_TRACE_WRITE_END_VALUE_ONLY() do { } while (0)
+#endif // CBS_TRACE
+
#define TYPE_LIST(...) { __VA_ARGS__ }
#define CBS_UNIT_TYPE_POD(type_, structure) { \
.nb_unit_types = 1, \
--
2.48.1
_______________________________________________
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] 9+ messages in thread
* [FFmpeg-devel] [PATCH v2 3/3] avformat/movenccenc: add support for CENC AV1 encryption
2025-03-21 19:42 ` [FFmpeg-devel] [PATCH 2/3] avcodec/cbs: allow fine tunning selection of features James Almer
@ 2025-03-21 19:42 ` James Almer
2025-03-22 14:25 ` [FFmpeg-devel] [PATCH 2/3] avcodec/cbs: allow fine tunning selection of features Andreas Rheinhardt
1 sibling, 0 replies; 9+ messages in thread
From: James Almer @ 2025-03-21 19:42 UTC (permalink / raw)
To: ffmpeg-devel
Signed-off-by: James Almer <jamrial@gmail.com>
---
configure | 2 +-
libavformat/Makefile | 1 +
libavformat/cbs.c | 10 ++
libavformat/cbs_av1.c | 6 ++
libavformat/movenc.c | 13 ++-
libavformat/movenccenc.c | 223 ++++++++++++++++++++++++++++++++++++++-
libavformat/movenccenc.h | 20 +++-
7 files changed, 269 insertions(+), 6 deletions(-)
create mode 100644 libavformat/cbs.c
create mode 100644 libavformat/cbs_av1.c
diff --git a/configure b/configure
index 14f7bcde0e..0f6b6c20fb 100755
--- a/configure
+++ b/configure
@@ -3689,7 +3689,7 @@ mlp_demuxer_select="mlp_parser"
mmf_muxer_select="riffenc"
mov_demuxer_select="iso_media riffdec"
mov_demuxer_suggest="iamfdec zlib"
-mov_muxer_select="iso_media iso_writer riffenc rtpenc_chain vp9_superframe_bsf aac_adtstoasc_bsf ac3_parser"
+mov_muxer_select="iso_media iso_writer riffenc rtpenc_chain vp9_superframe_bsf aac_adtstoasc_bsf ac3_parser cbs_av1"
mov_muxer_suggest="iamfenc"
mp3_demuxer_select="mpegaudio_parser"
mp3_muxer_select="mpegaudioheader"
diff --git a/libavformat/Makefile b/libavformat/Makefile
index 7730e7c4e6..1e57ae7d8a 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -740,6 +740,7 @@ SHLIBOBJS-$(CONFIG_JNI) += ffjni.o
SHLIBOBJS-$(CONFIG_JPEGXL_ANIM_DEMUXER) += jpegxl_parse.o
SHLIBOBJS-$(CONFIG_MATROSKA_DEMUXER) += mpeg4audio_sample_rates.o
SHLIBOBJS-$(CONFIG_MOV_DEMUXER) += ac3_channel_layout_tab.o
+SHLIBOBJS-$(CONFIG_MOV_MUXER) += cbs.o cbs_av1.o
SHLIBOBJS-$(CONFIG_MP3_MUXER) += mpegaudiotabs.o
SHLIBOBJS-$(CONFIG_MXF_MUXER) += golomb_tab.o \
rangecoder_dec.o
diff --git a/libavformat/cbs.c b/libavformat/cbs.c
new file mode 100644
index 0000000000..9e970004ba
--- /dev/null
+++ b/libavformat/cbs.c
@@ -0,0 +1,10 @@
+#define CBS_WRITE 0
+#define CBS_TRACE 0
+#define CBS_H264 0
+#define CBS_H265 0
+#define CBS_H266 0
+#define CBS_JPEG 0
+#define CBS_MPEG2 0
+#define CBS_VP8 0
+#define CBS_VP9 0
+#include "libavcodec/cbs.c"
diff --git a/libavformat/cbs_av1.c b/libavformat/cbs_av1.c
new file mode 100644
index 0000000000..47a4d0c3a1
--- /dev/null
+++ b/libavformat/cbs_av1.c
@@ -0,0 +1,6 @@
+#define CBS_WRITE 0
+#define CBS_TRACE 0
+#define CBS_OBU_TILE_LIST 0
+#define CBS_OBU_METADATA 0
+#define CBS_OBU_PADDING 0
+#include "libavcodec/cbs_av1.c"
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index af013e1fc6..c60c46012f 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -6767,7 +6767,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
} else {
size = ff_vvc_annexb2mp4(pb, pkt->data, pkt->size, 0, NULL);
}
- } else if (par->codec_id == AV_CODEC_ID_AV1) {
+ } else if (par->codec_id == AV_CODEC_ID_AV1 && !trk->cenc.aes_ctr) {
if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
ret = ff_av1_filter_obus_buf(pkt->data, &reformatted_data,
&size, &offset);
@@ -6815,6 +6815,13 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
} else if(par->codec_id == AV_CODEC_ID_VVC) {
ret = AVERROR_PATCHWELCOME;
+ } else if(par->codec_id == AV_CODEC_ID_AV1) {
+ av_assert0(size == pkt->size);
+ ret = ff_mov_cenc_av1_write_obus(s, &trk->cenc, pb, pkt);
+ if (ret > 0) {
+ size = ret;
+ ret = 0;
+ }
} else {
ret = ff_mov_cenc_write_packet(&trk->cenc, pb, pkt->data, size);
}
@@ -8135,8 +8142,8 @@ static int mov_init(AVFormatContext *s)
if (mov->encryption_scheme == MOV_ENC_CENC_AES_CTR) {
ret = ff_mov_cenc_init(&track->cenc, mov->encryption_key,
(track->par->codec_id == AV_CODEC_ID_H264 || track->par->codec_id == AV_CODEC_ID_HEVC ||
- track->par->codec_id == AV_CODEC_ID_VVC),
- s->flags & AVFMT_FLAG_BITEXACT);
+ track->par->codec_id == AV_CODEC_ID_VVC || track->par->codec_id == AV_CODEC_ID_AV1),
+ track->par->codec_id, s->flags & AVFMT_FLAG_BITEXACT);
if (ret)
return ret;
}
diff --git a/libavformat/movenccenc.c b/libavformat/movenccenc.c
index f54d3bcbca..af801eb3a0 100644
--- a/libavformat/movenccenc.c
+++ b/libavformat/movenccenc.c
@@ -19,6 +19,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "movenccenc.h"
+#include "libavcodec/av1_parse.h"
+#include "libavcodec/bytestream.h"
+#include "libavcodec/cbs_av1.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/mem.h"
#include "avio_internal.h"
@@ -280,6 +283,203 @@ int ff_mov_cenc_avc_write_nal_units(AVFormatContext *s, MOVMuxCencContext* ctx,
return 0;
}
+static int write_tiles(AVFormatContext *s, MOVMuxCencContext *ctx, AVIOContext *pb, AV1_OBU_Type type,
+ const AV1RawFrameHeader *frame_header, const uint8_t *fh_data, size_t fh_data_size,
+ const AV1RawTileGroup *tile_group)
+{
+ GetByteContext gb;
+ size_t tgh_data_size = tile_group->data_size;
+ int cur_tile_num = frame_header->tile_cols * frame_header->tile_rows;
+ int total = 0;
+
+ // Get the Frame Header size
+ if (type == AV1_OBU_FRAME)
+ fh_data_size -= tgh_data_size;
+ // Get the Tile Group Header size
+ tgh_data_size -= tile_group->tile_data.data_size;
+
+ if (ctx->tile_num < cur_tile_num) {
+ int ret = av_reallocp_array(&ctx->tile_group_sizes, cur_tile_num,
+ sizeof(*ctx->tile_group_sizes));
+ if (ret < 0) {
+ ctx->tile_num = 0;
+ return ret;
+ }
+ }
+ ctx->tile_num = cur_tile_num;
+
+ total = fh_data_size + tgh_data_size;
+ ctx->clear_bytes += total;
+
+ bytestream2_init(&gb, tile_group->tile_data.data, tile_group->tile_data.data_size);
+
+ // Build a table with block sizes for encrypted bytes and clear bytes
+ for (unsigned tile_num = tile_group->tg_start; tile_num <= tile_group->tg_end; tile_num++) {
+ uint32_t encrypted_bytes, tile_size_bytes, tile_size = 0;
+
+ if (tile_num == tile_group->tg_end) {
+ tile_size = bytestream2_get_bytes_left(&gb);
+ encrypted_bytes = tile_size & ~0xFU;
+ ctx->clear_bytes += tile_size & 0xFU;
+
+ ctx->tile_group_sizes[tile_num].encrypted_bytes = encrypted_bytes;
+ ctx->tile_group_sizes[tile_num].aux_clear_bytes = encrypted_bytes ? ctx->clear_bytes : 0;
+ ctx->tile_group_sizes[tile_num].write_clear_bytes = tile_size & 0xFU;
+
+ if (encrypted_bytes)
+ ctx->clear_bytes = 0;
+ total += tile_size;
+
+ break;
+ }
+
+ tile_size_bytes = frame_header->tile_size_bytes_minus1 + 1;
+ if (bytestream2_get_bytes_left(&gb) < tile_size_bytes)
+ return AVERROR_INVALIDDATA;
+
+ for (int i = 0; i < tile_size_bytes; i++)
+ tile_size |= bytestream2_get_byteu(&gb) << 8 * i;
+ if (bytestream2_get_bytes_left(&gb) <= tile_size)
+ return AVERROR_INVALIDDATA;
+ tile_size++;
+
+ // The spec requires encrypted bytes to be in blocks multiple of 16
+ encrypted_bytes = tile_size & ~0xFU;
+ ctx->clear_bytes += (tile_size & 0xFU) + tile_size_bytes;
+
+ ctx->tile_group_sizes[tile_num].encrypted_bytes = encrypted_bytes;
+ ctx->tile_group_sizes[tile_num].aux_clear_bytes = encrypted_bytes ? ctx->clear_bytes : 0;
+ ctx->tile_group_sizes[tile_num].write_clear_bytes = (tile_size & 0xFU) + tile_size_bytes;
+
+ if (encrypted_bytes)
+ ctx->clear_bytes = 0;
+
+ total += tile_size + tile_size_bytes;
+ bytestream2_skipu(&gb, tile_size);
+ }
+
+ bytestream2_init(&gb, tile_group->tile_data.data, tile_group->tile_data.data_size);
+
+ avio_write(pb, fh_data, fh_data_size);
+ avio_write(pb, tile_group->data, tgh_data_size);
+
+ for (unsigned tile_num = tile_group->tg_start; tile_num <= tile_group->tg_end; tile_num++) {
+ const struct MOVMuxCencAV1TGInfo *sizes = &ctx->tile_group_sizes[tile_num];
+
+ avio_write(pb, gb.buffer, sizes->write_clear_bytes);
+ bytestream2_skipu(&gb, sizes->write_clear_bytes);
+ mov_cenc_write_encrypted(ctx, pb, gb.buffer, sizes->encrypted_bytes);
+ bytestream2_skipu(&gb, sizes->encrypted_bytes);
+ if (sizes->encrypted_bytes) {
+ unsigned clear_bytes = sizes->aux_clear_bytes;
+ if (clear_bytes > UINT16_MAX) {
+ auxiliary_info_add_subsample(ctx, UINT16_MAX, 0);
+ clear_bytes -= UINT16_MAX;
+ }
+ auxiliary_info_add_subsample(ctx, clear_bytes, sizes->encrypted_bytes);
+ }
+ }
+
+ return total;
+}
+
+int ff_mov_cenc_av1_write_obus(AVFormatContext *s, MOVMuxCencContext* ctx,
+ AVIOContext *pb, const AVPacket *pkt)
+{
+ CodedBitstreamFragment *td = &ctx->temporal_unit;
+ const CodedBitstreamAV1Context *av1 = ctx->cbc->priv_data;
+ const AV1RawFrameHeader *frame_header = NULL;
+ const uint8_t *fh_data = NULL;
+ size_t fh_data_size;
+ int out_size = 0, ret;
+
+ ret = mov_cenc_start_packet(ctx);
+ if (ret) {
+ return ret;
+ }
+
+ ret = ff_cbs_read_packet(ctx->cbc, td, pkt);
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "CENC-AV1: Failed to parse temporal unit.\n");
+ return ret;
+ }
+
+ if (!av1->sequence_header) {
+ av_log(s, AV_LOG_ERROR, "CENC-AV1: No sequence header available\n");
+ ret = AVERROR_INVALIDDATA;
+ goto end;
+ }
+
+ for (int i = 0; i < td->nb_units; i++) {
+ const CodedBitstreamUnit *unit = &td->units[i];
+ const AV1RawOBU *obu = unit->content;
+
+ switch (unit->type) {
+ case AV1_OBU_FRAME_HEADER:
+ if (!obu->obu.frame_header.show_existing_frame) {
+ frame_header = &obu->obu.frame_header;
+ fh_data = unit->data;
+ fh_data_size = unit->data_size;
+ break;
+ }
+ // fall-through
+ case AV1_OBU_SEQUENCE_HEADER:
+ case AV1_OBU_METADATA:
+ avio_write(pb, unit->data, unit->data_size);
+ ctx->clear_bytes += unit->data_size;
+ out_size += unit->data_size;
+ break;
+ case AV1_OBU_FRAME:
+ frame_header = &obu->obu.frame.header;
+ fh_data = unit->data;
+ fh_data_size = unit->data_size;
+ // fall-through
+ case AV1_OBU_TILE_GROUP:
+ {
+ const AV1RawTileGroup *tile_group;
+
+ if (!frame_header){
+ ret = AVERROR_INVALIDDATA;
+ goto end;
+ }
+
+ if (unit->type == AV1_OBU_FRAME)
+ tile_group = &obu->obu.frame.tile_group;
+ else
+ tile_group = &obu->obu.tile_group;
+
+ ret = write_tiles(s, ctx, pb, unit->type,
+ frame_header, fh_data, fh_data_size, tile_group);
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "CENC-AV1: Failed to write tiles\n");
+ goto end;
+ }
+ av_assert0(ret == unit->data_size);
+ out_size += unit->data_size;
+ frame_header = NULL;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (ctx->clear_bytes)
+ auxiliary_info_add_subsample(ctx, ctx->clear_bytes, 0);
+ ctx->clear_bytes = 0;
+
+ ret = mov_cenc_end_packet(ctx);
+ if (ret) {
+ ret = AVERROR_INVALIDDATA;
+ goto end;
+ }
+
+ ret = out_size;
+end:
+ ff_cbs_fragment_reset(td);
+ return ret;
+}
+
/* TODO: reuse this function from movenc.c */
static int64_t update_size(AVIOContext *pb, int64_t pos)
{
@@ -388,8 +588,16 @@ int ff_mov_cenc_write_sinf_tag(MOVTrack* track, AVIOContext *pb, uint8_t* kid)
return update_size(pb, pos);
}
+static const CodedBitstreamUnitType decompose_unit_types[] = {
+ AV1_OBU_TEMPORAL_DELIMITER,
+ AV1_OBU_SEQUENCE_HEADER,
+ AV1_OBU_FRAME_HEADER,
+ AV1_OBU_TILE_GROUP,
+ AV1_OBU_FRAME,
+};
+
int ff_mov_cenc_init(MOVMuxCencContext* ctx, uint8_t* encryption_key,
- int use_subsamples, int bitexact)
+ int use_subsamples, enum AVCodecID codec_id, int bitexact)
{
int ret;
@@ -409,6 +617,15 @@ int ff_mov_cenc_init(MOVMuxCencContext* ctx, uint8_t* encryption_key,
ctx->use_subsamples = use_subsamples;
+ if (codec_id == AV_CODEC_ID_AV1) {
+ ret = ff_cbs_init(&ctx->cbc, codec_id, NULL);
+ if (ret < 0)
+ return ret;
+
+ ctx->cbc->decompose_unit_types = decompose_unit_types;
+ ctx->cbc->nb_decompose_unit_types = FF_ARRAY_ELEMS(decompose_unit_types);
+ }
+
return 0;
}
@@ -417,4 +634,8 @@ void ff_mov_cenc_free(MOVMuxCencContext* ctx)
av_aes_ctr_free(ctx->aes_ctr);
av_freep(&ctx->auxiliary_info);
av_freep(&ctx->auxiliary_info_sizes);
+
+ av_freep(&ctx->tile_group_sizes);
+ ff_cbs_fragment_free(&ctx->temporal_unit);
+ ff_cbs_close(&ctx->cbc);
}
diff --git a/libavformat/movenccenc.h b/libavformat/movenccenc.h
index 7da5268090..722914dc1c 100644
--- a/libavformat/movenccenc.h
+++ b/libavformat/movenccenc.h
@@ -23,6 +23,7 @@
#define AVFORMAT_MOVENCCENC_H
#include "libavutil/aes_ctr.h"
+#include "libavcodec/cbs.h"
#include "avformat.h"
#include "avio.h"
@@ -30,6 +31,12 @@
struct MOVTrack;
+struct MOVMuxCencAV1TGInfo {
+ uint32_t encrypted_bytes;
+ uint32_t write_clear_bytes;
+ uint32_t aux_clear_bytes;
+};
+
typedef struct {
struct AVAESCTR* aes_ctr;
uint8_t* auxiliary_info;
@@ -43,6 +50,14 @@ typedef struct {
size_t auxiliary_info_subsample_start;
uint8_t* auxiliary_info_sizes;
size_t auxiliary_info_sizes_alloc_size;
+
+ /* AV1 */
+ struct MOVMuxCencAV1TGInfo *tile_group_sizes;
+ uint32_t clear_bytes;
+ int tile_num;
+ /* CBS */
+ CodedBitstreamContext *cbc;
+ CodedBitstreamFragment temporal_unit;
} MOVMuxCencContext;
/**
@@ -50,7 +65,8 @@ typedef struct {
* @param key encryption key, must have a length of AES_CTR_KEY_SIZE
* @param use_subsamples when enabled parts of a packet can be encrypted, otherwise the whole packet is encrypted
*/
-int ff_mov_cenc_init(MOVMuxCencContext* ctx, uint8_t* encryption_key, int use_subsamples, int bitexact);
+int ff_mov_cenc_init(MOVMuxCencContext* ctx, uint8_t* encryption_key, int use_subsamples,
+ enum AVCodecID codec_id, int bitexact);
/**
* Free a CENC context
@@ -73,6 +89,8 @@ int ff_mov_cenc_avc_parse_nal_units(MOVMuxCencContext* ctx, AVIOContext *pb, con
int ff_mov_cenc_avc_write_nal_units(AVFormatContext *s, MOVMuxCencContext* ctx, int nal_length_size,
AVIOContext *pb, const uint8_t *buf_in, int size);
+int ff_mov_cenc_av1_write_obus(AVFormatContext *s, MOVMuxCencContext* ctx,
+ AVIOContext *pb, const AVPacket *pkt);
/**
* Write the cenc atoms that should reside inside stbl
*/
--
2.48.1
_______________________________________________
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] 9+ messages in thread
* Re: [FFmpeg-devel] [PATCH 2/3] avcodec/cbs: allow fine tunning selection of features
2025-03-21 19:42 ` [FFmpeg-devel] [PATCH 2/3] avcodec/cbs: allow fine tunning selection of features James Almer
2025-03-21 19:42 ` [FFmpeg-devel] [PATCH v2 3/3] avformat/movenccenc: add support for CENC AV1 encryption James Almer
@ 2025-03-22 14:25 ` Andreas Rheinhardt
1 sibling, 0 replies; 9+ messages in thread
From: Andreas Rheinhardt @ 2025-03-22 14:25 UTC (permalink / raw)
To: ffmpeg-devel
James Almer:
> This will be useful in an upcoming commit, where CBS will be utilized by
> a module outside libavcodec.
>
> Signed-off-by: James Almer <jamrial@gmail.com>
> ---
> libavcodec/cbs.c | 100 ++++++++++++++++++++++-----
> libavcodec/cbs_av1.c | 64 ++++++++++++++++-
> libavcodec/cbs_av1.h | 15 ++++
> libavcodec/cbs_av1_syntax_template.c | 6 ++
> libavcodec/cbs_internal.h | 48 +++++++++++++
> 5 files changed, 212 insertions(+), 21 deletions(-)
>
> diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c
> index 01dd916d81..94bf174700 100644
> --- a/libavcodec/cbs.c
> +++ b/libavcodec/cbs.c
> @@ -18,8 +18,6 @@
>
> #include <string.h>
>
> -#include "config.h"
> -
> #include "libavutil/avassert.h"
> #include "libavutil/buffer.h"
> #include "libavutil/common.h"
> @@ -33,55 +31,55 @@
>
>
> static const CodedBitstreamType *const cbs_type_table[] = {
> -#if CONFIG_CBS_AV1
> +#if CBS_AV1
> &ff_cbs_type_av1,
> #endif
> -#if CONFIG_CBS_H264
> +#if CBS_H264
> &ff_cbs_type_h264,
> #endif
> -#if CONFIG_CBS_H265
> +#if CBS_H265
> &ff_cbs_type_h265,
> #endif
> -#if CONFIG_CBS_H266
> +#if CBS_H266
> &ff_cbs_type_h266,
> #endif
> -#if CONFIG_CBS_JPEG
> +#if CBS_JPEG
> &ff_cbs_type_jpeg,
> #endif
> -#if CONFIG_CBS_MPEG2
> +#if CBS_MPEG2
> &ff_cbs_type_mpeg2,
> #endif
> -#if CONFIG_CBS_VP8
> +#if CBS_VP8
> &ff_cbs_type_vp8,
> #endif
> -#if CONFIG_CBS_VP9
> +#if CBS_VP9
> &ff_cbs_type_vp9,
> #endif
> };
>
> const enum AVCodecID ff_cbs_all_codec_ids[] = {
> -#if CONFIG_CBS_AV1
> +#if CBS_AV1
> AV_CODEC_ID_AV1,
> #endif
> -#if CONFIG_CBS_H264
> +#if CBS_H264
> AV_CODEC_ID_H264,
> #endif
> -#if CONFIG_CBS_H265
> +#if CBS_H265
> AV_CODEC_ID_H265,
> #endif
> -#if CONFIG_CBS_H266
> +#if CBS_H266
> AV_CODEC_ID_H266,
> #endif
> -#if CONFIG_CBS_JPEG
> +#if CBS_JPEG
> AV_CODEC_ID_MJPEG,
> #endif
> -#if CONFIG_CBS_MPEG2
> +#if CBS_MPEG2
> AV_CODEC_ID_MPEG2VIDEO,
> #endif
> -#if CONFIG_CBS_VP8
> +#if CBS_VP8
> AV_CODEC_ID_VP8,
> #endif
> -#if CONFIG_CBS_VP9
> +#if CBS_VP9
> AV_CODEC_ID_VP9,
> #endif
> AV_CODEC_ID_NONE
> @@ -234,6 +232,7 @@ static int cbs_read_fragment_content(CodedBitstreamContext *ctx,
> return 0;
> }
>
> +#if CBS_READ
> static int cbs_fill_fragment_data(CodedBitstreamFragment *frag,
> const uint8_t *data, size_t size)
> {
> @@ -282,37 +281,51 @@ static int cbs_read_data(CodedBitstreamContext *ctx,
>
> return cbs_read_fragment_content(ctx, frag);
> }
> +#endif
>
> int ff_cbs_read_extradata(CodedBitstreamContext *ctx,
> CodedBitstreamFragment *frag,
> const AVCodecParameters *par)
> {
> +#if CBS_READ
> return cbs_read_data(ctx, frag, NULL,
> par->extradata,
> par->extradata_size, 1);
> +#else
> + return AVERROR(ENOSYS);
> +#endif
> }
>
> int ff_cbs_read_extradata_from_codec(CodedBitstreamContext *ctx,
> CodedBitstreamFragment *frag,
> const AVCodecContext *avctx)
> {
> +#if CBS_READ
> return cbs_read_data(ctx, frag, NULL,
> avctx->extradata,
> avctx->extradata_size, 1);
> +#else
> + return AVERROR(ENOSYS);
> +#endif
> }
>
> int ff_cbs_read_packet(CodedBitstreamContext *ctx,
> CodedBitstreamFragment *frag,
> const AVPacket *pkt)
> {
> +#if CBS_READ
> return cbs_read_data(ctx, frag, pkt->buf,
> pkt->data, pkt->size, 0);
> +#else
> + return AVERROR(ENOSYS);
> +#endif
> }
>
> int ff_cbs_read_packet_side_data(CodedBitstreamContext *ctx,
> CodedBitstreamFragment *frag,
> const AVPacket *pkt)
> {
> +#if CBS_READ
> size_t side_data_size;
> const uint8_t *side_data =
> av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,
> @@ -320,16 +333,24 @@ int ff_cbs_read_packet_side_data(CodedBitstreamContext *ctx,
>
> return cbs_read_data(ctx, frag, NULL,
> side_data, side_data_size, 1);
> +#else
> + return AVERROR(ENOSYS);
> +#endif
> }
>
> int ff_cbs_read(CodedBitstreamContext *ctx,
> CodedBitstreamFragment *frag,
> const uint8_t *data, size_t size)
> {
> +#if CBS_READ
> return cbs_read_data(ctx, frag, NULL,
> data, size, 0);
> +#else
> + return AVERROR(ENOSYS);
> +#endif
> }
>
> +#if CBS_WRITE
> /**
> * Allocate a new internal data buffer of the given size in the unit.
> *
> @@ -405,10 +426,12 @@ static int cbs_write_unit_data(CodedBitstreamContext *ctx,
>
> return 0;
> }
> +#endif
>
> int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx,
> CodedBitstreamFragment *frag)
> {
> +#if CBS_WRITE
> int err, i;
>
> for (i = 0; i < frag->nb_units; i++) {
> @@ -440,12 +463,16 @@ int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx,
> av_assert0(frag->data && frag->data_ref);
>
> return 0;
> +#else
> + return AVERROR(ENOSYS);
> +#endif
> }
>
> int ff_cbs_write_extradata(CodedBitstreamContext *ctx,
> AVCodecParameters *par,
> CodedBitstreamFragment *frag)
> {
> +#if CBS_WRITE
> int err;
>
> err = ff_cbs_write_fragment_data(ctx, frag);
> @@ -469,12 +496,16 @@ int ff_cbs_write_extradata(CodedBitstreamContext *ctx,
> par->extradata_size = frag->data_size;
>
> return 0;
> +#else
> + return AVERROR(ENOSYS);
> +#endif
> }
>
> int ff_cbs_write_packet(CodedBitstreamContext *ctx,
> AVPacket *pkt,
> CodedBitstreamFragment *frag)
> {
> +#if CBS_WRITE
> AVBufferRef *buf;
> int err;
>
> @@ -493,16 +524,21 @@ int ff_cbs_write_packet(CodedBitstreamContext *ctx,
> pkt->size = frag->data_size;
>
> return 0;
> +#else
> + return AVERROR(ENOSYS);
> +#endif
> }
>
>
> void ff_cbs_trace_header(CodedBitstreamContext *ctx,
> const char *name)
> {
> +#if CBS_TRACE
> if (!ctx->trace_enable)
> return;
>
> av_log(ctx->log_ctx, ctx->trace_level, "%s\n", name);
> +#endif
> }
>
> void ff_cbs_trace_read_log(void *trace_context,
> @@ -510,6 +546,7 @@ void ff_cbs_trace_read_log(void *trace_context,
> const char *str, const int *subscripts,
> int64_t value)
> {
> +#if CBS_TRACE
> CodedBitstreamContext *ctx = trace_context;
> char name[256];
> char bits[256];
> @@ -561,6 +598,7 @@ void ff_cbs_trace_read_log(void *trace_context,
>
> av_log(ctx->log_ctx, ctx->trace_level, "%-10d %s%*s = %"PRId64"\n",
> position, name, pad, bits, value);
> +#endif
> }
>
> void ff_cbs_trace_write_log(void *trace_context,
> @@ -568,6 +606,7 @@ void ff_cbs_trace_write_log(void *trace_context,
> const char *str, const int *subscripts,
> int64_t value)
> {
> +#if CBS_TRACE
> CodedBitstreamContext *ctx = trace_context;
>
> // Ensure that the syntax element is written to the output buffer,
> @@ -591,6 +630,7 @@ void ff_cbs_trace_write_log(void *trace_context,
> skip_bits_long(&gbc, position - length);
>
> ff_cbs_trace_read_log(ctx, &gbc, length, str, subscripts, value);
> +#endif
> }
>
> static av_always_inline int cbs_read_unsigned(CodedBitstreamContext *ctx,
> @@ -633,15 +673,23 @@ int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc,
> const int *subscripts, uint32_t *write_to,
> uint32_t range_min, uint32_t range_max)
> {
> +#if CBS_READ
> return cbs_read_unsigned(ctx, gbc, width, name, subscripts,
> write_to, range_min, range_max);
> +#else
> + return AVERROR(ENOSYS);
> +#endif
> }
>
> int ff_cbs_read_simple_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc,
> int width, const char *name, uint32_t *write_to)
> {
> +#if CBS_READ
> return cbs_read_unsigned(ctx, gbc, width, name, NULL,
> write_to, 0, UINT32_MAX);
> +#else
> + return AVERROR(ENOSYS);
> +#endif
> }
>
> int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc,
> @@ -649,6 +697,7 @@ int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc,
> const int *subscripts, uint32_t value,
> uint32_t range_min, uint32_t range_max)
> {
> +#if CBS_WRITE
> CBS_TRACE_WRITE_START();
>
> av_assert0(width > 0 && width <= 32);
> @@ -671,13 +720,20 @@ int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc,
> CBS_TRACE_WRITE_END();
>
> return 0;
> +#else
> + return AVERROR(ENOSYS);
> +#endif
> }
>
> int ff_cbs_write_simple_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc,
> int width, const char *name, uint32_t value)
> {
> +#if CBS_WRITE
> return ff_cbs_write_unsigned(ctx, pbc, width, name, NULL,
> value, 0, MAX_UINT_BITS(width));
> +#else
> + return AVERROR(ENOSYS);
> +#endif
> }
>
> int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc,
> @@ -685,6 +741,7 @@ int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc,
> const int *subscripts, int32_t *write_to,
> int32_t range_min, int32_t range_max)
> {
> +#if CBS_READ
> int32_t value;
>
> CBS_TRACE_READ_START();
> @@ -710,6 +767,9 @@ int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc,
>
> *write_to = value;
> return 0;
> +#else
> + return AVERROR(ENOSYS);
> +#endif
> }
>
> int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc,
> @@ -717,6 +777,7 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc,
> const int *subscripts, int32_t value,
> int32_t range_min, int32_t range_max)
> {
> +#if CBS_WRITE
> CBS_TRACE_WRITE_START();
>
> av_assert0(width > 0 && width <= 32);
> @@ -739,6 +800,9 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc,
> CBS_TRACE_WRITE_END();
>
> return 0;
> +#else
> + return AVERROR(ENOSYS);
> +#endif
> }
>
>
> diff --git a/libavcodec/cbs_av1.c b/libavcodec/cbs_av1.c
> index d7862a2e48..e0a4eba20f 100644
> --- a/libavcodec/cbs_av1.c
> +++ b/libavcodec/cbs_av1.c
> @@ -27,6 +27,7 @@
> #include "libavutil/refstruct.h"
>
>
> +#if CBS_READ
> static int cbs_av1_read_uvlc(CodedBitstreamContext *ctx, GetBitContext *gbc,
> const char *name, uint32_t *write_to,
> uint32_t range_min, uint32_t range_max)
> @@ -84,7 +85,9 @@ static int cbs_av1_read_uvlc(CodedBitstreamContext *ctx, GetBitContext *gbc,
> *write_to = value;
> return 0;
> }
> +#endif
>
> +#if CBS_WRITE
> static int cbs_av1_write_uvlc(CodedBitstreamContext *ctx, PutBitContext *pbc,
> const char *name, uint32_t value,
> uint32_t range_min, uint32_t range_max)
> @@ -115,7 +118,9 @@ static int cbs_av1_write_uvlc(CodedBitstreamContext *ctx, PutBitContext *pbc,
>
> return 0;
> }
> +#endif
>
> +#if CBS_READ
> static int cbs_av1_read_leb128(CodedBitstreamContext *ctx, GetBitContext *gbc,
> const char *name, uint64_t *write_to)
> {
> @@ -146,7 +151,9 @@ static int cbs_av1_read_leb128(CodedBitstreamContext *ctx, GetBitContext *gbc,
> *write_to = value;
> return 0;
> }
> +#endif
>
> +#if CBS_WRITE
> static int cbs_av1_write_leb128(CodedBitstreamContext *ctx, PutBitContext *pbc,
> const char *name, uint64_t value, int fixed_length)
> {
> @@ -182,7 +189,9 @@ static int cbs_av1_write_leb128(CodedBitstreamContext *ctx, PutBitContext *pbc,
>
> return 0;
> }
> +#endif
>
> +#if CBS_READ
> static int cbs_av1_read_ns(CodedBitstreamContext *ctx, GetBitContext *gbc,
> uint32_t n, const char *name,
> const int *subscripts, uint32_t *write_to)
> @@ -220,7 +229,9 @@ static int cbs_av1_read_ns(CodedBitstreamContext *ctx, GetBitContext *gbc,
> *write_to = value;
> return 0;
> }
> +#endif
>
> +#if CBS_WRITE
> static int cbs_av1_write_ns(CodedBitstreamContext *ctx, PutBitContext *pbc,
> uint32_t n, const char *name,
> const int *subscripts, uint32_t value)
> @@ -256,7 +267,9 @@ static int cbs_av1_write_ns(CodedBitstreamContext *ctx, PutBitContext *pbc,
>
> return 0;
> }
> +#endif
>
> +#if CBS_READ
> static int cbs_av1_read_increment(CodedBitstreamContext *ctx, GetBitContext *gbc,
> uint32_t range_min, uint32_t range_max,
> const char *name, uint32_t *write_to)
> @@ -284,7 +297,9 @@ static int cbs_av1_read_increment(CodedBitstreamContext *ctx, GetBitContext *gbc
> *write_to = value;
> return 0;
> }
> +#endif
>
> +#if CBS_WRITE
> static int cbs_av1_write_increment(CodedBitstreamContext *ctx, PutBitContext *pbc,
> uint32_t range_min, uint32_t range_max,
> const char *name, uint32_t value)
> @@ -315,7 +330,9 @@ static int cbs_av1_write_increment(CodedBitstreamContext *ctx, PutBitContext *pb
>
> return 0;
> }
> +#endif
>
> +#if CBS_READ
> static int cbs_av1_read_subexp(CodedBitstreamContext *ctx, GetBitContext *gbc,
> uint32_t range_max, const char *name,
> const int *subscripts, uint32_t *write_to)
> @@ -360,7 +377,9 @@ static int cbs_av1_read_subexp(CodedBitstreamContext *ctx, GetBitContext *gbc,
> *write_to = value;
> return err;
> }
> +#endif
>
> +#if CBS_WRITE
> static int cbs_av1_write_subexp(CodedBitstreamContext *ctx, PutBitContext *pbc,
> uint32_t range_max, const char *name,
> const int *subscripts, uint32_t value)
> @@ -420,6 +439,7 @@ static int cbs_av1_write_subexp(CodedBitstreamContext *ctx, PutBitContext *pbc,
>
> return err;
> }
> +#endif
>
>
> static int cbs_av1_tile_log2(int blksize, int target)
> @@ -441,7 +461,7 @@ static int cbs_av1_get_relative_dist(const AV1RawSequenceHeader *seq,
> return diff;
> }
>
> -static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc)
> +static av_unused size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc)
> {
> GetBitContext tmp = *gbc;
> size_t size = 0;
> @@ -469,6 +489,7 @@ static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc)
>
> #define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL)
>
> +#if CBS_READ
> #define fc(width, name, range_min, range_max) \
> xf(width, name, current->name, range_min, range_max, 0, )
> #define flag(name) fb(1, name)
> @@ -584,8 +605,9 @@ static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc)
> #undef leb128
> #undef infer
> #undef byte_alignment
> +#endif // CBS_READ
>
> -
> +#if CBS_WRITE
> #define WRITE
> #define READWRITE write
> #define RWContext PutBitContext
> @@ -668,12 +690,13 @@ static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc)
> #undef leb128
> #undef infer
> #undef byte_alignment
> -
> +#endif // CBS_WRITE
>
> static int cbs_av1_split_fragment(CodedBitstreamContext *ctx,
> CodedBitstreamFragment *frag,
> int header)
> {
> +#if CBS_READ
> GetBitContext gbc;
> uint8_t *data;
> size_t size;
> @@ -777,6 +800,9 @@ success:
> fail:
> ctx->trace_enable = trace;
> return err;
> +#else
> + return AVERROR(ENOSYS);
> +#endif
> }
>
> static int cbs_av1_ref_tile_data(CodedBitstreamContext *ctx,
> @@ -809,6 +835,7 @@ static int cbs_av1_ref_tile_data(CodedBitstreamContext *ctx,
> static int cbs_av1_read_unit(CodedBitstreamContext *ctx,
> CodedBitstreamUnit *unit)
> {
> +#if CBS_READ
> CodedBitstreamAV1Context *priv = ctx->priv_data;
> AV1RawOBU *obu;
> GetBitContext gbc;
> @@ -931,6 +958,7 @@ static int cbs_av1_read_unit(CodedBitstreamContext *ctx,
> return err;
> }
> break;
> +#if CBS_OBU_TILE_LIST
> case AV1_OBU_TILE_LIST:
> {
> err = cbs_av1_read_tile_list_obu(ctx, &gbc,
> @@ -946,6 +974,8 @@ static int cbs_av1_read_unit(CodedBitstreamContext *ctx,
> return err;
> }
> break;
> +#endif
> +#if CBS_OBU_METADATA
> case AV1_OBU_METADATA:
> {
> err = cbs_av1_read_metadata_obu(ctx, &gbc, &obu->obu.metadata);
> @@ -953,6 +983,8 @@ static int cbs_av1_read_unit(CodedBitstreamContext *ctx,
> return err;
> }
> break;
> +#endif
> +#if CBS_OBU_PADDING
> case AV1_OBU_PADDING:
> {
> err = cbs_av1_read_padding_obu(ctx, &gbc, &obu->obu.padding);
> @@ -960,6 +992,7 @@ static int cbs_av1_read_unit(CodedBitstreamContext *ctx,
> return err;
> }
> break;
> +#endif
> default:
> return AVERROR(ENOSYS);
> }
> @@ -982,12 +1015,16 @@ static int cbs_av1_read_unit(CodedBitstreamContext *ctx,
> }
>
> return 0;
> +#else
> + return AVERROR(ENOSYS);
> +#endif
> }
>
> static int cbs_av1_write_obu(CodedBitstreamContext *ctx,
> CodedBitstreamUnit *unit,
> PutBitContext *pbc)
> {
> +#if CBS_WRITE
> CodedBitstreamAV1Context *priv = ctx->priv_data;
> AV1RawOBU *obu = unit->content;
> PutBitContext pbc_tmp;
> @@ -1087,6 +1124,7 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx,
> td = &tile_group->tile_data;
> }
> break;
> +#if CBS_OBU_TILE_LIST
> case AV1_OBU_TILE_LIST:
> {
> err = cbs_av1_write_tile_list_obu(ctx, pbc, &obu->obu.tile_list);
> @@ -1096,6 +1134,8 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx,
> td = &obu->obu.tile_list.tile_data;
> }
> break;
> +#endif
> +#if CBS_OBU_METADATA
> case AV1_OBU_METADATA:
> {
> err = cbs_av1_write_metadata_obu(ctx, pbc, &obu->obu.metadata);
> @@ -1103,6 +1143,8 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx,
> goto error;
> }
> break;
> +#endif
> +#if CBS_OBU_PADDING
> case AV1_OBU_PADDING:
> {
> err = cbs_av1_write_padding_obu(ctx, pbc, &obu->obu.padding);
> @@ -1110,6 +1152,7 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx,
> goto error;
> }
> break;
> +#endif
> default:
> err = AVERROR(ENOSYS);
> goto error;
> @@ -1182,11 +1225,15 @@ error:
> av_buffer_unref(&av1ctx.frame_header_ref);
>
> return err;
> +#else
> + return AVERROR(ENOSYS);
> +#endif
> }
>
> static int cbs_av1_assemble_fragment(CodedBitstreamContext *ctx,
> CodedBitstreamFragment *frag)
> {
> +#if CBS_WRITE
> size_t size, pos;
> int i;
>
> @@ -1210,6 +1257,9 @@ static int cbs_av1_assemble_fragment(CodedBitstreamContext *ctx,
> frag->data_size = size;
>
> return 0;
> +#else
> + return AVERROR(ENOSYS);
> +#endif
> }
>
> static void cbs_av1_flush(CodedBitstreamContext *ctx)
> @@ -1234,6 +1284,7 @@ static void cbs_av1_close(CodedBitstreamContext *ctx)
> av_buffer_unref(&priv->frame_header_ref);
> }
>
> +#if CBS_OBU_METADATA
> static void cbs_av1_free_metadata(AVRefStructOpaque unused, void *content)
> {
> AV1RawOBU *obu = content;
> @@ -1255,6 +1306,7 @@ static void cbs_av1_free_metadata(AVRefStructOpaque unused, void *content)
> av_buffer_unref(&md->metadata.unknown.payload_ref);
> }
> }
> +#endif
>
> static const CodedBitstreamUnitTypeDescriptor cbs_av1_unit_types[] = {
> CBS_UNIT_TYPE_POD(AV1_OBU_SEQUENCE_HEADER, AV1RawOBU),
> @@ -1284,13 +1336,19 @@ static const CodedBitstreamUnitTypeDescriptor cbs_av1_unit_types[] = {
> offsetof(AV1RawOBU, obu.frame.tile_group.tile_data.data) }
> },
> },
> +#if CBS_OBU_TILE_LIST
> CBS_UNIT_TYPE_INTERNAL_REF(AV1_OBU_TILE_LIST, AV1RawOBU,
> obu.tile_list.tile_data.data),
> +#endif
> +#if CBS_OBU_PADDING
> CBS_UNIT_TYPE_INTERNAL_REF(AV1_OBU_PADDING, AV1RawOBU,
> obu.padding.payload),
> +#endif
>
> +#if CBS_OBU_METADATA
> CBS_UNIT_TYPE_COMPLEX(AV1_OBU_METADATA, AV1RawOBU,
> &cbs_av1_free_metadata),
> +#endif
>
> CBS_UNIT_TYPE_END_OF_LIST
> };
> diff --git a/libavcodec/cbs_av1.h b/libavcodec/cbs_av1.h
> index 62c7720142..0c73e12c84 100644
> --- a/libavcodec/cbs_av1.h
> +++ b/libavcodec/cbs_av1.h
> @@ -25,6 +25,15 @@
> #include "av1.h"
> #include "cbs.h"
>
> +#ifndef CBS_OBU_METADATA
> +#define CBS_OBU_METADATA 1
> +#endif
> +#ifndef CBS_OBU_TILE_LIST
> +#define CBS_OBU_TILE_LIST 1
> +#endif
> +#ifndef CBS_OBU_PADDING
> +#define CBS_OBU_PADDING 1
> +#endif
>
> typedef struct AV1RawOBUHeader {
> uint8_t obu_forbidden_bit;
> @@ -411,9 +420,15 @@ typedef struct AV1RawOBU {
> AV1RawFrameHeader frame_header;
> AV1RawFrame frame;
> AV1RawTileGroup tile_group;
> +#if CBS_OBU_TILE_LIST
> AV1RawTileList tile_list;
> +#endif
> +#if CBS_OBU_METADATA
> AV1RawMetadata metadata;
> +#endif
> +#if CBS_OBU_PADDING
> AV1RawPadding padding;
> +#endif
> } obu;
> } AV1RawOBU;
>
> diff --git a/libavcodec/cbs_av1_syntax_template.c b/libavcodec/cbs_av1_syntax_template.c
> index 62a83945ec..b594bfd22b 100644
> --- a/libavcodec/cbs_av1_syntax_template.c
> +++ b/libavcodec/cbs_av1_syntax_template.c
> @@ -1868,6 +1868,7 @@ static int FUNC(frame_obu)(CodedBitstreamContext *ctx, RWContext *rw,
> return 0;
> }
>
> +#if CBS_OBU_TILE_LIST
> static int FUNC(tile_list_obu)(CodedBitstreamContext *ctx, RWContext *rw,
> AV1RawTileList *current)
> {
> @@ -1882,7 +1883,9 @@ static int FUNC(tile_list_obu)(CodedBitstreamContext *ctx, RWContext *rw,
>
> return 0;
> }
> +#endif
>
> +#if CBS_OBU_METADATA
> static int FUNC(metadata_hdr_cll)(CodedBitstreamContext *ctx, RWContext *rw,
> AV1RawMetadataHDRCLL *current)
> {
> @@ -2101,7 +2104,9 @@ static int FUNC(metadata_obu)(CodedBitstreamContext *ctx, RWContext *rw,
>
> return 0;
> }
> +#endif
>
> +#if CBS_OBU_PADDING
> static int FUNC(padding_obu)(CodedBitstreamContext *ctx, RWContext *rw,
> AV1RawPadding *current)
> {
> @@ -2125,3 +2130,4 @@ static int FUNC(padding_obu)(CodedBitstreamContext *ctx, RWContext *rw,
>
> return 0;
> }
> +#endif
> diff --git a/libavcodec/cbs_internal.h b/libavcodec/cbs_internal.h
> index 80cad2b162..f15ba1ab90 100644
> --- a/libavcodec/cbs_internal.h
> +++ b/libavcodec/cbs_internal.h
> @@ -22,6 +22,8 @@
> #include <stddef.h>
> #include <stdint.h>
>
> +#include "config.h"
> +
> #include "libavutil/log.h"
>
> #include "cbs.h"
> @@ -30,6 +32,40 @@
> #include "put_bits.h"
> #include "libavutil/refstruct.h"
>
> +#ifndef CBS_READ
> +#define CBS_READ 1
> +#endif
> +#ifndef CBS_WRITE
> +#define CBS_WRITE 1
> +#endif
> +#ifndef CBS_TRACE
> +#define CBS_TRACE 1
> +#endif
> +
> +#ifndef CBS_AV1
> +#define CBS_AV1 CONFIG_CBS_AV1
> +#endif
> +#ifndef CBS_H264
> +#define CBS_H264 CONFIG_CBS_H264
> +#endif
> +#ifndef CBS_H265
> +#define CBS_H265 CONFIG_CBS_H265
> +#endif
> +#ifndef CBS_H266
> +#define CBS_H266 CONFIG_CBS_H266
> +#endif
> +#ifndef CBS_JPEG
> +#define CBS_JPEG CONFIG_CBS_JPEG
> +#endif
> +#ifndef CBS_MPEG2
> +#define CBS_MPEG2 CONFIG_CBS_MPEG2
> +#endif
> +#ifndef CBS_VP8
> +#define CBS_VP8 CONFIG_CBS_VP8
> +#endif
> +#ifndef CBS_VP9
> +#define CBS_VP9 CONFIG_CBS_VP9
> +#endif
>
> enum CBSContentType {
> // Unit content may contain some references to other structures, but all
> @@ -204,6 +240,7 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc,
> #define MIN_INT_BITS(length) (-(INT64_C(1) << ((length) - 1)))
>
>
> +#if CBS_TRACE
> // Start of a syntax element during read tracing.
> #define CBS_TRACE_READ_START() \
> GetBitContext trace_start; \
> @@ -284,6 +321,17 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc,
> } \
> } while (0)
>
> +#else // CBS_TRACE
> +#define CBS_TRACE_READ_START() do { } while (0)
> +#define CBS_TRACE_READ_END() do { } while (0)
> +#define CBS_TRACE_READ_END_NO_SUBSCRIPTS() do { } while (0)
> +#define CBS_TRACE_READ_END_VALUE_ONLY() do { } while (0)
> +#define CBS_TRACE_WRITE_START() do { } while (0)
> +#define CBS_TRACE_WRITE_END() do { } while (0)
> +#define CBS_TRACE_WRITE_END_NO_SUBSCRIPTS() do { } while (0)
> +#define CBS_TRACE_WRITE_END_VALUE_ONLY() do { } while (0)
> +#endif // CBS_TRACE
> +
> #define TYPE_LIST(...) { __VA_ARGS__ }
> #define CBS_UNIT_TYPE_POD(type_, structure) { \
> .nb_unit_types = 1, \
This patch (or rather the next) breaks the fundamental rule of
duplicating object files: The object files really need to be interchangable.
(Rationale: It is possible to --enable-static and --enable-shared at the
same time and users are allowed to link a subset of libraries statically
and another subset in a dynamic manner. In such a scenario the archives
need to contain everything as if used for a dynamic build (because lavc
may be linked dynamically, so that its internal symbols aren't
available), but if linking is performed statically, then the duplicated
object files (here: lavf/cbs.o) are used everywhere. And this will cause
mayhem because your lavf versions are only stripped down.)
- 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] 9+ messages in thread
end of thread, other threads:[~2025-03-22 14:25 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-03-20 17:01 [FFmpeg-devel] [PATCH 1/2] avcodec/cbs_av1: also store a pointer to the start of the tile group data James Almer
2025-03-20 17:01 ` [FFmpeg-devel] [PATCH 2/2] avformat/movenccenc: add support for CENC AV1 encryption James Almer
2025-03-21 2:55 ` Andreas Rheinhardt
2025-03-21 3:30 ` James Almer
2025-03-21 3:52 ` Andreas Rheinhardt
2025-03-21 12:50 ` James Almer
2025-03-21 19:42 ` [FFmpeg-devel] [PATCH 2/3] avcodec/cbs: allow fine tunning selection of features James Almer
2025-03-21 19:42 ` [FFmpeg-devel] [PATCH v2 3/3] avformat/movenccenc: add support for CENC AV1 encryption James Almer
2025-03-22 14:25 ` [FFmpeg-devel] [PATCH 2/3] avcodec/cbs: allow fine tunning selection of features Andreas Rheinhardt
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git