[FFmpeg-devel] [PATCH 2/4] vaapi_encode_h265: Insert mastering display colour colume if needed

Mark Thompson sw at jkqxz.net
Fri May 4 00:43:51 EEST 2018


On 03/05/18 04:07, Haihao Xiang wrote:
> '-sei xxx' is added to control SEI insertion, so far only mastering
> display colour colume is available for testing.

Typo: "colume" (also in the commit title).

> v2: use the mastering display parameters from
> AVMasteringDisplayMetadata, set SEI_MASTERING_DISPLAY to 8 to match
> the H.264 part and take VAAPIEncodeH265Context::sei_needed as a ORed
> value so that we needn't check the correspoding SEI message again when
> writting the header.
> 
> Signed-off-by: Haihao Xiang <haihao.xiang at intel.com>
> ---
>  libavcodec/vaapi_encode_h265.c | 128 ++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 127 insertions(+), 1 deletion(-)
> 
> diff --git a/libavcodec/vaapi_encode_h265.c b/libavcodec/vaapi_encode_h265.c
> index 5203c6871d..326fe4fe66 100644
> --- a/libavcodec/vaapi_encode_h265.c
> +++ b/libavcodec/vaapi_encode_h265.c
> @@ -24,15 +24,20 @@
>  #include "libavutil/avassert.h"
>  #include "libavutil/common.h"
>  #include "libavutil/opt.h"
> +#include "libavutil/mastering_display_metadata.h"
>  
>  #include "avcodec.h"
>  #include "cbs.h"
>  #include "cbs_h265.h"
>  #include "hevc.h"
> +#include "hevc_sei.h"
>  #include "internal.h"
>  #include "put_bits.h"
>  #include "vaapi_encode.h"
>  
> +enum {
> +    SEI_MASTERING_DISPLAY       = 0x08,
> +};
>  
>  typedef struct VAAPIEncodeH265Context {
>      unsigned int ctu_width;
> @@ -47,6 +52,9 @@ typedef struct VAAPIEncodeH265Context {
>      H265RawSPS sps;
>      H265RawPPS pps;
>      H265RawSlice slice;
> +    H265RawSEI sei;
> +
> +    H265RawSEIMasteringDiplayColourVolume mastering_display;
>  
>      int64_t last_idr_frame;
>      int pic_order_cnt;
> @@ -58,6 +66,7 @@ typedef struct VAAPIEncodeH265Context {
>      CodedBitstreamContext *cbc;
>      CodedBitstreamFragment current_access_unit;
>      int aud_needed;
> +    int sei_needed;
>  } VAAPIEncodeH265Context;
>  
>  typedef struct VAAPIEncodeH265Options {
> @@ -65,6 +74,7 @@ typedef struct VAAPIEncodeH265Options {
>      int aud;
>      int profile;
>      int level;
> +    int sei;
>  } VAAPIEncodeH265Options;
>  
>  
> @@ -175,6 +185,64 @@ fail:
>      return err;
>  }
>  
> +static int vaapi_encode_h265_write_extra_header(AVCodecContext *avctx,
> +                                                VAAPIEncodePicture *pic,
> +                                                int index, int *type,
> +                                                char *data, size_t *data_len)
> +{
> +    VAAPIEncodeContext      *ctx = avctx->priv_data;
> +    VAAPIEncodeH265Context *priv = ctx->priv_data;
> +    CodedBitstreamFragment   *au = &priv->current_access_unit;
> +    int err, i;
> +
> +    if (priv->sei_needed) {
> +        if (priv->aud_needed) {
> +            err = vaapi_encode_h265_add_nal(avctx, au, &priv->aud);
> +            if (err < 0)
> +                goto fail;
> +            priv->aud_needed = 0;
> +        }
> +
> +        memset(&priv->sei, 0, sizeof(priv->sei));
> +        priv->sei.nal_unit_header  = (H265RawNALUnitHeader) {
> +            .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) {
> +            priv->sei.payload[i].payload_type = HEVC_SEI_TYPE_MASTERING_DISPLAY_INFO;
> +            priv->sei.payload[i].payload.mastering_display = priv->mastering_display;
> +            ++i;
> +        }
> +
> +        priv->sei.payload_count = i;
> +        av_assert0(priv->sei.payload_count > 0);
> +
> +        err = vaapi_encode_h265_add_nal(avctx, au, &priv->sei);
> +        if (err < 0)
> +            goto fail;
> +        priv->sei_needed = 0;
> +
> +        err = vaapi_encode_h265_write_access_unit(avctx, data, data_len, au);
> +        if (err < 0)
> +            goto fail;
> +
> +        ff_cbs_fragment_uninit(priv->cbc, au);
> +
> +        *type = VAEncPackedHeaderRawData;
> +        return 0;
> +    } else {
> +        return AVERROR_EOF;
> +    }
> +
> +fail:
> +    ff_cbs_fragment_uninit(priv->cbc, au);
> +    return err;
> +}
> +
>  static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx)
>  {
>      VAAPIEncodeContext                *ctx = avctx->priv_data;
> @@ -587,6 +655,53 @@ static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx,
>          priv->aud_needed = 0;
>      }
>  
> +    priv->sei_needed = 0;
> +
> +    if ((opt->sei & SEI_MASTERING_DISPLAY) &&
> +        (pic->type == PICTURE_TYPE_I || pic->type == PICTURE_TYPE_IDR)) {
> +        AVFrameSideData *sd =
> +            av_frame_get_side_data(pic->input_image,
> +                                   AV_FRAME_DATA_MASTERING_DISPLAY_METADATA);

Do you know when this side-data might be updated - can it arrive on a random frame in the middle of the stream?  (And if so, what should we do about it?)

> +
> +        if (sd) {
> +            AVMasteringDisplayMetadata *mdm =
> +                (AVMasteringDisplayMetadata *)sd->data;
> +
> +            if (mdm->has_primaries && mdm->has_luminance) {
> +                const int mapping[3] = {1, 2, 0};
> +                const int chroma_den = 50000;
> +                const int luma_den   = 10000;
> +
> +                for (i = 0; i < 3; i++) {
> +                    const int j = mapping[i];
> +                    priv->mastering_display.display_primaries_x[i] =
> +                        FFMIN(lrint(chroma_den *
> +                                    av_q2d(mdm->display_primaries[j][0])),
> +                              50000);
> +                    priv->mastering_display.display_primaries_y[i] =
> +                        FFMIN(lrint(chroma_den *
> +                                    av_q2d(mdm->display_primaries[j][1])),
> +                              50000);
> +                }
> +
> +                priv->mastering_display.white_point_x =
> +                    FFMIN(lrint(chroma_den * av_q2d(mdm->white_point[0])),
> +                          50000);
> +                priv->mastering_display.white_point_y =
> +                    FFMIN(lrint(chroma_den * av_q2d(mdm->white_point[1])),
> +                          50000);
> +
> +                priv->mastering_display.max_display_mastering_luminance =
> +                    lrint(luma_den * av_q2d(mdm->max_luminance));
> +                priv->mastering_display.min_display_mastering_luminance =
> +                    FFMIN(lrint(luma_den * av_q2d(mdm->min_luminance)),
> +                          priv->mastering_display.max_display_mastering_luminance);
> +
> +                priv->sei_needed |= SEI_MASTERING_DISPLAY;
> +            }
> +        }

There are has_primaries and has_luminance fields in AVMasteringDisplayMetadata - do they need to be checked here?  If they don't matter then please add a comment to that effect.

> +    }
> +
>      vpic->decoded_curr_pic = (VAPictureHEVC) {
>          .picture_id    = pic->recon_surface,
>          .pic_order_cnt = priv->pic_order_cnt,
> @@ -895,6 +1010,8 @@ static const VAAPIEncodeType vaapi_encode_type_h265 = {
>  
>      .slice_header_type     = VAEncPackedHeaderHEVC_Slice,
>      .write_slice_header    = &vaapi_encode_h265_write_slice_header,
> +
> +    .write_extra_header    = &vaapi_encode_h265_write_extra_header,
>  };
>  
>  static av_cold int vaapi_encode_h265_init(AVCodecContext *avctx)
> @@ -943,7 +1060,8 @@ static av_cold int vaapi_encode_h265_init(AVCodecContext *avctx)
>  
>      ctx->va_packed_headers =
>          VA_ENC_PACKED_HEADER_SEQUENCE | // VPS, SPS and PPS.
> -        VA_ENC_PACKED_HEADER_SLICE;     // Slice headers.
> +        VA_ENC_PACKED_HEADER_SLICE    | // Slice headers.
> +        VA_ENC_PACKED_HEADER_MISC;      // SEI
>  
>      ctx->surface_width  = FFALIGN(avctx->width,  16);
>      ctx->surface_height = FFALIGN(avctx->height, 16);
> @@ -1003,6 +1121,14 @@ static const AVOption vaapi_encode_h265_options[] = {
>      { LEVEL("6.2", 186) },
>  #undef LEVEL
>  
> +    { "sei", "Set SEI to include",
> +      OFFSET(sei), AV_OPT_TYPE_FLAGS,
> +      { .i64 = SEI_MASTERING_DISPLAY },
> +      0, INT_MAX, FLAGS, "sei" },
> +    { "mastering_display", "Include mastering display colour volume",
> +      0, AV_OPT_TYPE_CONST, { .i64 = SEI_MASTERING_DISPLAY },
> +      INT_MIN, INT_MAX, FLAGS, "sei" },
> +
>      { NULL },
>  };
>  
> 

Ignoring the mastering display part, all the SEI logic looks good.

Thanks,

- Mark


More information about the ffmpeg-devel mailing list