[FFmpeg-devel] [PATCH 03/27] cbs_h2645: Merge SEI message handling in common between codecs
Mark Thompson
sw at jkqxz.net
Fri Jan 1 23:35:13 EET 2021
---
libavcodec/Makefile | 4 +-
libavcodec/cbs_h264.h | 50 +---
libavcodec/cbs_h2645.c | 300 +++++++++++----------
libavcodec/cbs_h264_syntax_template.c | 173 +-----------
libavcodec/cbs_h265.h | 33 +--
libavcodec/cbs_h265_syntax_template.c | 269 +++----------------
libavcodec/cbs_sei.c | 369 ++++++++++++++++++++++++++
libavcodec/cbs_sei.h | 255 ++++++++++++++++++
libavcodec/cbs_sei_syntax_template.c | 215 +++++++++++++--
libavcodec/h264_metadata_bsf.c | 113 ++++----
libavcodec/vaapi_encode_h264.c | 51 ++--
libavcodec/vaapi_encode_h265.c | 38 +--
12 files changed, 1107 insertions(+), 763 deletions(-)
create mode 100644 libavcodec/cbs_sei.c
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 450781886d..6e12a8171d 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -71,8 +71,8 @@ OBJS-$(CONFIG_BSWAPDSP) += bswapdsp.o
OBJS-$(CONFIG_CABAC) += cabac.o
OBJS-$(CONFIG_CBS) += cbs.o
OBJS-$(CONFIG_CBS_AV1) += cbs_av1.o
-OBJS-$(CONFIG_CBS_H264) += cbs_h2645.o h2645_parse.o
-OBJS-$(CONFIG_CBS_H265) += cbs_h2645.o h2645_parse.o
+OBJS-$(CONFIG_CBS_H264) += cbs_h2645.o cbs_sei.o h2645_parse.o
+OBJS-$(CONFIG_CBS_H265) += cbs_h2645.o cbs_sei.o h2645_parse.o
OBJS-$(CONFIG_CBS_JPEG) += cbs_jpeg.o
OBJS-$(CONFIG_CBS_MPEG2) += cbs_mpeg2.o
OBJS-$(CONFIG_CBS_VP9) += cbs_vp9.o
diff --git a/libavcodec/cbs_h264.h b/libavcodec/cbs_h264.h
index 81113f1ad0..9eb97eae24 100644
--- a/libavcodec/cbs_h264.h
+++ b/libavcodec/cbs_h264.h
@@ -291,34 +291,9 @@ typedef struct H264RawSEIDisplayOrientation {
uint8_t display_orientation_extension_flag;
} H264RawSEIDisplayOrientation;
-typedef struct H264RawSEIPayload {
- uint32_t payload_type;
- uint32_t payload_size;
- union {
- H264RawSEIBufferingPeriod buffering_period;
- H264RawSEIPicTiming pic_timing;
- H264RawSEIPanScanRect pan_scan_rect;
- // H264RawSEIFiller filler -> no fields.
- SEIRawUserDataRegistered user_data_registered;
- SEIRawUserDataUnregistered user_data_unregistered;
- H264RawSEIRecoveryPoint recovery_point;
- H264RawSEIDisplayOrientation display_orientation;
- SEIRawMasteringDisplayColourVolume mastering_display_colour_volume;
- SEIRawAlternativeTransferCharacteristics
- alternative_transfer_characteristics;
- struct {
- uint8_t *data;
- AVBufferRef *data_ref;
- size_t data_length;
- } other;
- } payload;
-} H264RawSEIPayload;
-
typedef struct H264RawSEI {
H264RawNALUnitHeader nal_unit_header;
-
- H264RawSEIPayload payload[H264_MAX_SEI_PAYLOADS];
- uint8_t payload_count;
+ SEIRawMessageList message_list;
} H264RawSEI;
typedef struct H264RawSliceHeader {
@@ -438,27 +413,4 @@ typedef struct CodedBitstreamH264Context {
uint8_t last_slice_nal_unit_type;
} CodedBitstreamH264Context;
-
-/**
- * Add an SEI message to an access unit.
- *
- * On success, the payload will be owned by a unit in access_unit;
- * on failure, the content of the payload will be freed.
- */
-int ff_cbs_h264_add_sei_message(CodedBitstreamFragment *access_unit,
- H264RawSEIPayload *payload);
-
-/**
- * Delete an SEI message from an access unit.
- *
- * Deletes from nal_unit, which must be an SEI NAL unit. If this is the
- * last message in nal_unit, also deletes it from access_unit.
- *
- * Requires nal_unit to be a unit in access_unit and position to be >= 0
- * and < the payload count of the SEI nal_unit.
- */
-void ff_cbs_h264_delete_sei_message(CodedBitstreamFragment *access_unit,
- CodedBitstreamUnit *nal_unit,
- int position);
-
#endif /* AVCODEC_CBS_H264_H */
diff --git a/libavcodec/cbs_h2645.c b/libavcodec/cbs_h2645.c
index ce58e47a36..a00bc27370 100644
--- a/libavcodec/cbs_h2645.c
+++ b/libavcodec/cbs_h2645.c
@@ -348,6 +348,7 @@ static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc)
#define more_rbsp_data(var) ((var) = cbs_h2645_read_more_rbsp_data(rw))
+#define bit_position(rw) (get_bits_count(rw))
#define byte_alignment(rw) (get_bits_count(rw) % 8)
#define allocate(name, size) do { \
@@ -379,6 +380,7 @@ static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc)
#undef xse
#undef infer
#undef more_rbsp_data
+#undef bit_position
#undef byte_alignment
#undef allocate
@@ -424,6 +426,7 @@ static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc)
#define more_rbsp_data(var) (var)
+#define bit_position(rw) (put_bits_count(rw))
#define byte_alignment(rw) (put_bits_count(rw) % 8)
#define allocate(name, size) do { \
@@ -460,6 +463,7 @@ static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc)
#undef se
#undef infer
#undef more_rbsp_data
+#undef bit_position
#undef byte_alignment
#undef allocate
@@ -1372,36 +1376,11 @@ static void cbs_h265_close(CodedBitstreamContext *ctx)
av_buffer_unref(&h265->pps_ref[i]);
}
-static void cbs_h264_free_sei_payload(H264RawSEIPayload *payload)
-{
- switch (payload->payload_type) {
- case H264_SEI_TYPE_BUFFERING_PERIOD:
- case H264_SEI_TYPE_PIC_TIMING:
- case H264_SEI_TYPE_PAN_SCAN_RECT:
- case H264_SEI_TYPE_RECOVERY_POINT:
- case H264_SEI_TYPE_DISPLAY_ORIENTATION:
- case H264_SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME:
- case H264_SEI_TYPE_ALTERNATIVE_TRANSFER:
- break;
- case H264_SEI_TYPE_USER_DATA_REGISTERED:
- av_buffer_unref(&payload->payload.user_data_registered.data_ref);
- break;
- case H264_SEI_TYPE_USER_DATA_UNREGISTERED:
- av_buffer_unref(&payload->payload.user_data_unregistered.data_ref);
- break;
- default:
- av_buffer_unref(&payload->payload.other.data_ref);
- break;
- }
-}
-
static void cbs_h264_free_sei(void *opaque, uint8_t *content)
{
H264RawSEI *sei = (H264RawSEI*)content;
- int i;
- for (i = 0; i < sei->payload_count; i++)
- cbs_h264_free_sei_payload(&sei->payload[i]);
- av_freep(&content);
+ ff_cbs_sei_free_message_list(&sei->message_list);
+ av_free(content);
}
static const CodedBitstreamUnitTypeDescriptor cbs_h264_unit_types[] = {
@@ -1433,42 +1412,11 @@ static const CodedBitstreamUnitTypeDescriptor cbs_h264_unit_types[] = {
CBS_UNIT_TYPE_END_OF_LIST
};
-static void cbs_h265_free_sei_payload(H265RawSEIPayload *payload)
-{
- switch (payload->payload_type) {
- case HEVC_SEI_TYPE_BUFFERING_PERIOD:
- case HEVC_SEI_TYPE_PICTURE_TIMING:
- case HEVC_SEI_TYPE_PAN_SCAN_RECT:
- case HEVC_SEI_TYPE_RECOVERY_POINT:
- case HEVC_SEI_TYPE_DISPLAY_ORIENTATION:
- case HEVC_SEI_TYPE_ACTIVE_PARAMETER_SETS:
- case HEVC_SEI_TYPE_DECODED_PICTURE_HASH:
- case HEVC_SEI_TYPE_TIME_CODE:
- case HEVC_SEI_TYPE_MASTERING_DISPLAY_INFO:
- case HEVC_SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO:
- case HEVC_SEI_TYPE_ALTERNATIVE_TRANSFER_CHARACTERISTICS:
- case HEVC_SEI_TYPE_ALPHA_CHANNEL_INFO:
- break;
- case HEVC_SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35:
- av_buffer_unref(&payload->payload.user_data_registered.data_ref);
- break;
- case HEVC_SEI_TYPE_USER_DATA_UNREGISTERED:
- av_buffer_unref(&payload->payload.user_data_unregistered.data_ref);
- break;
- default:
- av_buffer_unref(&payload->payload.other.data_ref);
- break;
- }
- av_buffer_unref(&payload->extension_data.data_ref);
-}
-
static void cbs_h265_free_sei(void *opaque, uint8_t *content)
{
H265RawSEI *sei = (H265RawSEI*)content;
- int i;
- for (i = 0; i < sei->payload_count; i++)
- cbs_h265_free_sei_payload(&sei->payload[i]);
- av_freep(&content);
+ ff_cbs_sei_free_message_list(&sei->message_list);
+ av_free(content);
}
static const CodedBitstreamUnitTypeDescriptor cbs_h265_unit_types[] = {
@@ -1548,92 +1496,164 @@ const CodedBitstreamType ff_cbs_type_h265 = {
.close = &cbs_h265_close,
};
-int ff_cbs_h264_add_sei_message(CodedBitstreamFragment *au,
- H264RawSEIPayload *payload)
-{
- H264RawSEI *sei = NULL;
- int err, i;
-
- // Find an existing SEI NAL unit to add to.
- for (i = 0; i < au->nb_units; i++) {
- if (au->units[i].type == H264_NAL_SEI) {
- sei = au->units[i].content;
- if (sei->payload_count < H264_MAX_SEI_PAYLOADS)
- break;
-
- sei = NULL;
- }
- }
-
- if (!sei) {
- // Need to make a new SEI NAL unit. Insert it before the first
- // slice data NAL unit; if no slice data, add at the end.
- AVBufferRef *sei_ref;
-
- sei = av_mallocz(sizeof(*sei));
- if (!sei) {
- err = AVERROR(ENOMEM);
- goto fail;
- }
-
- sei->nal_unit_header.nal_unit_type = H264_NAL_SEI;
- sei->nal_unit_header.nal_ref_idc = 0;
-
- sei_ref = av_buffer_create((uint8_t*)sei, sizeof(*sei),
- &cbs_h264_free_sei, NULL, 0);
- if (!sei_ref) {
- av_freep(&sei);
- err = AVERROR(ENOMEM);
- goto fail;
- }
-
- for (i = 0; i < au->nb_units; i++) {
- if (au->units[i].type == H264_NAL_SLICE ||
- au->units[i].type == H264_NAL_IDR_SLICE)
- break;
- }
-
- err = ff_cbs_insert_unit_content(au, i, H264_NAL_SEI,
- sei, sei_ref);
- av_buffer_unref(&sei_ref);
- if (err < 0)
- goto fail;
- }
+static const SEIMessageTypeDescriptor cbs_sei_common_types[] = {
+ {
+ SEI_TYPE_FILLER_PAYLOAD,
+ 1, 1,
+ sizeof(SEIRawFillerPayload),
+ SEI_MESSAGE_RW(sei, filler_payload),
+ },
+ {
+ SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35,
+ 1, 1,
+ sizeof(SEIRawUserDataRegistered),
+ SEI_MESSAGE_RW(sei, user_data_registered),
+ },
+ {
+ SEI_TYPE_USER_DATA_UNREGISTERED,
+ 1, 1,
+ sizeof(SEIRawUserDataUnregistered),
+ SEI_MESSAGE_RW(sei, user_data_unregistered),
+ },
+ {
+ SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME,
+ 1, 0,
+ sizeof(SEIRawMasteringDisplayColourVolume),
+ SEI_MESSAGE_RW(sei, mastering_display_colour_volume),
+ },
+ {
+ SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO,
+ 1, 0,
+ sizeof(SEIRawContentLightLevelInfo),
+ SEI_MESSAGE_RW(sei, content_light_level_info),
+ },
+ {
+ SEI_TYPE_ALTERNATIVE_TRANSFER_CHARACTERISTICS,
+ 1, 0,
+ sizeof(SEIRawAlternativeTransferCharacteristics),
+ SEI_MESSAGE_RW(sei, alternative_transfer_characteristics),
+ },
+ SEI_MESSAGE_TYPE_END,
+};
- memcpy(&sei->payload[sei->payload_count], payload, sizeof(*payload));
- ++sei->payload_count;
+static const SEIMessageTypeDescriptor cbs_sei_h264_types[] = {
+ {
+ SEI_TYPE_BUFFERING_PERIOD,
+ 1, 0,
+ sizeof(H264RawSEIBufferingPeriod),
+ SEI_MESSAGE_RW(h264, sei_buffering_period),
+ },
+ {
+ SEI_TYPE_PIC_TIMING,
+ 1, 0,
+ sizeof(H264RawSEIPicTiming),
+ SEI_MESSAGE_RW(h264, sei_pic_timing),
+ },
+ {
+ SEI_TYPE_PAN_SCAN_RECT,
+ 1, 0,
+ sizeof(H264RawSEIPanScanRect),
+ SEI_MESSAGE_RW(h264, sei_pan_scan_rect),
+ },
+ {
+ SEI_TYPE_RECOVERY_POINT,
+ 1, 0,
+ sizeof(H264RawSEIRecoveryPoint),
+ SEI_MESSAGE_RW(h264, sei_recovery_point),
+ },
+ {
+ SEI_TYPE_DISPLAY_ORIENTATION,
+ 1, 0,
+ sizeof(H264RawSEIDisplayOrientation),
+ SEI_MESSAGE_RW(h264, sei_display_orientation),
+ },
+ SEI_MESSAGE_TYPE_END
+};
- return 0;
-fail:
- cbs_h264_free_sei_payload(payload);
- return err;
-}
+static const SEIMessageTypeDescriptor cbs_sei_h265_types[] = {
+ {
+ SEI_TYPE_BUFFERING_PERIOD,
+ 1, 0,
+ sizeof(H265RawSEIBufferingPeriod),
+ SEI_MESSAGE_RW(h265, sei_buffering_period),
+ },
+ {
+ SEI_TYPE_PIC_TIMING,
+ 1, 0,
+ sizeof(H265RawSEIPicTiming),
+ SEI_MESSAGE_RW(h265, sei_pic_timing),
+ },
+ {
+ SEI_TYPE_PAN_SCAN_RECT,
+ 1, 0,
+ sizeof(H265RawSEIPanScanRect),
+ SEI_MESSAGE_RW(h265, sei_pan_scan_rect),
+ },
+ {
+ SEI_TYPE_RECOVERY_POINT,
+ 1, 0,
+ sizeof(H265RawSEIRecoveryPoint),
+ SEI_MESSAGE_RW(h265, sei_recovery_point),
+ },
+ {
+ SEI_TYPE_DISPLAY_ORIENTATION,
+ 1, 0,
+ sizeof(H265RawSEIDisplayOrientation),
+ SEI_MESSAGE_RW(h265, sei_display_orientation),
+ },
+ {
+ SEI_TYPE_ACTIVE_PARAMETER_SETS,
+ 1, 0,
+ sizeof(H265RawSEIActiveParameterSets),
+ SEI_MESSAGE_RW(h265, sei_active_parameter_sets),
+ },
+ {
+ SEI_TYPE_DECODED_PICTURE_HASH,
+ 0, 1,
+ sizeof(H265RawSEIDecodedPictureHash),
+ SEI_MESSAGE_RW(h265, sei_decoded_picture_hash),
+ },
+ {
+ SEI_TYPE_TIME_CODE,
+ 1, 0,
+ sizeof(H265RawSEITimeCode),
+ SEI_MESSAGE_RW(h265, sei_time_code),
+ },
+ {
+ SEI_TYPE_ALPHA_CHANNEL_INFO,
+ 1, 0,
+ sizeof(H265RawSEIAlphaChannelInfo),
+ SEI_MESSAGE_RW(h265, sei_alpha_channel_info),
+ },
+ SEI_MESSAGE_TYPE_END
+};
-void ff_cbs_h264_delete_sei_message(CodedBitstreamFragment *au,
- CodedBitstreamUnit *nal,
- int position)
+const SEIMessageTypeDescriptor *ff_cbs_sei_find_type(CodedBitstreamContext *ctx,
+ int payload_type)
{
- H264RawSEI *sei = nal->content;
-
- av_assert0(nal->type == H264_NAL_SEI);
- av_assert0(position >= 0 && position < sei->payload_count);
-
- if (position == 0 && sei->payload_count == 1) {
- // Deleting NAL unit entirely.
- int i;
+ const SEIMessageTypeDescriptor *codec_list;
+ int i;
- for (i = 0; i < au->nb_units; i++) {
- if (&au->units[i] == nal)
- break;
- }
+ for (i = 0; cbs_sei_common_types[i].type >= 0; i++) {
+ if (cbs_sei_common_types[i].type == payload_type)
+ return &cbs_sei_common_types[i];
+ }
- ff_cbs_delete_unit(au, i);
- } else {
- cbs_h264_free_sei_payload(&sei->payload[position]);
+ switch (ctx->codec->codec_id) {
+ case AV_CODEC_ID_H264:
+ codec_list = cbs_sei_h264_types;
+ break;
+ case AV_CODEC_ID_H265:
+ codec_list = cbs_sei_h265_types;
+ break;
+ default:
+ return NULL;
+ }
- --sei->payload_count;
- memmove(sei->payload + position,
- sei->payload + position + 1,
- (sei->payload_count - position) * sizeof(*sei->payload));
+ for (i = 0; codec_list[i].type >= 0; i++) {
+ if (codec_list[i].type == payload_type)
+ return &codec_list[i];
}
+
+ return NULL;
}
diff --git a/libavcodec/cbs_h264_syntax_template.c b/libavcodec/cbs_h264_syntax_template.c
index 76ed51cc7b..9587f33985 100644
--- a/libavcodec/cbs_h264_syntax_template.c
+++ b/libavcodec/cbs_h264_syntax_template.c
@@ -511,7 +511,8 @@ static int FUNC(pps)(CodedBitstreamContext *ctx, RWContext *rw,
}
static int FUNC(sei_buffering_period)(CodedBitstreamContext *ctx, RWContext *rw,
- H264RawSEIBufferingPeriod *current)
+ H264RawSEIBufferingPeriod *current,
+ SEIMessageState *sei)
{
CodedBitstreamH264Context *h264 = ctx->priv_data;
const H264RawSPS *sps;
@@ -604,7 +605,8 @@ static int FUNC(sei_pic_timestamp)(CodedBitstreamContext *ctx, RWContext *rw,
}
static int FUNC(sei_pic_timing)(CodedBitstreamContext *ctx, RWContext *rw,
- H264RawSEIPicTiming *current)
+ H264RawSEIPicTiming *current,
+ SEIMessageState *sei)
{
CodedBitstreamH264Context *h264 = ctx->priv_data;
const H264RawSPS *sps;
@@ -675,7 +677,8 @@ static int FUNC(sei_pic_timing)(CodedBitstreamContext *ctx, RWContext *rw,
}
static int FUNC(sei_pan_scan_rect)(CodedBitstreamContext *ctx, RWContext *rw,
- H264RawSEIPanScanRect *current)
+ H264RawSEIPanScanRect *current,
+ SEIMessageState *sei)
{
int err, i;
@@ -701,7 +704,8 @@ static int FUNC(sei_pan_scan_rect)(CodedBitstreamContext *ctx, RWContext *rw,
}
static int FUNC(sei_recovery_point)(CodedBitstreamContext *ctx, RWContext *rw,
- H264RawSEIRecoveryPoint *current)
+ H264RawSEIRecoveryPoint *current,
+ SEIMessageState *sei)
{
int err;
@@ -716,7 +720,8 @@ static int FUNC(sei_recovery_point)(CodedBitstreamContext *ctx, RWContext *rw,
}
static int FUNC(sei_display_orientation)(CodedBitstreamContext *ctx, RWContext *rw,
- H264RawSEIDisplayOrientation *current)
+ H264RawSEIDisplayOrientation *current,
+ SEIMessageState *sei)
{
int err;
@@ -734,171 +739,17 @@ static int FUNC(sei_display_orientation)(CodedBitstreamContext *ctx, RWContext *
return 0;
}
-static int FUNC(sei_payload)(CodedBitstreamContext *ctx, RWContext *rw,
- H264RawSEIPayload *current)
-{
- int err, i;
- int start_position, end_position;
-
-#ifdef READ
- start_position = get_bits_count(rw);
-#else
- start_position = put_bits_count(rw);
-#endif
-
- switch (current->payload_type) {
- case H264_SEI_TYPE_BUFFERING_PERIOD:
- CHECK(FUNC(sei_buffering_period)
- (ctx, rw, ¤t->payload.buffering_period));
- break;
- case H264_SEI_TYPE_PIC_TIMING:
- CHECK(FUNC(sei_pic_timing)
- (ctx, rw, ¤t->payload.pic_timing));
- break;
- case H264_SEI_TYPE_PAN_SCAN_RECT:
- CHECK(FUNC(sei_pan_scan_rect)
- (ctx, rw, ¤t->payload.pan_scan_rect));
- break;
- case H264_SEI_TYPE_FILLER_PAYLOAD:
- {
- for (i = 0; i < current->payload_size; i++)
- fixed(8, ff_byte, 0xff);
- }
- break;
- case H264_SEI_TYPE_USER_DATA_REGISTERED:
- CHECK(FUNC_SEI(sei_user_data_registered)
- (ctx, rw, ¤t->payload.user_data_registered, ¤t->payload_size));
- break;
- case H264_SEI_TYPE_USER_DATA_UNREGISTERED:
- CHECK(FUNC_SEI(sei_user_data_unregistered)
- (ctx, rw, ¤t->payload.user_data_unregistered, ¤t->payload_size));
- break;
- case H264_SEI_TYPE_RECOVERY_POINT:
- CHECK(FUNC(sei_recovery_point)
- (ctx, rw, ¤t->payload.recovery_point));
- break;
- case H264_SEI_TYPE_DISPLAY_ORIENTATION:
- CHECK(FUNC(sei_display_orientation)
- (ctx, rw, ¤t->payload.display_orientation));
- break;
- case H264_SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME:
- CHECK(FUNC_SEI(sei_mastering_display_colour_volume)
- (ctx, rw, ¤t->payload.mastering_display_colour_volume));
- break;
- case H264_SEI_TYPE_ALTERNATIVE_TRANSFER:
- CHECK(FUNC_SEI(sei_alternative_transfer_characteristics)
- (ctx, rw, ¤t->payload.alternative_transfer_characteristics));
- break;
- default:
- {
-#ifdef READ
- current->payload.other.data_length = current->payload_size;
-#endif
- allocate(current->payload.other.data, current->payload.other.data_length);
- for (i = 0; i < current->payload.other.data_length; i++)
- xu(8, payload_byte[i], current->payload.other.data[i], 0, 255, 1, i);
- }
- }
-
- if (byte_alignment(rw)) {
- fixed(1, bit_equal_to_one, 1);
- while (byte_alignment(rw))
- fixed(1, bit_equal_to_zero, 0);
- }
-
-#ifdef READ
- end_position = get_bits_count(rw);
- if (end_position < start_position + 8 * current->payload_size) {
- av_log(ctx->log_ctx, AV_LOG_ERROR, "Incorrect SEI payload length: "
- "header %"PRIu32" bits, actually %d bits.\n",
- 8 * current->payload_size,
- end_position - start_position);
- return AVERROR_INVALIDDATA;
- }
-#else
- end_position = put_bits_count(rw);
- current->payload_size = (end_position - start_position) / 8;
-#endif
-
- return 0;
-}
-
static int FUNC(sei)(CodedBitstreamContext *ctx, RWContext *rw,
H264RawSEI *current)
{
- int err, k;
+ int err;
HEADER("Supplemental Enhancement Information");
CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header,
1 << H264_NAL_SEI));
-#ifdef READ
- for (k = 0; k < H264_MAX_SEI_PAYLOADS; k++) {
- uint32_t payload_type = 0;
- uint32_t payload_size = 0;
- uint32_t tmp;
-
- while (show_bits(rw, 8) == 0xff) {
- fixed(8, ff_byte, 0xff);
- payload_type += 255;
- }
- xu(8, last_payload_type_byte, tmp, 0, 254, 0);
- payload_type += tmp;
-
- while (show_bits(rw, 8) == 0xff) {
- fixed(8, ff_byte, 0xff);
- payload_size += 255;
- }
- xu(8, last_payload_size_byte, tmp, 0, 254, 0);
- payload_size += tmp;
-
- current->payload[k].payload_type = payload_type;
- current->payload[k].payload_size = payload_size;
-
- current->payload_count++;
- CHECK(FUNC(sei_payload)(ctx, rw, ¤t->payload[k]));
-
- if (!cbs_h2645_read_more_rbsp_data(rw))
- break;
- }
- if (k >= H264_MAX_SEI_PAYLOADS) {
- av_log(ctx->log_ctx, AV_LOG_ERROR, "Too many payloads in "
- "SEI message: found %d.\n", k);
- return AVERROR_INVALIDDATA;
- }
-#else
- for (k = 0; k < current->payload_count; k++) {
- PutBitContext start_state;
- uint32_t tmp;
- int need_size, i;
-
- // Somewhat clumsy: we write the payload twice when
- // we don't know the size in advance. This will mess
- // with trace output, but is otherwise harmless.
- start_state = *rw;
- need_size = !current->payload[k].payload_size;
- for (i = 0; i < 1 + need_size; i++) {
- *rw = start_state;
-
- tmp = current->payload[k].payload_type;
- while (tmp >= 255) {
- fixed(8, ff_byte, 0xff);
- tmp -= 255;
- }
- xu(8, last_payload_type_byte, tmp, 0, 254, 0);
-
- tmp = current->payload[k].payload_size;
- while (tmp >= 255) {
- fixed(8, ff_byte, 0xff);
- tmp -= 255;
- }
- xu(8, last_payload_size_byte, tmp, 0, 254, 0);
-
- CHECK(FUNC(sei_payload)(ctx, rw, ¤t->payload[k]));
- }
- }
-#endif
+ CHECK(FUNC_SEI(message_list)(ctx, rw, ¤t->message_list, 1));
CHECK(FUNC(rbsp_trailing_bits)(ctx, rw));
diff --git a/libavcodec/cbs_h265.h b/libavcodec/cbs_h265.h
index d8e93e3bb8..738cbeec2c 100644
--- a/libavcodec/cbs_h265.h
+++ b/libavcodec/cbs_h265.h
@@ -658,40 +658,9 @@ typedef struct H265RawSEIAlphaChannelInfo {
uint8_t alpha_channel_clip_type_flag;
} H265RawSEIAlphaChannelInfo;
-typedef struct H265RawSEIPayload {
- uint32_t payload_type;
- uint32_t payload_size;
- union {
- H265RawSEIBufferingPeriod buffering_period;
- H265RawSEIPicTiming pic_timing;
- H265RawSEIPanScanRect pan_scan_rect;
- SEIRawUserDataRegistered user_data_registered;
- SEIRawUserDataUnregistered user_data_unregistered;
- H265RawSEIRecoveryPoint recovery_point;
- H265RawSEIDisplayOrientation display_orientation;
- H265RawSEIActiveParameterSets active_parameter_sets;
- H265RawSEIDecodedPictureHash decoded_picture_hash;
- H265RawSEITimeCode time_code;
- SEIRawMasteringDisplayColourVolume
- mastering_display_colour_volume;
- SEIRawContentLightLevelInfo content_light_level;
- SEIRawAlternativeTransferCharacteristics
- alternative_transfer_characteristics;
- H265RawSEIAlphaChannelInfo alpha_channel_info;
- struct {
- uint8_t *data;
- AVBufferRef *data_ref;
- size_t data_length;
- } other;
- } payload;
- H265RawExtensionData extension_data;
-} H265RawSEIPayload;
-
typedef struct H265RawSEI {
H265RawNALUnitHeader nal_unit_header;
-
- H265RawSEIPayload payload[H265_MAX_SEI_PAYLOADS];
- uint8_t payload_count;
+ SEIRawMessageList message_list;
} H265RawSEI;
typedef struct CodedBitstreamH265Context {
diff --git a/libavcodec/cbs_h265_syntax_template.c b/libavcodec/cbs_h265_syntax_template.c
index e4cc1a9be8..d09934cfeb 100644
--- a/libavcodec/cbs_h265_syntax_template.c
+++ b/libavcodec/cbs_h265_syntax_template.c
@@ -1596,10 +1596,9 @@ static int FUNC(slice_segment_header)(CodedBitstreamContext *ctx, RWContext *rw,
return 0;
}
-static int FUNC(sei_buffering_period)(CodedBitstreamContext *ctx, RWContext *rw,
- H265RawSEIBufferingPeriod *current,
- uint32_t *payload_size,
- int *more_data)
+static int FUNC(sei_buffering_period)
+ (CodedBitstreamContext *ctx, RWContext *rw,
+ H265RawSEIBufferingPeriod *current, SEIMessageState *sei)
{
CodedBitstreamH265Context *h265 = ctx->priv_data;
const H265RawSPS *sps;
@@ -1687,7 +1686,7 @@ static int FUNC(sei_buffering_period)(CodedBitstreamContext *ctx, RWContext *rw,
#ifdef READ
end_pos = get_bits_count(rw);
- if (cbs_h265_payload_extension_present(rw, *payload_size,
+ if (cbs_h265_payload_extension_present(rw, sei->payload_size,
end_pos - start_pos))
flag(use_alt_cpb_params_flag);
else
@@ -1695,20 +1694,21 @@ static int FUNC(sei_buffering_period)(CodedBitstreamContext *ctx, RWContext *rw,
#else
// If unknown extension data exists, then use_alt_cpb_params_flag is
// coded in the bitstream and must be written even if it's 0.
- if (current->use_alt_cpb_params_flag || *more_data) {
+ if (current->use_alt_cpb_params_flag || sei->extension_present) {
flag(use_alt_cpb_params_flag);
// Ensure this bit is not the last in the payload by making the
// more_data_in_payload() check evaluate to true, so it may not
// be mistaken as something else by decoders.
- *more_data = 1;
+ sei->extension_present = 1;
}
#endif
return 0;
}
-static int FUNC(sei_pic_timing)(CodedBitstreamContext *ctx, RWContext *rw,
- H265RawSEIPicTiming *current)
+static int FUNC(sei_pic_timing)
+ (CodedBitstreamContext *ctx, RWContext *rw,
+ H265RawSEIPicTiming *current, SEIMessageState *sei)
{
CodedBitstreamH265Context *h265 = ctx->priv_data;
const H265RawSPS *sps;
@@ -1782,8 +1782,9 @@ static int FUNC(sei_pic_timing)(CodedBitstreamContext *ctx, RWContext *rw,
return 0;
}
-static int FUNC(sei_pan_scan_rect)(CodedBitstreamContext *ctx, RWContext *rw,
- H265RawSEIPanScanRect *current)
+static int FUNC(sei_pan_scan_rect)
+ (CodedBitstreamContext *ctx, RWContext *rw,
+ H265RawSEIPanScanRect *current, SEIMessageState *sei)
{
int err, i;
@@ -1808,8 +1809,9 @@ static int FUNC(sei_pan_scan_rect)(CodedBitstreamContext *ctx, RWContext *rw,
return 0;
}
-static int FUNC(sei_recovery_point)(CodedBitstreamContext *ctx, RWContext *rw,
- H265RawSEIRecoveryPoint *current)
+static int FUNC(sei_recovery_point)
+ (CodedBitstreamContext *ctx, RWContext *rw,
+ H265RawSEIRecoveryPoint *current, SEIMessageState *sei)
{
int err;
@@ -1823,8 +1825,9 @@ static int FUNC(sei_recovery_point)(CodedBitstreamContext *ctx, RWContext *rw,
return 0;
}
-static int FUNC(sei_display_orientation)(CodedBitstreamContext *ctx, RWContext *rw,
- H265RawSEIDisplayOrientation *current)
+static int FUNC(sei_display_orientation)
+ (CodedBitstreamContext *ctx, RWContext *rw,
+ H265RawSEIDisplayOrientation *current, SEIMessageState *sei)
{
int err;
@@ -1841,8 +1844,9 @@ static int FUNC(sei_display_orientation)(CodedBitstreamContext *ctx, RWContext *
return 0;
}
-static int FUNC(sei_active_parameter_sets)(CodedBitstreamContext *ctx, RWContext *rw,
- H265RawSEIActiveParameterSets *current)
+static int FUNC(sei_active_parameter_sets)
+ (CodedBitstreamContext *ctx, RWContext *rw,
+ H265RawSEIActiveParameterSets *current, SEIMessageState *sei)
{
CodedBitstreamH265Context *h265 = ctx->priv_data;
const H265RawVPS *vps;
@@ -1877,8 +1881,9 @@ static int FUNC(sei_active_parameter_sets)(CodedBitstreamContext *ctx, RWContext
return 0;
}
-static int FUNC(sei_decoded_picture_hash)(CodedBitstreamContext *ctx, RWContext *rw,
- H265RawSEIDecodedPictureHash *current)
+static int FUNC(sei_decoded_picture_hash)
+ (CodedBitstreamContext *ctx, RWContext *rw,
+ H265RawSEIDecodedPictureHash *current, SEIMessageState *sei)
{
CodedBitstreamH265Context *h265 = ctx->priv_data;
const H265RawSPS *sps = h265->active_sps;
@@ -1908,8 +1913,9 @@ static int FUNC(sei_decoded_picture_hash)(CodedBitstreamContext *ctx, RWContext
return 0;
}
-static int FUNC(sei_time_code)(CodedBitstreamContext *ctx, RWContext *rw,
- H265RawSEITimeCode *current)
+static int FUNC(sei_time_code)
+ (CodedBitstreamContext *ctx, RWContext *rw,
+ H265RawSEITimeCode *current, SEIMessageState *sei)
{
int err, i;
@@ -1958,9 +1964,9 @@ static int FUNC(sei_time_code)(CodedBitstreamContext *ctx, RWContext *rw,
return 0;
}
-static int FUNC(sei_alpha_channel_info)(CodedBitstreamContext *ctx,
- RWContext *rw,
- H265RawSEIAlphaChannelInfo *current)
+static int FUNC(sei_alpha_channel_info)
+ (CodedBitstreamContext *ctx, RWContext *rw,
+ H265RawSEIAlphaChannelInfo *current, SEIMessageState *sei)
{
int err, length;
@@ -1986,156 +1992,10 @@ static int FUNC(sei_alpha_channel_info)(CodedBitstreamContext *ctx,
return 0;
}
-static int FUNC(payload_extension)(CodedBitstreamContext *ctx, RWContext *rw,
- H265RawExtensionData *current, uint32_t payload_size,
- int cur_pos)
-{
- int err;
- size_t byte_length, k;
-
-#ifdef READ
- GetBitContext tmp;
- int bits_left, payload_zero_bits;
-
- if (!cbs_h265_payload_extension_present(rw, payload_size, cur_pos))
- return 0;
-
- bits_left = 8 * payload_size - cur_pos;
- tmp = *rw;
- if (bits_left > 8)
- skip_bits_long(&tmp, bits_left - 8);
- payload_zero_bits = get_bits(&tmp, FFMIN(bits_left, 8));
- if (!payload_zero_bits)
- return AVERROR_INVALIDDATA;
- payload_zero_bits = ff_ctz(payload_zero_bits);
- current->bit_length = bits_left - payload_zero_bits - 1;
- allocate(current->data, (current->bit_length + 7) / 8);
-#endif
-
- byte_length = (current->bit_length + 7) / 8;
- for (k = 0; k < byte_length; k++) {
- int length = FFMIN(current->bit_length - k * 8, 8);
- xu(length, reserved_payload_extension_data, current->data[k],
- 0, MAX_UINT_BITS(length), 0);
- }
-
- return 0;
-}
-
-static int FUNC(sei_payload)(CodedBitstreamContext *ctx, RWContext *rw,
- H265RawSEIPayload *current, int prefix)
-{
- int err, i;
- int start_position, current_position;
- int more_data = !!current->extension_data.bit_length;
-
-#ifdef READ
- start_position = get_bits_count(rw);
-#else
- start_position = put_bits_count(rw);
-#endif
-
- switch (current->payload_type) {
-#define SEI_TYPE_CHECK_VALID(name, prefix_valid, suffix_valid) do { \
- if (prefix && !prefix_valid) { \
- av_log(ctx->log_ctx, AV_LOG_ERROR, "SEI type %s invalid " \
- "as prefix SEI!\n", #name); \
- return AVERROR_INVALIDDATA; \
- } \
- if (!prefix && !suffix_valid) { \
- av_log(ctx->log_ctx, AV_LOG_ERROR, "SEI type %s invalid " \
- "as suffix SEI!\n", #name); \
- return AVERROR_INVALIDDATA; \
- } \
- } while (0)
-#define SEI_TYPE_N(type, prefix_valid, suffix_valid, name) \
- case HEVC_SEI_TYPE_ ## type: \
- SEI_TYPE_CHECK_VALID(name, prefix_valid, suffix_valid); \
- CHECK(FUNC(sei_ ## name)(ctx, rw, ¤t->payload.name)); \
- break
-#define SEI_TYPE_S(type, prefix_valid, suffix_valid, name) \
- case HEVC_SEI_TYPE_ ## type: \
- SEI_TYPE_CHECK_VALID(name, prefix_valid, suffix_valid); \
- CHECK(FUNC(sei_ ## name)(ctx, rw, ¤t->payload.name, \
- ¤t->payload_size)); \
- break
-#define SEI_TYPE_E(type, prefix_valid, suffix_valid, name) \
- case HEVC_SEI_TYPE_ ## type: \
- SEI_TYPE_CHECK_VALID(name, prefix_valid, suffix_valid); \
- CHECK(FUNC(sei_ ## name)(ctx, rw, ¤t->payload.name, \
- ¤t->payload_size, \
- &more_data)); \
- break
-
-#define SEI_TYPE_N2(type, prefix_valid, suffix_valid, name) \
- case HEVC_SEI_TYPE_ ## type: \
- SEI_TYPE_CHECK_VALID(name, prefix_valid, suffix_valid); \
- CHECK(FUNC_SEI(sei_ ## name)(ctx, rw, ¤t->payload.name)); \
- break
-#define SEI_TYPE_S2(type, prefix_valid, suffix_valid, name) \
- case HEVC_SEI_TYPE_ ## type: \
- SEI_TYPE_CHECK_VALID(name, prefix_valid, suffix_valid); \
- CHECK(FUNC_SEI(sei_ ## name)(ctx, rw, ¤t->payload.name, \
- ¤t->payload_size)); \
- break
-
- SEI_TYPE_E(BUFFERING_PERIOD, 1, 0, buffering_period);
- SEI_TYPE_N(PICTURE_TIMING, 1, 0, pic_timing);
- SEI_TYPE_N(PAN_SCAN_RECT, 1, 0, pan_scan_rect);
- SEI_TYPE_S2(USER_DATA_REGISTERED_ITU_T_T35,
- 1, 1, user_data_registered);
- SEI_TYPE_S2(USER_DATA_UNREGISTERED, 1, 1, user_data_unregistered);
- SEI_TYPE_N(RECOVERY_POINT, 1, 0, recovery_point);
- SEI_TYPE_N(DISPLAY_ORIENTATION, 1, 0, display_orientation);
- SEI_TYPE_N(ACTIVE_PARAMETER_SETS, 1, 0, active_parameter_sets);
- SEI_TYPE_N(DECODED_PICTURE_HASH, 0, 1, decoded_picture_hash);
- SEI_TYPE_N(TIME_CODE, 1, 0, time_code);
- SEI_TYPE_N2(MASTERING_DISPLAY_INFO, 1, 0, mastering_display_colour_volume);
- SEI_TYPE_N2(CONTENT_LIGHT_LEVEL_INFO,1, 0, content_light_level);
- SEI_TYPE_N2(ALTERNATIVE_TRANSFER_CHARACTERISTICS,
- 1, 0, alternative_transfer_characteristics);
- SEI_TYPE_N(ALPHA_CHANNEL_INFO, 1, 0, alpha_channel_info);
-
-#undef SEI_TYPE
- default:
- {
-#ifdef READ
- current->payload.other.data_length = current->payload_size;
-#endif
- allocate(current->payload.other.data, current->payload.other.data_length);
-
- for (i = 0; i < current->payload_size; i++)
- xu(8, payload_byte[i], current->payload.other.data[i], 0, 255,
- 1, i);
- }
- }
-
- // more_data_in_payload()
-#ifdef READ
- current_position = get_bits_count(rw) - start_position;
- if (current_position < 8 * current->payload_size) {
-#else
- current_position = put_bits_count(rw) - start_position;
- if (byte_alignment(rw) || more_data) {
-#endif
- CHECK(FUNC(payload_extension)(ctx, rw, ¤t->extension_data,
- current->payload_size, current_position));
- fixed(1, bit_equal_to_one, 1);
- while (byte_alignment(rw))
- fixed(1, bit_equal_to_zero, 0);
- }
-
-#ifdef WRITE
- current->payload_size = (put_bits_count(rw) - start_position) >> 3;
-#endif
-
- return 0;
-}
-
static int FUNC(sei)(CodedBitstreamContext *ctx, RWContext *rw,
H265RawSEI *current, int prefix)
{
- int err, k;
+ int err;
if (prefix)
HEADER("Prefix Supplemental Enhancement Information");
@@ -2146,72 +2006,7 @@ static int FUNC(sei)(CodedBitstreamContext *ctx, RWContext *rw,
prefix ? HEVC_NAL_SEI_PREFIX
: HEVC_NAL_SEI_SUFFIX));
-#ifdef READ
- for (k = 0; k < H265_MAX_SEI_PAYLOADS; k++) {
- uint32_t payload_type = 0;
- uint32_t payload_size = 0;
- uint32_t tmp;
-
- while (show_bits(rw, 8) == 0xff) {
- fixed(8, ff_byte, 0xff);
- payload_type += 255;
- }
- xu(8, last_payload_type_byte, tmp, 0, 254, 0);
- payload_type += tmp;
-
- while (show_bits(rw, 8) == 0xff) {
- fixed(8, ff_byte, 0xff);
- payload_size += 255;
- }
- xu(8, last_payload_size_byte, tmp, 0, 254, 0);
- payload_size += tmp;
-
- current->payload[k].payload_type = payload_type;
- current->payload[k].payload_size = payload_size;
-
- current->payload_count++;
- CHECK(FUNC(sei_payload)(ctx, rw, ¤t->payload[k], prefix));
-
- if (!cbs_h2645_read_more_rbsp_data(rw))
- break;
- }
- if (k >= H265_MAX_SEI_PAYLOADS) {
- av_log(ctx->log_ctx, AV_LOG_ERROR, "Too many payloads in "
- "SEI message: found %d.\n", k);
- return AVERROR_INVALIDDATA;
- }
-#else
- for (k = 0; k < current->payload_count; k++) {
- PutBitContext start_state;
- uint32_t tmp;
- int need_size, i;
-
- // Somewhat clumsy: we write the payload twice when
- // we don't know the size in advance. This will mess
- // with trace output, but is otherwise harmless.
- start_state = *rw;
- need_size = !current->payload[k].payload_size;
- for (i = 0; i < 1 + need_size; i++) {
- *rw = start_state;
-
- tmp = current->payload[k].payload_type;
- while (tmp >= 255) {
- fixed(8, ff_byte, 0xff);
- tmp -= 255;
- }
- xu(8, last_payload_type_byte, tmp, 0, 254, 0);
-
- tmp = current->payload[k].payload_size;
- while (tmp >= 255) {
- fixed(8, ff_byte, 0xff);
- tmp -= 255;
- }
- xu(8, last_payload_size_byte, tmp, 0, 254, 0);
-
- CHECK(FUNC(sei_payload)(ctx, rw, ¤t->payload[k], prefix));
- }
- }
-#endif
+ CHECK(FUNC_SEI(message_list)(ctx, rw, ¤t->message_list, prefix));
CHECK(FUNC(rbsp_trailing_bits)(ctx, rw));
diff --git a/libavcodec/cbs_sei.c b/libavcodec/cbs_sei.c
new file mode 100644
index 0000000000..323997b600
--- /dev/null
+++ b/libavcodec/cbs_sei.c
@@ -0,0 +1,369 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "cbs.h"
+#include "cbs_internal.h"
+#include "cbs_h264.h"
+#include "cbs_h265.h"
+#include "cbs_sei.h"
+
+static void cbs_free_user_data_registered(void *opaque, uint8_t *data)
+{
+ SEIRawUserDataRegistered *udr = (SEIRawUserDataRegistered*)data;
+ av_buffer_unref(&udr->data_ref);
+ av_free(udr);
+}
+
+static void cbs_free_user_data_unregistered(void *opaque, uint8_t *data)
+{
+ SEIRawUserDataUnregistered *udu = (SEIRawUserDataUnregistered*)data;
+ av_buffer_unref(&udu->data_ref);
+ av_free(udu);
+}
+
+int ff_cbs_sei_alloc_message_payload(SEIRawMessage *message,
+ const SEIMessageTypeDescriptor *desc)
+{
+ void (*free_func)(void*, uint8_t*);
+
+ av_assert0(message->payload == NULL &&
+ message->payload_ref == NULL);
+ message->payload_type = desc->type;
+
+ if (desc->type == SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35)
+ free_func = &cbs_free_user_data_registered;
+ else if (desc->type == SEI_TYPE_USER_DATA_UNREGISTERED)
+ free_func = &cbs_free_user_data_unregistered;
+ else
+ free_func = NULL;
+
+ if (free_func) {
+ message->payload = av_mallocz(desc->size);
+ if (!message->payload)
+ return AVERROR(ENOMEM);
+ message->payload_ref =
+ av_buffer_create(message->payload, desc->size,
+ free_func, NULL, 0);
+ } else {
+ message->payload_ref = av_buffer_alloc(desc->size);
+ }
+ if (!message->payload_ref)
+ return AVERROR(ENOMEM);
+ message->payload = message->payload_ref->data;
+
+ return 0;
+}
+
+int ff_cbs_sei_list_add(SEIRawMessageList *list)
+{
+ void *ptr;
+ int old_count = list->nb_messages_allocated;
+
+ av_assert0(list->nb_messages <= old_count);
+ if (list->nb_messages + 1 > old_count) {
+ int new_count = 2 * old_count + 1;
+
+ ptr = av_realloc_array(list->messages,
+ new_count, sizeof(*list->messages));
+ if (!ptr)
+ return AVERROR(ENOMEM);
+
+ list->messages = ptr;
+ list->nb_messages_allocated = new_count;
+
+ // Zero the newly-added entries.
+ memset(list->messages + old_count, 0,
+ (new_count - old_count) * sizeof(*list->messages));
+ }
+ ++list->nb_messages;
+ return 0;
+}
+
+void ff_cbs_sei_free_message_list(SEIRawMessageList *list)
+{
+ for (int i = 0; i < list->nb_messages; i++) {
+ SEIRawMessage *message = &list->messages[i];
+ av_buffer_unref(&message->payload_ref);
+ av_buffer_unref(&message->extension_data_ref);
+ }
+ av_free(list->messages);
+}
+
+static int cbs_sei_get_unit(CodedBitstreamContext *ctx,
+ CodedBitstreamFragment *au,
+ int prefix,
+ CodedBitstreamUnit **sei_unit)
+{
+ CodedBitstreamUnit *unit;
+ int sei_type, highest_vcl_type, err, i, position;
+
+ switch (ctx->codec->codec_id) {
+ case AV_CODEC_ID_H264:
+ // (We can ignore auxiliary slices because we only have prefix
+ // SEI in H.264 and an auxiliary picture must always follow a
+ // primary picture.)
+ highest_vcl_type = H264_NAL_IDR_SLICE;
+ if (prefix)
+ sei_type = H264_NAL_SEI;
+ else
+ return AVERROR(EINVAL);
+ break;
+ case AV_CODEC_ID_H265:
+ highest_vcl_type = HEVC_NAL_RSV_VCL31;
+ if (prefix)
+ sei_type = HEVC_NAL_SEI_PREFIX;
+ else
+ sei_type = HEVC_NAL_SEI_SUFFIX;
+ break;
+ default:
+ return AVERROR(EINVAL);
+ }
+
+ // Find an existing SEI NAL unit of the right type.
+ unit = NULL;
+ for (i = 0; i < au->nb_units; i++) {
+ if (au->units[i].type == sei_type) {
+ unit = &au->units[i];
+ break;
+ }
+ }
+
+ if (unit) {
+ *sei_unit = unit;
+ return 0;
+ }
+
+ // Need to add a new SEI NAL unit ...
+ if (prefix) {
+ // ... before the first VCL NAL unit.
+ for (i = 0; i < au->nb_units; i++) {
+ if (au->units[i].type < highest_vcl_type)
+ break;
+ }
+ position = i;
+ } else {
+ // ... after the last VCL NAL unit.
+ for (i = au->nb_units; i >= 0; i--) {
+ if (au->units[i].type < highest_vcl_type)
+ break;
+ }
+ if (i < 0) {
+ // No VCL units; just put it at the end.
+ position = -1;
+ } else {
+ position = i + 1;
+ }
+ }
+
+ err = ff_cbs_insert_unit_content(au, position, sei_type,
+ NULL, NULL);
+ if (err < 0)
+ return err;
+ unit = &au->units[position];
+ unit->type = sei_type;
+
+ err = ff_cbs_alloc_unit_content2(ctx, unit);
+ if (err < 0)
+ return err;
+
+ switch (ctx->codec->codec_id) {
+ case AV_CODEC_ID_H264:
+ {
+ H264RawSEI sei = {
+ .nal_unit_header = {
+ .nal_ref_idc = 0,
+ .nal_unit_type = sei_type,
+ },
+ };
+ memcpy(unit->content, &sei, sizeof(sei));
+ }
+ break;
+ case AV_CODEC_ID_H265:
+ {
+ H265RawSEI sei = {
+ .nal_unit_header = {
+ .nal_unit_type = sei_type,
+ .nuh_layer_id = 0,
+ .nuh_temporal_id_plus1 = 1,
+ },
+ };
+ memcpy(unit->content, &sei, sizeof(sei));
+ }
+ break;
+ default:
+ av_assert0(0);
+ }
+
+ *sei_unit = unit;
+ return 0;
+}
+
+static int cbs_sei_get_message_list(CodedBitstreamContext *ctx,
+ CodedBitstreamUnit *unit,
+ SEIRawMessageList **list)
+{
+ switch (ctx->codec->codec_id) {
+ case AV_CODEC_ID_H264:
+ {
+ H264RawSEI *sei = unit->content;
+ if (unit->type != H264_NAL_SEI)
+ return AVERROR(EINVAL);
+ *list = &sei->message_list;
+ }
+ break;
+ case AV_CODEC_ID_H265:
+ {
+ H265RawSEI *sei = unit->content;
+ if (unit->type != HEVC_NAL_SEI_PREFIX &&
+ unit->type != HEVC_NAL_SEI_SUFFIX)
+ return AVERROR(EINVAL);
+ *list = &sei->message_list;
+ }
+ break;
+ default:
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
+}
+
+int ff_cbs_sei_add_message(CodedBitstreamContext *ctx,
+ CodedBitstreamFragment *au,
+ int prefix,
+ uint32_t payload_type,
+ void *payload_data,
+ AVBufferRef *payload_buf)
+{
+ const SEIMessageTypeDescriptor *desc;
+ CodedBitstreamUnit *unit;
+ SEIRawMessageList *list;
+ SEIRawMessage *message;
+ AVBufferRef *payload_ref;
+ int err;
+
+ desc = ff_cbs_sei_find_type(ctx, payload_type);
+ if (!desc)
+ return AVERROR(EINVAL);
+
+ if (payload_buf) {
+ payload_ref = av_buffer_ref(payload_buf);
+ if (!payload_ref)
+ return AVERROR(ENOMEM);
+ } else {
+ payload_ref = NULL;
+ }
+
+ // Find an existing SEI unit or make a new one to add to.
+ err = cbs_sei_get_unit(ctx, au, prefix, &unit);
+ if (err < 0)
+ return err;
+
+ // Find the message list inside the codec-dependent unit.
+ err = cbs_sei_get_message_list(ctx, unit, &list);
+ if (err < 0)
+ return err;
+
+ // Add a new message to the message list.
+ err = ff_cbs_sei_list_add(list);
+ if (err < 0)
+ return err;
+
+ message = &list->messages[list->nb_messages - 1];
+
+ message->payload_type = payload_type;
+ message->payload = payload_data;
+ message->payload_ref = payload_ref;
+
+ return 0;
+}
+
+int ff_cbs_sei_find_message(CodedBitstreamContext *ctx,
+ CodedBitstreamFragment *au,
+ uint32_t payload_type,
+ SEIRawMessage **iter)
+{
+ int err, i, j, found;
+
+ found = 0;
+ for (i = 0; i < au->nb_units; i++) {
+ CodedBitstreamUnit *unit = &au->units[i];
+ SEIRawMessageList *list;
+
+ err = cbs_sei_get_message_list(ctx, unit, &list);
+ if (err < 0)
+ continue;
+
+ for (j = 0; j < list->nb_messages; j++) {
+ SEIRawMessage *message = &list->messages[j];
+
+ if (message->payload_type == payload_type) {
+ if (!*iter || found) {
+ *iter = message;
+ return 0;
+ }
+ if (message == *iter)
+ found = 1;
+ }
+ }
+ }
+
+ return AVERROR(ENOENT);
+}
+
+static void cbs_sei_delete_message(SEIRawMessageList *list,
+ int position)
+{
+ SEIRawMessage *message;
+
+ av_assert0(0 <= position && position < list->nb_messages);
+
+ message = &list->messages[position];
+ av_buffer_unref(&message->payload_ref);
+ av_buffer_unref(&message->extension_data_ref);
+
+ --list->nb_messages;
+
+ if (list->nb_messages > 0) {
+ memmove(list->messages + position,
+ list->messages + position + 1,
+ (list->nb_messages - position) * sizeof(*list->messages));
+ }
+}
+
+void ff_cbs_sei_delete_message_type(CodedBitstreamContext *ctx,
+ CodedBitstreamFragment *au,
+ uint32_t payload_type)
+{
+ int err, i, j;
+
+ for (i = 0; i < au->nb_units; i++) {
+ CodedBitstreamUnit *unit = &au->units[i];
+ SEIRawMessageList *list;
+
+ err = cbs_sei_get_message_list(ctx, unit, &list);
+ if (err < 0)
+ continue;
+
+ for (j = 0; j < list->nb_messages;) {
+ if (list->messages[j].payload_type == payload_type)
+ cbs_sei_delete_message(list, j);
+ else
+ ++j;
+ }
+ }
+}
diff --git a/libavcodec/cbs_sei.h b/libavcodec/cbs_sei.h
index 95beabf4d7..5ce4ad3ccd 100644
--- a/libavcodec/cbs_sei.h
+++ b/libavcodec/cbs_sei.h
@@ -21,8 +21,132 @@
#include <stddef.h>
#include <stdint.h>
+
#include "libavutil/buffer.h"
+#include "cbs.h"
+
+// SEI payload types form a common namespace between the H.264, H.265
+// and H.266 standards. A given payload type always has the same
+// meaning, but some names have different payload types in different
+// standards (e.g. scalable-nesting is 30 in H.264 but 133 in H.265).
+// The content of the payload data depends on the standard, though
+// many generic parts have the same interpretation everywhere (such as
+// mastering-display-colour-volume and user-data-unregistered).
+enum {
+ SEI_TYPE_BUFFERING_PERIOD = 0,
+ SEI_TYPE_PIC_TIMING = 1,
+ SEI_TYPE_PAN_SCAN_RECT = 2,
+ SEI_TYPE_FILLER_PAYLOAD = 3,
+ SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35 = 4,
+ SEI_TYPE_USER_DATA_UNREGISTERED = 5,
+ SEI_TYPE_RECOVERY_POINT = 6,
+ SEI_TYPE_DEC_REF_PIC_MARKING_REPETITION = 7,
+ SEI_TYPE_SPARE_PIC = 8,
+ SEI_TYPE_SCENE_INFO = 9,
+ SEI_TYPE_SUB_SEQ_INFO = 10,
+ SEI_TYPE_SUB_SEQ_LAYER_CHARACTERISTICS = 11,
+ SEI_TYPE_SUB_SEQ_CHARACTERISTICS = 12,
+ SEI_TYPE_FULL_FRAME_FREEZE = 13,
+ SEI_TYPE_FULL_FRAME_FREEZE_RELEASE = 14,
+ SEI_TYPE_FULL_FRAME_SNAPSHOT = 15,
+ SEI_TYPE_PROGRESSIVE_REFINEMENT_SEGMENT_START = 16,
+ SEI_TYPE_PROGRESSIVE_REFINEMENT_SEGMENT_END = 17,
+ SEI_TYPE_MOTION_CONSTRAINED_SLICE_GROUP_SET = 18,
+ SEI_TYPE_FILM_GRAIN_CHARACTERISTICS = 19,
+ SEI_TYPE_DEBLOCKING_FILTER_DISPLAY_PREFERENCE = 20,
+ SEI_TYPE_STEREO_VIDEO_INFO = 21,
+ SEI_TYPE_POST_FILTER_HINT = 22,
+ SEI_TYPE_TONE_MAPPING_INFO = 23,
+ SEI_TYPE_SCALABILITY_INFO = 24,
+ SEI_TYPE_SUB_PIC_SCALABLE_LAYER = 25,
+ SEI_TYPE_NON_REQUIRED_LAYER_REP = 26,
+ SEI_TYPE_PRIORITY_LAYER_INFO = 27,
+ SEI_TYPE_LAYERS_NOT_PRESENT_4 = 28,
+ SEI_TYPE_LAYER_DEPENDENCY_CHANGE = 29,
+ SEI_TYPE_SCALABLE_NESTING_4 = 30,
+ SEI_TYPE_BASE_LAYER_TEMPORAL_HRD = 31,
+ SEI_TYPE_QUALITY_LAYER_INTEGRITY_CHECK = 32,
+ SEI_TYPE_REDUNDANT_PIC_PROPERTY = 33,
+ SEI_TYPE_TL0_DEP_REP_INDEX = 34,
+ SEI_TYPE_TL_SWITCHING_POINT = 35,
+ SEI_TYPE_PARALLEL_DECODING_INFO = 36,
+ SEI_TYPE_MVC_SCALABLE_NESTING = 37,
+ SEI_TYPE_VIEW_SCALABILITY_INFO = 38,
+ SEI_TYPE_MULTIVIEW_SCENE_INFO_4 = 39,
+ SEI_TYPE_MULTIVIEW_ACQUISITION_INFO_4 = 40,
+ SEI_TYPE_NON_REQUIRED_VIEW_COMPONENT = 41,
+ SEI_TYPE_VIEW_DEPENDENCY_CHANGE = 42,
+ SEI_TYPE_OPERATION_POINTS_NOT_PRESENT = 43,
+ SEI_TYPE_BASE_VIEW_TEMPORAL_HRD = 44,
+ SEI_TYPE_FRAME_PACKING_ARRANGEMENT = 45,
+ SEI_TYPE_MULTIVIEW_VIEW_POSITION_4 = 46,
+ SEI_TYPE_DISPLAY_ORIENTATION = 47,
+ SEI_TYPE_MVCD_SCALABLE_NESTING = 48,
+ SEI_TYPE_MVCD_VIEW_SCALABILITY_INFO = 49,
+ SEI_TYPE_DEPTH_REPRESENTATION_INFO_4 = 50,
+ SEI_TYPE_THREE_DIMENSIONAL_REFERENCE_DISPLAYS_INFO_4 = 51,
+ SEI_TYPE_DEPTH_TIMING = 52,
+ SEI_TYPE_DEPTH_SAMPLING_INFO = 53,
+ SEI_TYPE_CONSTRAINED_DEPTH_PARAMETER_SET_IDENTIFIER = 54,
+ SEI_TYPE_GREEN_METADATA = 56,
+ SEI_TYPE_STRUCTURE_OF_PICTURES_INFO = 128,
+ SEI_TYPE_ACTIVE_PARAMETER_SETS = 129,
+ SEI_TYPE_DECODING_UNIT_INFO = 130,
+ SEI_TYPE_TEMPORAL_SUB_LAYER_ZERO_IDX = 131,
+ SEI_TYPE_DECODED_PICTURE_HASH = 132,
+ SEI_TYPE_SCALABLE_NESTING_5 = 133,
+ SEI_TYPE_REGION_REFRESH_INFO = 134,
+ SEI_TYPE_NO_DISPLAY = 135,
+ SEI_TYPE_TIME_CODE = 136,
+ SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME = 137,
+ SEI_TYPE_SEGMENTED_RECT_FRAME_PACKING_ARRANGEMENT = 138,
+ SEI_TYPE_TEMPORAL_MOTION_CONSTRAINED_TILE_SETS = 139,
+ SEI_TYPE_CHROMA_RESAMPLING_FILTER_HINT = 140,
+ SEI_TYPE_KNEE_FUNCTION_INFO = 141,
+ SEI_TYPE_COLOUR_REMAPPING_INFO = 142,
+ SEI_TYPE_DEINTERLACED_FIELD_IDENTIFICATION = 143,
+ SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO = 144,
+ SEI_TYPE_DEPENDENT_RAP_INDICATION = 145,
+ SEI_TYPE_CODED_REGION_COMPLETION = 146,
+ SEI_TYPE_ALTERNATIVE_TRANSFER_CHARACTERISTICS = 147,
+ SEI_TYPE_AMBIENT_VIEWING_ENVIRONMENT = 148,
+ SEI_TYPE_CONTENT_COLOUR_VOLUME = 149,
+ SEI_TYPE_EQUIRECTANGULAR_PROJECTION = 150,
+ SEI_TYPE_CUBEMAP_PROJECTION = 151,
+ SEI_TYPE_FISHEYE_VIDEO_INFO = 152,
+ SEI_TYPE_SPHERE_ROTATION = 154,
+ SEI_TYPE_REGIONWISE_PACKING = 155,
+ SEI_TYPE_OMNI_VIEWPORT = 156,
+ SEI_TYPE_REGIONAL_NESTING = 157,
+ SEI_TYPE_MCTS_EXTRACTION_INFO_SETS = 158,
+ SEI_TYPE_MCTS_EXTRACTION_INFO_NESTING = 159,
+ SEI_TYPE_LAYERS_NOT_PRESENT_5 = 160,
+ SEI_TYPE_INTER_LAYER_CONSTRAINED_TILE_SETS = 161,
+ SEI_TYPE_BSP_NESTING = 162,
+ SEI_TYPE_BSP_INITIAL_ARRIVAL_TIME = 163,
+ SEI_TYPE_SUB_BITSTREAM_PROPERTY = 164,
+ SEI_TYPE_ALPHA_CHANNEL_INFO = 165,
+ SEI_TYPE_OVERLAY_INFO = 166,
+ SEI_TYPE_TEMPORAL_MV_PREDICTION_CONSTRAINTS = 167,
+ SEI_TYPE_FRAME_FIELD_INFO = 168,
+ SEI_TYPE_THREE_DIMENSIONAL_REFERENCE_DISPLAYS_INFO = 176,
+ SEI_TYPE_DEPTH_REPRESENTATION_INFO_5 = 177,
+ SEI_TYPE_MULTIVIEW_SCENE_INFO_5 = 178,
+ SEI_TYPE_MULTIVIEW_ACQUISITION_INFO_5 = 179,
+ SEI_TYPE_MULTIVIEW_VIEW_POSITION_5 = 180,
+ SEI_TYPE_ALTERNATIVE_DEPTH_INFO = 181,
+ SEI_TYPE_SEI_MANIFEST = 200,
+ SEI_TYPE_SEI_PREFIX_INDICATION = 201,
+ SEI_TYPE_ANNOTATED_REGIONS = 202,
+ SEI_TYPE_SUBPIC_LEVEL_INFO = 203,
+ SEI_TYPE_SAMPLE_ASPECT_RATIO_INFO = 204,
+};
+
+
+typedef struct SEIRawFillerPayload {
+ uint32_t payload_size;
+} SEIRawFillerPayload;
typedef struct SEIRawUserDataRegistered {
uint8_t itu_t_t35_country_code;
@@ -57,4 +181,135 @@ typedef struct SEIRawAlternativeTransferCharacteristics {
uint8_t preferred_transfer_characteristics;
} SEIRawAlternativeTransferCharacteristics;
+typedef struct SEIRawMessage {
+ uint32_t payload_type;
+ uint32_t payload_size;
+ void *payload;
+ AVBufferRef *payload_ref;
+ uint8_t *extension_data;
+ AVBufferRef *extension_data_ref;
+ size_t extension_bit_length;
+} SEIRawMessage;
+
+typedef struct SEIRawMessageList {
+ SEIRawMessage *messages;
+ int nb_messages;
+ int nb_messages_allocated;
+} SEIRawMessageList;
+
+
+typedef struct SEIMessageState {
+ // The type of the payload being written.
+ uint32_t payload_type;
+ // When reading, contains the size of the payload to allow finding the
+ // end of variable-length fields (such as user_data_payload_byte[]).
+ // (When writing, the size will be derived from the total number of
+ // bytes actually written.)
+ uint32_t payload_size;
+ // When writing, indicates that payload extension data is present so
+ // all extended fields must be written. May be updated by the writer
+ // to indicate that extended fields have been written, so the extension
+ // end bits must be written too.
+ uint8_t extension_present;
+} SEIMessageState;
+
+struct GetBitContext;
+struct PutBitContext;
+
+typedef int (*SEIMessageReadFunction)(CodedBitstreamContext *ctx,
+ struct GetBitContext *rw,
+ void *current,
+ SEIMessageState *sei);
+
+typedef int (*SEIMessageWriteFunction)(CodedBitstreamContext *ctx,
+ struct PutBitContext *rw,
+ void *current,
+ SEIMessageState *sei);
+
+typedef struct SEIMessageTypeDescriptor {
+ // Payload type for the message. (-1 in this field ends a list.)
+ int type;
+ // Valid in a prefix SEI NAL unit (always for H.264).
+ uint8_t prefix;
+ // Valid in a suffix SEI NAL unit (never for H.264).
+ uint8_t suffix;
+ // Size of the decomposed structure.
+ size_t size;
+ // Read bitstream into SEI message.
+ SEIMessageReadFunction read;
+ // Write bitstream from SEI message.
+ SEIMessageWriteFunction write;
+} SEIMessageTypeDescriptor;
+
+// Macro for the read/write pair. The clumsy cast is needed because the
+// current pointer is typed in all of the read/write functions but has to
+// be void here to fit all cases.
+#define SEI_MESSAGE_RW(codec, name) \
+ .read = (SEIMessageReadFunction) cbs_ ## codec ## _read_ ## name, \
+ .write = (SEIMessageWriteFunction)cbs_ ## codec ## _write_ ## name
+
+// End-of-list sentinel element.
+#define SEI_MESSAGE_TYPE_END { .type = -1 }
+
+
+/**
+ * Find the type descriptor for the given payload type.
+ *
+ * Returns NULL if the payload type is not known.
+ */
+const SEIMessageTypeDescriptor *ff_cbs_sei_find_type(CodedBitstreamContext *ctx,
+ int payload_type);
+
+/**
+ * Allocate a new payload for the given SEI message.
+ */
+int ff_cbs_sei_alloc_message_payload(SEIRawMessage *message,
+ const SEIMessageTypeDescriptor *desc);
+
+/**
+ * Allocate a new empty SEI message in a message list.
+ *
+ * The new message is in place nb_messages - 1.
+ */
+int ff_cbs_sei_list_add(SEIRawMessageList *list);
+
+/**
+ * Free all SEI messages in a message list.
+ */
+void ff_cbs_sei_free_message_list(SEIRawMessageList *list);
+
+/**
+ * Add an SEI message to an access unit.
+ *
+ * Will add to an existing SEI NAL unit, or create a new one for the
+ * message if there is no suitable existing one.
+ *
+ * Takes a new reference to payload_buf, if set. If payload_buf is
+ * NULL then the new message will not be reference counted.
+ */
+int ff_cbs_sei_add_message(CodedBitstreamContext *ctx,
+ CodedBitstreamFragment *au,
+ int prefix,
+ uint32_t payload_type,
+ void *payload_data,
+ AVBufferRef *payload_buf);
+
+/**
+ * Iterate over messages with the given payload type in an access unit.
+ *
+ * Set message to NULL in the first call. Returns 0 while more messages
+ * are available, AVERROR(ENOENT) when all messages have been found.
+ */
+int ff_cbs_sei_find_message(CodedBitstreamContext *ctx,
+ CodedBitstreamFragment *au,
+ uint32_t payload_type,
+ SEIRawMessage **message);
+
+/**
+ * Delete all messages with the given payload type from an access unit.
+ */
+void ff_cbs_sei_delete_message_type(CodedBitstreamContext *ctx,
+ CodedBitstreamFragment *au,
+ uint32_t payload_type);
+
#endif /* AVCODEC_CBS_SEI_H */
diff --git a/libavcodec/cbs_sei_syntax_template.c b/libavcodec/cbs_sei_syntax_template.c
index cc900830ae..1a0516acce 100644
--- a/libavcodec/cbs_sei_syntax_template.c
+++ b/libavcodec/cbs_sei_syntax_template.c
@@ -16,9 +16,27 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-static int FUNC(sei_user_data_registered)
+static int FUNC(filler_payload)
(CodedBitstreamContext *ctx, RWContext *rw,
- SEIRawUserDataRegistered *current, uint32_t *payload_size)
+ SEIRawFillerPayload *current, SEIMessageState *state)
+{
+ int err, i;
+
+ HEADER("Filler Payload");
+
+#ifdef READ
+ current->payload_size = state->payload_size;
+#endif
+
+ for (i = 0; i < current->payload_size; i++)
+ fixed(8, ff_byte, 0xff);
+
+ return 0;
+}
+
+static int FUNC(user_data_registered)
+ (CodedBitstreamContext *ctx, RWContext *rw,
+ SEIRawUserDataRegistered *current, SEIMessageState *state)
{
int err, i, j;
@@ -33,14 +51,12 @@ static int FUNC(sei_user_data_registered)
}
#ifdef READ
- if (*payload_size < i) {
+ if (state->payload_size < i) {
av_log(ctx->log_ctx, AV_LOG_ERROR,
"Invalid SEI user data registered payload.\n");
return AVERROR_INVALIDDATA;
}
- current->data_length = *payload_size - i;
-#else
- *payload_size = i + current->data_length;
+ current->data_length = state->payload_size - i;
#endif
allocate(current->data, current->data_length);
@@ -50,23 +66,21 @@ static int FUNC(sei_user_data_registered)
return 0;
}
-static int FUNC(sei_user_data_unregistered)
+static int FUNC(user_data_unregistered)
(CodedBitstreamContext *ctx, RWContext *rw,
- SEIRawUserDataUnregistered *current, uint32_t *payload_size)
+ SEIRawUserDataUnregistered *current, SEIMessageState *state)
{
int err, i;
HEADER("User Data Unregistered");
#ifdef READ
- if (*payload_size < 16) {
+ if (state->payload_size < 16) {
av_log(ctx->log_ctx, AV_LOG_ERROR,
"Invalid SEI user data unregistered payload.\n");
return AVERROR_INVALIDDATA;
}
- current->data_length = *payload_size - 16;
-#else
- *payload_size = 16 + current->data_length;
+ current->data_length = state->payload_size - 16;
#endif
for (i = 0; i < 16; i++)
@@ -80,9 +94,9 @@ static int FUNC(sei_user_data_unregistered)
return 0;
}
-static int FUNC(sei_mastering_display_colour_volume)
+static int FUNC(mastering_display_colour_volume)
(CodedBitstreamContext *ctx, RWContext *rw,
- SEIRawMasteringDisplayColourVolume *current)
+ SEIRawMasteringDisplayColourVolume *current, SEIMessageState *state)
{
int err, c;
@@ -104,13 +118,13 @@ static int FUNC(sei_mastering_display_colour_volume)
return 0;
}
-static int FUNC(sei_content_light_level)
+static int FUNC(content_light_level_info)
(CodedBitstreamContext *ctx, RWContext *rw,
- SEIRawContentLightLevelInfo *current)
+ SEIRawContentLightLevelInfo *current, SEIMessageState *state)
{
int err;
- HEADER("Content Light Level");
+ HEADER("Content Light Level Information");
ub(16, max_content_light_level);
ub(16, max_pic_average_light_level);
@@ -118,9 +132,10 @@ static int FUNC(sei_content_light_level)
return 0;
}
-static int FUNC(sei_alternative_transfer_characteristics)
+static int FUNC(alternative_transfer_characteristics)
(CodedBitstreamContext *ctx, RWContext *rw,
- SEIRawAlternativeTransferCharacteristics *current)
+ SEIRawAlternativeTransferCharacteristics *current,
+ SEIMessageState *state)
{
int err;
@@ -130,3 +145,165 @@ static int FUNC(sei_alternative_transfer_characteristics)
return 0;
}
+
+static int FUNC(message)(CodedBitstreamContext *ctx, RWContext *rw,
+ SEIRawMessage *current)
+{
+ const SEIMessageTypeDescriptor *desc;
+ int err, i;
+
+ desc = ff_cbs_sei_find_type(ctx, current->payload_type);
+ if (desc) {
+ SEIMessageState state = {
+ .payload_type = current->payload_type,
+ .payload_size = current->payload_size,
+ .extension_present = current->extension_bit_length > 0,
+ };
+ int start_position, current_position, bits_written;
+
+#ifdef READ
+ CHECK(ff_cbs_sei_alloc_message_payload(current, desc));
+#endif
+
+ start_position = bit_position(rw);
+
+ CHECK(desc->READWRITE(ctx, rw, current->payload, &state));
+
+ current_position = bit_position(rw);
+ bits_written = current_position - start_position;
+
+ if (byte_alignment(rw) || state.extension_present ||
+ bits_written < 8 * current->payload_size) {
+ size_t bits_left;
+
+#ifdef READ
+ GetBitContext tmp = *rw;
+ int trailing_bits, trailing_zero_bits;
+
+ bits_left = 8 * current->payload_size - bits_written;
+ if (bits_left > 8)
+ skip_bits_long(&tmp, bits_left - 8);
+ trailing_bits = get_bits(&tmp, FFMIN(bits_left, 8));
+ if (trailing_bits == 0) {
+ // The trailing bits must contain a bit_equal_to_one, so
+ // they can't all be zero.
+ return AVERROR_INVALIDDATA;
+ }
+ trailing_zero_bits = ff_ctz(trailing_bits);
+ current->extension_bit_length =
+ bits_left - 1 - trailing_zero_bits;
+#endif
+
+ if (current->extension_bit_length > 0) {
+ allocate(current->extension_data,
+ (current->extension_bit_length + 7) / 8);
+
+ bits_left = current->extension_bit_length;
+ for (i = 0; bits_left > 0; i++) {
+ int length = FFMIN(bits_left, 8);
+ xu(length, reserved_payload_extension_data,
+ current->extension_data[i],
+ 0, MAX_UINT_BITS(length), 0);
+ bits_left -= length;
+ }
+ }
+
+ fixed(1, bit_equal_to_one, 1);
+ while (byte_alignment(rw))
+ fixed(1, bit_equal_to_zero, 0);
+ }
+
+#ifdef WRITE
+ current->payload_size = (put_bits_count(rw) - start_position) / 8;
+#endif
+ } else {
+ uint8_t *data;
+
+ allocate(current->payload, current->payload_size);
+ data = current->payload;
+
+ for (i = 0; i < current->payload_size; i++)
+ xu(8, payload_byte[i], data[i], 0, 255, 1, i);
+ }
+
+ return 0;
+}
+
+static int FUNC(message_list)(CodedBitstreamContext *ctx, RWContext *rw,
+ SEIRawMessageList *current, int prefix)
+{
+ SEIRawMessage *message;
+ int err, k;
+
+#ifdef READ
+ for (k = 0;; k++) {
+ uint32_t payload_type = 0;
+ uint32_t payload_size = 0;
+ uint32_t tmp;
+
+ while (show_bits(rw, 8) == 0xff) {
+ fixed(8, ff_byte, 0xff);
+ payload_type += 255;
+ }
+ xu(8, last_payload_type_byte, tmp, 0, 254, 0);
+ payload_type += tmp;
+
+ while (show_bits(rw, 8) == 0xff) {
+ fixed(8, ff_byte, 0xff);
+ payload_size += 255;
+ }
+ xu(8, last_payload_size_byte, tmp, 0, 254, 0);
+ payload_size += tmp;
+
+ CHECK(ff_cbs_sei_list_add(current));
+ message = ¤t->messages[k];
+
+ message->payload_type = payload_type;
+ message->payload_size = payload_size;
+
+ CHECK(FUNC(message)(ctx, rw, message));
+
+ if (!cbs_h2645_read_more_rbsp_data(rw))
+ break;
+ }
+#else
+ for (k = 0; k < current->nb_messages; k++) {
+ PutBitContext start_state;
+ uint32_t tmp;
+ int trace, i;
+
+ message = ¤t->messages[k];
+
+ // We write the payload twice in order to find the size. Trace
+ // output is switched off for the first write.
+ trace = ctx->trace_enable;
+ ctx->trace_enable = 0;
+
+ start_state = *rw;
+ for (i = 0; i < 2; i++) {
+ *rw = start_state;
+
+ tmp = message->payload_type;
+ while (tmp >= 255) {
+ fixed(8, ff_byte, 0xff);
+ tmp -= 255;
+ }
+ xu(8, last_payload_type_byte, tmp, 0, 254, 0);
+
+ tmp = message->payload_size;
+ while (tmp >= 255) {
+ fixed(8, ff_byte, 0xff);
+ tmp -= 255;
+ }
+ xu(8, last_payload_size_byte, tmp, 0, 254, 0);
+
+ err = FUNC(message)(ctx, rw, message);
+ ctx->trace_enable = trace;
+ if (err < 0)
+ return err;
+ }
+ }
+#endif
+
+ return 0;
+}
diff --git a/libavcodec/h264_metadata_bsf.c b/libavcodec/h264_metadata_bsf.c
index f39e649ac6..4ab97aee3a 100644
--- a/libavcodec/h264_metadata_bsf.c
+++ b/libavcodec/h264_metadata_bsf.c
@@ -78,13 +78,14 @@ typedef struct H264MetadataContext {
int crop_bottom;
const char *sei_user_data;
- H264RawSEIPayload sei_user_data_payload;
+ SEIRawUserDataUnregistered sei_user_data_payload;
int delete_filler;
int display_orientation;
double rotate;
int flip;
+ H264RawSEIDisplayOrientation display_orientation_payload;
int level;
} H264MetadataContext;
@@ -414,7 +415,9 @@ static int h264_metadata_filter(AVBSFContext *bsf, AVPacket *pkt)
// Only insert the SEI in access units containing SPSs, and also
// unconditionally in the first access unit we ever see.
if (ctx->sei_user_data && (has_sps || !ctx->done_first_au)) {
- err = ff_cbs_h264_add_sei_message(au, &ctx->sei_user_data_payload);
+ err = ff_cbs_sei_add_message(ctx->output, au, 1,
+ H264_SEI_TYPE_USER_DATA_UNREGISTERED,
+ &ctx->sei_user_data_payload, NULL);
if (err < 0) {
av_log(bsf, AV_LOG_ERROR, "Failed to add user data SEI "
"message to access unit.\n");
@@ -428,74 +431,54 @@ static int h264_metadata_filter(AVBSFContext *bsf, AVPacket *pkt)
ff_cbs_delete_unit(au, i);
continue;
}
-
- if (au->units[i].type == H264_NAL_SEI) {
- // Filler SEI messages.
- H264RawSEI *sei = au->units[i].content;
-
- for (j = sei->payload_count - 1; j >= 0; j--) {
- if (sei->payload[j].payload_type ==
- H264_SEI_TYPE_FILLER_PAYLOAD)
- ff_cbs_h264_delete_sei_message(au, &au->units[i], j);
- }
- }
}
+
+ ff_cbs_sei_delete_message_type(ctx->output, au,
+ H264_SEI_TYPE_FILLER_PAYLOAD);
}
if (ctx->display_orientation != PASS) {
- for (i = au->nb_units - 1; i >= 0; i--) {
- H264RawSEI *sei;
- if (au->units[i].type != H264_NAL_SEI)
- continue;
- sei = au->units[i].content;
-
- for (j = sei->payload_count - 1; j >= 0; j--) {
- H264RawSEIDisplayOrientation *disp;
- int32_t *matrix;
-
- if (sei->payload[j].payload_type !=
- H264_SEI_TYPE_DISPLAY_ORIENTATION)
- continue;
- disp = &sei->payload[j].payload.display_orientation;
-
- if (ctx->display_orientation == REMOVE ||
- ctx->display_orientation == INSERT) {
- ff_cbs_h264_delete_sei_message(au, &au->units[i], j);
- continue;
- }
-
- matrix = av_malloc(9 * sizeof(int32_t));
- if (!matrix) {
- err = AVERROR(ENOMEM);
- goto fail;
- }
+ SEIRawMessage *message = NULL;
+ while (ff_cbs_sei_find_message(ctx->output, au,
+ H264_SEI_TYPE_DISPLAY_ORIENTATION,
+ &message) == 0) {
+ H264RawSEIDisplayOrientation *disp = message->payload;
+ int32_t *matrix;
+
+ matrix = av_malloc(9 * sizeof(int32_t));
+ if (!matrix) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
- av_display_rotation_set(matrix,
- disp->anticlockwise_rotation *
- 180.0 / 65536.0);
- av_display_matrix_flip(matrix, disp->hor_flip, disp->ver_flip);
-
- // If there are multiple display orientation messages in an
- // access unit, then the last one added to the packet (i.e.
- // the first one in the access unit) will prevail.
- err = av_packet_add_side_data(pkt, AV_PKT_DATA_DISPLAYMATRIX,
- (uint8_t*)matrix,
- 9 * sizeof(int32_t));
- if (err < 0) {
- av_log(bsf, AV_LOG_ERROR, "Failed to attach extracted "
- "displaymatrix side data to packet.\n");
- av_free(matrix);
- goto fail;
- }
+ av_display_rotation_set(matrix,
+ disp->anticlockwise_rotation *
+ 180.0 / 65536.0);
+ av_display_matrix_flip(matrix, disp->hor_flip, disp->ver_flip);
+
+ // If there are multiple display orientation messages in an
+ // access unit, then the last one added to the packet (i.e.
+ // the first one in the access unit) will prevail.
+ err = av_packet_add_side_data(pkt, AV_PKT_DATA_DISPLAYMATRIX,
+ (uint8_t*)matrix,
+ 9 * sizeof(int32_t));
+ if (err < 0) {
+ av_log(bsf, AV_LOG_ERROR, "Failed to attach extracted "
+ "displaymatrix side data to packet.\n");
+ av_free(matrix);
+ goto fail;
}
}
+
+ if (ctx->display_orientation == REMOVE ||
+ ctx->display_orientation == INSERT) {
+ ff_cbs_sei_delete_message_type(ctx->output, au,
+ H264_SEI_TYPE_DISPLAY_ORIENTATION);
+ }
}
if (ctx->display_orientation == INSERT) {
- H264RawSEIPayload payload = {
- .payload_type = H264_SEI_TYPE_DISPLAY_ORIENTATION,
- };
H264RawSEIDisplayOrientation *disp =
- &payload.payload.display_orientation;
+ &ctx->display_orientation_payload;
uint8_t *data;
int size;
int write = 0;
@@ -551,7 +534,9 @@ static int h264_metadata_filter(AVBSFContext *bsf, AVPacket *pkt)
if (write) {
disp->display_orientation_repetition_period = 1;
- err = ff_cbs_h264_add_sei_message(au, &payload);
+ err = ff_cbs_sei_add_message(ctx->output, au, 1,
+ H264_SEI_TYPE_DISPLAY_ORIENTATION,
+ disp, NULL);
if (err < 0) {
av_log(bsf, AV_LOG_ERROR, "Failed to add display orientation "
"SEI message to access unit.\n");
@@ -585,13 +570,9 @@ static int h264_metadata_init(AVBSFContext *bsf)
int err, i;
if (ctx->sei_user_data) {
- SEIRawUserDataUnregistered *udu =
- &ctx->sei_user_data_payload.payload.user_data_unregistered;
+ SEIRawUserDataUnregistered *udu = &ctx->sei_user_data_payload;
int j;
- ctx->sei_user_data_payload.payload_type =
- H264_SEI_TYPE_USER_DATA_UNREGISTERED;
-
// Parse UUID. It must be a hex string of length 32, possibly
// containing '-'s between hex digits (which we ignore).
for (i = j = 0; j < 32 && i < 64 && ctx->sei_user_data[i]; i++) {
diff --git a/libavcodec/vaapi_encode_h264.c b/libavcodec/vaapi_encode_h264.c
index b577d09caf..d24462414c 100644
--- a/libavcodec/vaapi_encode_h264.c
+++ b/libavcodec/vaapi_encode_h264.c
@@ -90,7 +90,6 @@ typedef struct VAAPIEncodeH264Context {
H264RawAUD raw_aud;
H264RawSPS raw_sps;
H264RawPPS raw_pps;
- H264RawSEI raw_sei;
H264RawSlice raw_slice;
H264RawSEIBufferingPeriod sei_buffering_period;
@@ -210,11 +209,9 @@ static int vaapi_encode_h264_write_extra_header(AVCodecContext *avctx,
{
VAAPIEncodeH264Context *priv = avctx->priv_data;
CodedBitstreamFragment *au = &priv->current_access_unit;
- int err, i;
+ int err;
if (priv->sei_needed) {
- H264RawSEI *sei = &priv->raw_sei;
-
if (priv->aud_needed) {
err = vaapi_encode_h264_add_nal(avctx, au, &priv->raw_aud);
if (err < 0)
@@ -222,41 +219,35 @@ static int vaapi_encode_h264_write_extra_header(AVCodecContext *avctx,
priv->aud_needed = 0;
}
- *sei = (H264RawSEI) {
- .nal_unit_header = {
- .nal_unit_type = H264_NAL_SEI,
- },
- };
-
- i = 0;
-
if (priv->sei_needed & SEI_IDENTIFIER) {
- sei->payload[i].payload_type = H264_SEI_TYPE_USER_DATA_UNREGISTERED;
- sei->payload[i].payload.user_data_unregistered = priv->sei_identifier;
- ++i;
+ err = ff_cbs_sei_add_message(priv->cbc, au, 1,
+ H264_SEI_TYPE_USER_DATA_UNREGISTERED,
+ &priv->sei_identifier, NULL);
+ if (err < 0)
+ goto fail;
}
if (priv->sei_needed & SEI_TIMING) {
if (pic->type == PICTURE_TYPE_IDR) {
- sei->payload[i].payload_type = H264_SEI_TYPE_BUFFERING_PERIOD;
- sei->payload[i].payload.buffering_period = priv->sei_buffering_period;
- ++i;
+ err = ff_cbs_sei_add_message(priv->cbc, au, 1,
+ H264_SEI_TYPE_BUFFERING_PERIOD,
+ &priv->sei_buffering_period, NULL);
+ if (err < 0)
+ goto fail;
}
- sei->payload[i].payload_type = H264_SEI_TYPE_PIC_TIMING;
- sei->payload[i].payload.pic_timing = priv->sei_pic_timing;
- ++i;
+ err = ff_cbs_sei_add_message(priv->cbc, au, 1,
+ H264_SEI_TYPE_PIC_TIMING,
+ &priv->sei_pic_timing, NULL);
+ if (err < 0)
+ goto fail;
}
if (priv->sei_needed & SEI_RECOVERY_POINT) {
- sei->payload[i].payload_type = H264_SEI_TYPE_RECOVERY_POINT;
- sei->payload[i].payload.recovery_point = priv->sei_recovery_point;
- ++i;
+ err = ff_cbs_sei_add_message(priv->cbc, au, 1,
+ H264_SEI_TYPE_RECOVERY_POINT,
+ &priv->sei_recovery_point, NULL);
+ if (err < 0)
+ goto fail;
}
- sei->payload_count = i;
- av_assert0(sei->payload_count > 0);
-
- err = vaapi_encode_h264_add_nal(avctx, au, sei);
- if (err < 0)
- goto fail;
priv->sei_needed = 0;
err = vaapi_encode_h264_write_access_unit(avctx, data, data_len, au);
diff --git a/libavcodec/vaapi_encode_h265.c b/libavcodec/vaapi_encode_h265.c
index a7af763ae4..2e8e772008 100644
--- a/libavcodec/vaapi_encode_h265.c
+++ b/libavcodec/vaapi_encode_h265.c
@@ -73,7 +73,6 @@ typedef struct VAAPIEncodeH265Context {
H265RawVPS raw_vps;
H265RawSPS raw_sps;
H265RawPPS raw_pps;
- H265RawSEI raw_sei;
H265RawSlice raw_slice;
SEIRawMasteringDisplayColourVolume sei_mastering_display;
@@ -195,11 +194,9 @@ static int vaapi_encode_h265_write_extra_header(AVCodecContext *avctx,
{
VAAPIEncodeH265Context *priv = avctx->priv_data;
CodedBitstreamFragment *au = &priv->current_access_unit;
- int err, i;
+ int err;
if (priv->sei_needed) {
- H265RawSEI *sei = &priv->raw_sei;
-
if (priv->aud_needed) {
err = vaapi_encode_h265_add_nal(avctx, au, &priv->aud);
if (err < 0)
@@ -207,35 +204,22 @@ static int vaapi_encode_h265_write_extra_header(AVCodecContext *avctx,
priv->aud_needed = 0;
}
- *sei = (H265RawSEI) {
- .nal_unit_header = {
- .nal_unit_type = HEVC_NAL_SEI_PREFIX,
- .nuh_layer_id = 0,
- .nuh_temporal_id_plus1 = 1,
- },
- };
-
- i = 0;
-
if (priv->sei_needed & SEI_MASTERING_DISPLAY) {
- sei->payload[i].payload_type = HEVC_SEI_TYPE_MASTERING_DISPLAY_INFO;
- sei->payload[i].payload.mastering_display_colour_volume =
- priv->sei_mastering_display;
- ++i;
+ err = ff_cbs_sei_add_message(priv->cbc, au, 1,
+ HEVC_SEI_TYPE_MASTERING_DISPLAY_INFO,
+ &priv->sei_mastering_display, NULL);
+ if (err < 0)
+ goto fail;
}
if (priv->sei_needed & SEI_CONTENT_LIGHT_LEVEL) {
- sei->payload[i].payload_type = HEVC_SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO;
- sei->payload[i].payload.content_light_level = priv->sei_content_light_level;
- ++i;
+ err = ff_cbs_sei_add_message(priv->cbc, au, 1,
+ HEVC_SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO,
+ &priv->sei_content_light_level, NULL);
+ if (err < 0)
+ goto fail;
}
- sei->payload_count = i;
- av_assert0(sei->payload_count > 0);
-
- err = vaapi_encode_h265_add_nal(avctx, au, sei);
- if (err < 0)
- goto fail;
priv->sei_needed = 0;
err = vaapi_encode_h265_write_access_unit(avctx, data, data_len, au);
--
2.29.2
More information about the ffmpeg-devel
mailing list