static bool_t h264_dec_init_decoder(VTH264DecCtx *ctx) { OSStatus status; CFMutableDictionaryRef pixel_parameters = NULL; CFNumberRef value; const int pixel_format = kCVPixelFormatType_420YpCbCr8Planar; VTDecompressionOutputCallbackRecord dec_cb = { (VTDecompressionOutputCallback)h264_dec_output_cb, ctx }; ms_message("VideoToolboxDecoder: creating a decoding session"); value = CFNumberCreate(NULL, kCFNumberIntType, &pixel_format); pixel_parameters = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); CFDictionaryAddValue(pixel_parameters, kCVPixelBufferPixelFormatTypeKey, value); if(ctx->format_desc == NULL) { ms_error("VideoToolboxDecoder: could not create the decoding context: no format description"); return FALSE; } status = VTDecompressionSessionCreate(NULL, ctx->format_desc, NULL, pixel_parameters, &dec_cb, &ctx->session); CFRelease(pixel_parameters); if(status != noErr) { ms_error("VideoToolboxDecoder: could not create the decoding context: error %d", status); return FALSE; } return TRUE; }
nsresult AppleVTDecoder::InitializeSession() { OSStatus rv; AutoCFRelease<CFDictionaryRef> extensions = CreateDecoderExtensions(); rv = CMVideoFormatDescriptionCreate(kCFAllocatorDefault, kCMVideoCodecType_H264, mPictureWidth, mPictureHeight, extensions, &mFormat); if (rv != noErr) { NS_ERROR("Couldn't create format description!"); return NS_ERROR_FAILURE; } // Contruct video decoder selection spec. AutoCFRelease<CFDictionaryRef> spec = CreateDecoderSpecification(); // Contruct output configuration. AutoCFRelease<CFDictionaryRef> outputConfiguration = CreateOutputConfiguration(); VTDecompressionOutputCallbackRecord cb = { PlatformCallback, this }; rv = VTDecompressionSessionCreate(kCFAllocatorDefault, mFormat, spec, // Video decoder selection. outputConfiguration, // Output video format. &cb, &mSession); if (rv != noErr) { NS_ERROR("Couldn't create decompression session!"); return NS_ERROR_FAILURE; } if (AppleVTLinker::skPropUsingHWAccel) { CFBooleanRef isUsingHW = nullptr; rv = VTSessionCopyProperty(mSession, AppleVTLinker::skPropUsingHWAccel, kCFAllocatorDefault, &isUsingHW); if (rv != noErr) { LOG("AppleVTDecoder: system doesn't support hardware acceleration"); } mIsHardwareAccelerated = rv == noErr && isUsingHW == kCFBooleanTrue; LOG("AppleVTDecoder: %s hardware accelerated decoding", mIsHardwareAccelerated ? "using" : "not using"); } else { LOG("AppleVTDecoder: couldn't determine hardware acceleration status."); } return NS_OK; }
static OSStatus gst_vtdec_create_session (GstVtdec * vtdec, GstVideoFormat format, gboolean enable_hardware) { CFMutableDictionaryRef output_image_buffer_attrs; VTDecompressionOutputCallbackRecord callback; CFMutableDictionaryRef videoDecoderSpecification; OSStatus status; guint32 cv_format = 0; g_return_val_if_fail (vtdec->session == NULL, FALSE); switch (format) { case GST_VIDEO_FORMAT_NV12: cv_format = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange; break; case GST_VIDEO_FORMAT_UYVY: cv_format = kCVPixelFormatType_422YpCbCr8; break; case GST_VIDEO_FORMAT_RGBA: cv_format = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange; break; default: g_warn_if_reached (); break; } videoDecoderSpecification = CFDictionaryCreateMutable (NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); /* This is the default on iOS and the key does not exist there */ #ifndef HAVE_IOS gst_vtutil_dict_set_boolean (videoDecoderSpecification, kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder, enable_hardware); if (enable_hardware && vtdec->require_hardware) gst_vtutil_dict_set_boolean (videoDecoderSpecification, kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder, TRUE); #endif output_image_buffer_attrs = CFDictionaryCreateMutable (NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); gst_vtutil_dict_set_i32 (output_image_buffer_attrs, kCVPixelBufferPixelFormatTypeKey, cv_format); gst_vtutil_dict_set_i32 (output_image_buffer_attrs, kCVPixelBufferWidthKey, vtdec->video_info.width); gst_vtutil_dict_set_i32 (output_image_buffer_attrs, kCVPixelBufferHeightKey, vtdec->video_info.height); callback.decompressionOutputCallback = gst_vtdec_session_output_callback; callback.decompressionOutputRefCon = vtdec; status = VTDecompressionSessionCreate (NULL, vtdec->format_description, videoDecoderSpecification, output_image_buffer_attrs, &callback, &vtdec->session); CFRelease (output_image_buffer_attrs); return status; }
nsresult AppleVTDecoder::InitializeSession() { OSStatus rv; #ifdef LOG_MEDIA_SHA1 SHA1Sum avc_hash; avc_hash.update(mExtraData->Elements(),mExtraData->Length()); uint8_t digest_buf[SHA1Sum::kHashSize]; avc_hash.finish(digest_buf); nsAutoCString avc_digest; for (size_t i = 0; i < sizeof(digest_buf); i++) { avc_digest.AppendPrintf("%02x", digest_buf[i]); } LOG("AVCDecoderConfig %ld bytes sha1 %s", mExtraData->Length(), avc_digest.get()); #endif // LOG_MEDIA_SHA1 AutoCFRelease<CFDictionaryRef> extensions = CreateDecoderExtensions(); rv = CMVideoFormatDescriptionCreate(kCFAllocatorDefault, kCMVideoCodecType_H264, mPictureWidth, mPictureHeight, extensions, &mFormat); if (rv != noErr) { NS_ERROR("Couldn't create format description!"); return NS_ERROR_FAILURE; } // Contruct video decoder selection spec. AutoCFRelease<CFDictionaryRef> spec = CreateDecoderSpecification(); // Contruct output configuration. AutoCFRelease<CFDictionaryRef> outputConfiguration = CreateOutputConfiguration(); VTDecompressionOutputCallbackRecord cb = { PlatformCallback, this }; rv = VTDecompressionSessionCreate(kCFAllocatorDefault, mFormat, spec, // Video decoder selection. outputConfiguration, // Output video format. &cb, &mSession); if (rv != noErr) { NS_ERROR("Couldn't create decompression session!"); return NS_ERROR_FAILURE; } if (AppleVTLinker::skPropUsingHWAccel) { CFBooleanRef isUsingHW = nullptr; rv = VTSessionCopyProperty(mSession, AppleVTLinker::skPropUsingHWAccel, kCFAllocatorDefault, &isUsingHW); if (rv != noErr) { LOG("AppleVTDecoder: system doesn't support hardware acceleration"); } mIsHardwareAccelerated = rv == noErr && isUsingHW == kCFBooleanTrue; LOG("AppleVTDecoder: %s hardware accelerated decoding", mIsHardwareAccelerated ? "using" : "not using"); } else { LOG("AppleVTDecoder: couldn't determine hardware acceleration status."); } return NS_OK; }
static int video_vtb_codec_create(media_codec_t *mc, const media_codec_params_t *mcp, media_pipe_t *mp) { OSStatus status; if(!video_settings.video_accel) return 1; switch(mc->codec_id) { case AV_CODEC_ID_H264: break; default: return 1; } if(mcp == NULL || mcp->extradata == NULL || mcp->extradata_size == 0 || ((const uint8_t *)mcp->extradata)[0] != 1) return h264_annexb_to_avc(mc, mp, &video_vtb_codec_create); CFMutableDictionaryRef config_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(config_dict, kCVImageBufferChromaLocationBottomFieldKey, kCVImageBufferChromaLocation_Left); CFDictionarySetValue(config_dict, kCVImageBufferChromaLocationTopFieldKey, kCVImageBufferChromaLocation_Left); // Setup extradata CFMutableDictionaryRef extradata_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDataRef extradata = CFDataCreate(kCFAllocatorDefault, mcp->extradata, mcp->extradata_size); CFDictionarySetValue(extradata_dict, CFSTR("avcC"), extradata); CFRelease(extradata); CFDictionarySetValue(config_dict, kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms, extradata_dict); CFRelease(extradata_dict); #if !TARGET_OS_IPHONE // Enable and force HW accelration CFDictionarySetValue(config_dict, kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder, kCFBooleanTrue); CFDictionarySetValue(config_dict, kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder, kCFBooleanTrue); #endif CMVideoFormatDescriptionRef fmt; status = CMVideoFormatDescriptionCreate(kCFAllocatorDefault, kCMVideoCodecType_H264, mcp->width, mcp->height, config_dict, &fmt); if(status) { TRACE(TRACE_DEBUG, "VTB", "Unable to create description %d", status); return 1; } CFMutableDictionaryRef surface_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(surface_dict, #if !TARGET_OS_IPHONE kCVPixelBufferOpenGLCompatibilityKey, #else kCVPixelBufferOpenGLESCompatibilityKey, #endif kCFBooleanTrue); vtb_decoder_t *vtbd = calloc(1, sizeof(vtb_decoder_t)); dict_set_int32(surface_dict, kCVPixelBufferWidthKey, mcp->width); dict_set_int32(surface_dict, kCVPixelBufferHeightKey, mcp->height); #if TARGET_OS_IPHONE vtbd->vtbd_pixel_format = kCVPixelFormatType_420YpCbCr8BiPlanarFullRange; #else vtbd->vtbd_pixel_format = kCVPixelFormatType_420YpCbCr8Planar; #endif dict_set_int32(surface_dict, kCVPixelBufferPixelFormatTypeKey, vtbd->vtbd_pixel_format); int linewidth = mcp->width; switch(vtbd->vtbd_pixel_format) { case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange: case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange: linewidth *= 2; break; } dict_set_int32(surface_dict, kCVPixelBufferBytesPerRowAlignmentKey, linewidth); VTDecompressionOutputCallbackRecord cb = { .decompressionOutputCallback = picture_out, .decompressionOutputRefCon = vtbd }; /* create decompression session */ status = VTDecompressionSessionCreate(kCFAllocatorDefault, fmt, config_dict, surface_dict, &cb, &vtbd->vtbd_session); CFRelease(config_dict); CFRelease(surface_dict); if(status) { TRACE(TRACE_DEBUG, "VTB", "Failed to open -- %d", status); CFRelease(fmt); return 1; } vtbd->vtbd_fmt = fmt; vtbd->vtbd_max_ts = PTS_UNSET; vtbd->vtbd_flush_to = PTS_UNSET; vtbd->vtbd_last_pts = PTS_UNSET; mc->opaque = vtbd; mc->decode = vtb_decode; mc->close = vtb_close; mc->flush = vtb_flush; TRACE(TRACE_DEBUG, "VTB", "Opened decoder"); return 0; }
nsresult AppleVTDecoder::InitializeSession() { OSStatus rv; AutoCFRelease<CFMutableDictionaryRef> extensions = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); AppleUtils::SetCFDict(extensions, "CVImageBufferChromaLocationBottomField", "left"); AppleUtils::SetCFDict(extensions, "CVImageBufferChromaLocationTopField", "left"); AppleUtils::SetCFDict(extensions, "FullRangeVideo", true); AutoCFRelease<CFMutableDictionaryRef> atoms = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); AutoCFRelease<CFDataRef> avc_data = CFDataCreate(NULL, mConfig.extra_data.begin(), mConfig.extra_data.length()); #ifdef LOG_MEDIA_SHA1 SHA1Sum avc_hash; avc_hash.update(mConfig.extra_data.begin(), mConfig.extra_data.length()); uint8_t digest_buf[SHA1Sum::kHashSize]; avc_hash.finish(digest_buf); nsAutoCString avc_digest; for (size_t i = 0; i < sizeof(digest_buf); i++) { avc_digest.AppendPrintf("%02x", digest_buf[i]); } LOG("AVCDecoderConfig %ld bytes sha1 %s", mConfig.extra_data.length(), avc_digest.get()); #endif // LOG_MEDIA_SHA1 CFDictionarySetValue(atoms, CFSTR("avcC"), avc_data); CFDictionarySetValue(extensions, CFSTR("SampleDescriptionExtensionAtoms"), atoms); rv = CMVideoFormatDescriptionCreate(NULL, // Use default allocator. kCMVideoCodecType_H264, mConfig.display_width, mConfig.display_height, extensions, &mFormat); if (rv != noErr) { NS_ERROR("Couldn't create format description!"); return NS_ERROR_FAILURE; } // Contruct video decoder selection spec. AutoCFRelease<CFMutableDictionaryRef> spec = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); // This key is supported (or ignored) but not declared prior to OSX 10.9. AutoCFRelease<CFStringRef> kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder = CFStringCreateWithCString(NULL, "EnableHardwareAcceleratedVideoDecoder", kCFStringEncodingUTF8); CFDictionarySetValue(spec, kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder, kCFBooleanTrue); VTDecompressionOutputCallbackRecord cb = { PlatformCallback, this }; rv = VTDecompressionSessionCreate(NULL, // Allocator. mFormat, spec, // Video decoder selection. NULL, // Output video format. &cb, &mSession); if (rv != noErr) { NS_ERROR("Couldn't create decompression session!"); return NS_ERROR_FAILURE; } return NS_OK; }
static GF_Err VTBDec_InitDecoder(VTBDec *ctx, Bool force_dsi_rewrite) { CFMutableDictionaryRef dec_dsi, dec_type; CFMutableDictionaryRef dsi; VTDecompressionOutputCallbackRecord cbacks; CFDictionaryRef buffer_attribs; OSStatus status; OSType kColorSpace; CFDataRef data = NULL; char *dsi_data=NULL; u32 dsi_data_size=0; dec_dsi = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); kColorSpace = kCVPixelFormatType_420YpCbCr8Planar; ctx->pix_fmt = GF_PIXEL_YV12; switch (ctx->esd->decoderConfig->objectTypeIndication) { case GPAC_OTI_VIDEO_AVC : if (ctx->sps && ctx->pps) { AVCState avc; s32 idx; memset(&avc, 0, sizeof(AVCState)); avc.sps_active_idx = -1; idx = gf_media_avc_read_sps(ctx->sps, ctx->sps_size, &avc, 0, NULL); ctx->vtb_type = kCMVideoCodecType_H264; assert(ctx->sps); ctx->width = avc.sps[idx].width; ctx->height = avc.sps[idx].height; if (avc.sps[idx].vui.par_num && avc.sps[idx].vui.par_den) { ctx->pixel_ar = avc.sps[idx].vui.par_num; ctx->pixel_ar <<= 16; ctx->pixel_ar |= avc.sps[idx].vui.par_den; } ctx->chroma_format = avc.sps[idx].chroma_format; ctx->luma_bit_depth = 8 + avc.sps[idx].luma_bit_depth_m8; ctx->chroma_bit_depth = 8 + avc.sps[idx].chroma_bit_depth_m8; switch (ctx->chroma_format) { case 2: //422 decoding doesn't seem supported ... if (ctx->luma_bit_depth>8) { kColorSpace = kCVPixelFormatType_422YpCbCr10; ctx->pix_fmt = GF_PIXEL_YUV422_10; } else { kColorSpace = kCVPixelFormatType_422YpCbCr8; ctx->pix_fmt = GF_PIXEL_YUV422; } break; case 3: if (ctx->luma_bit_depth>8) { kColorSpace = kCVPixelFormatType_444YpCbCr10; ctx->pix_fmt = GF_PIXEL_YUV444_10; } else { kColorSpace = kCVPixelFormatType_444YpCbCr8; ctx->pix_fmt = GF_PIXEL_YUV444; } break; default: if (ctx->luma_bit_depth>8) { kColorSpace = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange; ctx->pix_fmt = GF_PIXEL_YV12_10; } break; } if (!ctx->esd->decoderConfig->decoderSpecificInfo || force_dsi_rewrite || !ctx->esd->decoderConfig->decoderSpecificInfo->data) { GF_AVCConfigSlot *slc_s, *slc_p; GF_AVCConfig *cfg = gf_odf_avc_cfg_new(); cfg->configurationVersion = 1; cfg->profile_compatibility = avc.sps[idx].prof_compat; cfg->AVCProfileIndication = avc.sps[idx].profile_idc; cfg->AVCLevelIndication = avc.sps[idx].level_idc; cfg->chroma_format = avc.sps[idx].chroma_format; cfg->luma_bit_depth = 8 + avc.sps[idx].luma_bit_depth_m8; cfg->chroma_bit_depth = 8 + avc.sps[idx].chroma_bit_depth_m8; cfg->nal_unit_size = 4; GF_SAFEALLOC(slc_s, GF_AVCConfigSlot); slc_s->data = ctx->sps; slc_s->size = ctx->sps_size; gf_list_add(cfg->sequenceParameterSets, slc_s); GF_SAFEALLOC(slc_p, GF_AVCConfigSlot); slc_p->data = ctx->pps; slc_p->size = ctx->pps_size; gf_list_add(cfg->pictureParameterSets , slc_p); gf_odf_avc_cfg_write(cfg, &dsi_data, &dsi_data_size); slc_s->data = slc_p->data = NULL; gf_odf_avc_cfg_del((cfg)); } else { dsi_data = ctx->esd->decoderConfig->decoderSpecificInfo->data; dsi_data_size = ctx->esd->decoderConfig->decoderSpecificInfo->dataLength; } dsi = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); data = CFDataCreate(kCFAllocatorDefault, dsi_data, dsi_data_size); if (data) { CFDictionarySetValue(dsi, CFSTR("avcC"), data); CFDictionarySetValue(dec_dsi, kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms, dsi); CFRelease(data); } CFRelease(dsi); if (!ctx->esd->decoderConfig->decoderSpecificInfo || !ctx->esd->decoderConfig->decoderSpecificInfo->data) { gf_free(ctx->sps); ctx->sps = NULL; gf_free(ctx->pps); ctx->pps = NULL; gf_free(dsi_data); } } break; case GPAC_OTI_VIDEO_MPEG2_SIMPLE: case GPAC_OTI_VIDEO_MPEG2_MAIN: case GPAC_OTI_VIDEO_MPEG2_SNR: case GPAC_OTI_VIDEO_MPEG2_SPATIAL: case GPAC_OTI_VIDEO_MPEG2_HIGH: case GPAC_OTI_VIDEO_MPEG2_422: ctx->vtb_type = kCMVideoCodecType_MPEG2Video; if (!ctx->width || !ctx->height) { ctx->init_mpeg12 = GF_TRUE; return GF_OK; } ctx->init_mpeg12 = GF_FALSE; break; case GPAC_OTI_VIDEO_MPEG1: ctx->vtb_type = kCMVideoCodecType_MPEG1Video; if (!ctx->width || !ctx->height) { ctx->init_mpeg12 = GF_TRUE; return GF_OK; } ctx->init_mpeg12 = GF_FALSE; break; case GPAC_OTI_VIDEO_MPEG4_PART2 : { Bool reset_dsi = GF_FALSE; ctx->vtb_type = kCMVideoCodecType_MPEG4Video; if (!ctx->esd->decoderConfig->decoderSpecificInfo) { ctx->esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG); } if (!ctx->esd->decoderConfig->decoderSpecificInfo->data) { reset_dsi = GF_TRUE; ctx->esd->decoderConfig->decoderSpecificInfo->data = ctx->vosh; ctx->esd->decoderConfig->decoderSpecificInfo->dataLength = ctx->vosh_size; } if (ctx->esd->decoderConfig->decoderSpecificInfo->data) { GF_M4VDecSpecInfo vcfg; GF_BitStream *bs; gf_m4v_get_config(ctx->esd->decoderConfig->decoderSpecificInfo->data, ctx->esd->decoderConfig->decoderSpecificInfo->dataLength, &vcfg); ctx->width = vcfg.width; ctx->height = vcfg.height; if (ctx->esd->slConfig) { ctx->esd->slConfig->predefined = 2; } bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); gf_bs_write_u32(bs, 0); gf_odf_desc_write_bs((GF_Descriptor *) ctx->esd, bs); gf_bs_get_content(bs, &dsi_data, &dsi_data_size); gf_bs_del(bs); dsi = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); data = CFDataCreate(kCFAllocatorDefault, dsi_data, dsi_data_size); gf_free(dsi_data); if (data) { CFDictionarySetValue(dsi, CFSTR("esds"), data); CFDictionarySetValue(dec_dsi, kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms, dsi); CFRelease(data); } CFRelease(dsi); if (reset_dsi) { ctx->esd->decoderConfig->decoderSpecificInfo->data = NULL; ctx->esd->decoderConfig->decoderSpecificInfo->dataLength = 0; } ctx->skip_mpeg4_vosh = GF_FALSE; } else { ctx->skip_mpeg4_vosh = GF_TRUE; return GF_OK; } break; } case GPAC_OTI_MEDIA_GENERIC: if (ctx->esd->decoderConfig->decoderSpecificInfo && ctx->esd->decoderConfig->decoderSpecificInfo->dataLength) { char *dsi = ctx->esd->decoderConfig->decoderSpecificInfo->data; if (ctx->esd->decoderConfig->decoderSpecificInfo->dataLength<8) return GF_NON_COMPLIANT_BITSTREAM; if (strnicmp(dsi, "s263", 4)) return GF_NOT_SUPPORTED; ctx->width = ((u8) dsi[4]); ctx->width<<=8; ctx->width |= ((u8) dsi[5]); ctx->height = ((u8) dsi[6]); ctx->height<<=8; ctx->height |= ((u8) dsi[7]); ctx->vtb_type = kCMVideoCodecType_H263; } break; default : return GF_NOT_SUPPORTED; } if (! ctx->width || !ctx->height) return GF_NOT_SUPPORTED; status = CMVideoFormatDescriptionCreate(kCFAllocatorDefault, ctx->vtb_type, ctx->width, ctx->height, dec_dsi, &ctx->fmt_desc); if (!ctx->fmt_desc) { if (dec_dsi) CFRelease(dec_dsi); return GF_NON_COMPLIANT_BITSTREAM; } buffer_attribs = VTBDec_CreateBufferAttributes(ctx->width, ctx->height, kColorSpace); cbacks.decompressionOutputCallback = VTBDec_on_frame; cbacks.decompressionOutputRefCon = ctx; dec_type = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(dec_type, kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder, kCFBooleanTrue); ctx->is_hardware = GF_TRUE; status = VTDecompressionSessionCreate(NULL, ctx->fmt_desc, dec_type, NULL, &cbacks, &ctx->vtb_session); //if HW decoder not available, try soft one if (status) { status = VTDecompressionSessionCreate(NULL, ctx->fmt_desc, NULL, buffer_attribs, &cbacks, &ctx->vtb_session); ctx->is_hardware = GF_FALSE; } if (dec_dsi) CFRelease(dec_dsi); if (dec_type) CFRelease(dec_type); if (buffer_attribs) CFRelease(buffer_attribs); switch (status) { case kVTVideoDecoderNotAvailableNowErr: case kVTVideoDecoderUnsupportedDataFormatErr: return GF_NOT_SUPPORTED; case kVTVideoDecoderMalfunctionErr: return GF_IO_ERR; case kVTVideoDecoderBadDataErr : return GF_BAD_PARAM; case kVTPixelTransferNotSupportedErr: case kVTCouldNotFindVideoDecoderErr: return GF_NOT_SUPPORTED; case 0: break; default: return GF_SERVICE_ERROR; } //good to go ! if (ctx->pix_fmt == GF_PIXEL_YUV422) { ctx->out_size = ctx->width*ctx->height*2; } else if (ctx->pix_fmt == GF_PIXEL_YUV444) { ctx->out_size = ctx->width*ctx->height*3; } else { // (ctx->pix_fmt == GF_PIXEL_YV12) ctx->out_size = ctx->width*ctx->height*3/2; } if (ctx->luma_bit_depth>8) { ctx->out_size *= 2; } return GF_OK; }
nsresult AppleVTDecoder::InitializeSession() { OSStatus rv; AutoCFRelease<CFMutableDictionaryRef> extensions = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); AppleUtils::SetCFDict(extensions, "CVImageBufferChromaLocationBottomField", "left"); AppleUtils::SetCFDict(extensions, "CVImageBufferChromaLocationTopField", "left"); AppleUtils::SetCFDict(extensions, "FullRangeVideo", true); AutoCFRelease<CFMutableDictionaryRef> atoms = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); AutoCFRelease<CFDataRef> avc_data = CFDataCreate(NULL, mConfig.extra_data.begin(), mConfig.extra_data.length()); #ifdef LOG_MEDIA_SHA1 SHA1Sum avc_hash; avc_hash.update(mConfig.extra_data.begin(), mConfig.extra_data.length()); uint8_t digest_buf[SHA1Sum::kHashSize]; avc_hash.finish(digest_buf); nsAutoCString avc_digest; for (size_t i = 0; i < sizeof(digest_buf); i++) { avc_digest.AppendPrintf("%02x", digest_buf[i]); } LOG("AVCDecoderConfig %ld bytes sha1 %s", mConfig.extra_data.length(), avc_digest.get()); #endif // LOG_MEDIA_SHA1 CFDictionarySetValue(atoms, CFSTR("avcC"), avc_data); CFDictionarySetValue(extensions, CFSTR("SampleDescriptionExtensionAtoms"), atoms); rv = CMVideoFormatDescriptionCreate(NULL, // Use default allocator. kCMVideoCodecType_H264, mConfig.display_width, mConfig.display_height, extensions, &mFormat); if (rv != noErr) { NS_ERROR("Couldn't create format description!"); return NS_ERROR_FAILURE; } // Contruct video decoder selection spec. AutoCFRelease<CFMutableDictionaryRef> spec = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); // FIXME: Enabling hardware acceleration causes crashes in // VTDecompressionSessionCreate() with multiple videos. Bug 1055694 #if 0 // This key is supported (or ignored) but not declared prior to OSX 10.9. AutoCFRelease<CFStringRef> kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder = CFStringCreateWithCString(NULL, "EnableHardwareAcceleratedVideoDecoder", kCFStringEncodingUTF8); CFDictionarySetValue(spec, kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder, kCFBooleanTrue); #endif // Contruct output configuration. SInt32 PixelFormatTypeValue = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange; AutoCFRelease<CFNumberRef> PixelFormatTypeNumber = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &PixelFormatTypeValue); const void* outputKeys[] = { kCVPixelBufferPixelFormatTypeKey }; const void* outputValues[] = { PixelFormatTypeNumber }; static_assert(ArrayLength(outputKeys) == ArrayLength(outputValues), "Non matching keys/values array size"); AutoCFRelease<CFDictionaryRef> outputConfiguration = CFDictionaryCreate(kCFAllocatorDefault, outputKeys, outputValues, ArrayLength(outputKeys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); VTDecompressionOutputCallbackRecord cb = { PlatformCallback, this }; rv = VTDecompressionSessionCreate(NULL, // Allocator. mFormat, spec, // Video decoder selection. outputConfiguration, // Output video format. &cb, &mSession); if (rv != noErr) { NS_ERROR("Couldn't create decompression session!"); return NS_ERROR_FAILURE; } return NS_OK; }