nsresult AppleVDADecoder::InitializeSession() { OSStatus rv; AutoCFRelease<CFDictionaryRef> decoderConfig = CreateDecoderSpecification(); AutoCFRelease<CFDictionaryRef> outputConfiguration = CreateOutputConfiguration(); rv = VDADecoderCreate(decoderConfig, outputConfiguration, (VDADecoderOutputCallback*)PlatformCallback, this, &mDecoder); if (rv != noErr) { NS_WARNING("AppleVDADecoder: Couldn't create hardware VDA decoder"); return NS_ERROR_FAILURE; } return NS_OK; }
OSStatus MoonVDADecoder::CreateDecoder (SInt32 inHeight, SInt32 inWidth, OSType inSourceFormat, CFDataRef inAVCCData) { OSStatus status; CFMutableDictionaryRef decoderConfiguration = NULL; CFMutableDictionaryRef destinationImageBufferAttributes = NULL; CFDictionaryRef emptyDictionary; CFNumberRef height = NULL; CFNumberRef width= NULL; CFNumberRef sourceFormat = NULL; CFNumberRef pixelFormat = NULL; // source must be H.264 if (inSourceFormat != 'avc1') { fprintf (stderr, "Source format is not H.264!\n"); return paramErr; } // the avcC data chunk from the bitstream must be present if (inAVCCData == NULL) { fprintf (stderr, "avc1 decoder configuration data cannot be NULL!\n"); return paramErr; } decoderConfiguration = CFDictionaryCreateMutable (kCFAllocatorDefault, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); height = CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt32Type, &inHeight); width = CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt32Type, &inWidth); sourceFormat = CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt32Type, &inSourceFormat); CFDictionarySetValue (decoderConfiguration, kVDADecoderConfiguration_Height, height); CFDictionarySetValue (decoderConfiguration, kVDADecoderConfiguration_Width, width); CFDictionarySetValue (decoderConfiguration, kVDADecoderConfiguration_SourceFormat, sourceFormat); CFDictionarySetValue (decoderConfiguration, kVDADecoderConfiguration_avcCData, inAVCCData); destinationImageBufferAttributes = CFDictionaryCreateMutable (kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); OSType cvPixelFormatType = kCVPixelFormatType_422YpCbCr8; pixelFormat = CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt32Type, &cvPixelFormatType); emptyDictionary = CFDictionaryCreate (kCFAllocatorDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue (destinationImageBufferAttributes, kCVPixelBufferPixelFormatTypeKey, pixelFormat); CFDictionarySetValue (destinationImageBufferAttributes, kCVPixelBufferIOSurfacePropertiesKey, emptyDictionary); status = VDADecoderCreate (decoderConfiguration, destinationImageBufferAttributes, (VDADecoderOutputCallback*) VDADecoderCallback, this, (VDADecoder*) &decoder); if (decoderConfiguration) CFRelease (decoderConfiguration); if (destinationImageBufferAttributes) CFRelease (destinationImageBufferAttributes); if (emptyDictionary) CFRelease (emptyDictionary); return status; }
bool CDVDVideoCodecVDA::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) { if (CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_USEVDA) && !hints.software) { CCocoaAutoPool pool; // int width = hints.width; int height = hints.height; int level = hints.level; int profile = hints.profile; switch(profile) { case FF_PROFILE_H264_HIGH_10: case FF_PROFILE_H264_HIGH_10_INTRA: case FF_PROFILE_H264_HIGH_422: case FF_PROFILE_H264_HIGH_422_INTRA: case FF_PROFILE_H264_HIGH_444_PREDICTIVE: case FF_PROFILE_H264_HIGH_444_INTRA: case FF_PROFILE_H264_CAVLC_444: CLog::Log(LOGNOTICE, "%s - unsupported h264 profile(%d)", __FUNCTION__, hints.profile); return false; break; } if (width <= 0 || height <= 0) { CLog::Log(LOGNOTICE, "%s - bailing with bogus hints, width(%d), height(%d)", __FUNCTION__, width, height); return false; } if (Cocoa_GPUForDisplayIsNvidiaPureVideo3() && !CDVDCodecUtils::IsVP3CompatibleWidth(width)) { CLog::Log(LOGNOTICE, "%s - Nvidia 9400 GPU hardware limitation, cannot decode a width of %d", __FUNCTION__, width); return false; } CFDataRef avcCData; switch (hints.codec) { case AV_CODEC_ID_H264: m_bitstream = new CBitstreamConverter; if (!m_bitstream->Open(hints.codec, (uint8_t*)hints.extradata, hints.extrasize, false)) return false; avcCData = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)m_bitstream->GetExtraData(), m_bitstream->GetExtraSize()); m_format = 'avc1'; m_pFormatName = "vda-h264"; break; default: return false; break; } // check the avcC atom's sps for number of reference frames and // bail if interlaced, VDA does not handle interlaced h264. uint32_t avcc_len = CFDataGetLength(avcCData); if (avcc_len < 8) { // avcc atoms with length less than 8 are borked. CFRelease(avcCData); delete m_bitstream, m_bitstream = NULL; return false; } else { bool interlaced = true; uint8_t *spc = (uint8_t*)CFDataGetBytePtr(avcCData) + 6; uint32_t sps_size = BS_RB16(spc); if (sps_size) m_bitstream->parseh264_sps(spc+3, sps_size-1, &interlaced, &m_max_ref_frames); if (interlaced) { CLog::Log(LOGNOTICE, "%s - possible interlaced content.", __FUNCTION__); CFRelease(avcCData); return false; } } if (profile == FF_PROFILE_H264_MAIN && level == 32 && m_max_ref_frames > 4) { // [email protected], VDA cannot handle greater than 4 reference frames CLog::Log(LOGNOTICE, "%s - [email protected] detected, VDA cannot decode.", __FUNCTION__); CFRelease(avcCData); return false; } std::string rendervendor = g_Windowing.GetRenderVendor(); StringUtils::ToLower(rendervendor); if (rendervendor.find("nvidia") != std::string::npos) { // Nvidia gpu's are all powerful and work the way god intended m_decode_async = true; // The gods are liars, ignore the sirens for now. m_use_cvBufferRef = false; } else if (rendervendor.find("intel") != std::string::npos) { // Intel gpu are borked when using cvBufferRef m_decode_async = true; m_use_cvBufferRef = false; } else { // ATI gpu's are borked when using async decode m_decode_async = false; // They lie here too. m_use_cvBufferRef = false; } if (!m_use_cvBufferRef) { // allocate a YV12 DVDVideoPicture buffer. // first make sure all properties are reset. memset(&m_videobuffer, 0, sizeof(DVDVideoPicture)); unsigned int iPixels = width * height; unsigned int iChromaPixels = iPixels/4; m_videobuffer.dts = DVD_NOPTS_VALUE; m_videobuffer.pts = DVD_NOPTS_VALUE; m_videobuffer.iFlags = DVP_FLAG_ALLOCATED; m_videobuffer.format = RENDER_FMT_YUV420P; m_videobuffer.color_range = 0; m_videobuffer.color_matrix = 4; m_videobuffer.iWidth = width; m_videobuffer.iHeight = height; m_videobuffer.iDisplayWidth = width; m_videobuffer.iDisplayHeight = height; m_videobuffer.iLineSize[0] = width; //Y m_videobuffer.iLineSize[1] = width/2; //U m_videobuffer.iLineSize[2] = width/2; //V m_videobuffer.iLineSize[3] = 0; m_videobuffer.data[0] = (uint8_t*)malloc(16 + iPixels); m_videobuffer.data[1] = (uint8_t*)malloc(16 + iChromaPixels); m_videobuffer.data[2] = (uint8_t*)malloc(16 + iChromaPixels); m_videobuffer.data[3] = NULL; // set all data to 0 for less artifacts.. hmm.. what is black in YUV?? memset(m_videobuffer.data[0], 0, iPixels); memset(m_videobuffer.data[1], 0, iChromaPixels); memset(m_videobuffer.data[2], 0, iChromaPixels); } // setup the decoder configuration dict CFMutableDictionaryRef decoderConfiguration = CFDictionaryCreateMutable( kCFAllocatorDefault, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFNumberRef avcWidth = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &width); CFNumberRef avcHeight = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &height); CFNumberRef avcFormat = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &m_format); CFDictionarySetValue(decoderConfiguration, kVDADecoderConfiguration_Height, avcHeight); CFDictionarySetValue(decoderConfiguration, kVDADecoderConfiguration_Width, avcWidth); CFDictionarySetValue(decoderConfiguration, kVDADecoderConfiguration_SourceFormat, avcFormat); CFDictionarySetValue(decoderConfiguration, kVDADecoderConfiguration_avcCData, avcCData); // release the retained object refs, decoderConfiguration owns them now CFRelease(avcWidth); CFRelease(avcHeight); CFRelease(avcFormat); CFRelease(avcCData); // setup the destination image buffer dict, vda will output this pict format CFMutableDictionaryRef destinationImageBufferAttributes = CFDictionaryCreateMutable( kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); OSType cvPixelFormatType = kCVPixelFormatType_422YpCbCr8; CFNumberRef pixelFormat = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &cvPixelFormatType); // an IOSurface properties dictionary CFDictionaryRef iosurfaceDictionary = CFDictionaryCreate(kCFAllocatorDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(destinationImageBufferAttributes, kCVPixelBufferPixelFormatTypeKey, pixelFormat); CFDictionarySetValue(destinationImageBufferAttributes, kCVPixelBufferIOSurfacePropertiesKey, iosurfaceDictionary); // release the retained object refs, destinationImageBufferAttributes owns them now CFRelease(pixelFormat); CFRelease(iosurfaceDictionary); // create the VDADecoder object OSStatus status; try { status = VDADecoderCreate(decoderConfiguration, destinationImageBufferAttributes, (VDADecoderOutputCallback*)VDADecoderCallback, this, (VDADecoder*)&m_vda_decoder); } catch (...) { CLog::Log(LOGERROR, "%s - exception",__FUNCTION__); status = kVDADecoderDecoderFailedErr; } CFRelease(decoderConfiguration); CFRelease(destinationImageBufferAttributes); if (CDarwinUtils::DeviceHasLeakyVDA()) CFRelease(pixelFormat); if (status != kVDADecoderNoErr) { if (status == kVDADecoderDecoderFailedErr) CLog::Log(LOGNOTICE, "%s - VDADecoder Codec failed to open, currently in use by another process", __FUNCTION__); else CLog::Log(LOGNOTICE, "%s - VDADecoder Codec failed to open, status(%d), profile(%d), level(%d)", __FUNCTION__, (int)status, profile, level); return false; } m_DropPictures = false; m_max_ref_frames = std::max(m_max_ref_frames + 1, 5); m_sort_time = 0; return true; } return false; }
int ff_vda_create_decoder(struct vda_context *vda_ctx, uint8_t *extradata, int extradata_size) { OSStatus status = kVDADecoderNoErr; CFNumberRef height; CFNumberRef width; CFNumberRef format; CFDataRef avc_data; CFMutableDictionaryRef config_info; CFMutableDictionaryRef buffer_attributes; CFMutableDictionaryRef io_surface_properties; CFNumberRef cv_pix_fmt; vda_ctx->bitstream = NULL; vda_ctx->ref_size = 0; pthread_mutex_init(&vda_ctx->queue_mutex, NULL); /* Each VCL NAL in the bistream sent to the decoder * is preceded by a 4 bytes length header. * Change the avcC atom header if needed, to signal headers of 4 bytes. */ if (extradata_size >= 4 && (extradata[4] & 0x03) != 0x03) { uint8_t *rw_extradata; if (!(rw_extradata = av_malloc(extradata_size))) return AVERROR(ENOMEM); memcpy(rw_extradata, extradata, extradata_size); rw_extradata[4] |= 0x03; avc_data = CFDataCreate(kCFAllocatorDefault, rw_extradata, extradata_size); av_freep(&rw_extradata); } else { avc_data = CFDataCreate(kCFAllocatorDefault, extradata, extradata_size); } config_info = CFDictionaryCreateMutable(kCFAllocatorDefault, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); height = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->height); width = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->width); format = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->format); CFDictionarySetValue(config_info, kVDADecoderConfiguration_Height, height); CFDictionarySetValue(config_info, kVDADecoderConfiguration_Width, width); CFDictionarySetValue(config_info, kVDADecoderConfiguration_SourceFormat, format); CFDictionarySetValue(config_info, kVDADecoderConfiguration_avcCData, avc_data); buffer_attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); io_surface_properties = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); cv_pix_fmt = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->cv_pix_fmt_type); CFDictionarySetValue(buffer_attributes, kCVPixelBufferPixelFormatTypeKey, cv_pix_fmt); CFDictionarySetValue(buffer_attributes, kCVPixelBufferIOSurfacePropertiesKey, io_surface_properties); status = VDADecoderCreate(config_info, buffer_attributes, (VDADecoderOutputCallback *)vda_decoder_callback, vda_ctx, &vda_ctx->decoder); CFRelease(height); CFRelease(width); CFRelease(format); CFRelease(avc_data); CFRelease(config_info); CFRelease(io_surface_properties); CFRelease(cv_pix_fmt); CFRelease(buffer_attributes); if (kVDADecoderNoErr != status) return status; return 0; }
static int video_vda_codec_create(media_codec_t *mc, const media_codec_params_t *mcp, media_pipe_t *mp) { OSStatus status = kVDADecoderNoErr; CFNumberRef height; CFNumberRef width; CFNumberRef format; CFDataRef avc_data; CFMutableDictionaryRef ci; CFMutableDictionaryRef ba; CFMutableDictionaryRef isp; CFNumberRef cv_pix_fmt; int zero_copy = 1; if(mc->codec_id != AV_CODEC_ID_H264 || !video_settings.vda) 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_vda_codec_create); const int pixfmt = zero_copy ? kCVPixelFormatType_422YpCbCr8 : kCVPixelFormatType_420YpCbCr8Planar; const int avc1 = 'avc1'; ci = CFDictionaryCreateMutable(kCFAllocatorDefault, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); height = CFNumberCreate(NULL, kCFNumberSInt32Type, &mcp->height); width = CFNumberCreate(NULL, kCFNumberSInt32Type, &mcp->width); format = CFNumberCreate(NULL, kCFNumberSInt32Type, &avc1); avc_data = CFDataCreate(NULL, mcp->extradata, mcp->extradata_size); CFDictionarySetValue(ci, kVDADecoderConfiguration_Height, height); CFDictionarySetValue(ci, kVDADecoderConfiguration_Width, width); CFDictionarySetValue(ci, kVDADecoderConfiguration_SourceFormat, format); CFDictionarySetValue(ci, kVDADecoderConfiguration_avcCData, avc_data); ba = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); isp = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); cv_pix_fmt = CFNumberCreate(NULL, kCFNumberSInt32Type, &pixfmt); CFDictionarySetValue(ba, kCVPixelBufferPixelFormatTypeKey, cv_pix_fmt); CFDictionarySetValue(ba, kCVPixelBufferIOSurfacePropertiesKey, isp); vda_decoder_t *vdad = calloc(1, sizeof(vda_decoder_t)); vdad->vdad_zero_copy = zero_copy; status = VDADecoderCreate(ci, ba, (void *)vda_callback, vdad, &vdad->vdad_decoder); CFRelease(height); CFRelease(width); CFRelease(format); CFRelease(avc_data); CFRelease(ci); CFRelease(isp); CFRelease(cv_pix_fmt); CFRelease(ba); if(kVDADecoderNoErr != status) { free(vdad); return 1; } hts_mutex_init(&vdad->vdad_mutex); vdad->vdad_max_ts = PTS_UNSET; vdad->vdad_flush_to = PTS_UNSET; vdad->vdad_last_pts = PTS_UNSET; vdad->vdad_mc = mc; mc->opaque = vdad; mc->decode = vda_decode; mc->close = vda_close; mc->flush = vda_flush; TRACE(TRACE_DEBUG, "VDA", "Opened decoder"); return 0; }
int ff_vda_default_init(AVCodecContext *avctx) { AVVDAContext *vda_ctx = avctx->hwaccel_context; OSStatus status = kVDADecoderNoErr; CFNumberRef height; CFNumberRef width; CFNumberRef format; CFDataRef avc_data; CFMutableDictionaryRef config_info; CFMutableDictionaryRef buffer_attributes; CFMutableDictionaryRef io_surface_properties; CFNumberRef cv_pix_fmt; int32_t fmt = 'avc1', pix_fmt = vda_ctx->cv_pix_fmt_type; // kCVPixelFormatType_420YpCbCr8Planar; /* Each VCL NAL in the bitstream sent to the decoder * is preceded by a 4 bytes length header. * Change the avcC atom header if needed, to signal headers of 4 bytes. */ if (avctx->extradata_size >= 4 && (avctx->extradata[4] & 0x03) != 0x03) { uint8_t *rw_extradata; if (!(rw_extradata = av_malloc(avctx->extradata_size))) return AVERROR(ENOMEM); memcpy(rw_extradata, avctx->extradata, avctx->extradata_size); rw_extradata[4] |= 0x03; avc_data = CFDataCreate(kCFAllocatorDefault, rw_extradata, avctx->extradata_size); av_freep(&rw_extradata); } else { avc_data = CFDataCreate(kCFAllocatorDefault, avctx->extradata, avctx->extradata_size); } config_info = CFDictionaryCreateMutable(kCFAllocatorDefault, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); height = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &avctx->height); width = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &avctx->width); format = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &fmt); CFDictionarySetValue(config_info, kVDADecoderConfiguration_Height, height); CFDictionarySetValue(config_info, kVDADecoderConfiguration_Width, width); CFDictionarySetValue(config_info, kVDADecoderConfiguration_avcCData, avc_data); CFDictionarySetValue(config_info, kVDADecoderConfiguration_SourceFormat, format); buffer_attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); io_surface_properties = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); cv_pix_fmt = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &pix_fmt); CFDictionarySetValue(buffer_attributes, kCVPixelBufferPixelFormatTypeKey, cv_pix_fmt); CFDictionarySetValue(buffer_attributes, kCVPixelBufferIOSurfacePropertiesKey, io_surface_properties); status = VDADecoderCreate(config_info, buffer_attributes, (VDADecoderOutputCallback *)ff_vda_output_callback, avctx, &vda_ctx->decoder); CFRelease(format); CFRelease(height); CFRelease(width); CFRelease(avc_data); CFRelease(config_info); CFRelease(cv_pix_fmt); CFRelease(io_surface_properties); CFRelease(buffer_attributes); if (status != kVDADecoderNoErr) { av_log(avctx, AV_LOG_ERROR, "Cannot initialize VDA %d\n", status); } switch (status) { case kVDADecoderHardwareNotSupportedErr: case kVDADecoderFormatNotSupportedErr: return AVERROR(ENOSYS); case kVDADecoderConfigurationError: return AVERROR(EINVAL); case kVDADecoderDecoderFailedErr: return AVERROR_INVALIDDATA; case kVDADecoderNoErr: return 0; default: return AVERROR_UNKNOWN; } }