$(eval $(call import.MODULE.defs,LIBMFX,libmfx))
$(eval $(call import.CONTRIB.defs,LIBMFX))
-LIBMFX.FETCH.url = http://download.handbrake.fr/contrib/mfx_dispatcher_2013_4.0.tar.bz2
+LIBMFX.FETCH.url = http://download.handbrake.fr/contrib/libmfx_intel_msdk_2013r2.tar.bz2
LIBMFX.CONFIGURE.bootstrap = rm -fr aclocal.m4 autom4te.cache; autoreconf -fiv;
pv->job->vcodec == HB_VCODEC_QSV_H264 && pv->job->title->video_codec_param == AV_CODEC_ID_H264 ){
pv->context->hwaccel_context = &pv->qsv_config;
pv->qsv_config.io_pattern = MFX_IOPATTERN_OUT_OPAQUE_MEMORY;
+ if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_LOOKAHEAD)
+ pv->qsv_config.additional_buffers = 160; // LA might need more surfaces
+ else
pv->qsv_config.additional_buffers = 64; // FIFO_LARGE for now
// decode is async, sync only at encode
pv->qsv_config.sync_need = 0;
int ret;
hb_dict_t *qsv_opts = NULL;
hb_dict_entry_t *entry = NULL;
- qsv_param_set_defaults(&pv->qsv_config, hb_qsv_info);
+ qsv_param_set_defaults(&pv->qsv_config, hb_qsv_info,job);
if (job->advanced_opts != NULL && *job->advanced_opts != '\0')
{
qsv_opts = hb_encopts_to_dict(job->advanced_opts, job->vcodec);
if(job && job->vcodec == HB_VCODEC_QSV_H264 ){
pv->context->hwaccel_context = &pv->qsv_config;
pv->qsv_config.io_pattern = MFX_IOPATTERN_OUT_OPAQUE_MEMORY;
+ if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_LOOKAHEAD)
+ pv->qsv_config.additional_buffers = 160;
+ else
pv->qsv_config.additional_buffers = 64;
pv->qsv_config.sync_need = 0;
pv->qsv_config.usage_threaded = 1;
if(job && job->vcodec == HB_VCODEC_QSV_H264 ){
pv->context->hwaccel_context = &pv->qsv_config;
pv->qsv_config.io_pattern = MFX_IOPATTERN_OUT_OPAQUE_MEMORY;
+ if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_LOOKAHEAD)
+ pv->qsv_config.additional_buffers = 160;
+ else
pv->qsv_config.additional_buffers = 64;
pv->qsv_config.sync_need = 0;
pv->qsv_config.usage_threaded = 1;
mfxExtCodingOption2 qsv_coding_option2_config;
mfxExtCodingOption qsv_coding_option_config;
int mbbrx_param_idx;
+
+ // lookahead
+ mfxU16 la_depth;
};
extern char* get_codec_id(hb_work_private_t *pv);
AV_QSV_ZERO_MEMORY(qsv_encode->m_mfxVideoParam);
AV_QSV_ZERO_MEMORY(qsv_encode->m_mfxVideoParam.mfx);
- qsv_param_set_defaults(&pv->qsv_config, hb_qsv_info);
+ qsv_param_set_defaults(&pv->qsv_config, hb_qsv_info,job);
hb_dict_t *qsv_opts_dict = NULL;
if( job->advanced_opts != NULL && *job->advanced_opts != '\0' )
qsv_opts_dict = hb_encopts_to_dict( job->advanced_opts, job->vcodec );
+ int gop_pic_size_force = 0;
int ret;
hb_dict_entry_t *entry = NULL;
while( ( entry = hb_dict_next( qsv_opts_dict, entry ) ) )
{
ret = qsv_param_parse( &pv->qsv_config, entry->key, entry->value );
+ if(!strcmp(entry->key,QSV_NAME_gop_pic_size))
+ gop_pic_size_force = 1;
if( ret == QSV_PARAM_BAD_NAME )
hb_log( "QSV options: Unknown suboption %s", entry->key );
else
qsv_encode->m_mfxVideoParam.mfx.TargetKbps = 2000;
qsv_encode->m_mfxVideoParam.mfx.RateControlMethod = MFX_RATECONTROL_VBR;
+ int old_TargetKbps = qsv_encode->m_mfxVideoParam.mfx.TargetKbps;
+
if (job->vquality >= 0)
{
int cqp_offset_i,cqp_offset_p,cqp_offset_b;
//
qsv_encode->m_mfxVideoParam.mfx.RateControlMethod = MFX_RATECONTROL_VBR;
qsv_encode->m_mfxVideoParam.mfx.TargetKbps = job->vbitrate;
+ old_TargetKbps = qsv_encode->m_mfxVideoParam.mfx.TargetKbps;
// make it work like x264 for ease of use
// (more convenient if switching back and forth)
hb_error("wrong parameters setting");
}
+ if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_LOOKAHEAD)
+ {
+ int use_la = 0;
+
+ if (qsv_encode->m_mfxVideoParam.mfx.RateControlMethod == MFX_RATECONTROL_VBR ||
+ qsv_encode->m_mfxVideoParam.mfx.RateControlMethod == MFX_RATECONTROL_AVBR)
+ {
+ if ((entry = hb_dict_get(qsv_opts_dict, QSV_NAME_lookahead)) != NULL && entry->value != NULL)
+ use_la |= atoi(entry->value);
+ else
+ if (qsv_encode->m_mfxVideoParam.mfx.TargetUsage < 3)
+ use_la = 1; // sort of default value
+ }
+ if (use_la)
+ {
+ qsv_encode->m_mfxVideoParam.mfx.RateControlMethod = MFX_RATECONTROL_LA;
+ qsv_encode->m_mfxVideoParam.mfx.TargetKbps = old_TargetKbps;
+ }
+ }
+
+ if (!gop_pic_size_force && qsv_encode->m_mfxVideoParam.mfx.RateControlMethod == MFX_RATECONTROL_CQP)
+ {
+ pv->qsv_config.gop_pic_size = 32; // default for CQP, if not forced
+ }
+
// version-specific encoder options
- if (hb_qsv_info->capabilities & HB_QSV_CAP_MSDK_1_6)
+ if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_BRC)
{
if ((entry = hb_dict_get(qsv_opts_dict, QSV_NAME_mbbrc)) != NULL && entry->value != NULL)
{
pv->mbbrc =atoi(entry->value);
}
else
- pv->mbbrc = 1; // MFX_CODINGOPTION_ON
+ pv->mbbrc = 1; // default: MFX_CODINGOPTION_ON
if ((entry = hb_dict_get(qsv_opts_dict, QSV_NAME_extbrc)) != NULL && entry->value != NULL)
{
pv->extbrc =atoi(entry->value);
}
else
- pv->extbrc = 2; //MFX_CODINGOPTION_OFF
+ pv->extbrc = 2; // default: MFX_CODINGOPTION_OFF
}
+
+ if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_LOOKAHEAD)
+ if ((entry = hb_dict_get(qsv_opts_dict, QSV_NAME_lookaheaddepth)) != NULL && entry->value != NULL)
+ pv->la_depth = atoi(entry->value);
+ else
+ pv->la_depth = 40; // default: value
+
hb_dict_free( &qsv_opts_dict );
if(pv->qsv_config.async_depth)
break;
case MFX_RATECONTROL_CQP : rc_method = "MFX_RATECONTROL_CQP";
break;
+ case MFX_RATECONTROL_LA : rc_method = "MFX_RATECONTROL_LA";
+ break;
default : rc_method = "unknown";
};
if( qsv_encode->m_mfxVideoParam.mfx.RateControlMethod == MFX_RATECONTROL_CQP )
hb_log("qsv: RateControlMethod:%s(I:%d/P:%d/B:%d)",rc_method,
qsv_encode->m_mfxVideoParam.mfx.QPI, qsv_encode->m_mfxVideoParam.mfx.QPP, qsv_encode->m_mfxVideoParam.mfx.QPB );
+ else
+ if( qsv_encode->m_mfxVideoParam.mfx.RateControlMethod == MFX_RATECONTROL_LA )
+ hb_log("qsv: RateControlMethod:%s LookAheadDepth:%d TargetKbps:%d",rc_method , pv->la_depth, qsv_encode->m_mfxVideoParam.mfx.TargetKbps );
else
hb_log("qsv: RateControlMethod:%s TargetKbps:%d",rc_method , qsv_encode->m_mfxVideoParam.mfx.TargetKbps );
if(!pv->is_sys_mem)
qsv_encode->p_ext_param_num = 1; // for MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION
- if(pv->mbbrc || pv->extbrc){
+ if (pv->mbbrc || pv->extbrc || qsv_encode->m_mfxVideoParam.mfx.RateControlMethod == MFX_RATECONTROL_LA)
+ {
qsv_encode->p_ext_param_num++;
}
qsv_encode->m_mfxVideoParam.NumExtParam = qsv_encode->p_ext_param_num;
- if(qsv_encode->m_mfxVideoParam.NumExtParam){
+ if (qsv_encode->m_mfxVideoParam.NumExtParam)
+ {
int cur_idx = 0;
qsv_encode->p_ext_params = av_mallocz(sizeof(mfxExtBuffer *)*qsv_encode->p_ext_param_num);
AV_QSV_CHECK_POINTER(qsv_encode->p_ext_params, MFX_ERR_MEMORY_ALLOC);
pv->qsv_coding_option_config.PicTimingSEI = MFX_CODINGOPTION_OFF;
qsv_encode->p_ext_params[cur_idx++] = (mfxExtBuffer*)&pv->qsv_coding_option_config;
- if(!pv->is_sys_mem){
+ if (!pv->is_sys_mem)
+ {
memset(&qsv_encode->ext_opaque_alloc, 0, sizeof(mfxExtOpaqueSurfaceAlloc));
qsv_encode->ext_opaque_alloc.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION;
qsv_encode->ext_opaque_alloc.Header.BufferSz = sizeof(mfxExtOpaqueSurfaceAlloc);
qsv_encode->ext_opaque_alloc.In.Type = qsv_encode->request[0].Type;
}
- if(pv->mbbrc || pv->extbrc){
+ if (pv->mbbrc || pv->extbrc || qsv_encode->m_mfxVideoParam.mfx.RateControlMethod == MFX_RATECONTROL_LA)
+ {
pv->qsv_coding_option2_config.Header.BufferId = MFX_EXTBUFF_CODING_OPTION2;
pv->qsv_coding_option2_config.Header.BufferSz = sizeof(mfxExtCodingOption2);
pv->qsv_coding_option2_config.MBBRC = pv->mbbrc << 4;
// default is off
pv->qsv_coding_option2_config.ExtBRC = pv->extbrc == 0 ? MFX_CODINGOPTION_OFF : pv->extbrc << 4;
+ pv->qsv_coding_option2_config.LookAheadDepth = pv->la_depth;
// reset if out of the ranges
if(pv->qsv_coding_option2_config.MBBRC > MFX_CODINGOPTION_ADAPTIVE)
if( pv->mbbrx_param_idx ){
pv->qsv_coding_option2_config.MBBRC = MFX_CODINGOPTION_UNKNOWN;
pv->qsv_coding_option2_config.ExtBRC = MFX_CODINGOPTION_OFF;
+ pv->qsv_coding_option2_config.LookAheadDepth = 0;
pv->mbbrx_param_idx = 0;
}
}
pv->bfrm_delay = FFMAX(pv->bfrm_delay, 0);
// check whether we need to generate DTS ourselves (MSDK API < 1.6 or VFR)
pv->bfrm_workaround = job->cfr != 1 || !(hb_qsv_info->capabilities &
- HB_QSV_CAP_MSDK_1_6);
+ HB_QSV_CAP_BITSTREAM_DTS);
if (pv->bfrm_delay && pv->bfrm_workaround)
{
pv->bfrm_workaround = 1;
{
// MSDK API < 1.6 or VFR, so generate our own DTS
if ((pv->frames_out == 0) &&
- (hb_qsv_info->capabilities & HB_QSV_CAP_MSDK_1_6) &&
- (hb_qsv_info->capabilities & HB_QSV_CAP_BPYRAMID))
+ (hb_qsv_info->capabilities & HB_QSV_CAP_BITSTREAM_DTS) &&
+ (hb_qsv_info->capabilities & HB_QSV_CAP_H264_BPYRAMID))
{
// with B-pyramid, the delay may be more than 1 frame,
// so compute the actual delay based on the initial DTS
!strcmp(name,QSV_NAME_extbrc) ||
!strcmp(name,QSV_NAME_cqp_offset_i) ||
!strcmp(name,QSV_NAME_cqp_offset_p) ||
- !strcmp(name,QSV_NAME_cqp_offset_b)
+ !strcmp(name,QSV_NAME_cqp_offset_b) ||
+ !strcmp(name,QSV_NAME_lookaheaddepth) ||
+ !strcmp(name,QSV_NAME_lookahead)
)
ret = QSV_PARAM_OK;
else
return ret;
}
-void qsv_param_set_defaults( av_qsv_config* config, hb_qsv_info_t *qsv_info ){
+void qsv_param_set_defaults( av_qsv_config* config, hb_qsv_info_t *qsv_info, hb_job_t *job ){
if(!config)
return;
config->async_depth = AV_QSV_ASYNC_DEPTH_DEFAULT;
config->target_usage = MFX_TARGETUSAGE_BEST_QUALITY + 1;
+ config->num_ref_frame = 0;
config->gop_ref_dist = 4;
- config->gop_pic_size = 32;
+
+ int used_rate = round((float)job->vrate/(float)job->vrate_base);
+ config->gop_pic_size = (used_rate * 5) + 1;
}
#define QSV_NAME_cqp_offset_i "cqp-offset-i"
#define QSV_NAME_cqp_offset_p "cqp-offset-p"
#define QSV_NAME_cqp_offset_b "cqp-offset-b"
+#define QSV_NAME_lookaheaddepth "lookahead-depth"
+#define QSV_NAME_lookahead "lookahead"
typedef enum {
QSV_PARAM_OK = 0,
} qsv_param_errors;
int qsv_param_parse( av_qsv_config* config, const char *name, const char *value);
-void qsv_param_set_defaults( av_qsv_config* config, hb_qsv_info_t *qsv_info );
+void qsv_param_set_defaults( av_qsv_config* config, hb_qsv_info_t *qsv_info, hb_job_t *job );
#endif //ENC_QSV_H
return (hb_qsv_info == NULL);
init_done = 1;
- hb_qsv_info = malloc(sizeof(*hb_qsv_info));
+ hb_qsv_info = calloc(sizeof(*hb_qsv_info),1);
if (hb_qsv_info == NULL)
{
hb_error("hb_qsv_info_init: malloc failure");
}
mfxSession session;
- hb_qsv_info->capabilities = 0;
hb_qsv_info->minimum_version.Major = HB_QSV_MINVERSION_MAJOR;
hb_qsv_info->minimum_version.Minor = HB_QSV_MINVERSION_MINOR;
hb_qsv_info->software_available = hb_qsv_info->hardware_available = 0;
{
if (HB_QSV_MIN_HARDWARE(1, 6))
{
- hb_qsv_info->capabilities |= HB_QSV_CAP_MSDK_1_6;
+ hb_qsv_info->capabilities |= HB_QSV_CAP_OPTION2_BRC;
+ hb_qsv_info->capabilities |= HB_QSV_CAP_BITSTREAM_DTS;
}
+ if (HB_QSV_MIN_HARDWARE(1, 7))
+ {
if (hb_qsv_info->cpu_platform == HB_CPU_PLATFORM_INTEL_HSW)
{
- hb_qsv_info->capabilities |= HB_QSV_CAP_BPYRAMID;
+ hb_qsv_info->capabilities |= HB_QSV_CAP_OPTION2_LOOKAHEAD;
}
}
- else
+ if (hb_qsv_info->cpu_platform == HB_CPU_PLATFORM_INTEL_HSW)
+ {
+ hb_qsv_info->capabilities |= HB_QSV_CAP_H264_BPYRAMID;
+ }
+ }
+ else if (hb_qsv_info->software_available)
{
if (HB_QSV_MIN_SOFTWARE(1, 6))
{
- hb_qsv_info->capabilities |= HB_QSV_CAP_MSDK_1_6;
- hb_qsv_info->capabilities |= HB_QSV_CAP_BPYRAMID;
+ hb_qsv_info->capabilities |= HB_QSV_CAP_OPTION2_BRC;
+ hb_qsv_info->capabilities |= HB_QSV_CAP_BITSTREAM_DTS;
+ hb_qsv_info->capabilities |= HB_QSV_CAP_H264_BPYRAMID;
}
}
// supported version-specific or hardware-specific capabilities
int capabilities;
-#define HB_QSV_CAP_MSDK_1_6 0x0000001
-#define HB_QSV_CAP_BPYRAMID 0x0000010
+#define HB_QSV_CAP_H264_BPYRAMID 1 << 0 // H.264: reference B-frames
+#define HB_QSV_CAP_BITSTREAM_DTS 1 << 1 // mfxBitStream: DecodeTimeStamp
+#define HB_QSV_CAP_OPTION2_BRC 1 << 2 // mfxExtCodingOption2: MBBRC/ExtBRC
+#define HB_QSV_CAP_OPTION2_LOOKAHEAD 1 << 3 // mfxExtCodingOption2: LookAhead
// if a feature depends on the cpu generation
enum
av_qsv_add_context_usage(qsv,HAVE_THREADS);
- qsv_param_set_defaults(&pv->qsv_config, hb_qsv_info);
+ qsv_param_set_defaults(&pv->qsv_config, hb_qsv_info,pv->job);
hb_dict_t * qsv_opts = NULL;
if( pv->job->advanced_opts != NULL && *pv->job->advanced_opts != '\0' )
qsv_opts = hb_encopts_to_dict( pv->job->advanced_opts, pv->job->vcodec );
"### QSV Options, via --encopts=\"option1=value1:option2=value2\" -----------\n\n"
" - target-usage A range of numbers that indicate trade-offs between\n"
" <number> quality and speed, from 1 to 7 inclusive.\n"
- " - num-ref-frame Number of reference frames; if equal to 0, this parameter is\n"
- " <number> not specified.\n"
- " - gop-pic-size Number of pictures within the current GOP (Group of Pictures);\n"
- " <number> if equal to 0, then the GOP size is unspecified.\n"
+ " Default is 2\n"
+ " - num-ref-frame Number of reference frames; if equal to 0,\n"
+ " <number> this parameter is not specified.\n"
+ " - gop-pic-size Number of pictures within the current GOP.\n"
+ " <number> If equal to 0, then the GOP size is unspecified.\n"
" If equal to 1, only I-frames are used.\n"
" - gop-ref-dist Distance between I- or P- key frames; if it is zero,\n"
" <number> the GOP structure is unspecified.\n"
" Note: If GopRefDist = 1, there are no B-frames used.\n"
- " - async-depth Specifies how many asynchronous operations an application performs\n"
- " <number> before the application explicitly synchronizes the result.\n"
+ " - async-depth Specifies how many asynchronous operations an\n"
+ " <number> application performsbefore the application\n"
+ " explicitly synchronizes the result.\n"
" If zero, the value is not specified. Default is 4\n"
+ " - mbbrc Setting this flag enables macroblock level bitrate\n"
+ " <number> control that generally improves subjective\n"
+ " visual quality.\n"
+ " Enabling this flag may have negative impact on\n"
+ " performance and objective visual quality metric.\n"
+ " Default is ON\n"
+ " - extbrc Setting this flag instructs encoder to use extended\n"
+ " <number> bitrate control algorithms. It generally improves\n"
+ " objective and subjective visual quality, but it\n"
+ " also leads to violation of HRD conformance and may\n"
+ " significantly reduce performance.\n"
+ " Default is OFF\n"
+ " - cqp-offset-i\n"
+ " - cqp-offset-p\n"
+ " - cqp-offset-b Specify shift/offset for QP(CQP) mode and each\n"
+ " Default is \"0:2:4\"\n"
+ " <number> I, P and B frames respectively.\n"
+ " - lookahead Use the look ahead bitrate control algorithm.\n"
+ " <number> Value more than 0 - enables the feature,\n"
+ " if supported by runtime hardware and driver\n"
+ " - lookahead-depth Specifies the depth of look ahead rate control\n"
+ " <number> algorithm. It is number of frames that SDK\n"
+ " encoder analyzes before encoding. Valid value\n"
+ " range is from 10 to 100 inclusive.\n"
+ " Default is 40\n"
"\n"
);
}
if (hb_qsv_available())
{
/* XXX: for testing workarounds */
- hb_qsv_info->capabilities &= ~HB_QSV_CAP_MSDK_1_6;
+ hb_qsv_info->capabilities &= ~HB_QSV_CAP_BITSTREAM_DTS;
+ hb_qsv_info->capabilities &= ~HB_QSV_CAP_OPTION2_BRC;
+ hb_qsv_info->capabilities &= ~HB_QSV_CAP_OPTION2_LOOKAHEAD;
}
#endif
break;
case "h264Level":\r
preset.Task.H264Level = kvp.Value;\r
break;\r
-\r
+ case "QsvPreset":\r
+ preset.Task.QsvPreset = EnumHelper<QsvPreset>.GetValue(kvp.Value, true);\r
+ break;\r
// Chapter Markers Tab\r
case "ChapterMarkers":\r
preset.Task.IncludeChapterMarkers = kvp.Value == 1;\r
\r
preset.Task.VideoEncoder = VideoEncoder.QuickSync;\r
preset.Task.Quality = 20;\r
- preset.Task.AdvancedEncoderOptions =\r
- "gop-ref-dist=4:gop-pic-size=32:async-depth=4";\r
+ preset.Task.AdvancedEncoderOptions = "async-depth=4";\r
preset.Task.AudioTracks = new ObservableCollection<AudioTrack>();\r
preset.Task.AudioTracks.Add(new AudioTrack { Bitrate = 224, Encoder = AudioEncoder.ffaac, MixDown = Mixdown.DolbyProLogicII});\r
preset.Task.Anamorphic = Anamorphic.Loose;\r
AddEncodeElement(xmlWriter, "x264OptionExtra", "string", parsed.AdvancedEncoderOptions);\r
AddEncodeElement(xmlWriter, "x264Preset", "string", parsed.X264Preset.ToString().ToLower());\r
AddEncodeElement(xmlWriter, "h264Profile", "string", parsed.H264Profile.ToString().ToLower());\r
+ AddEncodeElement(xmlWriter, "QsvPreset", "string", parsed.QsvPreset.ToString());\r
string tune = parsed.X264Tune.ToString().ToLower();\r
if (parsed.FastDecode)\r
{\r
public EncoderOptionsViewModel()\r
{\r
this.Task = new EncodeTask();\r
- cachedOptions.Add(VideoEncoder.QuickSync, "gop-ref-dist=4:gop-pic-size=32:async-depth=4");\r
+ cachedOptions.Add(VideoEncoder.QuickSync, "async-depth=4");\r
}\r
\r
/// <summary>\r
/// Shutdown this View\r
/// </summary>\r
void Shutdown();\r
+\r
+ EncodeTask GetCurrentTask();\r
}\r
}
\ No newline at end of file
this.scanService.Scan(task.Source, task.Title, this.UserSettingService.GetUserSetting<int>(ASUserSettingConstants.PreviewScanCount), QueueEditAction);\r
}\r
\r
+ public EncodeTask GetCurrentTask()\r
+ {\r
+ return this.CurrentTask;\r
+ }\r
+\r
/// <summary>\r
/// Pause an Encode\r
/// </summary>\r
<TextBlock Text="Quality" FontWeight="Bold" Margin="0,0,0,10"/>\r
\r
<StackPanel Orientation="Horizontal" Margin="0,0,0,10" >\r
- <RadioButton Content="Constant Quality:" IsChecked="{Binding IsConstantQuantity}" Margin="0,0,10,0"/>\r
+ <RadioButton Content="Constant Quality:" IsChecked="{Binding IsConstantQuantity}" Margin="0,0,10,0" Checked="qsv_preset_radiobutton"/>\r
<TextBlock Text="{Binding DisplayRF}" MinWidth="30" />\r
<TextBlock Text="{Binding Rfqp}" FontWeight="Bold" Margin="5,0,0,0" />\r
\r
</Grid>\r
\r
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">\r
- <RadioButton Content="Avg Bitrate (kbps):" IsChecked="{Binding IsConstantQuantity, Converter={StaticResource boolConverter}, ConverterParameter=true}" Margin="0,0,10,0"/>\r
+ <RadioButton Content="Avg Bitrate (kbps):" IsChecked="{Binding IsConstantQuantity, Converter={StaticResource boolConverter}, ConverterParameter=true}" Margin="0,0,10,0" Checked="qsv_preset_radiobutton"/>\r
<TextBox Width="75" Text="{Binding Task.VideoBitrate, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding IsConstantQuantity, Converter={StaticResource boolConverter}, ConverterParameter=true}" />\r
</StackPanel>\r
\r
<StackPanel Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="3" Orientation="Horizontal"\r
Visibility="{Binding DisplayQSVOptions, Converter={StaticResource boolToVisConverter}}" >\r
<Slider Minimum="0" Maximum="{Binding QsvSliderMax}" Width="150" Value="{Binding QsvPresetValue, Mode=Default, UpdateSourceTrigger=PropertyChanged}" \r
- IsSnapToTickEnabled="True" TickFrequency="1" TickPlacement="BottomRight" />\r
+ IsSnapToTickEnabled="True" TickFrequency="1" TickPlacement="BottomRight" ValueChanged="qsv_preset_ValueChanged"/>\r
<TextBlock Text="{Binding QsvPreset, Converter={StaticResource enumComboConverter}}" Margin="5,0,0,0" />\r
</StackPanel>\r
\r
namespace HandBrakeWPF.Views\r
{\r
using System.Windows.Controls;\r
+ using System.Collections.Generic;\r
+ using System.Windows;\r
+ using Caliburn.Micro;\r
+ using HandBrake.ApplicationServices.Model;\r
+ using HandBrake.ApplicationServices.Utilities;\r
+ using HandBrake.Interop.Model.Encoding;\r
+\r
+ using HandBrakeWPF.ViewModels.Interfaces;\r
\r
/// <summary>\r
/// Interaction logic for VideoView.xaml\r
{\r
InitializeComponent();\r
}\r
+\r
+ private void qsv_preset_radiobutton(object sender, System.Windows.RoutedEventArgs e)\r
+ {\r
+ qsv_preset_ValueChanged(sender,null);\r
+ }\r
+\r
+ private void qsv_preset_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)\r
+ {\r
+ IMainViewModel mvm = IoC.Get<IMainViewModel>();\r
+ EncodeTask task = mvm.GetCurrentTask();\r
+ string addon = "";\r
+\r
+ if (SystemInfo.IsHswOrNewer)\r
+ {\r
+ if (task.VideoEncodeRateType == VideoEncodeRateType.ConstantQuality)\r
+ {\r
+ if (task.QsvPreset == QsvPreset.Balanced ||\r
+ task.QsvPreset == QsvPreset.Speed)\r
+ addon = "num-ref-frame=1";\r
+}\r
+ if (task.VideoEncodeRateType == VideoEncodeRateType.AverageBitrate)\r
+ {\r
+ if (task.QsvPreset == QsvPreset.Quality) \r
+ addon = "lookahead=1:gop-ref-dist=3";\r
+ else\r
+ if (task.QsvPreset == QsvPreset.Balanced)\r
+ {\r
+ addon = "num-ref-frame=1:gop-ref-dist=1";\r
+ }\r
+ else\r
+ if (task.QsvPreset == QsvPreset.Speed)\r
+ addon = "gop-ref-dist=1";\r
+ }\r
+ }\r
+\r
+\r
+ string full_string = addon + ":";\r
+\r
+ IDictionary<string, string> newOptions = new Dictionary<string, string>();\r
+ string[] existingSegments = full_string.Split(':');\r
+ foreach (string existingSegment in existingSegments)\r
+ {\r
+ string optionName = existingSegment;\r
+ string optionValue = string.Empty; \r
+ int equalsIndex = existingSegment.IndexOf('=');\r
+ if (equalsIndex >= 0)\r
+ {\r
+ optionName = existingSegment.Substring(\r
+ 0, existingSegment.IndexOf("=", System.StringComparison.Ordinal));\r
+ optionValue = existingSegment.Substring(equalsIndex);\r
+ }\r
+\r
+ if (optionName != string.Empty)\r
+ {\r
+ if (newOptions.ContainsKey(optionName)) \r
+ newOptions.Remove(optionName);\r
+ newOptions.Add(optionName, optionValue);\r
+ }\r
+ }\r
+\r
+ full_string = "";\r
+ foreach (KeyValuePair<string, string> entry in newOptions)\r
+ {\r
+ full_string += entry.Key;\r
+ if (entry.Value != string.Empty) \r
+ full_string += entry.Value;\r
+ full_string += ":";\r
+ }\r
+ full_string = full_string.TrimEnd(':');\r
+\r
+ task.AdvancedEncoderOptions = full_string;\r
+ task.NotifyOfPropertyChange(() => task.AdvancedEncoderOptions);\r
+ }\r
}\r
}\r