static CGImageRef CreateCGImageFromPixelBuffer(QTPixelBuffer buffer) { #if USE(ACCELERATED_COMPOSITING) CGDataProviderRef provider = 0; CGColorSpaceRef colorSpace = 0; CGImageRef image = 0; size_t bitsPerComponent = 0; size_t bitsPerPixel = 0; CGImageAlphaInfo alphaInfo = kCGImageAlphaNone; if (buffer.pixelFormatIs32BGRA()) { bitsPerComponent = 8; bitsPerPixel = 32; alphaInfo = (CGImageAlphaInfo)(kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little); } else if (buffer.pixelFormatIs32ARGB()) { bitsPerComponent = 8; bitsPerPixel = 32; alphaInfo = (CGImageAlphaInfo)(kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big); } else { // All other pixel formats are currently unsupported: ASSERT_NOT_REACHED(); } CGDataProviderDirectAccessCallbacks callbacks = { &QTPixelBuffer::dataProviderGetBytePointerCallback, &QTPixelBuffer::dataProviderReleaseBytePointerCallback, &QTPixelBuffer::dataProviderGetBytesAtPositionCallback, &QTPixelBuffer::dataProviderReleaseInfoCallback, }; // Colorspace should be device, so that Quartz does not have to do an extra render. colorSpace = CGColorSpaceCreateDeviceRGB(); require(colorSpace, Bail); provider = CGDataProviderCreateDirectAccess(buffer.pixelBufferRef(), buffer.dataSize(), &callbacks); require(provider, Bail); // CGDataProvider does not retain the buffer, but it will release it later, so do an extra retain here: QTPixelBuffer::retainCallback(buffer.pixelBufferRef()); image = CGImageCreate(buffer.width(), buffer.height(), bitsPerComponent, bitsPerPixel, buffer.bytesPerRow(), colorSpace, alphaInfo, provider, 0, false, kCGRenderingIntentDefault); Bail: // Once the image is created we can release our reference to the provider and the colorspace, they are retained by the image if (provider) CGDataProviderRelease(provider); if (colorSpace) CGColorSpaceRelease(colorSpace); return image; #else return 0; #endif }
void MediaPlayerPrivateQuickTimeVisualContext::paint(GraphicsContext* p, const IntRect& r) { MediaRenderingMode currentMode = currentRenderingMode(); if (currentMode == MediaRenderingNone) return; if (currentMode == MediaRenderingSoftwareRenderer && !m_visualContext) return; QTPixelBuffer buffer = m_visualContext->imageForTime(0); if (buffer.pixelBufferRef()) { #if USE(ACCELERATED_COMPOSITING) if (m_qtVideoLayer) { // We are probably being asked to render the video into a canvas, but // there's a good chance the QTPixelBuffer is not ARGB and thus can't be // drawn using CG. If so, fire up an ICMDecompressionSession and convert // the current frame into something which can be rendered by CG. if (!buffer.pixelFormatIs32ARGB() && !buffer.pixelFormatIs32BGRA()) { // The decompression session will only decompress a specific pixelFormat // at a specific width and height; if these differ, the session must be // recreated with the new parameters. if (!m_decompressionSession || !m_decompressionSession->canDecompress(buffer)) m_decompressionSession = QTDecompressionSession::create(buffer.pixelFormatType(), buffer.width(), buffer.height()); buffer = m_decompressionSession->decompress(buffer); } } #endif CGImageRef image = CreateCGImageFromPixelBuffer(buffer); CGContextRef context = p->platformContext(); CGContextSaveGState(context); CGContextTranslateCTM(context, r.x(), r.y()); CGContextTranslateCTM(context, 0, r.height()); CGContextScaleCTM(context, 1, -1); CGContextDrawImage(context, CGRectMake(0, 0, r.width(), r.height()), image); CGContextRestoreGState(context); CGImageRelease(image); } paintCompleted(*p, r); }