On Sun, Nov 12, 2017 at 10:22 AM, Aman Gupta <ffm...@tmm1.net> wrote:
> From: Aman Gupta <a...@tmm1.net> > > --- > configure | 2 + > libavcodec/allcodecs.c | 1 + > libavcodec/videotoolboxenc.c | 153 ++++++++++++++++++++++++++++++ > +++++++++---- > 3 files changed, 143 insertions(+), 13 deletions(-) > > diff --git a/configure b/configure > index 2cf18ecc12..39b9d4cb0c 100755 > --- a/configure > +++ b/configure > @@ -2928,6 +2928,8 @@ pcm_mulaw_at_encoder_select="audio_frame_queue" > chromaprint_muxer_deps="chromaprint" > h264_videotoolbox_encoder_deps="pthreads" > h264_videotoolbox_encoder_select="videotoolbox_encoder" > +hevc_videotoolbox_encoder_deps="pthreads" > +hevc_videotoolbox_encoder_select="videotoolbox_encoder" > libcelt_decoder_deps="libcelt" > libfdk_aac_decoder_deps="libfdk_aac" > libfdk_aac_encoder_deps="libfdk_aac" > diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c > index c817003693..d8be53a52a 100644 > --- a/libavcodec/allcodecs.c > +++ b/libavcodec/allcodecs.c > @@ -670,6 +670,7 @@ static void register_all(void) > REGISTER_ENCODER(HEVC_QSV, hevc_qsv); > REGISTER_ENCODER(HEVC_V4L2M2M, hevc_v4l2m2m); > REGISTER_ENCODER(HEVC_VAAPI, hevc_vaapi); > + REGISTER_ENCODER(HEVC_VIDEOTOOLBOX, hevc_videotoolbox); > REGISTER_ENCODER(LIBKVAZAAR, libkvazaar); > REGISTER_DECODER(MJPEG_CUVID, mjpeg_cuvid); > REGISTER_ENCODER(MJPEG_QSV, mjpeg_qsv); > diff --git a/libavcodec/videotoolboxenc.c b/libavcodec/videotoolboxenc.c > index eba6cc672f..5f6a382672 100644 > --- a/libavcodec/videotoolboxenc.c > +++ b/libavcodec/videotoolboxenc.c > @@ -35,6 +35,17 @@ > #include "h264_sei.h" > #include <dlfcn.h> > > +#if !HAVE_KCMVIDEOCODECTYPE_HEVC > +enum { kCMVideoCodecType_HEVC = 'hvc1' }; > +#endif > + > +typedef OSStatus (*getParameterSetAtIndex)(CMFormatDescriptionRef > videoDesc, > + size_t parameterSetIndex, > + const uint8_t * _Nullable > *parameterSetPointerOut, > + size_t *parameterSetSizeOut, > + size_t *parameterSetCountOut, > + int *NALUnitHeaderLengthOut); > + > //These symbols may not be present > static struct{ > CFStringRef kCVImageBufferColorPrimaries_ITU_R_2020; > @@ -65,10 +76,15 @@ static struct{ > CFStringRef kVTProfileLevel_H264_High_5_2; > CFStringRef kVTProfileLevel_H264_High_AutoLevel; > > + CFStringRef kVTProfileLevel_HEVC_Main_AutoLevel; > + CFStringRef kVTProfileLevel_HEVC_Main10_AutoLevel; > + > CFStringRef kVTCompressionPropertyKey_RealTime; > > CFStringRef kVTVideoEncoderSpecification_ > EnableHardwareAcceleratedVideoEncoder; > CFStringRef kVTVideoEncoderSpecification_ > RequireHardwareAcceleratedVideoEncoder; > + > + getParameterSetAtIndex CMVideoFormatDescriptionGetHEV > CParameterSetAtIndex; > } compat_keys; > > #define GET_SYM(symbol, defaultVal) \ > @@ -83,6 +99,12 @@ do{ > \ > static pthread_once_t once_ctrl = PTHREAD_ONCE_INIT; > > static void loadVTEncSymbols(){ > + compat_keys.CMVideoFormatDescriptionGetHEVCParameterSetAtIndex = > + (getParameterSetAtIndex)dlsym( > + RTLD_DEFAULT, > + "CMVideoFormatDescriptionGetHEVCParameterSetAtIndex" > + ); > + > GET_SYM(kCVImageBufferColorPrimaries_ITU_R_2020, "ITU_R_2020"); > GET_SYM(kCVImageBufferTransferFunction_ITU_R_2020, "ITU_R_2020"); > GET_SYM(kCVImageBufferYCbCrMatrix_ITU_R_2020, "ITU_R_2020"); > @@ -111,6 +133,9 @@ static void loadVTEncSymbols(){ > GET_SYM(kVTProfileLevel_H264_High_5_2, "H264_High_5_2"); > GET_SYM(kVTProfileLevel_H264_High_AutoLevel, > "H264_High_AutoLevel"); > > + GET_SYM(kVTProfileLevel_HEVC_Main_AutoLevel, > "HEVC_Main_AutoLevel"); > + GET_SYM(kVTProfileLevel_HEVC_Main10_AutoLevel, > "HEVC_Main10_AutoLevel"); > + > GET_SYM(kVTCompressionPropertyKey_RealTime, "RealTime"); > > GET_SYM(kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideo > Encoder, > @@ -133,6 +158,13 @@ typedef enum VTH264Entropy{ > VT_CABAC > } VTH264Entropy; > > +typedef enum VT_HEVCProfile { > + HEVC_PROF_AUTO, > + HEVC_PROF_MAIN, > + HEVC_PROF_MAIN10, > + HEVC_PROF_COUNT > +} VT_HEVCProfile; > + > static const uint8_t start_code[] = { 0, 0, 0, 1 }; > > typedef struct ExtraSEI { > @@ -149,10 +181,12 @@ typedef struct BufNode { > > typedef struct VTEncContext { > AVClass *class; > + enum AVCodecID codec_id; > VTCompressionSessionRef session; > CFStringRef ycbcr_matrix; > CFStringRef color_primaries; > CFStringRef transfer_function; > + getParameterSetAtIndex get_param_set_func; > > pthread_mutex_t lock; > pthread_cond_t cv_sample_sent; > @@ -348,6 +382,7 @@ static CMVideoCodecType get_cm_codec_type(enum > AVCodecID id) > { > switch (id) { > case AV_CODEC_ID_H264: return kCMVideoCodecType_H264; > + case AV_CODEC_ID_HEVC: return kCMVideoCodecType_HEVC; > default: return 0; > } > } > @@ -365,12 +400,13 @@ static int get_params_size( > CMVideoFormatDescriptionRef vid_fmt, > size_t *size) > { > + VTEncContext *vtctx = avctx->priv_data; > size_t total_size = 0; > size_t ps_count; > int is_count_bad = 0; > size_t i; > int status; > - status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(vid_fmt, > + status = vtctx->get_param_set_func(vid_fmt, > 0, > NULL, > NULL, > @@ -385,7 +421,7 @@ static int get_params_size( > for (i = 0; i < ps_count || is_count_bad; i++) { > const uint8_t *ps; > size_t ps_size; > - status = CMVideoFormatDescriptionGetH26 > 4ParameterSetAtIndex(vid_fmt, > + status = vtctx->get_param_set_func(vid_fmt, > i, > &ps, > > &ps_size, > @@ -419,13 +455,14 @@ static int copy_param_sets( > uint8_t *dst, > size_t dst_size) > { > + VTEncContext *vtctx = avctx->priv_data; > size_t ps_count; > int is_count_bad = 0; > int status; > size_t offset = 0; > size_t i; > > - status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(vid_fmt, > + status = vtctx->get_param_set_func(vid_fmt, > 0, > NULL, > NULL, > @@ -443,7 +480,7 @@ static int copy_param_sets( > size_t ps_size; > size_t next_offset; > > - status = CMVideoFormatDescriptionGetH26 > 4ParameterSetAtIndex(vid_fmt, > + status = vtctx->get_param_set_func(vid_fmt, > i, > &ps, > > &ps_size, > @@ -548,6 +585,7 @@ static int get_length_code_size( > CMSampleBufferRef sample_buffer, > size_t *size) > { > + VTEncContext *vtctx = avctx->priv_data; > CMVideoFormatDescriptionRef vid_fmt; > int isize; > int status; > @@ -558,7 +596,7 @@ static int get_length_code_size( > return AVERROR_EXTERNAL; > } > > - status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(vid_fmt, > + status = vtctx->get_param_set_func(vid_fmt, > 0, > NULL, > NULL, > @@ -579,8 +617,8 @@ static int get_length_code_size( > * If profile_level_val is NULL and this method returns true, don't > specify the > * profile/level to the encoder. > */ > -static bool get_vt_profile_level(AVCodecContext *avctx, > - CFStringRef *profile_level_val) > +static bool get_vt_h264_profile_level(AVCodecContext *avctx, > + CFStringRef *profile_level_val) > { > VTEncContext *vtctx = avctx->priv_data; > int64_t profile = vtctx->profile; > @@ -670,6 +708,41 @@ static bool get_vt_profile_level(AVCodecContext > *avctx, > return true; > } > > +/* > + * Returns true on success. > + * > + * If profile_level_val is NULL and this method returns true, don't > specify the > + * profile/level to the encoder. > + */ > +static bool get_vt_hevc_profile_level(AVCodecContext *avctx, > + CFStringRef *profile_level_val) > +{ > + VTEncContext *vtctx = avctx->priv_data; > + int64_t profile = vtctx->profile; > + > + *profile_level_val = NULL; > + > + switch (profile) { > + case HEVC_PROF_AUTO: > + return true; > + case HEVC_PROF_MAIN: > + *profile_level_val = > + compat_keys.kVTProfileLevel_HEVC_Main_AutoLevel; > + break; > + case HEVC_PROF_MAIN10: > + *profile_level_val = > + compat_keys.kVTProfileLevel_HEVC_Main10_AutoLevel; > + break; > + } > + > + if (!*profile_level_val) { > + av_log(avctx, AV_LOG_ERROR, "Invalid Profile/Level.\n"); > + return false; > + } > + > + return true; > +} > + > static int get_cv_pixel_format(AVCodecContext* avctx, > enum AVPixelFormat fmt, > enum AVColorRange range, > @@ -944,6 +1017,8 @@ static int vtenc_create_encoder(AVCodecContext > *avctx, > return AVERROR_EXTERNAL; > } > > + if (vtctx->codec_id == AV_CODEC_ID_H264) { > + // kVTCompressionPropertyKey_DataRateLimits is not available for HEVC > bytes_per_second_value = max_rate >> 3; > bytes_per_second = CFNumberCreate(kCFAllocatorDefault, > kCFNumberSInt64Type, > @@ -959,10 +1034,10 @@ static int vtenc_create_encoder(AVCodecContext > *avctx, > CFRelease(bytes_per_second); > return AVERROR(ENOMEM); > } > - nums[0] = bytes_per_second; > - nums[1] = one_second; > + nums[0] = (void *)bytes_per_second; > + nums[1] = (void *)one_second; > data_rate_limits = CFArrayCreate(kCFAllocatorDefault, > - nums, > + (const void **)nums, > 2, > &kCFTypeArrayCallBacks); > > @@ -992,6 +1067,7 @@ static int vtenc_create_encoder(AVCodecContext > *avctx, > av_log(avctx, AV_LOG_ERROR, "Error setting profile/level > property: %d\n", status); > } > } > + } > > if (avctx->gop_size > 0) { > CFNumberRef interval = CFNumberCreate(kCFAllocatorDefault, > @@ -1205,6 +1281,11 @@ static av_cold int vtenc_init(AVCodecContext *avctx) > return AVERROR(EINVAL); > } > > + vtctx->codec_id = avctx->codec_id; > + > + if (vtctx->codec_id == AV_CODEC_ID_H264) { > + vtctx->get_param_set_func = CMVideoFormatDescriptionGetH26 > 4ParameterSetAtIndex; > + > vtctx->has_b_frames = avctx->max_b_frames > 0; > if(vtctx->has_b_frames && vtctx->profile == H264_PROF_BASELINE){ > av_log(avctx, AV_LOG_WARNING, "Cannot use B-frames with baseline > profile. Output will not contain B-frames.\n"); > @@ -1216,7 +1297,11 @@ static av_cold int vtenc_init(AVCodecContext *avctx) > vtctx->entropy = VT_ENTROPY_NOT_SET; > } > > - if (!get_vt_profile_level(avctx, &profile_level)) return > AVERROR(EINVAL); > + if (!get_vt_h264_profile_level(avctx, &profile_level)) return > AVERROR(EINVAL); > + } else { > + vtctx->get_param_set_func = compat_keys. > CMVideoFormatDescriptionGetHEVCParameterSetAtIndex; > + if (!get_vt_hevc_profile_level(avctx, &profile_level)) return > AVERROR(EINVAL); > + } > > vtctx->session = NULL; > > @@ -2426,7 +2511,7 @@ static const enum AVPixelFormat pix_fmts[] = { > > #define OFFSET(x) offsetof(VTEncContext, x) > #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM > -static const AVOption options[] = { > +static const AVOption h264_options[] = { > { "profile", "Profile", OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = > H264_PROF_AUTO }, H264_PROF_AUTO, H264_PROF_COUNT, VE, "profile" }, > { "baseline", "Baseline Profile", 0, AV_OPT_TYPE_CONST, { .i64 = > H264_PROF_BASELINE }, INT_MIN, INT_MAX, VE, "profile" }, > { "main", "Main Profile", 0, AV_OPT_TYPE_CONST, { .i64 = > H264_PROF_MAIN }, INT_MIN, INT_MAX, VE, "profile" }, > @@ -2469,7 +2554,7 @@ static const AVOption options[] = { > static const AVClass h264_videotoolbox_class = { > .class_name = "h264_videotoolbox", > .item_name = av_default_item_name, > - .option = options, > + .option = h264_options, > .version = LIBAVUTIL_VERSION_INT, > }; > > @@ -2488,3 +2573,45 @@ AVCodec ff_h264_videotoolbox_encoder = { > .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | > FF_CODEC_CAP_INIT_CLEANUP, > }; > + > +static const AVOption hevc_options[] = { > + { "profile", "Profile", OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = > HEVC_PROF_AUTO }, HEVC_PROF_AUTO, HEVC_PROF_COUNT, VE, "profile" }, > + { "main", "Main Profile", 0, AV_OPT_TYPE_CONST, { .i64 = > HEVC_PROF_MAIN }, INT_MIN, INT_MAX, VE, "profile" }, > + { "main10", "Main10 Profile", 0, AV_OPT_TYPE_CONST, { .i64 = > HEVC_PROF_MAIN10 }, INT_MIN, INT_MAX, VE, "profile" }, > + > + { "allow_sw", "Allow software encoding", OFFSET(allow_sw), > AV_OPT_TYPE_BOOL, > + { .i64 = 0 }, 0, 1, VE }, > + > + { "realtime", "Hint that encoding should happen in real-time if not > faster (e.g. capturing from camera).", > + OFFSET(realtime), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, > + > + { "frames_before", "Other frames will come before the frames in this > session. This helps smooth concatenation issues.", > + OFFSET(frames_before), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, > + { "frames_after", "Other frames will come after the frames in this > session. This helps smooth concatenation issues.", > + OFFSET(frames_after), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, > + > + { NULL }, > +}; > + > +static const AVClass hevc_videotoolbox_class = { > + .class_name = "hevc_videotoolbox", > + .item_name = av_default_item_name, > + .option = hevc_options, > + .version = LIBAVUTIL_VERSION_INT, > +}; > + > +AVCodec ff_hevc_videotoolbox_encoder = { > + .name = "hevc_videotoolbox", > + .long_name = NULL_IF_CONFIG_SMALL("VideoToolbox H.265 > Encoder"), > + .type = AVMEDIA_TYPE_VIDEO, > + .id = AV_CODEC_ID_HEVC, > + .priv_data_size = sizeof(VTEncContext), > + .pix_fmts = pix_fmts, > + .init = vtenc_init, > + .encode2 = vtenc_frame, > + .close = vtenc_close, > + .capabilities = AV_CODEC_CAP_DELAY, > + .priv_class = &hevc_videotoolbox_class, > + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | > + FF_CODEC_CAP_INIT_CLEANUP, > +}; > Patchset applied with minor changes, after review from rcombs. Aman > -- > 2.14.2 > > _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel