Skip to content

Commit

Permalink
VideoToolbox Hardware Decoding for HEVC enabled
Browse files Browse the repository at this point in the history
Forbid H.265 vtb-hw-decoding when lower than iOS 11 and unsupported devices
  • Loading branch information
yinwenjie authored and raymondzheng committed Jan 24, 2018
1 parent 44dd409 commit edfca47
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -894,7 +894,7 @@ static void dict_set_i32(CFMutableDictionaryRef dict, CFStringRef key,
CFRelease(number);
}

static CMFormatDescriptionRef CreateFormatDescriptionFromCodecData(Uint32 format_id, int width, int height, const uint8_t *extradata, int extradata_size, uint32_t atom)
static CMFormatDescriptionRef CreateFormatDescriptionFromCodecData(CMVideoCodecType format_id, int width, int height, const uint8_t *extradata, int extradata_size, uint32_t atom)
{
CMFormatDescriptionRef fmt_desc = NULL;
OSStatus status;
Expand All @@ -906,8 +906,19 @@ static CMFormatDescriptionRef CreateFormatDescriptionFromCodecData(Uint32 format
/* CVPixelAspectRatio dict */
dict_set_i32(par, CFSTR ("HorizontalSpacing"), 0);
dict_set_i32(par, CFSTR ("VerticalSpacing"), 0);

/* SampleDescriptionExtensionAtoms dict */
dict_set_data(atoms, CFSTR ("avcC"), (uint8_t *)extradata, extradata_size);
switch (format_id) {
case kCMVideoCodecType_H264:
dict_set_data(atoms, CFSTR ("avcC"), (uint8_t *)extradata, extradata_size);
break;
case kCMVideoCodecType_HEVC:
dict_set_data(atoms, CFSTR ("hvcC"), (uint8_t *)extradata, extradata_size);
break;
default:
break;
}


/* Extensions dict */
dict_set_string(extensions, CFSTR ("CVImageBufferChromaLocationBottomField"), "left");
Expand Down Expand Up @@ -1032,6 +1043,9 @@ static int vtbformat_init(VTBFormatDesc *fmt_desc, AVCodecParameters *codecpar)
int codec = codecpar->codec_id;
uint8_t* extradata = codecpar->extradata;

bool isHevcSupported = false;
CMVideoCodecType format_id = 0;

#if 0
switch (profile) {
case FF_PROFILE_H264_HIGH_10:
Expand All @@ -1053,19 +1067,39 @@ static int vtbformat_init(VTBFormatDesc *fmt_desc, AVCodecParameters *codecpar)
goto fail;
}

if (extrasize < 7 || extradata == NULL) {
ALOGI("%s - avcC or hvcC atom data too small or missing", __FUNCTION__);
goto fail;
}

switch (codec) {
case AV_CODEC_ID_H264:
if (extrasize < 7 || extradata == NULL) {
ALOGI("%s - avcC atom too data small or missing", __FUNCTION__);
case AV_CODEC_ID_HEVC:
format_id = kCMVideoCodecType_HEVC;
if (@available(iOS 11.0, *)) {
isHevcSupported = VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC);
} else {
// Fallback on earlier versions
isHevcSupported = false;
}
if (!isHevcSupported) {
goto fail;
}

if (extradata[0] == 1) {
if (!validate_avcC_spc(extradata, extrasize, &fmt_desc->max_ref_frames, &sps_level, &sps_profile)) {
//goto failed;
}
if (level == 0 && sps_level > 0)
level = sps_level;
break;

case AV_CODEC_ID_H264:
format_id = kCMVideoCodecType_H264;
break;

default:
goto fail;
}

if (extradata[0] == 1) {
// if (!validate_avcC_spc(extradata, extrasize, &fmt_desc->max_ref_frames, &sps_level, &sps_profile)) {
//goto failed;
// }
if (level == 0 && sps_level > 0)
level = sps_level;

if (profile == 0 && sps_profile > 0)
profile = sps_profile;
Expand All @@ -1079,10 +1113,10 @@ static int vtbformat_init(VTBFormatDesc *fmt_desc, AVCodecParameters *codecpar)
fmt_desc->convert_3byteTo4byteNALSize = true;
}

fmt_desc->fmt_desc = CreateFormatDescriptionFromCodecData(kCMVideoCodecType_H264, width, height, extradata, extrasize, IJK_VTB_FCC_AVCC);
if (fmt_desc->fmt_desc == NULL) {
goto fail;
}
fmt_desc->fmt_desc = CreateFormatDescriptionFromCodecData(format_id, width, height, extradata, extrasize, IJK_VTB_FCC_AVCC);
if (fmt_desc->fmt_desc == NULL) {
goto fail;
}

ALOGI("%s - using avcC atom of size(%d), ref_frames(%d)", __FUNCTION__, extrasize, fmt_desc->max_ref_frames);
} else {
Expand All @@ -1104,20 +1138,16 @@ static int vtbformat_init(VTBFormatDesc *fmt_desc, AVCodecParameters *codecpar)
goto fail;
}

fmt_desc->fmt_desc = CreateFormatDescriptionFromCodecData(kCMVideoCodecType_H264, width, height, extradata, extrasize, IJK_VTB_FCC_AVCC);
if (fmt_desc->fmt_desc == NULL) {
goto fail;
}

av_free(extradata);
} else {
ALOGI("%s - invalid avcC atom data", __FUNCTION__);
goto fail;
}
fmt_desc->fmt_desc = CreateFormatDescriptionFromCodecData(format_id, width, height, extradata, extrasize, IJK_VTB_FCC_AVCC);
if (fmt_desc->fmt_desc == NULL) {
goto fail;
}
break;
default:

av_free(extradata);
} else {
ALOGI("%s - invalid avcC atom data", __FUNCTION__);
goto fail;
}
}

