|
|
|
@ -32,6 +32,7 @@ |
|
|
|
|
#include "libavutil/hwcontext.h" |
|
|
|
|
#include "bytestream.h" |
|
|
|
|
#include "h264dec.h" |
|
|
|
|
#include "hevcdec.h" |
|
|
|
|
#include "mpegvideo.h" |
|
|
|
|
#include <TargetConditionals.h> |
|
|
|
|
|
|
|
|
@ -39,6 +40,10 @@ |
|
|
|
|
# define kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder CFSTR("RequireHardwareAcceleratedVideoDecoder") |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
#if !HAVE_KCMVIDEOCODECTYPE_HEVC |
|
|
|
|
enum { kCMVideoCodecType_HEVC = 'hvc1' }; |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
#define VIDEOTOOLBOX_ESDS_EXTRADATA_PADDING 12 |
|
|
|
|
|
|
|
|
|
static void videotoolbox_buffer_release(void *opaque, uint8_t *data) |
|
|
|
@ -115,6 +120,164 @@ CFDataRef ff_videotoolbox_avcc_extradata_create(AVCodecContext *avctx) |
|
|
|
|
return data; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
CFDataRef ff_videotoolbox_hvcc_extradata_create(AVCodecContext *avctx) |
|
|
|
|
{ |
|
|
|
|
HEVCContext *h = avctx->priv_data; |
|
|
|
|
const HEVCVPS *vps = (const HEVCVPS *)h->ps.vps_list[0]->data; |
|
|
|
|
const HEVCSPS *sps = (const HEVCSPS *)h->ps.sps_list[0]->data; |
|
|
|
|
int i, num_pps = 0; |
|
|
|
|
const HEVCPPS *pps = h->ps.pps; |
|
|
|
|
PTLCommon ptlc = vps->ptl.general_ptl; |
|
|
|
|
VUI vui = sps->vui; |
|
|
|
|
uint8_t parallelismType; |
|
|
|
|
CFDataRef data = NULL; |
|
|
|
|
uint8_t *p; |
|
|
|
|
int vt_extradata_size = 23 + 5 + vps->data_size + 5 + sps->data_size + 3; |
|
|
|
|
uint8_t *vt_extradata; |
|
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_PPS_COUNT; i++) { |
|
|
|
|
if (h->ps.pps_list[i]) { |
|
|
|
|
const HEVCPPS *pps = (const HEVCPPS *)h->ps.pps_list[i]->data; |
|
|
|
|
vt_extradata_size += 2 + pps->data_size; |
|
|
|
|
num_pps++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
vt_extradata = av_malloc(vt_extradata_size); |
|
|
|
|
if (!vt_extradata) |
|
|
|
|
return NULL; |
|
|
|
|
p = vt_extradata; |
|
|
|
|
|
|
|
|
|
/* unsigned int(8) configurationVersion = 1; */ |
|
|
|
|
AV_W8(p + 0, 1); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* unsigned int(2) general_profile_space; |
|
|
|
|
* unsigned int(1) general_tier_flag; |
|
|
|
|
* unsigned int(5) general_profile_idc; |
|
|
|
|
*/ |
|
|
|
|
AV_W8(p + 1, ptlc.profile_space << 6 | |
|
|
|
|
ptlc.tier_flag << 5 | |
|
|
|
|
ptlc.profile_idc); |
|
|
|
|
|
|
|
|
|
/* unsigned int(32) general_profile_compatibility_flags; */ |
|
|
|
|
memcpy(p + 2, ptlc.profile_compatibility_flag, 4); |
|
|
|
|
|
|
|
|
|
/* unsigned int(48) general_constraint_indicator_flags; */ |
|
|
|
|
AV_W8(p + 6, ptlc.progressive_source_flag << 7 | |
|
|
|
|
ptlc.interlaced_source_flag << 6 | |
|
|
|
|
ptlc.non_packed_constraint_flag << 5 | |
|
|
|
|
ptlc.frame_only_constraint_flag << 4); |
|
|
|
|
AV_W8(p + 7, 0); |
|
|
|
|
AV_WN32(p + 8, 0); |
|
|
|
|
|
|
|
|
|
/* unsigned int(8) general_level_idc; */ |
|
|
|
|
AV_W8(p + 12, ptlc.level_idc); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* bit(4) reserved = ‘1111’b; |
|
|
|
|
* unsigned int(12) min_spatial_segmentation_idc; |
|
|
|
|
*/ |
|
|
|
|
AV_W8(p + 13, 0xf0 | (vui.min_spatial_segmentation_idc >> 4)); |
|
|
|
|
AV_W8(p + 14, vui.min_spatial_segmentation_idc & 0xff); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* bit(6) reserved = ‘111111’b; |
|
|
|
|
* unsigned int(2) parallelismType; |
|
|
|
|
*/ |
|
|
|
|
if (!vui.min_spatial_segmentation_idc) |
|
|
|
|
parallelismType = 0; |
|
|
|
|
else if (pps->entropy_coding_sync_enabled_flag && pps->tiles_enabled_flag) |
|
|
|
|
parallelismType = 0; |
|
|
|
|
else if (pps->entropy_coding_sync_enabled_flag) |
|
|
|
|
parallelismType = 3; |
|
|
|
|
else if (pps->tiles_enabled_flag) |
|
|
|
|
parallelismType = 2; |
|
|
|
|
else |
|
|
|
|
parallelismType = 1; |
|
|
|
|
AV_W8(p + 15, 0xfc | parallelismType); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* bit(6) reserved = ‘111111’b; |
|
|
|
|
* unsigned int(2) chromaFormat; |
|
|
|
|
*/ |
|
|
|
|
AV_W8(p + 16, sps->chroma_format_idc | 0xfc); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* bit(5) reserved = ‘11111’b; |
|
|
|
|
* unsigned int(3) bitDepthLumaMinus8; |
|
|
|
|
*/ |
|
|
|
|
AV_W8(p + 17, (sps->bit_depth - 8) | 0xfc); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* bit(5) reserved = ‘11111’b; |
|
|
|
|
* unsigned int(3) bitDepthChromaMinus8; |
|
|
|
|
*/ |
|
|
|
|
AV_W8(p + 18, (sps->bit_depth_chroma - 8) | 0xfc); |
|
|
|
|
|
|
|
|
|
/* bit(16) avgFrameRate; */ |
|
|
|
|
AV_WB16(p + 19, 0); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* bit(2) constantFrameRate; |
|
|
|
|
* bit(3) numTemporalLayers; |
|
|
|
|
* bit(1) temporalIdNested; |
|
|
|
|
* unsigned int(2) lengthSizeMinusOne; |
|
|
|
|
*/ |
|
|
|
|
AV_W8(p + 21, 0 << 6 | |
|
|
|
|
sps->max_sub_layers << 3 | |
|
|
|
|
sps->temporal_id_nesting_flag << 2 | |
|
|
|
|
3); |
|
|
|
|
|
|
|
|
|
/* unsigned int(8) numOfArrays; */ |
|
|
|
|
AV_W8(p + 22, 3); |
|
|
|
|
|
|
|
|
|
p += 23; |
|
|
|
|
/* vps */ |
|
|
|
|
/*
|
|
|
|
|
* bit(1) array_completeness; |
|
|
|
|
* unsigned int(1) reserved = 0; |
|
|
|
|
* unsigned int(6) NAL_unit_type; |
|
|
|
|
*/ |
|
|
|
|
AV_W8(p, 1 << 7 | |
|
|
|
|
HEVC_NAL_VPS & 0x3f); |
|
|
|
|
/* unsigned int(16) numNalus; */ |
|
|
|
|
AV_WB16(p + 1, 1); |
|
|
|
|
/* unsigned int(16) nalUnitLength; */ |
|
|
|
|
AV_WB16(p + 3, vps->data_size); |
|
|
|
|
/* bit(8*nalUnitLength) nalUnit; */ |
|
|
|
|
memcpy(p + 5, vps->data, vps->data_size); |
|
|
|
|
p += 5 + vps->data_size; |
|
|
|
|
|
|
|
|
|
/* sps */ |
|
|
|
|
AV_W8(p, 1 << 7 | |
|
|
|
|
HEVC_NAL_SPS & 0x3f); |
|
|
|
|
AV_WB16(p + 1, 1); |
|
|
|
|
AV_WB16(p + 3, sps->data_size); |
|
|
|
|
memcpy(p + 5, sps->data, sps->data_size); |
|
|
|
|
p += 5 + sps->data_size; |
|
|
|
|
|
|
|
|
|
/* pps */ |
|
|
|
|
AV_W8(p, 1 << 7 | |
|
|
|
|
HEVC_NAL_PPS & 0x3f); |
|
|
|
|
AV_WB16(p + 1, num_pps); |
|
|
|
|
p += 3; |
|
|
|
|
for (i = 0; i < MAX_PPS_COUNT; i++) { |
|
|
|
|
if (h->ps.pps_list[i]) { |
|
|
|
|
const HEVCPPS *pps = (const HEVCPPS *)h->ps.pps_list[i]->data; |
|
|
|
|
AV_WB16(p, pps->data_size); |
|
|
|
|
memcpy(p + 2, pps->data, pps->data_size); |
|
|
|
|
p += 2 + pps->data_size; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
av_assert0(p - vt_extradata == vt_extradata_size); |
|
|
|
|
|
|
|
|
|
data = CFDataCreate(kCFAllocatorDefault, vt_extradata, vt_extradata_size); |
|
|
|
|
av_free(vt_extradata); |
|
|
|
|
return data; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int ff_videotoolbox_buffer_create(VTContext *vtctx, AVFrame *frame) |
|
|
|
|
{ |
|
|
|
|
av_buffer_unref(&frame->buf[0]); |
|
|
|
@ -445,6 +608,18 @@ static int videotoolbox_h264_end_frame(AVCodecContext *avctx) |
|
|
|
|
return videotoolbox_common_end_frame(avctx, frame); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int videotoolbox_hevc_end_frame(AVCodecContext *avctx) |
|
|
|
|
{ |
|
|
|
|
HEVCContext *h = avctx->priv_data; |
|
|
|
|
AVFrame *frame = h->ref->frame; |
|
|
|
|
VTContext *vtctx = avctx->internal->hwaccel_priv_data; |
|
|
|
|
int ret; |
|
|
|
|
|
|
|
|
|
ret = videotoolbox_common_end_frame(avctx, frame); |
|
|
|
|
vtctx->bitstream_size = 0; |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int videotoolbox_mpeg_start_frame(AVCodecContext *avctx, |
|
|
|
|
const uint8_t *buffer, |
|
|
|
|
uint32_t size) |
|
|
|
@ -501,6 +676,11 @@ static CFDictionaryRef videotoolbox_decoder_config_create(CMVideoCodecType codec |
|
|
|
|
if (data) |
|
|
|
|
CFDictionarySetValue(avc_info, CFSTR("avcC"), data); |
|
|
|
|
break; |
|
|
|
|
case kCMVideoCodecType_HEVC : |
|
|
|
|
data = ff_videotoolbox_hvcc_extradata_create(avctx); |
|
|
|
|
if (data) |
|
|
|
|
CFDictionarySetValue(avc_info, CFSTR("hvcC"), data); |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
@ -600,6 +780,9 @@ static int videotoolbox_default_init(AVCodecContext *avctx) |
|
|
|
|
case AV_CODEC_ID_H264 : |
|
|
|
|
videotoolbox->cm_codec_type = kCMVideoCodecType_H264; |
|
|
|
|
break; |
|
|
|
|
case AV_CODEC_ID_HEVC : |
|
|
|
|
videotoolbox->cm_codec_type = kCMVideoCodecType_HEVC; |
|
|
|
|
break; |
|
|
|
|
case AV_CODEC_ID_MPEG1VIDEO : |
|
|
|
|
videotoolbox->cm_codec_type = kCMVideoCodecType_MPEG1Video; |
|
|
|
|
break; |
|
|
|
@ -782,6 +965,20 @@ AVHWAccel ff_h263_videotoolbox_hwaccel = { |
|
|
|
|
.priv_data_size = sizeof(VTContext), |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
AVHWAccel ff_hevc_videotoolbox_hwaccel = { |
|
|
|
|
.name = "hevc_videotoolbox", |
|
|
|
|
.type = AVMEDIA_TYPE_VIDEO, |
|
|
|
|
.id = AV_CODEC_ID_HEVC, |
|
|
|
|
.pix_fmt = AV_PIX_FMT_VIDEOTOOLBOX, |
|
|
|
|
.alloc_frame = ff_videotoolbox_alloc_frame, |
|
|
|
|
.start_frame = ff_videotoolbox_h264_start_frame, |
|
|
|
|
.decode_slice = ff_videotoolbox_h264_decode_slice, |
|
|
|
|
.end_frame = videotoolbox_hevc_end_frame, |
|
|
|
|
.init = videotoolbox_common_init, |
|
|
|
|
.uninit = ff_videotoolbox_uninit, |
|
|
|
|
.priv_data_size = sizeof(VTContext), |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
AVHWAccel ff_h264_videotoolbox_hwaccel = { |
|
|
|
|
.name = "h264_videotoolbox", |
|
|
|
|
.type = AVMEDIA_TYPE_VIDEO, |
|
|
|
|