From: Damiano Galassi Date: Thu, 15 Nov 2018 12:56:16 +0000 (+0100) Subject: Add VideoToolbox hardware encoding thru FFmpeg. X-Git-Tag: 1.2.0~66 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5c127e80911b92a8a47b08a51e8dfb52e67fc206;p=handbrake Add VideoToolbox hardware encoding thru FFmpeg. --- diff --git a/contrib/ffmpeg/A04-videotoolbox.patch b/contrib/ffmpeg/A04-videotoolbox.patch new file mode 100644 index 000000000..387af0d66 --- /dev/null +++ b/contrib/ffmpeg/A04-videotoolbox.patch @@ -0,0 +1,27 @@ +diff --git a/libavcodec/videotoolboxenc.c b/libavcodec/videotoolboxenc.c +index 7796a68..e8b6245 100644 +--- a/libavcodec/videotoolboxenc.c ++++ b/libavcodec/videotoolboxenc.c +@@ -866,6 +866,14 @@ static int get_cv_color_primaries(AVCodecContext *avctx, + *primaries = NULL; + break; + ++ case AVCOL_PRI_BT470BG: ++ *primaries = kCVImageBufferColorPrimaries_EBU_3213; ++ break; ++ ++ case AVCOL_PRI_SMPTE170M: ++ *primaries = kCVImageBufferColorPrimaries_SMPTE_C; ++ break; ++ + case AVCOL_PRI_BT709: + *primaries = kCVImageBufferColorPrimaries_ITU_R_709_2; + break; +@@ -1302,6 +1310,7 @@ static av_cold int vtenc_init(AVCodecContext *avctx) + vtctx->get_param_set_func = compat_keys.CMVideoFormatDescriptionGetHEVCParameterSetAtIndex; + if (!vtctx->get_param_set_func) return AVERROR(EINVAL); + if (!get_vt_hevc_profile_level(avctx, &profile_level)) return AVERROR(EINVAL); ++ vtctx->has_b_frames = avctx->max_b_frames > 0; + } + + vtctx->session = NULL; diff --git a/contrib/ffmpeg/module.defs b/contrib/ffmpeg/module.defs index 87f236380..d2b41be0c 100644 --- a/contrib/ffmpeg/module.defs +++ b/contrib/ffmpeg/module.defs @@ -75,7 +75,10 @@ FFMPEG.CONFIGURE.extra += \ --enable-muxer=ipod ifeq (darwin,$(BUILD.system)) - FFMPEG.CONFIGURE.extra += --disable-audiotoolbox --disable-coreimage --disable-videotoolbox + FFMPEG.CONFIGURE.extra += --disable-audiotoolbox --disable-coreimage \ + --enable-encoder=h264_videotoolbox \ + --enable-encoder=hevc_videotoolbox + ifeq (x86_64,$(BUILD.arch)) FFMPEG.CONFIGURE.extra += --arch=x86_64 endif diff --git a/libhb/common.c b/libhb/common.c index 2d668f810..16085bb44 100644 --- a/libhb/common.c +++ b/libhb/common.c @@ -39,6 +39,10 @@ #include "vce_common.h" #endif +#ifdef __APPLE__ +#include "platform/macosx/vt_common.h" +#endif + static int mixdown_get_opus_coupled_stream_count(int mixdown); /********************************************************************** @@ -246,6 +250,7 @@ hb_encoder_internal_t hb_video_encoders[] = { { "H.264 (Intel QSV)", "qsv_h264", "H.264 (Intel Media SDK)", HB_VCODEC_QSV_H264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_H264, }, { { "H.264 (AMD VCE)", "vce_h264", "H.264 (AMD VCE)", HB_VCODEC_FFMPEG_VCE_H264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_H264, }, { { "H.264 (NVEnc)", "nvenc_h264", "H.264 (NVEnc)", HB_VCODEC_FFMPEG_NVENC_H264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_H264, }, + { { "H.264 (VideoToolbox)","vt_h264", "H.264 (libavcodec)", HB_VCODEC_FFMPEG_VT_H264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_H264, }, { { "H.265 (x265)", "x265", "H.265 (libx265)", HB_VCODEC_X265_8BIT, HB_MUX_AV_MP4|HB_MUX_AV_MKV, }, NULL, 1, HB_GID_VCODEC_H265, }, { { "H.265 10-bit (x265)", "x265_10bit", "H.265 10-bit (libx265)", HB_VCODEC_X265_10BIT, HB_MUX_AV_MP4|HB_MUX_AV_MKV, }, NULL, 1, HB_GID_VCODEC_H265, }, { { "H.265 12-bit (x265)", "x265_12bit", "H.265 12-bit (libx265)", HB_VCODEC_X265_12BIT, HB_MUX_AV_MP4|HB_MUX_AV_MKV, }, NULL, 1, HB_GID_VCODEC_H265, }, @@ -254,6 +259,7 @@ hb_encoder_internal_t hb_video_encoders[] = { { "H.265 10-bit (Intel QSV)","qsv_h265_10bit", "H.265 10-bit (Intel Media SDK)", HB_VCODEC_QSV_H265_10BIT, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_H265, }, { { "H.265 (AMD VCE)", "vce_h265", "H.265 (AMD VCE)", HB_VCODEC_FFMPEG_VCE_H265, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_H265, }, { { "H.265 (NVEnc)", "nvenc_h265", "H.265 (NVEnc)", HB_VCODEC_FFMPEG_NVENC_H265, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_H265, }, + { { "H.265 (VideoToolbox)","vt_h265", "H.265 (libavcodec)", HB_VCODEC_FFMPEG_VT_H265, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_H265, }, { { "MPEG-4", "mpeg4", "MPEG-4 (libavcodec)", HB_VCODEC_FFMPEG_MPEG4, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_MPEG4, }, { { "MPEG-2", "mpeg2", "MPEG-2 (libavcodec)", HB_VCODEC_FFMPEG_MPEG2, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_MPEG2, }, { { "VP8", "VP8", "VP8 (libvpx)", HB_VCODEC_FFMPEG_VP8, HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_VP8, }, @@ -293,6 +299,13 @@ static int hb_video_encoder_is_enabled(int encoder) return hb_nvenc_h265_available(); #endif +#ifdef __APPLE__ + case HB_VCODEC_FFMPEG_VT_H264: + return hb_vt_h264_is_available(); + case HB_VCODEC_FFMPEG_VT_H265: + return hb_vt_h265_is_available(); +#endif + #ifdef USE_X265 case HB_VCODEC_X265_8BIT: case HB_VCODEC_X265_10BIT: @@ -1365,6 +1378,14 @@ void hb_video_quality_get_limits(uint32_t codec, float *low, float *high, *high = 63.; break; + case HB_VCODEC_FFMPEG_VT_H264: + case HB_VCODEC_FFMPEG_VT_H265: + *direction = 1; + *granularity = 0.1; + *low = 0.; + *high = 0.; + break; + case HB_VCODEC_FFMPEG_MPEG2: case HB_VCODEC_FFMPEG_MPEG4: default: @@ -1511,6 +1532,8 @@ const char* const* hb_video_encoder_get_profiles(int encoder) case HB_VCODEC_FFMPEG_NVENC_H264: case HB_VCODEC_FFMPEG_NVENC_H265: + case HB_VCODEC_FFMPEG_VT_H264: + case HB_VCODEC_FFMPEG_VT_H265: return hb_av_profile_get_names(encoder); default: return NULL; @@ -1531,6 +1554,7 @@ const char* const* hb_video_encoder_get_levels(int encoder) case HB_VCODEC_X264_8BIT: case HB_VCODEC_X264_10BIT: case HB_VCODEC_FFMPEG_NVENC_H264: + case HB_VCODEC_FFMPEG_VT_H264: return hb_h264_level_names; #ifdef USE_VCE @@ -1546,6 +1570,11 @@ const char* const* hb_video_encoder_get_levels(int encoder) case HB_VCODEC_FFMPEG_VCE_H265: return hb_h265_level_names; +#ifdef __APPLE__ + case HB_VCODEC_FFMPEG_VT_H265: + return hb_vt_h265_level_names; +#endif + default: return NULL; } diff --git a/libhb/common.h b/libhb/common.h index 25b2bab99..a3dca1e59 100644 --- a/libhb/common.h +++ b/libhb/common.h @@ -512,7 +512,9 @@ struct hb_job_s #define HB_VCODEC_FFMPEG_VCE_H265 0x00080000 #define HB_VCODEC_FFMPEG_NVENC_H264 0x00100000 #define HB_VCODEC_FFMPEG_NVENC_H265 0x00200000 -#define HB_VCODEC_FFMPEG_MASK (0x00000F0|HB_VCODEC_FFMPEG_VCE_H264|HB_VCODEC_FFMPEG_VCE_H265|HB_VCODEC_FFMPEG_NVENC_H264|HB_VCODEC_FFMPEG_NVENC_H265) +#define HB_VCODEC_FFMPEG_VT_H264 0x00400000 +#define HB_VCODEC_FFMPEG_VT_H265 0x00800000 +#define HB_VCODEC_FFMPEG_MASK (0x00000F0|HB_VCODEC_FFMPEG_VCE_H264|HB_VCODEC_FFMPEG_VCE_H265|HB_VCODEC_FFMPEG_NVENC_H264|HB_VCODEC_FFMPEG_NVENC_H265|HB_VCODEC_FFMPEG_VT_H264|HB_VCODEC_FFMPEG_VT_H265) #define HB_VCODEC_QSV_H264 0x0000100 #define HB_VCODEC_QSV_H265_8BIT 0x0000200 #define HB_VCODEC_QSV_H265_10BIT 0x0000400 @@ -523,14 +525,14 @@ struct hb_job_s #define HB_VCODEC_X264 HB_VCODEC_X264_8BIT #define HB_VCODEC_X264_10BIT 0x0020000 #define HB_VCODEC_X264_MASK 0x0030000 -#define HB_VCODEC_H264_MASK (HB_VCODEC_X264_MASK|HB_VCODEC_QSV_H264|HB_VCODEC_FFMPEG_VCE_H264|HB_VCODEC_FFMPEG_NVENC_H264) +#define HB_VCODEC_H264_MASK (HB_VCODEC_X264_MASK|HB_VCODEC_QSV_H264|HB_VCODEC_FFMPEG_VCE_H264|HB_VCODEC_FFMPEG_NVENC_H264|HB_VCODEC_FFMPEG_VT_H264) #define HB_VCODEC_X265_8BIT 0x0001000 #define HB_VCODEC_X265 HB_VCODEC_X265_8BIT #define HB_VCODEC_X265_10BIT 0x0002000 #define HB_VCODEC_X265_12BIT 0x0004000 #define HB_VCODEC_X265_16BIT 0x0008000 #define HB_VCODEC_X265_MASK 0x000F000 -#define HB_VCODEC_H265_MASK (HB_VCODEC_X265_MASK|HB_VCODEC_QSV_H265_MASK|HB_VCODEC_FFMPEG_VCE_H265|HB_VCODEC_FFMPEG_NVENC_H265) +#define HB_VCODEC_H265_MASK (HB_VCODEC_X265_MASK|HB_VCODEC_QSV_H265_MASK|HB_VCODEC_FFMPEG_VCE_H265|HB_VCODEC_FFMPEG_NVENC_H265|HB_VCODEC_FFMPEG_VT_H265) /* define an invalid CQ value compatible with all CQ-capable codecs */ #define HB_INVALID_VIDEO_QUALITY (-1000.) diff --git a/libhb/encavcodec.c b/libhb/encavcodec.c index dc94310c6..159421533 100644 --- a/libhb/encavcodec.c +++ b/libhb/encavcodec.c @@ -83,6 +83,20 @@ static const char * const h265_nvenc_profile_names[] = "auto", "main", NULL // "main10", "rext" We do not currently support 10bit encodes with this encoder. }; +static const char * const h26x_vt_preset_name[] = +{ + "default", NULL +}; + +static const char * const h264_vt_profile_name[] = +{ + "auto", "baseline", "main", "high", NULL +}; + +static const char * const h265_vt_profile_name[] = +{ + "auto", "main", "main10", NULL +}; int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) { @@ -136,6 +150,10 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) hb_log("encavcodecInit: H.264 (AMD VCE)"); codec = avcodec_find_encoder_by_name("h264_amf"); break; + case HB_VCODEC_FFMPEG_VT_H264: + hb_log("encavcodecInit: H.264 (VideoToolbox)"); + codec = avcodec_find_encoder_by_name("h264_videotoolbox"); + break; } }break; case AV_CODEC_ID_HEVC: @@ -149,6 +167,10 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) hb_log("encavcodecInit: H.265 (AMD VCE)"); codec = avcodec_find_encoder_by_name("hevc_amf"); break; + case HB_VCODEC_FFMPEG_VT_H265: + hb_log("encavcodecInit: H.265 (VideoToolbox)"); + codec = avcodec_find_encoder_by_name("hevc_videotoolbox"); + break; } }break; default: @@ -406,6 +428,47 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) context->flags |= AV_CODEC_FLAG_GRAY; } + if (job->vcodec == HB_VCODEC_FFMPEG_VT_H264) + { + // Set profile and level + if (job->encoder_profile != NULL && *job->encoder_profile) + { + if (!strcasecmp(job->encoder_profile, "baseline")) + av_dict_set(&av_opts, "profile", "baseline", 0); + else if (!strcasecmp(job->encoder_profile, "main")) + av_dict_set(&av_opts, "profile", "main", 0); + else if (!strcasecmp(job->encoder_profile, "high")) + av_dict_set(&av_opts, "profile", "high", 0); + } + + if (job->encoder_level != NULL && *job->encoder_level) + { + int i = 1; + while (hb_h264_level_names[i] != NULL) + { + if (!strcasecmp(job->encoder_level, hb_h264_level_names[i])) + av_dict_set(&av_opts, "level", job->encoder_level, 0); + ++i; + } + } + + context->max_b_frames = 16; + } + + if (job->vcodec == HB_VCODEC_FFMPEG_VT_H265) + { + // Set profile and level + if (job->encoder_profile != NULL && *job->encoder_profile) + { + if (!strcasecmp(job->encoder_profile, "main")) + av_dict_set(&av_opts, "profile", "main", 0); + else if (!strcasecmp(job->encoder_profile, "main10")) + av_dict_set(&av_opts, "profile", "main10", 0); + } + + context->max_b_frames = 16; + } + if (job->vcodec == HB_VCODEC_FFMPEG_VCE_H264) { // Set profile and level @@ -935,6 +998,10 @@ const char* const* hb_av_preset_get_names(int encoder) case HB_VCODEC_FFMPEG_NVENC_H265: return h26x_nvenc_preset_names; + case HB_VCODEC_FFMPEG_VT_H264: + case HB_VCODEC_FFMPEG_VT_H265: + return h26x_vt_preset_name; + default: return NULL; } @@ -948,6 +1015,10 @@ const char* const* hb_av_profile_get_names(int encoder) return h264_nvenc_profile_names; case HB_VCODEC_FFMPEG_NVENC_H265: return h265_nvenc_profile_names; + case HB_VCODEC_FFMPEG_VT_H264: + return h264_vt_profile_name; + case HB_VCODEC_FFMPEG_VT_H265: + return h265_vt_profile_name; default: return NULL; diff --git a/libhb/muxavformat.c b/libhb/muxavformat.c index 5f2d7fe87..9f15f52c1 100644 --- a/libhb/muxavformat.c +++ b/libhb/muxavformat.c @@ -252,6 +252,7 @@ static int avformatInit( hb_mux_object_t * m ) case HB_VCODEC_FFMPEG_VCE_H264: case HB_VCODEC_FFMPEG_NVENC_H264: + case HB_VCODEC_FFMPEG_VT_H264: track->st->codecpar->codec_id = AV_CODEC_ID_H264; if (job->mux == HB_MUX_AV_MP4 && job->inline_parameter_sets) { @@ -387,6 +388,7 @@ static int avformatInit( hb_mux_object_t * m ) case HB_VCODEC_FFMPEG_VCE_H265: case HB_VCODEC_FFMPEG_NVENC_H265: + case HB_VCODEC_FFMPEG_VT_H265: track->st->codecpar->codec_id = AV_CODEC_ID_HEVC; if (job->mux == HB_MUX_AV_MP4 && job->inline_parameter_sets) { diff --git a/libhb/platform/macosx/vt_common.c b/libhb/platform/macosx/vt_common.c new file mode 100644 index 000000000..be75018ea --- /dev/null +++ b/libhb/platform/macosx/vt_common.c @@ -0,0 +1,63 @@ +/* vt_common.c + + Copyright (c) 2003-2018 HandBrake Team + This file is part of the HandBrake source code + Homepage: . + It may be used under the terms of the GNU General Public License v2. + For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html + */ + +#include "hb.h" +#include "vt_common.h" + +#include +#include +#include + +//#define VT_STATS + +#ifdef VT_STATS +static void toggle_vt_gva_stats(bool state) +{ + CFPropertyListRef cf_state = state ? kCFBooleanTrue : kCFBooleanFalse; + CFPreferencesSetValue(CFSTR("gvaEncoderPerf"), cf_state, CFSTR("com.apple.GVAEncoder"), kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); + CFPreferencesSetValue(CFSTR("gvaEncoderPSNR"), cf_state, CFSTR("com.apple.GVAEncoder"), kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); + CFPreferencesSetValue(CFSTR("gvaEncoderSSIM"), cf_state, CFSTR("com.apple.GVAEncoder"), kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); + + //CFPreferencesSetValue(CFSTR("gvaEncoderStats"), cf_state, CFSTR("com.apple.GVAEncoder"), kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); + //CFPreferencesSetValue(CFSTR("gvaDebug"), cf_state, CFSTR("com.apple.AppleGVA"), kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); +} +#endif + +static const CFStringRef encoder_id_h264 = CFSTR("com.apple.videotoolbox.videoencoder.h264.gva"); +static const CFStringRef encoder_id_h265 = CFSTR("com.apple.videotoolbox.videoencoder.hevc.gva"); + +int encvt_available(CFStringRef encoder) +{ + CFArrayRef encoder_list; + VTCopyVideoEncoderList(NULL, &encoder_list); + CFIndex size = CFArrayGetCount(encoder_list); + + for (CFIndex i = 0; i < size; i++ ) + { + CFDictionaryRef encoder_dict = CFArrayGetValueAtIndex(encoder_list, i); + CFStringRef encoder_id = CFDictionaryGetValue(encoder_dict, kVTVideoEncoderSpecification_EncoderID); + if (CFEqual(encoder_id, encoder)) + { + CFRelease(encoder_list); + return 1; + } + } + CFRelease(encoder_list); + return 0; +} + +int hb_vt_h264_is_available() +{ + return encvt_available(encoder_id_h264); +} + +int hb_vt_h265_is_available() +{ + return encvt_available(encoder_id_h265); +} diff --git a/libhb/platform/macosx/vt_common.h b/libhb/platform/macosx/vt_common.h new file mode 100644 index 000000000..22187d0cc --- /dev/null +++ b/libhb/platform/macosx/vt_common.h @@ -0,0 +1,16 @@ +/* vt_common.h + + Copyright (c) 2003-2018 HandBrake Team + This file is part of the HandBrake source code + Homepage: . + It may be used under the terms of the GNU General Public License v2. + For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html + */ + +int hb_vt_h264_is_available(); +int hb_vt_h265_is_available(); + +static const char * const hb_vt_h265_level_names[] = +{ + "auto", NULL, +}; diff --git a/libhb/work.c b/libhb/work.c index 9a3eb55a7..350af0cc7 100644 --- a/libhb/work.c +++ b/libhb/work.c @@ -284,6 +284,16 @@ hb_work_object_t* hb_video_encoder(hb_handle_t *h, int vcodec) w->codec_param = AV_CODEC_ID_HEVC; break; #endif +#ifdef __APPLE__ + case HB_VCODEC_FFMPEG_VT_H264: + w = hb_get_work(h, WORK_ENCAVCODEC); + w->codec_param = AV_CODEC_ID_H264; + break; + case HB_VCODEC_FFMPEG_VT_H265: + w = hb_get_work(h, WORK_ENCAVCODEC); + w->codec_param = AV_CODEC_ID_HEVC; + break; +#endif default: hb_error("Unknown video codec (0x%x)", vcodec ); diff --git a/macosx/Base.lproj/Video.xib b/macosx/Base.lproj/Video.xib index 8f69b26bb..8bd3cd262 100644 --- a/macosx/Base.lproj/Video.xib +++ b/macosx/Base.lproj/Video.xib @@ -86,6 +86,7 @@ + @@ -124,6 +125,14 @@ + + + + + + + + @@ -253,6 +262,14 @@ x264 is lossless at RF 0. NSIsNotNil + + + + + + + + HBQualityTransformer @@ -273,6 +290,7 @@ x264 is lossless at RF 0. + @@ -289,6 +307,14 @@ x264 is lossless at RF 0. + + + + + + + + NSIsNotNil diff --git a/macosx/HBVideo+UIAdditions.h b/macosx/HBVideo+UIAdditions.h index 5ce7648a7..236096916 100644 --- a/macosx/HBVideo+UIAdditions.h +++ b/macosx/HBVideo+UIAdditions.h @@ -21,6 +21,7 @@ @property (nonatomic, readonly) NSArray *levels; @property (nonatomic, readonly) BOOL fastDecodeSupported; +@property (nonatomic, readonly) BOOL twoPassSupported; @property (nonatomic, readonly) BOOL turboTwoPassSupported; @property (nonatomic, readonly) NSString *unparseOptions; @@ -29,6 +30,7 @@ @property (nonatomic, readonly) double qualityMinValue; @property (nonatomic, readonly) double qualityMaxValue; +@property (nonatomic, readonly) BOOL isConstantQualitySupported; @end diff --git a/macosx/HBVideo+UIAdditions.m b/macosx/HBVideo+UIAdditions.m index e23c1ab72..d7cbc0eda 100644 --- a/macosx/HBVideo+UIAdditions.m +++ b/macosx/HBVideo+UIAdditions.m @@ -104,6 +104,17 @@ (self.encoder & HB_VCODEC_X265_MASK)); } ++ (NSSet *)keyPathsForValuesAffectingTwoPassSupported +{ + return [NSSet setWithObjects:@"encoder", nil]; +} + +- (BOOL)twoPassSupported +{ + return !((self.encoder & HB_VCODEC_FFMPEG_VT_H264) || + (self.encoder & HB_VCODEC_FFMPEG_VT_H265)); +} + + (NSSet *)keyPathsForValuesAffectingConstantQualityLabel { return [NSSet setWithObjects:@"encoder", nil]; @@ -114,6 +125,16 @@ return @(hb_video_quality_get_name(self.encoder)); } ++ (NSSet *)keyPathsForValuesAffectingIsConstantQualitySupported +{ + return [NSSet setWithObjects:@"encoder", nil]; +} + +- (BOOL)isConstantQualitySupported +{ + return (self.qualityMaxValue == 0 && self.qualityMinValue == 0) == NO; +} + + (NSSet *)keyPathsForValuesAffectingUnparseOptions { return [NSSet setWithObjects:@"encoder", @"preset", @"tune", @"profile", @"level", diff --git a/macosx/HBVideo.m b/macosx/HBVideo.m index 15c2f67ae..1119aaa5c 100644 --- a/macosx/HBVideo.m +++ b/macosx/HBVideo.m @@ -105,6 +105,7 @@ NSString * const HBVideoChangedNotification = @"HBVideoChangedNotification"; if (!(self.undo.isUndoing || self.undo.isRedoing)) { + [self validateQualityType]; [self validatePresetsSettings]; [self validateVideoOptionExtra:previousEncoder]; } @@ -281,11 +282,42 @@ NSString * const HBVideoChangedNotification = @"HBVideoChangedNotification"; [self postChangedNotification]; } +- (void)validateQualityType +{ + if (self.qualityType != 0) + { + int direction; + float minValue, maxValue, granularity; + hb_video_quality_get_limits(self.encoder, + &minValue, &maxValue, &granularity, &direction); + + if (minValue == 0 && maxValue == 0) + { + self.qualityType = 0; + } + } + else + { + if ((self.encoder & HB_VCODEC_FFMPEG_VT_H264) || + (self.encoder & HB_VCODEC_FFMPEG_VT_H265)) + { + self.twoPass = NO; + } + } +} + - (void)validatePresetsSettings { NSArray *presets = self.presets; if (presets.count && ![presets containsObject:self.preset]) { - self.preset = presets[self.mediumPresetIndex]; + if (presets.count > self.mediumPresetIndex) + { + self.preset = presets[self.mediumPresetIndex]; + } + else + { + self.preset = presets.firstObject; + } } NSArray *tunes = self.tunes; diff --git a/macosx/HandBrake.xcodeproj/project.pbxproj b/macosx/HandBrake.xcodeproj/project.pbxproj index 586fcae64..f0ad8c6d2 100644 --- a/macosx/HandBrake.xcodeproj/project.pbxproj +++ b/macosx/HandBrake.xcodeproj/project.pbxproj @@ -225,6 +225,8 @@ A9906B2C1A710920001D82D5 /* HBQueueController.m in Sources */ = {isa = PBXBuildFile; fileRef = A9906B2B1A710920001D82D5 /* HBQueueController.m */; }; A99F40CF1B624E7E00750170 /* HBPictureViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A99F40CD1B624E7E00750170 /* HBPictureViewController.m */; }; A9A0CBE81CCEA3670045B3DF /* HBPlayerTrack.m in Sources */ = {isa = PBXBuildFile; fileRef = A9A0CBE61CCEA1D10045B3DF /* HBPlayerTrack.m */; }; + A9A25D9C21182741005A8A0F /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9A25D9B21182741005A8A0F /* CoreMedia.framework */; }; + A9A25D9D21182753005A8A0F /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9A25D9B21182741005A8A0F /* CoreMedia.framework */; }; A9A7E27C1FE2A0B5006BE79F /* HBPreviewViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A9A7E27A1FE2A0B5006BE79F /* HBPreviewViewController.m */; }; A9A96B8220CAD2C200A39AFB /* HBPictureHUDController.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9A96B8420CAD2C200A39AFB /* HBPictureHUDController.xib */; }; A9A96B8520CAD2CC00A39AFB /* HBEncodingProgressHUDController.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9A96B8720CAD2CC00A39AFB /* HBEncodingProgressHUDController.xib */; }; @@ -247,6 +249,9 @@ A9A96BDD20CAD66000A39AFB /* OutputPanel.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9A96BDB20CAD66000A39AFB /* OutputPanel.xib */; }; A9A96BE020CAD66500A39AFB /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9A96BDE20CAD66500A39AFB /* Preferences.xib */; }; A9A96BE320CAD6CD00A39AFB /* HBPreviewViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9A96BE120CAD6CD00A39AFB /* HBPreviewViewController.xib */; }; + A9AB9AA5211819A500BB3C7E /* VideoToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9AB9AA4211819A500BB3C7E /* VideoToolbox.framework */; }; + A9AB9AA621181CA900BB3C7E /* VideoToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9AB9AA4211819A500BB3C7E /* VideoToolbox.framework */; }; + A9AB9AA821181CC700BB3C7E /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9AB9AA721181CC700BB3C7E /* CoreVideo.framework */; }; A9ABD1A61E2A0F0700EC8B65 /* CoreText.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9ABD1A51E2A0F0700EC8B65 /* CoreText.framework */; }; A9ABD1A71E2A0F7500EC8B65 /* CoreText.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9ABD1A51E2A0F0700EC8B65 /* CoreText.framework */; }; A9ABD1A91E2A0F8200EC8B65 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9ABD1A81E2A0F8200EC8B65 /* CoreGraphics.framework */; }; @@ -579,6 +584,7 @@ A99F40CD1B624E7E00750170 /* HBPictureViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBPictureViewController.m; sourceTree = ""; }; A9A0CBE51CCEA1D10045B3DF /* HBPlayerTrack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBPlayerTrack.h; sourceTree = ""; }; A9A0CBE61CCEA1D10045B3DF /* HBPlayerTrack.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBPlayerTrack.m; sourceTree = ""; }; + A9A25D9B21182741005A8A0F /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; }; A9A7E2791FE2A0B5006BE79F /* HBPreviewViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HBPreviewViewController.h; sourceTree = ""; }; A9A7E27A1FE2A0B5006BE79F /* HBPreviewViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HBPreviewViewController.m; sourceTree = ""; }; A9A96B8320CAD2C200A39AFB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/HBPictureHUDController.xib; sourceTree = ""; }; @@ -610,6 +616,8 @@ A9AA447B1970724D00D7DEFC /* HBAdvancedController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HBAdvancedController.h; sourceTree = ""; }; A9AA447C1970726500D7DEFC /* HBQueueController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HBQueueController.h; sourceTree = ""; }; A9AA447D1970729300D7DEFC /* HBPreviewGenerator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HBPreviewGenerator.h; sourceTree = ""; }; + A9AB9AA4211819A500BB3C7E /* VideoToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VideoToolbox.framework; path = System/Library/Frameworks/VideoToolbox.framework; sourceTree = SDKROOT; }; + A9AB9AA721181CC700BB3C7E /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; }; A9ABD1A51E2A0F0700EC8B65 /* CoreText.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; }; A9ABD1A81E2A0F8200EC8B65 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; A9B34D74197696FE00871B7D /* DiskArbitration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DiskArbitration.framework; path = System/Library/Frameworks/DiskArbitration.framework; sourceTree = SDKROOT; }; @@ -676,6 +684,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + A9A25D9C21182741005A8A0F /* CoreMedia.framework in Frameworks */, + A9AB9AA821181CC700BB3C7E /* CoreVideo.framework in Frameworks */, + A9AB9AA621181CA900BB3C7E /* VideoToolbox.framework in Frameworks */, A9ABD1A91E2A0F8200EC8B65 /* CoreGraphics.framework in Frameworks */, A9ABD1A71E2A0F7500EC8B65 /* CoreText.framework in Frameworks */, A9E165521C523016003EF30E /* libavfilter.a in Frameworks */, @@ -731,6 +742,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + A9A25D9D21182753005A8A0F /* CoreMedia.framework in Frameworks */, + A9AB9AA5211819A500BB3C7E /* VideoToolbox.framework in Frameworks */, A9ABD1AA1E2A0F8F00EC8B65 /* CoreGraphics.framework in Frameworks */, A9ABD1A61E2A0F0700EC8B65 /* CoreText.framework in Frameworks */, A91119A31C7DD591001C463C /* IOKit.framework in Frameworks */, @@ -868,6 +881,9 @@ 273F203414ADBAC30021BE6D /* Frameworks */ = { isa = PBXGroup; children = ( + A9A25D9B21182741005A8A0F /* CoreMedia.framework */, + A9AB9AA721181CC700BB3C7E /* CoreVideo.framework */, + A9AB9AA4211819A500BB3C7E /* VideoToolbox.framework */, A9ABD1A81E2A0F8200EC8B65 /* CoreGraphics.framework */, A9ABD1A51E2A0F0700EC8B65 /* CoreText.framework */, A91CE2D31C7DABE40068F46F /* libiconv.tbd */, diff --git a/test/module.defs b/test/module.defs index eaa10ea69..92ae40c45 100644 --- a/test/module.defs +++ b/test/module.defs @@ -74,7 +74,7 @@ endif TEST.GCC.I += $(LIBHB.GCC.I) ifeq ($(BUILD.system),darwin) - TEST.GCC.f += IOKit CoreServices CoreText CoreGraphics AudioToolbox Foundation + TEST.GCC.f += IOKit CoreServices CoreText CoreGraphics AudioToolbox VideoToolbox CoreMedia CoreVideo Foundation TEST.GCC.l += iconv else ifeq ($(BUILD.system),linux) TEST.GCC.l += pthread dl m