New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for AMD VCE Encoder. #88

Closed
wants to merge 1 commit into
base: master
from
Jump to file or symbol
Failed to load files and symbols.
+1,684 −41
Diff settings

Always

Just for now

View

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -43,6 +43,7 @@ FFMPEG.CONFIGURE.extra = \
--enable-encoder=mpeg2video \
--enable-encoder=mpeg4 \
--enable-encoder=libmp3lame \
--enable-encoder=h264_vce \
--enable-libvpx \
--enable-encoder=libvpx_vp8 \
--disable-decoder=libvpx_vp8 \
View
@@ -233,6 +233,7 @@ hb_encoder_internal_t hb_video_encoders[] =
{ { "H.264 (x264)", "x264", "H.264 (libx264)", HB_VCODEC_X264_8BIT, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_H264, },
{ { "H.264 10-bit (x264)", "x264_10bit", "H.264 10-bit (libx264)", HB_VCODEC_X264_10BIT, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_H264, },
{ { "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 (libavcodec)", HB_VCODEC_VCE_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, },
@@ -261,6 +262,7 @@ static int hb_video_encoder_is_enabled(int encoder)
case HB_VCODEC_FFMPEG_MPEG2:
case HB_VCODEC_FFMPEG_VP8:
case HB_VCODEC_FFMPEG_VP9:
case HB_VCODEC_VCE_H264:
return 1;
#ifdef USE_X265
@@ -1350,6 +1352,8 @@ const char* const* hb_video_encoder_get_presets(int encoder)
case HB_VCODEC_X265_16BIT:
return x265_preset_names;
#endif
case HB_VCODEC_VCE_H264:
return hb_vce_preset_names;
default:
return NULL;
}
@@ -1400,6 +1404,9 @@ const char* const* hb_video_encoder_get_profiles(int encoder)
case HB_VCODEC_X265_16BIT:
return hb_h265_profile_names_16bit;
case HB_VCODEC_VCE_H264:
return hb_h264_profile_names_8bit;
default:
return NULL;
}
@@ -1418,6 +1425,7 @@ const char* const* hb_video_encoder_get_levels(int encoder)
{
case HB_VCODEC_X264_8BIT:
case HB_VCODEC_X264_10BIT:
case HB_VCODEC_VCE_H264:
return hb_h264_level_names;
default:
View
@@ -495,6 +495,7 @@ struct hb_job_s
#define HB_VCODEC_FFMPEG_MPEG2 0x0000020
#define HB_VCODEC_FFMPEG_VP8 0x0000040
#define HB_VCODEC_FFMPEG_VP9 0x0000080
#define HB_VCODEC_VCE_H264 0x0000160
#define HB_VCODEC_FFMPEG_MASK 0x00000F0
#define HB_VCODEC_QSV_H264 0x0000100
#define HB_VCODEC_QSV_H265 0x0000200
@@ -503,7 +504,7 @@ 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)
#define HB_VCODEC_H264_MASK (HB_VCODEC_X264|HB_VCODEC_QSV_H264|HB_VCODEC_VCE_H264)
#define HB_VCODEC_X265_8BIT 0x0001000
#define HB_VCODEC_X265 HB_VCODEC_X265_8BIT
#define HB_VCODEC_X265_10BIT 0x0002000
View
@@ -10,6 +10,7 @@
#include "hb.h"
#include "hb_dict.h"
#include "hbffmpeg.h"
#include "h264_common.h"
/*
* The frame info struct remembers information about each frame across calls
@@ -83,41 +84,45 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
int clock_min, clock_max, clock;
hb_video_framerate_get_limits(&clock_min, &clock_max, &clock);
switch ( w->codec_param )
{
case AV_CODEC_ID_MPEG4:
{
hb_log("encavcodecInit: MPEG-4 ASP encoder");
} break;
case AV_CODEC_ID_MPEG2VIDEO:
{
hb_log("encavcodecInit: MPEG-2 encoder");
} break;
case AV_CODEC_ID_VP8:
{
hb_log("encavcodecInit: VP8 encoder");
} break;
case AV_CODEC_ID_VP9:
{
hb_log("encavcodecInit: VP9 encoder");
} break;
default:
{
hb_error("encavcodecInit: unsupported encoder!");
ret = 1;
goto done;
}
}
codec = avcodec_find_encoder( w->codec_param );
if( !codec )
switch (w->codec_param)
{
case AV_CODEC_ID_MPEG4:
{
hb_log("encavcodecInit: MPEG-4 ASP encoder");
} break;
case AV_CODEC_ID_MPEG2VIDEO:
{
hb_log("encavcodecInit: MPEG-2 encoder");
} break;
case AV_CODEC_ID_VP8:
{
hb_log("encavcodecInit: VP8 encoder");
} break;
case AV_CODEC_ID_VP9:
{
hb_log("encavcodecInit: VP9 encoder");
} break;
case AV_CODEC_ID_H264:
{
hb_log("encavcodecInit: AMD VCE H.264 encoder");
} break;
default:
{
hb_error("encavcodecInit: unsupported encoder!");
ret = 1;
goto done;
}
}
codec = avcodec_find_encoder(w->codec_param);
if (codec == NULL)
{
hb_log( "encavcodecInit: avcodec_find_encoder "
"failed" );
ret = 1;
goto done;
}
context = avcodec_alloc_context3( codec );
context = avcodec_alloc_context3(codec);
// Set things in context that we will allow the user to
// override with advanced settings.
@@ -176,6 +181,21 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
context->gop_size = ((double)job->orig_vrate.num / job->orig_vrate.den +
0.5) * 10;
if (job->vcodec == HB_VCODEC_VCE_H264)
{
// Set profile and level
context->profile = FF_PROFILE_UNKNOWN;
if (job->encoder_preset != NULL && *job->encoder_preset)
{
if ((!strcasecmp(job->encoder_preset, "balanced"))
|| (!strcasecmp(job->encoder_preset, "speed"))
|| (!strcasecmp(job->encoder_preset, "quality")))
{
av_opt_set(context, "preset", job->encoder_preset, AV_OPT_SEARCH_CHILDREN);
}
}
}
/* place job->encoder_options in an hb_dict_t for convenience */
hb_dict_t * lavc_opts = NULL;
if (job->encoder_options != NULL && *job->encoder_options)
@@ -285,6 +305,32 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
context->flags |= CODEC_FLAG_GRAY;
}
if (job->vcodec == HB_VCODEC_VCE_H264)
{
// Set profile and level
context->profile = FF_PROFILE_UNKNOWN;
if (job->encoder_profile != NULL && *job->encoder_profile)
{
if (!strcasecmp(job->encoder_profile, "baseline"))
context->profile = FF_PROFILE_H264_BASELINE;
else if (!strcasecmp(job->encoder_profile, "main"))
context->profile = FF_PROFILE_H264_MAIN;
else if (!strcasecmp(job->encoder_profile, "high"))
context->profile = FF_PROFILE_H264_HIGH;
}
context->level = FF_LEVEL_UNKNOWN;
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]))
context->level = hb_h264_level_values[i];
++i;
}
}
}
if( job->pass_id == HB_PASS_ENCODE_1ST ||
job->pass_id == HB_PASS_ENCODE_2ND )
{
@@ -349,6 +395,7 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
if (hb_avcodec_open(context, codec, &av_opts, HB_FFMPEG_THREADS_AUTO))
{
hb_log( "encavcodecInit: avcodec_open failed" );
return 1;
}
// avcodec_open populates the opts dictionary with the
// things it didn't recognize.
@@ -366,11 +413,51 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
{
job->areBframes = 1;
}
if( ( job->mux & HB_MUX_MASK_MP4 ) && job->pass_id != HB_PASS_ENCODE_1ST )
{
w->config->mpeg4.length = context->extradata_size;
memcpy( w->config->mpeg4.bytes, context->extradata,
context->extradata_size );
if (w->codec_param == AV_CODEC_ID_H264)
{
// Scan extradata for the loacation on the SPS/PPS headers
unsigned char header[4] = { 0x00, 0x00, 0x00, 0x01 };
int headerCount = 0;
int headerPositions[80];
int ppsPos = -1;
int spsPos = -1;
int i;
unsigned char *data = context->extradata;
for (i = 0; i + 4 < context->extradata_size; ++i)
{
if (data[i + 0] == header[0] && data[i + 1] == header[1] && data[i + 2] == header[2] && data[i + 3] == header[3])
{
if ((data[i + 4] & 0x1f) == 7)
spsPos = headerCount;
if ((data[i + 4] & 0x1f) == 8)
ppsPos = headerCount;
headerPositions[headerCount] = i;
++headerCount;
}
}
headerPositions[headerCount] = context->extradata_size;
if (spsPos >= 0)
{
// SPS found, copy into work object
w->config->h264.sps_length = headerPositions[spsPos + 1] - headerPositions[spsPos] - 4;
memcpy(w->config->h264.sps, &data[headerPositions[spsPos] + 4], w->config->h264.sps_length);
}
if (ppsPos >= 0)
{
// PPS found, copy into work object
w->config->h264.pps_length = headerPositions[ppsPos + 1] - headerPositions[ppsPos] - 4;
memcpy(w->config->h264.pps, &data[headerPositions[ppsPos] + 4], w->config->h264.pps_length);
}
}
else
{
w->config->mpeg4.length = context->extradata_size;
memcpy( w->config->mpeg4.bytes, context->extradata,
context->extradata_size );
}
}
done:
View
@@ -7,6 +7,9 @@
For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html
*/
#ifndef HB_FFMPEG_H
#define HB_FFMPEG_H
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/channel_layout.h"
@@ -33,3 +36,7 @@ struct SwsContext*
hb_sws_get_context(int srcW, int srcH, enum AVPixelFormat srcFormat,
int dstW, int dstH, enum AVPixelFormat dstFormat,
int flags);
static const char* const hb_vce_preset_names[] = { "speed", "balanced", "quality", NULL, };
#endif
View
@@ -217,6 +217,7 @@ static int avformatInit( hb_mux_object_t * m )
case HB_VCODEC_X264_8BIT:
case HB_VCODEC_X264_10BIT:
case HB_VCODEC_QSV_H264:
case HB_VCODEC_VCE_H264:
track->st->codec->codec_id = AV_CODEC_ID_H264;
/* Taken from x264 muxers.c */
View
@@ -218,6 +218,10 @@ hb_work_object_t* hb_video_encoder(hb_handle_t *h, int vcodec)
case HB_VCODEC_FFMPEG_VP9:
w = hb_get_work(h, WORK_ENCAVCODEC);
w->codec_param = AV_CODEC_ID_VP9;
break;
case HB_VCODEC_VCE_H264:
w = hb_get_work(h, WORK_ENCAVCODEC);
w->codec_param = AV_CODEC_ID_H264;
break;
case HB_VCODEC_X264_8BIT:
case HB_VCODEC_X264_10BIT:
@@ -459,6 +463,7 @@ void hb_display_job_info(hb_job_t *job)
case HB_VCODEC_X265_16BIT:
case HB_VCODEC_QSV_H264:
case HB_VCODEC_QSV_H265:
case HB_VCODEC_VCE_H264:
hb_log(" + profile: %s", job->encoder_profile);
default:
break;
@@ -472,6 +477,7 @@ void hb_display_job_info(hb_job_t *job)
case HB_VCODEC_X264_10BIT:
case HB_VCODEC_QSV_H264:
case HB_VCODEC_QSV_H265:
case HB_VCODEC_VCE_H264:
hb_log(" + level: %s", job->encoder_level);
default:
break;
@@ -34,6 +34,10 @@ public enum VideoEncoder
[ShortName("qsv_h265")]
QuickSyncH265,
[Display(Name = "H.264 (AMD VCE)")]
[ShortName("vce_h264")]
AMDVCE,
[Display(Name = "MPEG-4")]
[ShortName("mpeg4")]
FFMpeg,
@@ -74,5 +74,16 @@ public static bool IsQsvAvailableH265
}
}
}
/// <summary>
/// Gets a value indicating whether is amdvce available.
/// </summary>
public static bool IsAMDVCEAvailable
{
get
{
return true; // TODO this needs to hook into LibHB.
}
}
}
}
@@ -87,6 +87,11 @@ public object Convert(object[] values, Type targetType, object parameter, Cultur
encoders.Remove(VideoEncoder.QuickSyncH265);
}
if (!SystemInfo.IsAMDVCEAvailable)
{
encoders.Remove(VideoEncoder.AMDVCE);
}
return EnumHelper<VideoEncoder>.GetEnumDisplayValuesSubset(encoders);
}
Oops, something went wrong.
ProTip! Use n and p to navigate between commits in a pull request.