Quoting Mark Thompson (2017-07-29 23:16:32)
> This is able to modify some header metadata found in the SPS/VUI,
> and can also add/remove AUDs and insert user data in SEI NAL units.
> ---
> * Adds cropping parameters.
> * SEI user data insert code improved as suggested by Jun Zhao.
>
>
> doc/bitstream_filters.texi | 57 +++++
> libavcodec/Makefile | 2 +
> libavcodec/bitstream_filters.c | 1 +
> libavcodec/h264_metadata_bsf.c | 490
> +++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 550 insertions(+)
> create mode 100644 libavcodec/h264_metadata_bsf.c
>
> diff --git a/doc/bitstream_filters.texi b/doc/bitstream_filters.texi
> index af14b67ad..34f0af922 100644
> --- a/doc/bitstream_filters.texi
> +++ b/doc/bitstream_filters.texi
> @@ -39,6 +39,63 @@ When this option is enabled, the long-term headers are
> removed from the
> bitstream after extraction.
> @end table
>
> +@section h264_metadata
> +
> +Modify metadata embedded in an H.264 stream.
> +
> +@table @option
> +@item aud
> +Insert or remove AUD NAL units in all access units of the stream.
> +
> +@table @samp
> +@item insert
> +@item remove
> +@end table
> +
> +@item sample_aspect_ratio
> +Set the sample aspect ratio in the stream in the VUI parameters.
> +
> +@item video_format
> +@item video_full_range_flag
> +Set the video format in the stream (see H.264 section E.2.1 and
> +table E-2).
> +
> +@item colour_primaries
> +@item transfer_characteristics
> +@item matrix_coefficients
> +Set the colour description in the stream (see H.264 section E.2.1
> +and tables E-3, E-4 and E-5).
> +
> +@item chroma_sample_loc_type
> +Set the chroma sample location in the stream (see H.264 section
> +E.2.1 and figure E-1).
> +
> +@item frame_rate
> +@item fixed_frame_rate_flag
> +Set the frame rate in the VUI parameters (num_units_in_tick /
> +time_scale). Note that this is likely to be overridden by container
> +parameters when the stream is in a container.
> +
> +@item crop_left
> +@item crop_right
> +@item crop_top
> +@item crop_bottom
> +Set the frame cropping offsets in the SPS. These values will replace
> +the current ones if the stream is already cropped.
> +
> +The units of these fields are dependent on the chroma subsampling
> +and whether the stream is interlaced (see H.264 section 7.4.2.1.1).
It would be more user-friendly to have crop_* set the values in pixels,
with validity checking and all that, and perhaps in addition crop_*_raw
that set the raw bitstream values. Or maybe just rename those to _raw if
you don't feel like implementing this right now.
> +static int h264_metadata_filter(AVBSFContext *bsf, AVPacket *out)
> +{
> + H264MetadataContext *ctx = bsf->priv_data;
> + AVPacket *in = NULL;
> + CodedBitstreamFragment *au = &ctx->access_unit;
> + int err, i, j, has_sps;
> + char *sei_udu_string = NULL;
> +
> + err = ff_bsf_get_packet(bsf, &in);
> + if (err < 0)
> + goto fail;
> +
> + err = ff_cbs_read_packet(&ctx->cbc, au, in);
> + if (err < 0) {
> + av_log(bsf, AV_LOG_ERROR, "Failed to read packet.\n");
> + goto fail;
> + }
> +
> + if (au->nb_units == 0) {
> + av_log(bsf, AV_LOG_ERROR, "No NAL units in packet.\n");
> + err = AVERROR_INVALIDDATA;
> + goto fail;
> + }
> +
> + // If an AUD is present, it must be the first NAL unit.
> + if (au->units[0].type == H264_NAL_AUD) {
> + if (ctx->aud == REMOVE)
> + ff_cbs_delete_unit(&ctx->cbc, au, 0);
> + } else {
> + if (ctx->aud == INSERT) {
> + static const int primary_pic_type_table[] = {
> + 0x084, // 2, 7
> + 0x0a5, // 0, 2, 5, 7
> + 0x0e7, // 0, 1, 2, 5, 6, 7
> + 0x210, // 4, 9
> + 0x318, // 3, 4, 8, 9
> + 0x294, // 2, 4, 7, 9
> + 0x3bd, // 0, 2, 3, 4, 5, 7, 8, 9
> + 0x3ff, // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
> + };
> + int primary_pic_type_mask = 0xff;
> + H264RawAUD *aud = &ctx->aud_nal;
> +
> + for (i = 0; i < au->nb_units; i++) {
> + if (au->units[i].type == H264_NAL_SLICE ||
> + au->units[i].type == H264_NAL_IDR_SLICE) {
> + H264RawSlice *slice = au->units[i].content;
> + for (j = 0; j < FF_ARRAY_ELEMS(primary_pic_type_table);
> j++) {
> + if (!(primary_pic_type_table[j] &
> + (1 << slice->header.slice_type)))
> + primary_pic_type_mask &= ~(1 << j);
> + }
> + }
> + }
> + for (j = 0; j < FF_ARRAY_ELEMS(primary_pic_type_table); j++)
> + if (primary_pic_type_mask & (1 << j))
> + break;
> + if (j >= FF_ARRAY_ELEMS(primary_pic_type_table)) {
> + av_log(bsf, AV_LOG_ERROR, "No usable primary_pic_type: "
> + "invalid slice types?\n");
> + err = AVERROR_INVALIDDATA;
> + goto fail;
> + }
> +
> + aud->nal_unit_header.nal_unit_type = H264_NAL_AUD;
> + aud->primary_pic_type = j;
> +
> + err = ff_cbs_insert_unit_content(&ctx->cbc, au,
> + 0, H264_NAL_AUD, aud);
> + if (err) {
> + av_log(bsf, AV_LOG_ERROR, "Failed to insert AUD.\n");
> + goto fail;
> + }
> + }
> + }
> +
> + has_sps = 0;
> + for (i = 0; i < au->nb_units; i++) {
> + if (au->units[i].type == H264_NAL_SPS) {
> + h264_metadata_update_sps(bsf, au->units[i].content);
> + has_sps = 1;
> + }
> + }
> +
> + // Only insert the SEI in access units containing SPSs.
> + if (has_sps && ctx->sei_user_data) {
> + H264RawSEI *sei;
> + H264RawSEIPayload *payload;
> + H264RawSEIUserDataUnregistered *udu;
> + int sei_pos;
> +
> + for (i = 0; i < au->nb_units; i++) {
> + if (au->units[i].type == H264_NAL_SEI ||
> + au->units[i].type == H264_NAL_SLICE ||
> + au->units[i].type == H264_NAL_IDR_SLICE)
> + break;
> + }
> + sei_pos = i;
> +
> + if (sei_pos < au->nb_units &&
> + au->units[sei_pos].type == H264_NAL_SEI) {
> + sei = au->units[sei_pos].content;
> + } else {
> + sei = &ctx->sei_nal;
> + memset(sei, 0, sizeof(*sei));
> +
> + sei->nal_unit_header.nal_unit_type = H264_NAL_SEI;
> +
> + err = ff_cbs_insert_unit_content(&ctx->cbc, au,
> + sei_pos, H264_NAL_SEI, sei);
> + if (err < 0) {
> + av_log(bsf, AV_LOG_ERROR, "Failed to insert SEI.\n");
> + goto fail;
> + }
> + }
> +
> + payload = &sei->payload[sei->payload_count];
> +
> + payload->payload_type = H264_SEI_TYPE_USER_DATA_UNREGISTERED;
> + udu = &payload->payload.user_data_unregistered;
> +
> + for (i = j = 0; j < 32 && ctx->sei_user_data[i]; i++) {
> + int c, v;
> + c = ctx->sei_user_data[i];
> + if (c == '-') {
> + continue;
> + } else if (av_isxdigit(c)) {
> + c = av_tolower(c);
> + v = (c <= '9' ? c - '0' : c - 'a' + 10);
> + } else {
> + goto invalid_user_data;
weird indentation
Otherwise ok
--
Anton Khirnov
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel