From f005170eb16dc05989c59bee0372f0d1da698ffc Mon Sep 17 00:00:00 2001 From: handbrake Date: Tue, 6 Aug 2013 13:50:18 +0000 Subject: [PATCH] QSV: Trellis option support git-svn-id: svn://svn.handbrake.fr/HandBrake/branches/qsv@5692 b64f7644-9d1e-0410-96f1-a4d463321fa5 --- libhb/enc_qsv.c | 46 +++++++++++++++++---- libhb/enc_qsv.h | 2 +- libhb/qsv_common.c | 99 ++++++++++++++++++++++++++++++++++++++++++++-- libhb/qsv_common.h | 13 +++++- test/test.c | 3 +- 5 files changed, 147 insertions(+), 16 deletions(-) diff --git a/libhb/enc_qsv.c b/libhb/enc_qsv.c index 081294eb4..57c1f0851 100644 --- a/libhb/enc_qsv.c +++ b/libhb/enc_qsv.c @@ -142,6 +142,7 @@ struct hb_work_private_s // only set if supported mfxU16 mbbrc; mfxU16 extbrc; + mfxU16 trellis; mfxU16 la_depth; int mbbrx_param_idx; mfxExtCodingOption2 qsv_coding_option2_config; @@ -481,6 +482,15 @@ int qsv_enc_init(av_qsv_context *qsv, hb_work_private_t *pv) pv->extbrc = 2; // default: MFX_CODINGOPTION_OFF } + if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_TRELLIS) + { + if ((entry = hb_dict_get(qsv_opts_dict, QSV_NAME_trellis)) != NULL && entry->value != NULL) + { + pv->trellis = hb_qsv_trellisvalue_xlat(atoi(entry->value)); + } + else + pv->trellis = MFX_TRELLIS_UNKNOWN; + } 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) @@ -529,6 +539,19 @@ int qsv_enc_init(av_qsv_context *qsv, hb_work_private_t *pv) hb_log("qsv: RateControlMethod:%s TargetKbps:%d",rc_method , qsv_encode->m_mfxVideoParam.mfx.TargetKbps ); hb_log("qsv: TargetUsage:%d AsyncDepth:%d", qsv_encode->m_mfxVideoParam.mfx.TargetUsage,qsv_encode->m_mfxVideoParam.AsyncDepth); + + if (pv->trellis != MFX_TRELLIS_UNKNOWN) + { + char mask[] = "OFF"; + if (!(pv->trellis & MFX_TRELLIS_OFF)) + { + mask[0] = pv->trellis & MFX_TRELLIS_I ? 'I' : ' '; + mask[1] = pv->trellis & MFX_TRELLIS_P ? 'P' : ' '; + mask[2] = pv->trellis & MFX_TRELLIS_B ? 'B' : ' '; + } + hb_log("qsv: Trellis mask: \"%c%c%c\"", mask[0],mask[1],mask[2] ); + } + qsv_encode->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtN = job->vrate; qsv_encode->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtD = job->vrate_base; qsv_encode->m_mfxVideoParam.mfx.FrameInfo.AspectRatioW = job->anamorphic.par_width; @@ -609,7 +632,9 @@ int qsv_enc_init(av_qsv_context *qsv, hb_work_private_t *pv) if(!pv->is_sys_mem) qsv_encode->p_ext_param_num = 1; // for MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION - if (pv->mbbrc || pv->extbrc || qsv_encode->m_mfxVideoParam.mfx.RateControlMethod == MFX_RATECONTROL_LA) + if (pv->mbbrc || pv->extbrc || + qsv_encode->m_mfxVideoParam.mfx.RateControlMethod == MFX_RATECONTROL_LA || + pv->extbrc != MFX_TRELLIS_UNKNOWN) { qsv_encode->p_ext_param_num++; } @@ -662,7 +687,9 @@ int qsv_enc_init(av_qsv_context *qsv, hb_work_private_t *pv) qsv_encode->ext_opaque_alloc.In.Type = qsv_encode->request[0].Type; } - if (pv->mbbrc || pv->extbrc || qsv_encode->m_mfxVideoParam.mfx.RateControlMethod == MFX_RATECONTROL_LA) + if (pv->mbbrc || pv->extbrc || + qsv_encode->m_mfxVideoParam.mfx.RateControlMethod == MFX_RATECONTROL_LA || + pv->extbrc != MFX_TRELLIS_UNKNOWN) { pv->qsv_coding_option2_config.Header.BufferId = MFX_EXTBUFF_CODING_OPTION2; pv->qsv_coding_option2_config.Header.BufferSz = sizeof(mfxExtCodingOption2); @@ -670,10 +697,11 @@ int qsv_enc_init(av_qsv_context *qsv, hb_work_private_t *pv) // 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; + pv->qsv_coding_option2_config.Trellis = pv->trellis; // reset if out of the ranges if(pv->qsv_coding_option2_config.MBBRC > MFX_CODINGOPTION_ADAPTIVE) - pv->qsv_coding_option2_config.MBBRC = MFX_CODINGOPTION_UNKNOWN; + pv->qsv_coding_option2_config.MBBRC = MFX_CODINGOPTION_UNKNOWN; if(pv->qsv_coding_option2_config.ExtBRC > MFX_CODINGOPTION_ADAPTIVE) pv->qsv_coding_option2_config.ExtBRC = MFX_CODINGOPTION_OFF; @@ -688,9 +716,10 @@ int qsv_enc_init(av_qsv_context *qsv, hb_work_private_t *pv) // if not supported first time we will reset if( sts < MFX_ERR_NONE ){ 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.MBBRC = MFX_CODINGOPTION_UNKNOWN; + pv->qsv_coding_option2_config.ExtBRC = MFX_CODINGOPTION_OFF; pv->qsv_coding_option2_config.LookAheadDepth = 0; + pv->qsv_coding_option2_config.Trellis = MFX_TRELLIS_UNKNOWN; pv->mbbrx_param_idx = 0; } } @@ -745,7 +774,7 @@ int qsv_enc_init(av_qsv_context *qsv, hb_work_private_t *pv) 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_BITSTREAM_DTS); + HB_QSV_CAP_MSDK_API_1_6); if (pv->bfrm_delay && pv->bfrm_workaround) { pv->bfrm_workaround = 1; @@ -1206,7 +1235,7 @@ int encqsvWork( hb_work_object_t * w, hb_buffer_t ** buf_in, { // MSDK API < 1.6 or VFR, so generate our own DTS if ((pv->frames_out == 0) && - (hb_qsv_info->capabilities & HB_QSV_CAP_BITSTREAM_DTS) && + (hb_qsv_info->capabilities & HB_QSV_CAP_MSDK_API_1_6) && (hb_qsv_info->capabilities & HB_QSV_CAP_H264_BPYRAMID)) { // with B-pyramid, the delay may be more than 1 frame, @@ -1412,7 +1441,8 @@ int qsv_param_parse( av_qsv_config* config, const char *name, const char *value) !strcmp(name,QSV_NAME_cqp_offset_p) || !strcmp(name,QSV_NAME_cqp_offset_b) || !strcmp(name,QSV_NAME_lookaheaddepth) || - !strcmp(name,QSV_NAME_lookahead) + !strcmp(name,QSV_NAME_lookahead) || + !strcmp(name,QSV_NAME_trellis) ) ret = QSV_PARAM_OK; else diff --git a/libhb/enc_qsv.h b/libhb/enc_qsv.h index c000a143b..f42ffbd76 100644 --- a/libhb/enc_qsv.h +++ b/libhb/enc_qsv.h @@ -37,7 +37,6 @@ int nal_find_start_code(uint8_t** pb, size_t* size); void parse_nalus( uint8_t *nal_inits, size_t length, hb_buffer_t *buf, uint32_t frame_num); -#define QSV_NAME_async_depth "async-depth" #define QSV_NAME_target_usage "target-usage" #define QSV_NAME_num_ref_frame "num-ref-frame" #define QSV_NAME_gop_ref_dist "gop-ref-dist" @@ -52,6 +51,7 @@ void parse_nalus( uint8_t *nal_inits, size_t length, hb_buffer_t *buf, uint32_t #define QSV_NAME_cqp_offset_b "cqp-offset-b" #define QSV_NAME_lookaheaddepth "lookahead-depth" #define QSV_NAME_lookahead "lookahead" +#define QSV_NAME_trellis "trellis" typedef enum { QSV_PARAM_OK = 0, diff --git a/libhb/qsv_common.c b/libhb/qsv_common.c index 35992fc84..9460f53eb 100644 --- a/libhb/qsv_common.c +++ b/libhb/qsv_common.c @@ -8,7 +8,12 @@ */ #include "common.h" +#include "hb_dict.h" #include "qsv_common.h" +#include "h264_common.h" + +// for x264_vidformat_names etc. +#include "x264.h" // avoids a warning #include "libavutil/cpu.h" @@ -84,7 +89,7 @@ int hb_qsv_info_init() hb_qsv_info->cpu_name++; } } - + // Intel 64 and IA-32 Architectures Software Developer's Manual, Vol. 3C // Table 35-1: CPUID Signature Values of DisplayFamily_DisplayModel if (family == 0x06) @@ -142,13 +147,14 @@ int hb_qsv_info_init() if (HB_CHECK_MFX_VERSION(qsv_hardware_version, 1, 6)) { 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_MSDK_API_1_6; } if (HB_CHECK_MFX_VERSION(qsv_hardware_version, 1, 7)) { if (hb_qsv_info->cpu_platform == HB_CPU_PLATFORM_INTEL_HSW) { hb_qsv_info->capabilities |= HB_QSV_CAP_OPTION2_LOOKAHEAD; + hb_qsv_info->capabilities |= HB_QSV_CAP_OPTION2_TRELLIS; } } if (hb_qsv_info->cpu_platform == HB_CPU_PLATFORM_INTEL_HSW) @@ -161,7 +167,7 @@ int hb_qsv_info_init() if (HB_CHECK_MFX_VERSION(qsv_software_version, 1, 6)) { 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_MSDK_API_1_6; hb_qsv_info->capabilities |= HB_QSV_CAP_H264_BPYRAMID; } } @@ -239,7 +245,7 @@ const char* hb_qsv_decode_get_codec_name(enum AVCodecID codec_id) { case AV_CODEC_ID_H264: return "h264_qsv"; - + default: return NULL; } @@ -264,3 +270,88 @@ int hb_qsv_decode_is_supported(enum AVCodecID codec_id, return 0; } } + +int hb_qsv_codingoption_xlat(int val) +{ + switch (HB_QSV_CLIP3(-1, 2, val)) + { + case 0: + return MFX_CODINGOPTION_OFF; + case 1: + case 2: // MFX_CODINGOPTION_ADAPTIVE, reserved + return MFX_CODINGOPTION_ON; + case -1: + default: + return MFX_CODINGOPTION_UNKNOWN; + } +} + +int hb_qsv_trellisvalue_xlat(int val) +{ + switch (HB_QSV_CLIP3(-1, 3, val)) + { + case 0: + return MFX_TRELLIS_OFF; + case 1: // I-frames only + return MFX_TRELLIS_I; + case 2: // I- and P-frames + return MFX_TRELLIS_I|MFX_TRELLIS_P; + case 3: // all frames + return MFX_TRELLIS_I|MFX_TRELLIS_P|MFX_TRELLIS_B; + case -1: + default: + return MFX_TRELLIS_UNKNOWN; + } +} + +int hb_qsv_atoindex(const char* const *arr, const char *str, int *err) +{ + int i; + for (i = 0; arr[i] != NULL; i++) + { + if (!strcasecmp(arr[i], str)) + { + break; + } + } + *err = (arr[i] == NULL); + return i; +} +// adapted from libx264 +int hb_qsv_atobool(const char *str, int *err) +{ + if (!strcasecmp(str, "1") || + !strcasecmp(str, "yes") || + !strcasecmp(str, "true")) + { + return 1; + } + if (!strcasecmp(str, "0") || + !strcasecmp(str, "no") || + !strcasecmp(str, "false")) + { + return 0; + } + *err = 1; + return 0; +} +int hb_qsv_atoi(const char *str, int *err) +{ + char *end; + int v = strtol(str, &end, 0); + if (end == str || end[0] != '\0') + { + *err = 1; + } + return v; +} +float hb_qsv_atof(const char *str, int *err) +{ + char *end; + float v = strtod(str, &end); + if (end == str || end[0] != '\0') + { + *err = 1; + } + return v; +} diff --git a/libhb/qsv_common.h b/libhb/qsv_common.h index c2f4f710c..ecc7f6ff1 100644 --- a/libhb/qsv_common.h +++ b/libhb/qsv_common.h @@ -6,7 +6,7 @@ * 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 */ - + #ifndef HB_QSV_COMMON_H #define HB_QSV_COMMON_H @@ -31,9 +31,10 @@ typedef struct hb_qsv_info_s // supported version-specific or hardware-specific capabilities int capabilities; #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_MSDK_API_1_6 (1 << 1) // Support for API 1.6 or later #define HB_QSV_CAP_OPTION2_BRC (1 << 2) // mfxExtCodingOption2: MBBRC/ExtBRC #define HB_QSV_CAP_OPTION2_LOOKAHEAD (1 << 3) // mfxExtCodingOption2: LookAhead +#define HB_QSV_CAP_OPTION2_TRELLIS (1 << 4) // mfxExtCodingOption2: Trellis // if a feature depends on the cpu generation enum @@ -64,4 +65,12 @@ const char* hb_qsv_decode_get_codec_name(enum AVCodecID codec_id); int hb_qsv_decode_is_enabled(hb_job_t *job); int hb_qsv_decode_is_supported(enum AVCodecID codec_id, enum AVPixelFormat pix_fmt); +#define HB_QSV_CLIP3(min, max, val) ((val < min) ? min : (val > max) ? max : val) +int hb_qsv_codingoption_xlat(int val); +int hb_qsv_trellisvalue_xlat(int val); +int hb_qsv_atoindex(const char* const *arr, const char *str, int *err); +int hb_qsv_atobool (const char *str, int *err); +int hb_qsv_atoi (const char *str, int *err); +float hb_qsv_atof (const char *str, int *err); + #endif diff --git a/test/test.c b/test/test.c index 7341f2c7e..23ec08e17 100644 --- a/test/test.c +++ b/test/test.c @@ -4245,8 +4245,9 @@ static int ParseOptions( int argc, char ** argv ) if (hb_qsv_available()) { /* XXX: for testing workarounds */ - hb_qsv_info->capabilities &= ~HB_QSV_CAP_BITSTREAM_DTS; + hb_qsv_info->capabilities &= ~HB_QSV_CAP_MSDK_API_1_6; hb_qsv_info->capabilities &= ~HB_QSV_CAP_OPTION2_BRC; + hb_qsv_info->capabilities &= ~HB_QSV_CAP_OPTION2_TRELLIS; hb_qsv_info->capabilities &= ~HB_QSV_CAP_OPTION2_LOOKAHEAD; } break; -- 2.40.0