summaryrefslogtreecommitdiffstats
path: root/libhb
diff options
context:
space:
mode:
authorDamiano Galassi <[email protected]>2018-11-15 13:56:16 +0100
committerDamiano Galassi <[email protected]>2018-11-15 13:56:16 +0100
commit5c127e80911b92a8a47b08a51e8dfb52e67fc206 (patch)
tree563ef7ebb98d787281f6d4196e6aad59724e78ab /libhb
parentba7d33db36abe423aadbd36e91bccdabf25709aa (diff)
Add VideoToolbox hardware encoding thru FFmpeg.
Diffstat (limited to 'libhb')
-rw-r--r--libhb/common.c29
-rw-r--r--libhb/common.h8
-rw-r--r--libhb/encavcodec.c71
-rw-r--r--libhb/muxavformat.c2
-rw-r--r--libhb/platform/macosx/vt_common.c63
-rw-r--r--libhb/platform/macosx/vt_common.h16
-rw-r--r--libhb/work.c10
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 );