fmt_desc->max_ref_frames = FFMAX(fmt_desc->max_ref_frames, 2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -761,7 +761,7 @@ static void dict_set_i32(CFMutableDictionaryRef dict, CFStringRef key,
CFRelease(number);
}

static CMFormatDescriptionRef CreateFormatDescriptionFromCodecData(Uint32 format_id, int width, int height, const uint8_t *extradata, int extradata_size, uint32_t atom)
static CMFormatDescriptionRef CreateFormatDescriptionFromCodecData(CMVideoCodecType format_id, int width, int height, const uint8_t *extradata, int extradata_size, uint32_t atom)
{
CMFormatDescriptionRef fmt_desc = NULL;
OSStatus status;
Expand All @@ -773,8 +773,19 @@ static CMFormatDescriptionRef CreateFormatDescriptionFromCodecData(Uint32 format
/* CVPixelAspectRatio dict */
dict_set_i32(par, CFSTR ("HorizontalSpacing"), 0);
dict_set_i32(par, CFSTR ("VerticalSpacing"), 0);

/* SampleDescriptionExtensionAtoms dict */
dict_set_data(atoms, CFSTR ("avcC"), (uint8_t *)extradata, extradata_size);
switch (format_id) {
case kCMVideoCodecType_H264:
dict_set_data(atoms, CFSTR ("avcC"), (uint8_t *)extradata, extradata_size);
break;
case kCMVideoCodecType_HEVC:
dict_set_data(atoms, CFSTR ("hvcC"), (uint8_t *)extradata, extradata_size);
break;
default:
break;
}


/* Extensions dict */
dict_set_string(extensions, CFSTR ("CVImageBufferChromaLocationBottomField"), "left");
Expand Down Expand Up @@ -896,6 +907,9 @@ static int vtbformat_init(VTBFormatDesc *fmt_desc, AVCodecParameters *codecpar)
int codec = codecpar->codec_id;
uint8_t* extradata = codecpar->extradata;

bool isHevcSupported = false;
CMVideoCodecType format_id = 0;

#if 0
switch (profile) {
case FF_PROFILE_H264_HIGH_10:
Expand All @@ -917,19 +931,39 @@ static int vtbformat_init(VTBFormatDesc *fmt_desc, AVCodecParameters *codecpar)
goto fail;
}

if (extrasize < 7 || extradata == NULL) {
ALOGI("%s - avcC or hvcC atom data too small or missing", __FUNCTION__);
goto fail;
}

switch (codec) {
case AV_CODEC_ID_H264:
if (extrasize < 7 || extradata == NULL) {
ALOGI("%s - avcC atom too data small or missing", __FUNCTION__);
case AV_CODEC_ID_HEVC:
format_id = kCMVideoCodecType_HEVC;
if (@available(iOS 11.0, *)) {
isHevcSupported = VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC);
} else {
// Fallback on earlier versions
isHevcSupported = false;
}
if (!isHevcSupported) {
goto fail;
}

if (extradata[0] == 1) {
if (!validate_avcC_spc(extradata, extrasize, &fmt_desc->max_ref_frames, &sps_level, &sps_profile)) {
//goto failed;
}
if (level == 0 && sps_level > 0)
level = sps_level;
break;

case AV_CODEC_ID_H264:
format_id = kCMVideoCodecType_H264;
break;

default:
goto fail;
}

if (extradata[0] == 1) {
// if (!validate_avcC_spc(extradata, extrasize, &fmt_desc->max_ref_frames, &sps_level, &sps_profile)) {
//goto failed;
// }
if (level == 0 && sps_level > 0)
level = sps_level;

if (profile == 0 && sps_profile > 0)
profile = sps_profile;
Expand All @@ -943,10 +977,10 @@ static int vtbformat_init(VTBFormatDesc *fmt_desc, AVCodecParameters *codecpar)
fmt_desc->convert_3byteTo4byteNALSize = true;
}

fmt_desc->fmt_desc = CreateFormatDescriptionFromCodecData(kCMVideoCodecType_H264, width, height, extradata, extrasize, IJK_VTB_FCC_AVCC);
if (fmt_desc->fmt_desc == NULL) {
goto fail;
}
fmt_desc->fmt_desc = CreateFormatDescriptionFromCodecData(format_id, width, height, extradata, extrasize, IJK_VTB_FCC_AVCC);
if (fmt_desc->fmt_desc == NULL) {
goto fail;
}

ALOGI("%s - using avcC atom of size(%d), ref_frames(%d)", __FUNCTION__, extrasize, fmt_desc->max_ref_frames);
} else {
Expand All @@ -968,20 +1002,16 @@ static int vtbformat_init(VTBFormatDesc *fmt_desc, AVCodecParameters *codecpar)
goto fail;
}

fmt_desc->fmt_desc = CreateFormatDescriptionFromCodecData(kCMVideoCodecType_H264, width, height, extradata, extrasize, IJK_VTB_FCC_AVCC);
if (fmt_desc->fmt_desc == NULL) {
goto fail;
}

av_free(extradata);
} else {
ALOGI("%s - invalid avcC atom data", __FUNCTION__);
goto fail;
}
fmt_desc->fmt_desc = CreateFormatDescriptionFromCodecData(format_id, width, height, extradata, extrasize, IJK_VTB_FCC_AVCC);
if (fmt_desc->fmt_desc == NULL) {
goto fail;
}
break;
default:

av_free(extradata);
} else {
ALOGI("%s - invalid avcC atom data", __FUNCTION__);
goto fail;
}
}

fmt_desc->max_ref_frames = FFMAX(fmt_desc->max_ref_frames, 2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,13 +112,14 @@ static int func_run_sync(IJKFF_Pipenode *node)
opaque->avctx = opaque->decoder->avctx;
switch (opaque->avctx->codec_id) {
case AV_CODEC_ID_H264:
if (ffp->vtb_async)
opaque->context = Ijk_VideoToolbox_Async_Create(ffp, opaque->avctx);
else
opaque->context = Ijk_VideoToolbox_Sync_Create(ffp, opaque->avctx);
case AV_CODEC_ID_HEVC:
if (ffp->vtb_async)
opaque->context = Ijk_VideoToolbox_Async_Create(ffp, opaque->avctx);
else
opaque->context = Ijk_VideoToolbox_Sync_Create(ffp, opaque->avctx);
break;
default:
ALOGI("Videotoolbox-pipeline:open_video_decoder: not H264\n");
ALOGI("Videotoolbox-pipeline:open_video_decoder: not H264 or H265\n");
goto fail;
}
if (opaque->context == NULL) {
Expand Down

0 comments on commit edfca47

Please sign in to comment.