You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-08-15 14:13:16 +02:00
lavc/videotoolboxenc: Set colorimetry values
Signed-off-by: Rick Kern <kernrj@gmail.com>
This commit is contained in:
5
configure
vendored
5
configure
vendored
@@ -2079,6 +2079,7 @@ CONFIG_EXTRA="
|
|||||||
vp3dsp
|
vp3dsp
|
||||||
vp56dsp
|
vp56dsp
|
||||||
vp8dsp
|
vp8dsp
|
||||||
|
vt_bt2020
|
||||||
wma_freqs
|
wma_freqs
|
||||||
wmv2dsp
|
wmv2dsp
|
||||||
"
|
"
|
||||||
@@ -2742,7 +2743,8 @@ nvenc_hevc_encoder_deps="nvenc"
|
|||||||
videotoolbox_deps="VideoToolbox_VideoToolbox_h"
|
videotoolbox_deps="VideoToolbox_VideoToolbox_h"
|
||||||
videotoolbox_extralibs="-framework CoreFoundation -framework VideoToolbox -framework CoreMedia -framework CoreVideo"
|
videotoolbox_extralibs="-framework CoreFoundation -framework VideoToolbox -framework CoreMedia -framework CoreVideo"
|
||||||
videotoolbox_encoder_deps="videotoolbox VTCompressionSessionPrepareToEncodeFrames"
|
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
|
# demuxers / muxers
|
||||||
ac3_demuxer_select="ac3_parser"
|
ac3_demuxer_select="ac3_parser"
|
||||||
@@ -5445,6 +5447,7 @@ check_header vdpau/vdpau_x11.h
|
|||||||
check_header VideoDecodeAcceleration/VDADecoder.h
|
check_header VideoDecodeAcceleration/VDADecoder.h
|
||||||
check_header VideoToolbox/VideoToolbox.h
|
check_header VideoToolbox/VideoToolbox.h
|
||||||
check_func_headers VideoToolbox/VTCompressionSession.h VTCompressionSessionPrepareToEncodeFrames -framework VideoToolbox
|
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 windows.h
|
||||||
check_header X11/extensions/XvMClib.h
|
check_header X11/extensions/XvMClib.h
|
||||||
check_header asm/types.h
|
check_header asm/types.h
|
||||||
|
@@ -33,6 +33,12 @@
|
|||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#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 {
|
typedef enum VT_H264Profile {
|
||||||
H264_PROF_AUTO,
|
H264_PROF_AUTO,
|
||||||
H264_PROF_BASELINE,
|
H264_PROF_BASELINE,
|
||||||
@@ -58,6 +64,9 @@ typedef struct BufNode {
|
|||||||
typedef struct VTEncContext {
|
typedef struct VTEncContext {
|
||||||
AVClass *class;
|
AVClass *class;
|
||||||
VTCompressionSessionRef session;
|
VTCompressionSessionRef session;
|
||||||
|
CFStringRef ycbcr_matrix;
|
||||||
|
CFStringRef color_primaries;
|
||||||
|
CFStringRef transfer_function;
|
||||||
|
|
||||||
pthread_mutex_t lock;
|
pthread_mutex_t lock;
|
||||||
pthread_cond_t cv_sample_sent;
|
pthread_cond_t cv_sample_sent;
|
||||||
@@ -527,6 +536,28 @@ static int get_cv_pixel_format(AVCodecContext* avctx,
|
|||||||
return 0;
|
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,
|
static int create_cv_pixel_buffer_info(AVCodecContext* avctx,
|
||||||
CFMutableDictionaryRef* dict)
|
CFMutableDictionaryRef* dict)
|
||||||
{
|
{
|
||||||
@@ -580,6 +611,8 @@ static int create_cv_pixel_buffer_info(AVCodecContext* avctx,
|
|||||||
height_num);
|
height_num);
|
||||||
vt_release_num(&height_num);
|
vt_release_num(&height_num);
|
||||||
|
|
||||||
|
add_color_attr(avctx, pixel_buffer_info);
|
||||||
|
|
||||||
*dict = pixel_buffer_info;
|
*dict = pixel_buffer_info;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -592,6 +625,110 @@ pbinfo_nomem:
|
|||||||
return AVERROR(ENOMEM);
|
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)
|
static av_cold int vtenc_init(AVCodecContext *avctx)
|
||||||
{
|
{
|
||||||
CFMutableDictionaryRef enc_info;
|
CFMutableDictionaryRef enc_info;
|
||||||
@@ -602,6 +739,7 @@ static av_cold int vtenc_init(AVCodecContext *avctx)
|
|||||||
SInt32 bit_rate = avctx->bit_rate;
|
SInt32 bit_rate = avctx->bit_rate;
|
||||||
CFNumberRef bit_rate_num;
|
CFNumberRef bit_rate_num;
|
||||||
CFBooleanRef has_b_frames_cfbool;
|
CFBooleanRef has_b_frames_cfbool;
|
||||||
|
CFNumberRef gamma_level;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
codec_type = get_cm_codec_type(avctx->codec_id);
|
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) {
|
if (!vtctx->has_b_frames) {
|
||||||
status = VTSessionSetProperty(vtctx->session,
|
status = VTSessionSetProperty(vtctx->session,
|
||||||
kVTCompressionPropertyKey_AllowFrameReordering,
|
kVTCompressionPropertyKey_AllowFrameReordering,
|
||||||
@@ -1375,9 +1556,18 @@ static int create_cv_pixel_buffer(AVCodecContext *avctx,
|
|||||||
size_t strides[AV_NUM_DATA_POINTERS];
|
size_t strides[AV_NUM_DATA_POINTERS];
|
||||||
int status;
|
int status;
|
||||||
size_t contiguous_buf_size;
|
size_t contiguous_buf_size;
|
||||||
|
#if TARGET_OS_IPHONE
|
||||||
CVPixelBufferPoolRef pix_buf_pool;
|
CVPixelBufferPoolRef pix_buf_pool;
|
||||||
VTEncContext* vtctx = avctx->priv_data;
|
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) {
|
if (avctx->pix_fmt == AV_PIX_FMT_VIDEOTOOLBOX) {
|
||||||
av_assert0(frame->format == 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
|
cv_img
|
||||||
);
|
);
|
||||||
|
|
||||||
|
add_color_attr(avctx, pix_buf_attachments);
|
||||||
|
CVBufferSetAttachments(*cv_img, pix_buf_attachments, kCVAttachmentMode_ShouldPropagate);
|
||||||
|
CFRelease(pix_buf_attachments);
|
||||||
|
|
||||||
if (status) {
|
if (status) {
|
||||||
av_log(avctx, AV_LOG_ERROR, "Error: Could not create CVPixelBuffer: %d\n", status);
|
av_log(avctx, AV_LOG_ERROR, "Error: Could not create CVPixelBuffer: %d\n", status);
|
||||||
return AVERROR_EXTERNAL;
|
return AVERROR_EXTERNAL;
|
||||||
@@ -1605,6 +1799,21 @@ static av_cold int vtenc_close(AVCodecContext *avctx)
|
|||||||
CFRelease(vtctx->session);
|
CFRelease(vtctx->session);
|
||||||
vtctx->session = NULL;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user