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
libav-devel@libav.org
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to