[FFmpeg-devel] [PATCH 5/8] Support encoding of Active Format Description (AFD) in libx264

Aaron Levinson alevinsn_dev at levland.net
Sat Dec 30 09:25:36 EET 2017


On 12/29/2017 10:12 AM, Devin Heitmueller wrote:
> If AFD side data is present, include it in an H.264 SEI payload when
> encoding with libx264.
> 
> This is done in the same manner that we currently handle A53 closed
> captions (where the business logic for constructing the SEI is in
> libavcodec/utils.c), so it should be portable to the other encoder
> types (i.e. videotoolbox, etc).
> 
> Updated to reflect feedback from Derek Buitenhuis <derek.buitenhuis at gmail.com>
> 
> Signed-off-by: Devin Heitmueller <dheitmueller at ltnglobal.com>
> ---
>   libavcodec/internal.h |  3 +++
>   libavcodec/libx264.c  | 47 +++++++++++++++++++++++++++++++++++++++++++----
>   libavcodec/utils.c    | 36 ++++++++++++++++++++++++++++++++++++
>   3 files changed, 82 insertions(+), 4 deletions(-)
> 
> diff --git a/libavcodec/internal.h b/libavcodec/internal.h
> index 6deaf1d204..4db33eb020 100644
> --- a/libavcodec/internal.h
> +++ b/libavcodec/internal.h
> @@ -408,6 +408,9 @@ int ff_side_data_set_encoder_stats(AVPacket *pkt, int quality, int64_t *error, i
>   int ff_alloc_a53_sei(const AVFrame *frame, size_t prefix_len,
>                        void **data, size_t *sei_size);
>   
> +int ff_alloc_afd_sei(const AVFrame *frame, size_t prefix_len,
> +                     void **data, size_t *sei_size);
> +
>   /**
>    * Get an estimated video bitrate based on frame size, frame rate and coded
>    * bits per pixel.
> diff --git a/libavcodec/libx264.c b/libavcodec/libx264.c
> index 9c67c91f33..9a9667079e 100644
> --- a/libavcodec/libx264.c
> +++ b/libavcodec/libx264.c
> @@ -86,6 +86,7 @@ typedef struct X264Context {
>       int forced_idr;
>       int coder;
>       int a53_cc;
> +    int afd;
>       int b_frame_strategy;
>       int chroma_offset;
>       int scenechange_threshold;
> @@ -275,6 +276,7 @@ static int X264_frame(AVCodecContext *ctx, AVPacket *pkt, const AVFrame *frame,
>       x264_nal_t *nal;
>       int nnal, i, ret;
>       x264_picture_t pic_out = {0};
> +    int num_payloads = 0;
>       int pict_type;
>   
>       x264_picture_init( &x4->pic );
> @@ -323,10 +325,46 @@ static int X264_frame(AVCodecContext *ctx, AVPacket *pkt, const AVFrame *frame,
>                   } else {
>                       x4->pic.extra_sei.sei_free = av_free;
>   
> -                    x4->pic.extra_sei.payloads[0].payload_size = sei_size;
> -                    x4->pic.extra_sei.payloads[0].payload = sei_data;
> -                    x4->pic.extra_sei.num_payloads = 1;
> -                    x4->pic.extra_sei.payloads[0].payload_type = 4;
> +                    x4->pic.extra_sei.payloads[num_payloads].payload_size = sei_size;
> +                    x4->pic.extra_sei.payloads[num_payloads].payload = sei_data;
> +                    x4->pic.extra_sei.payloads[num_payloads].payload_type = 4;
> +                    x4->pic.extra_sei.num_payloads++;
> +                    num_payloads++;
> +                }
> +            }
> +        }
> +
> +        /* Active Format Description */
> +        if (x4->afd) {
> +            void *sei_data;
> +            size_t sei_size;
> +
> +            ret = ff_alloc_afd_sei(frame, 0, &sei_data, &sei_size);
> +            if (ret < 0) {
> +                for (i = 0; i < num_payloads; i++)
> +                    av_free(x4->pic.extra_sei.payloads[i].payload);
> +                av_free(x4->pic.extra_sei.payloads);

Seems like it would be appropriate to use av_freep() for the last one to 
make sure that payloads is zeroed out before returning.  Applies in 
other places.

> +                return AVERROR(ENOMEM);
> +            } else if (sei_data) {
> +                x264_sei_payload_t *payloads;
> +                payloads = av_realloc(x4->pic.extra_sei.payloads,
> +                                      sizeof(x4->pic.extra_sei.payloads[0]) * (num_payloads + 1));
> +                if (payloads == NULL) {
> +                    av_log(ctx, AV_LOG_ERROR, "Not enough memory for AFD, skipping\n");
> +                    for (i = 0; i < num_payloads; i++)
> +                        av_free(x4->pic.extra_sei.payloads[i].payload);
> +                    av_free(x4->pic.extra_sei.payloads);
> +                    av_free(sei_data);
> +                    return AVERROR(ENOMEM);
> +                } else {
> +                    x4->pic.extra_sei.payloads = payloads;
> +                    x4->pic.extra_sei.sei_free = av_free;
> +
> +                    x4->pic.extra_sei.payloads[num_payloads].payload_size = sei_size;
> +                    x4->pic.extra_sei.payloads[num_payloads].payload = sei_data;
> +                    x4->pic.extra_sei.payloads[num_payloads].payload_type = 4;
> +                    x4->pic.extra_sei.num_payloads++;
> +                    num_payloads++;
>                   }
>               }
>           }
> @@ -892,6 +930,7 @@ static const AVOption options[] = {
>       {"passlogfile", "Filename for 2 pass stats", OFFSET(stats), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, VE},
>       {"wpredp", "Weighted prediction for P-frames", OFFSET(wpredp), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, VE},
>       {"a53cc",          "Use A53 Closed Captions (if available)",          OFFSET(a53_cc),        AV_OPT_TYPE_BOOL,   {.i64 = 1}, 0, 1, VE},
> +    {"afd",            "Use Active Format Description (AFD) (if available)",OFFSET(afd),        AV_OPT_TYPE_BOOL,   {.i64 = 1}, 0, 1, VE},
>       {"x264opts", "x264 options", OFFSET(x264opts), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, VE},
>       { "crf",           "Select the quality for constant quality mode",    OFFSET(crf),           AV_OPT_TYPE_FLOAT,  {.dbl = -1 }, -1, FLT_MAX, VE },
>       { "crf_max",       "In CRF mode, prevents VBV from lowering quality beyond this point.",OFFSET(crf_max), AV_OPT_TYPE_FLOAT, {.dbl = -1 }, -1, FLT_MAX, VE },
> diff --git a/libavcodec/utils.c b/libavcodec/utils.c
> index baf09119fe..5fc925b8cd 100644
> --- a/libavcodec/utils.c
> +++ b/libavcodec/utils.c
> @@ -2403,6 +2403,42 @@ int ff_alloc_a53_sei(const AVFrame *frame, size_t prefix_len,
>       return 0;
>   }
>   
> +/* Defined in SCTE 128-1 2013 Sec 8.1 */
> +int ff_alloc_afd_sei(const AVFrame *frame, size_t prefix_len,
> +                     void **data, size_t *sei_size)
> +{
> +    AVFrameSideData *side_data = NULL;
> +    uint8_t *sei_data;
> +
> +    if (frame)
> +        side_data = av_frame_get_side_data(frame, AV_FRAME_DATA_AFD);
> +
> +    if (!side_data) {
> +        *data = NULL;
> +        return 0;
> +    }
> +
> +    *sei_size = 9;
> +    *data = av_mallocz(*sei_size + prefix_len);
> +    if (!*data)
> +        return AVERROR(ENOMEM);
> +    sei_data = (uint8_t*)*data + prefix_len;
> +
> +    /* country code (SCTE 128-1 Sec 8.1.1) */
> +    sei_data[0] = 181;
> +    sei_data[1] = 0;
> +    sei_data[2] = 49;
> +
> +    /* country code (SCTE 128-1 Sec 8.1.2) */
> +    AV_WL32(sei_data + 3, MKTAG('D', 'T', 'G', '1'));
> +
> +    /* country code (SCTE 128-1 Sec 8.2.5) */
> +    sei_data[7] = 0x41;
> +    sei_data[8] = 0xf0 | side_data->data[0];
> +
> +    return 0;
> +}
> +
>   int64_t ff_guess_coded_bitrate(AVCodecContext *avctx)
>   {
>       AVRational framerate = avctx->framerate;
> 

I don't know enough about this to review the technical aspects of this 
code, but I will say that these changes don't help those users that are 
encoding in H.264 but using hardware encoders such as Intel QuickSync.

Aaron Levinson


More information about the ffmpeg-devel mailing list