diff options
author | Mark Thompson <sw@jkqxz.net> | 2021-01-01 21:35:13 +0000 |
---|---|---|
committer | Mark Thompson <sw@jkqxz.net> | 2021-01-21 17:13:54 +0000 |
commit | 8843607f495c95c1e67a3ce3d6f15dca6e252439 (patch) | |
tree | 271e6d17f79e53247b9f9d4ac8367ac4600d547a /libavcodec | |
parent | 773857df592d8f3095a548b3085c6b7fe6b30dfe (diff) | |
download | ffmpeg-8843607f495c95c1e67a3ce3d6f15dca6e252439.tar.gz |
cbs_h2645: Merge SEI message handling in common between codecs
Diffstat (limited to 'libavcodec')
-rw-r--r-- | libavcodec/Makefile | 4 | ||||
-rw-r--r-- | libavcodec/cbs_h264.h | 50 | ||||
-rw-r--r-- | libavcodec/cbs_h2645.c | 300 | ||||
-rw-r--r-- | libavcodec/cbs_h264_syntax_template.c | 173 | ||||
-rw-r--r-- | libavcodec/cbs_h265.h | 33 | ||||
-rw-r--r-- | libavcodec/cbs_h265_syntax_template.c | 272 | ||||
-rw-r--r-- | libavcodec/cbs_sei.c | 369 | ||||
-rw-r--r-- | libavcodec/cbs_sei.h | 139 | ||||
-rw-r--r-- | libavcodec/cbs_sei_syntax_template.c | 215 | ||||
-rw-r--r-- | libavcodec/h264_metadata_bsf.c | 113 | ||||
-rw-r--r-- | libavcodec/vaapi_encode_h264.c | 51 | ||||
-rw-r--r-- | libavcodec/vaapi_encode_h265.c | 38 |
12 files changed, 991 insertions, 766 deletions
diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 446e6e6b3b..1fcb94fa48 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 4478a6f810..6005d46e0d 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 @@ -1381,36 +1385,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 SEI_TYPE_BUFFERING_PERIOD: - case SEI_TYPE_PIC_TIMING: - case SEI_TYPE_PAN_SCAN_RECT: - case SEI_TYPE_RECOVERY_POINT: - case SEI_TYPE_DISPLAY_ORIENTATION: - case SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME: - case SEI_TYPE_ALTERNATIVE_TRANSFER_CHARACTERISTICS: - break; - case SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35: - av_buffer_unref(&payload->payload.user_data_registered.data_ref); - break; - case 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[] = { @@ -1442,42 +1421,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 SEI_TYPE_BUFFERING_PERIOD: - case SEI_TYPE_PIC_TIMING: - case SEI_TYPE_PAN_SCAN_RECT: - case SEI_TYPE_RECOVERY_POINT: - case SEI_TYPE_DISPLAY_ORIENTATION: - case SEI_TYPE_ACTIVE_PARAMETER_SETS: - case SEI_TYPE_DECODED_PICTURE_HASH: - case SEI_TYPE_TIME_CODE: - case SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME: - case SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO: - case SEI_TYPE_ALTERNATIVE_TRANSFER_CHARACTERISTICS: - case SEI_TYPE_ALPHA_CHANNEL_INFO: - break; - case SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35: - av_buffer_unref(&payload->payload.user_data_registered.data_ref); - break; - case 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[] = { @@ -1557,92 +1505,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 37047dc30b..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 SEI_TYPE_BUFFERING_PERIOD: - CHECK(FUNC(sei_buffering_period) - (ctx, rw, ¤t->payload.buffering_period)); - break; - case SEI_TYPE_PIC_TIMING: - CHECK(FUNC(sei_pic_timing) - (ctx, rw, ¤t->payload.pic_timing)); - break; - case SEI_TYPE_PAN_SCAN_RECT: - CHECK(FUNC(sei_pan_scan_rect) - (ctx, rw, ¤t->payload.pan_scan_rect)); - break; - case SEI_TYPE_FILLER_PAYLOAD: - { - for (i = 0; i < current->payload_size; i++) - fixed(8, ff_byte, 0xff); - } - break; - case SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35: - CHECK(FUNC_SEI(sei_user_data_registered) - (ctx, rw, ¤t->payload.user_data_registered, ¤t->payload_size)); - break; - case SEI_TYPE_USER_DATA_UNREGISTERED: - CHECK(FUNC_SEI(sei_user_data_unregistered) - (ctx, rw, ¤t->payload.user_data_unregistered, ¤t->payload_size)); - break; - case SEI_TYPE_RECOVERY_POINT: - CHECK(FUNC(sei_recovery_point) - (ctx, rw, ¤t->payload.recovery_point)); - break; - case SEI_TYPE_DISPLAY_ORIENTATION: - CHECK(FUNC(sei_display_orientation) - (ctx, rw, ¤t->payload.display_orientation)); - break; - case SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME: - CHECK(FUNC_SEI(sei_mastering_display_colour_volume) - (ctx, rw, ¤t->payload.mastering_display_colour_volume)); - break; - case SEI_TYPE_ALTERNATIVE_TRANSFER_CHARACTERISTICS: - 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 64afc3f01d..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,159 +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 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 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 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 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 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(PIC_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_COLOUR_VOLUME, - 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_N -#undef SEI_TYPE_S -#undef SEI_TYPE_E - 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"); @@ -2149,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..c49830ad77 --- /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) { + av_freep(&message->payload); + 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 - 1; 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 = list->nb_messages - 1; j >= 0; j--) { + if (list->messages[j].payload_type == payload_type) + cbs_sei_delete_message(list, j); + } + } +} diff --git a/libavcodec/cbs_sei.h b/libavcodec/cbs_sei.h index 95beabf4d7..c7a7a95be0 100644 --- a/libavcodec/cbs_sei.h +++ b/libavcodec/cbs_sei.h @@ -21,8 +21,16 @@ #include <stddef.h> #include <stdint.h> + #include "libavutil/buffer.h" +#include "cbs.h" +#include "sei.h" + + +typedef struct SEIRawFillerPayload { + uint32_t payload_size; +} SEIRawFillerPayload; typedef struct SEIRawUserDataRegistered { uint8_t itu_t_t35_country_code; @@ -57,4 +65,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 93d9fafde1..5f84246663 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 2228761113..6badb97b9e 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, + 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 == - SEI_TYPE_FILLER_PAYLOAD) - ff_cbs_h264_delete_sei_message(au, &au->units[i], j); - } - } } + + ff_cbs_sei_delete_message_type(ctx->output, au, + 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 != - 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, + 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, + SEI_TYPE_DISPLAY_ORIENTATION); + } } if (ctx->display_orientation == INSERT) { - H264RawSEIPayload payload = { - .payload_type = 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, + 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 = - 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 13120b05af..ce73e269f9 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 = 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, + 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 = 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, + SEI_TYPE_BUFFERING_PERIOD, + &priv->sei_buffering_period, NULL); + if (err < 0) + goto fail; } - sei->payload[i].payload_type = 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, + 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 = 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, + 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 aa7faf39f3..2c356fbd38 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 = SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME; - sei->payload[i].payload.mastering_display_colour_volume = - priv->sei_mastering_display; - ++i; + err = ff_cbs_sei_add_message(priv->cbc, au, 1, + SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME, + &priv->sei_mastering_display, NULL); + if (err < 0) + goto fail; } if (priv->sei_needed & SEI_CONTENT_LIGHT_LEVEL) { - sei->payload[i].payload_type = 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, + 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); |