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; }
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; }