diff options
author | Damiano Galassi <[email protected]> | 2018-11-15 13:56:16 +0100 |
---|---|---|
committer | Damiano Galassi <[email protected]> | 2018-11-15 13:56:16 +0100 |
commit | 5c127e80911b92a8a47b08a51e8dfb52e67fc206 (patch) | |
tree | 563ef7ebb98d787281f6d4196e6aad59724e78ab /libhb | |
parent | ba7d33db36abe423aadbd36e91bccdabf25709aa (diff) |
Add VideoToolbox hardware encoding thru FFmpeg.
Diffstat (limited to 'libhb')
-rw-r--r-- | libhb/common.c | 29 | ||||
-rw-r--r-- | libhb/common.h | 8 | ||||
-rw-r--r-- | libhb/encavcodec.c | 71 | ||||
-rw-r--r-- | libhb/muxavformat.c | 2 | ||||
-rw-r--r-- | libhb/platform/macosx/vt_common.c | 63 | ||||
-rw-r--r-- | libhb/platform/macosx/vt_common.h | 16 | ||||
-rw-r--r-- | libhb/work.c | 10 |
7 files changed, 196 insertions, 3 deletions
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: <http://handbrake.fr/>. + 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 <VideoToolbox/VideoToolbox.h> +#include <CoreMedia/CoreMedia.h> +#include <CoreVideo/CoreVideo.h> + +//#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: <http://handbrake.fr/>. + 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 ); |