From dc750194b6c9c3f95d33f03f6f7d1992a8a2f885 Mon Sep 17 00:00:00 2001 From: Rick Kern Date: Wed, 27 Apr 2016 10:53:15 -0400 Subject: [PATCH] lavc/videotoolboxenc: Set colorimetry values Signed-off-by: Rick Kern --- configure | 5 +- libavcodec/videotoolboxenc.c | 209 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 74fd2109d1..18c43765c6 100755 --- a/configure +++ b/configure @@ -2079,6 +2079,7 @@ CONFIG_EXTRA=" vp3dsp vp56dsp vp8dsp + vt_bt2020 wma_freqs wmv2dsp " @@ -2742,7 +2743,8 @@ nvenc_hevc_encoder_deps="nvenc" videotoolbox_deps="VideoToolbox_VideoToolbox_h" videotoolbox_extralibs="-framework CoreFoundation -framework VideoToolbox -framework CoreMedia -framework CoreVideo" videotoolbox_encoder_deps="videotoolbox VTCompressionSessionPrepareToEncodeFrames" -videotoolbox_encoder_suggest="vda_framework" +videotoolbox_encoder_suggest="vda_framework vt_bt2020" +vt_bt2020_deps="kCVImageBufferColorPrimaries_ITU_R_2020" # demuxers / muxers ac3_demuxer_select="ac3_parser" @@ -5445,6 +5447,7 @@ check_header vdpau/vdpau_x11.h check_header VideoDecodeAcceleration/VDADecoder.h check_header VideoToolbox/VideoToolbox.h check_func_headers VideoToolbox/VTCompressionSession.h VTCompressionSessionPrepareToEncodeFrames -framework VideoToolbox +enabled videotoolbox && check_func_headers CoreVideo/CVImageBuffer.h kCVImageBufferColorPrimaries_ITU_R_2020 -framework CoreVideo check_header windows.h check_header X11/extensions/XvMClib.h check_header asm/types.h diff --git a/libavcodec/videotoolboxenc.c b/libavcodec/videotoolboxenc.c index 4a40f3507f..57ea2b336f 100644 --- a/libavcodec/videotoolboxenc.c +++ b/libavcodec/videotoolboxenc.c @@ -33,6 +33,12 @@ #include "internal.h" #include +#if !CONFIG_VT_BT2020 +# define kCVImageBufferColorPrimaries_ITU_R_2020 CFSTR("ITU_R_2020") +# define kCVImageBufferTransferFunction_ITU_R_2020 CFSTR("ITU_R_2020") +# define kCVImageBufferYCbCrMatrix_ITU_R_2020 CFSTR("ITU_R_2020") +#endif + typedef enum VT_H264Profile { H264_PROF_AUTO, H264_PROF_BASELINE, @@ -58,6 +64,9 @@ typedef struct BufNode { typedef struct VTEncContext { AVClass *class; VTCompressionSessionRef session; + CFStringRef ycbcr_matrix; + CFStringRef color_primaries; + CFStringRef transfer_function; pthread_mutex_t lock; pthread_cond_t cv_sample_sent; @@ -527,6 +536,28 @@ static int get_cv_pixel_format(AVCodecContext* avctx, return 0; } +static void add_color_attr(AVCodecContext *avctx, CFMutableDictionaryRef dict) { + VTEncContext *vtctx = avctx->priv_data; + + if (vtctx->color_primaries) { + CFDictionarySetValue(dict, + kCVImageBufferColorPrimariesKey, + vtctx->color_primaries); + } + + if (vtctx->transfer_function) { + CFDictionarySetValue(dict, + kCVImageBufferTransferFunctionKey, + vtctx->transfer_function); + } + + if (vtctx->ycbcr_matrix) { + CFDictionarySetValue(dict, + kCVImageBufferYCbCrMatrixKey, + vtctx->ycbcr_matrix); + } +} + static int create_cv_pixel_buffer_info(AVCodecContext* avctx, CFMutableDictionaryRef* dict) { @@ -580,6 +611,8 @@ static int create_cv_pixel_buffer_info(AVCodecContext* avctx, height_num); vt_release_num(&height_num); + add_color_attr(avctx, pixel_buffer_info); + *dict = pixel_buffer_info; return 0; @@ -592,6 +625,110 @@ pbinfo_nomem: return AVERROR(ENOMEM); } +static int get_cv_color_primaries(AVCodecContext *avctx, + CFStringRef *primaries) +{ + enum AVColorPrimaries pri = avctx->color_primaries; + switch (pri) { + case AVCOL_PRI_UNSPECIFIED: + *primaries = NULL; + break; + + case AVCOL_PRI_BT709: + *primaries = kCVImageBufferColorPrimaries_ITU_R_709_2; + break; + + case AVCOL_PRI_BT2020: + *primaries = kCVImageBufferColorPrimaries_ITU_R_2020; + break; + + default: + av_log(avctx, AV_LOG_ERROR, "Color primaries %s is not supported.\n", av_color_primaries_name(pri)); + *primaries = NULL; + return -1; + } + + return 0; +} + +static int get_cv_transfer_function(AVCodecContext *avctx, + CFStringRef *transfer_fnc, + CFNumberRef *gamma_level) +{ + enum AVColorTransferCharacteristic trc = avctx->color_trc; + Float32 gamma; + *gamma_level = NULL; + + switch (trc) { + case AVCOL_TRC_UNSPECIFIED: + *transfer_fnc = NULL; + break; + + case AVCOL_TRC_BT709: + *transfer_fnc = kCVImageBufferTransferFunction_ITU_R_709_2; + break; + + case AVCOL_TRC_SMPTE240M: + *transfer_fnc = kCVImageBufferTransferFunction_SMPTE_240M_1995; + break; + + case AVCOL_TRC_GAMMA22: + gamma = 2.2; + *transfer_fnc = kCVImageBufferTransferFunction_UseGamma; + *gamma_level = CFNumberCreate(NULL, kCFNumberFloat32Type, &gamma); + break; + + case AVCOL_TRC_GAMMA28: + gamma = 2.8; + *transfer_fnc = kCVImageBufferTransferFunction_UseGamma; + *gamma_level = CFNumberCreate(NULL, kCFNumberFloat32Type, &gamma); + break; + + case AVCOL_TRC_BT2020_10: + case AVCOL_TRC_BT2020_12: + *transfer_fnc = kCVImageBufferTransferFunction_ITU_R_2020; + break; + + default: + av_log(avctx, AV_LOG_ERROR, "Transfer function %s is not supported.\n", av_color_transfer_name(trc)); + return -1; + } + + return 0; +} + +static int get_cv_ycbcr_matrix(AVCodecContext *avctx, CFStringRef *matrix) { + switch(avctx->colorspace) { + case AVCOL_SPC_BT709: + *matrix = kCVImageBufferYCbCrMatrix_ITU_R_709_2; + break; + + case AVCOL_SPC_UNSPECIFIED: + *matrix = NULL; + break; + + case AVCOL_SPC_BT470BG: + case AVCOL_SPC_SMPTE170M: + *matrix = kCVImageBufferYCbCrMatrix_ITU_R_601_4; + break; + + case AVCOL_SPC_SMPTE240M: + *matrix = kCVImageBufferYCbCrMatrix_SMPTE_240M_1995; + break; + + case AVCOL_SPC_BT2020_NCL: + *matrix = kCVImageBufferYCbCrMatrix_ITU_R_2020; + break; + + default: + av_log(avctx, AV_LOG_ERROR, "Color space %s is not supported.\n", av_color_space_name(avctx->colorspace)); + return -1; + } + + return 0; +} + + static av_cold int vtenc_init(AVCodecContext *avctx) { CFMutableDictionaryRef enc_info; @@ -602,6 +739,7 @@ static av_cold int vtenc_init(AVCodecContext *avctx) SInt32 bit_rate = avctx->bit_rate; CFNumberRef bit_rate_num; CFBooleanRef has_b_frames_cfbool; + CFNumberRef gamma_level; int status; codec_type = get_cm_codec_type(avctx->codec_id); @@ -811,6 +949,49 @@ static av_cold int vtenc_init(AVCodecContext *avctx) } } + status = get_cv_transfer_function(avctx, &vtctx->transfer_function, &gamma_level); + if (!status && vtctx->transfer_function) { + status = VTSessionSetProperty(vtctx->session, + kVTCompressionPropertyKey_TransferFunction, + vtctx->transfer_function); + + if (status) { + av_log(avctx, AV_LOG_WARNING, "Could not set transfer function: %d\n", status); + } + } + + status = get_cv_ycbcr_matrix(avctx, &vtctx->ycbcr_matrix); + if (!status && vtctx->ycbcr_matrix) { + status = VTSessionSetProperty(vtctx->session, + kVTCompressionPropertyKey_YCbCrMatrix, + vtctx->ycbcr_matrix); + + if (status) { + av_log(avctx, AV_LOG_WARNING, "Could not set ycbcr matrix: %d\n", status); + } + } + + status = get_cv_color_primaries(avctx, &vtctx->color_primaries); + if (!status && vtctx->color_primaries) { + status = VTSessionSetProperty(vtctx->session, + kVTCompressionPropertyKey_ColorPrimaries, + vtctx->color_primaries); + + if (status) { + av_log(avctx, AV_LOG_WARNING, "Could not set color primaries: %d\n", status); + } + } + + if (!status && gamma_level) { + status = VTSessionSetProperty(vtctx->session, + kCVImageBufferGammaLevelKey, + gamma_level); + + if (status) { + av_log(avctx, AV_LOG_WARNING, "Could not set gamma level: %d\n", status); + } + } + if (!vtctx->has_b_frames) { status = VTSessionSetProperty(vtctx->session, kVTCompressionPropertyKey_AllowFrameReordering, @@ -1375,9 +1556,18 @@ static int create_cv_pixel_buffer(AVCodecContext *avctx, size_t strides[AV_NUM_DATA_POINTERS]; int status; size_t contiguous_buf_size; +#if TARGET_OS_IPHONE CVPixelBufferPoolRef pix_buf_pool; VTEncContext* vtctx = avctx->priv_data; +#else + CFMutableDictionaryRef pix_buf_attachments = CFDictionaryCreateMutable( + kCFAllocatorDefault, + 10, + &kCFCopyStringDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (!pix_buf_attachments) return AVERROR(ENOMEM); +#endif if (avctx->pix_fmt == AV_PIX_FMT_VIDEOTOOLBOX) { av_assert0(frame->format == AV_PIX_FMT_VIDEOTOOLBOX); @@ -1468,6 +1658,10 @@ static int create_cv_pixel_buffer(AVCodecContext *avctx, cv_img ); + add_color_attr(avctx, pix_buf_attachments); + CVBufferSetAttachments(*cv_img, pix_buf_attachments, kCVAttachmentMode_ShouldPropagate); + CFRelease(pix_buf_attachments); + if (status) { av_log(avctx, AV_LOG_ERROR, "Error: Could not create CVPixelBuffer: %d\n", status); return AVERROR_EXTERNAL; @@ -1605,6 +1799,21 @@ static av_cold int vtenc_close(AVCodecContext *avctx) CFRelease(vtctx->session); vtctx->session = NULL; + if (vtctx->color_primaries) { + CFRelease(vtctx->color_primaries); + vtctx->color_primaries = NULL; + } + + if (vtctx->transfer_function) { + CFRelease(vtctx->transfer_function); + vtctx->transfer_function = NULL; + } + + if (vtctx->ycbcr_matrix) { + CFRelease(vtctx->ycbcr_matrix); + vtctx->ycbcr_matrix = NULL; + } + return 0; } -- 2.11.0