Mac: Avoid using k32BGRAPixelFormat on certain platforms.
authorjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 24 Jan 2013 20:18:49 +0000 (20:18 +0000)
committerjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 24 Jan 2013 20:18:49 +0000 (20:18 +0000)
https://bugs.webkit.org/show_bug.cgi?id=107732

Reviewed by Eric Carlson.

Using a AVPlayerItemVideoOutput to generate ARGB pixel buffers is a potential performance
hit, as the AVPlayerItemVideoOutput will send YUV buffers through a VTPixeBufferTransferSession
to convert them to ARGB regardless of whether or not a given buffer will be used. Instead,
ask the AVPlayerItemVideoOutput for pixel buffers in the decoder's native pixel format and use
the VTPixelBufferTransferSession to convert to ARGB only those pixel buffers which were actually
requested.

* platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h:
* platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
(WebCore::MediaPlayerPrivateAVFoundationObjC::createVideoOutput): Ask for the decoder's native
    pixel format.
(WebCore::MediaPlayerPrivateAVFoundationObjC::createPixelBuffer): Lazily create a VTPixelTransferSession
    and convert output pixel buffers to k32BGRAPixelFormat.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@140706 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h
Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm

index 07cb29a..af29a3a 100644 (file)
@@ -1,3 +1,24 @@
+2013-01-23  Jer Noble  <jer.noble@apple.com>
+
+        Mac: Avoid using k32BGRAPixelFormat on certain platforms.
+        https://bugs.webkit.org/show_bug.cgi?id=107732
+
+        Reviewed by Eric Carlson.
+
+        Using a AVPlayerItemVideoOutput to generate ARGB pixel buffers is a potential performance
+        hit, as the AVPlayerItemVideoOutput will send YUV buffers through a VTPixeBufferTransferSession
+        to convert them to ARGB regardless of whether or not a given buffer will be used. Instead,
+        ask the AVPlayerItemVideoOutput for pixel buffers in the decoder's native pixel format and use
+        the VTPixelBufferTransferSession to convert to ARGB only those pixel buffers which were actually
+        requested.
+
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h:
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::createVideoOutput): Ask for the decoder's native
+            pixel format.
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::createPixelBuffer): Lazily create a VTPixelTransferSession
+            and convert output pixel buffers to k32BGRAPixelFormat.
+
 2013-01-24  Christian Biesinger  <cbiesinger@chromium.org>
 
         Convert RenderFullScreen to use the non-deprecated flexbox
index a3c2e18..62a02eb 100644 (file)
@@ -48,6 +48,7 @@ OBJC_CLASS AVAssetResourceLoadingRequest;
 
 typedef struct CGImage *CGImageRef;
 typedef struct __CVBuffer *CVPixelBufferRef;
+typedef struct OpaqueVTPixelTransferSession* VTPixelTransferSessionRef;
 
 namespace WebCore {
 
@@ -174,6 +175,10 @@ private:
     RetainPtr<CVPixelBufferRef> m_lastImage;
 #endif
 
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
+    RetainPtr<VTPixelTransferSessionRef> m_pixelTransferSession;
+#endif
+
 #if ENABLE(ENCRYPTED_MEDIA) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
     RetainPtr<WebCoreAVFLoaderDelegate> m_loaderDelegate;
     HashMap<String, RetainPtr<AVAssetResourceLoadingRequest> > m_keyURIToRequestMap;
index 3d14780..f1dfa70 100644 (file)
 #import <wtf/Uint16Array.h>
 #import <wtf/Uint32Array.h>
 
-#import <CoreMedia/CoreMedia.h>
 #import <AVFoundation/AVFoundation.h>
+#import <CoreMedia/CoreMedia.h>
+#import <CoreVideo/CoreVideo.h>
+#import <VideoToolbox/VideoToolbox.h>
 
 SOFT_LINK_FRAMEWORK_OPTIONAL(AVFoundation)
 SOFT_LINK_FRAMEWORK_OPTIONAL(CoreMedia)
+SOFT_LINK_FRAMEWORK_OPTIONAL(CoreVideo)
+SOFT_LINK_FRAMEWORK_OPTIONAL(VideoToolbox)
 
 SOFT_LINK(CoreMedia, CMTimeCompare, int32_t, (CMTime time1, CMTime time2), (time1, time2))
 SOFT_LINK(CoreMedia, CMTimeMakeWithSeconds, CMTime, (Float64 seconds, int32_t preferredTimeScale), (seconds, preferredTimeScale))
 SOFT_LINK(CoreMedia, CMTimeGetSeconds, Float64, (CMTime time), (time))
 SOFT_LINK(CoreMedia, CMTimeRangeGetEnd, CMTime, (CMTimeRange range), (range))
+SOFT_LINK(CoreVideo, CVPixelBufferGetWidth, size_t, (CVPixelBufferRef pixelBuffer), (pixelBuffer))
+SOFT_LINK(CoreVideo, CVPixelBufferGetHeight, size_t, (CVPixelBufferRef pixelBuffer), (pixelBuffer))
+SOFT_LINK(VideoToolbox, VTPixelTransferSessionCreate, OSStatus, (CFAllocatorRef allocator, VTPixelTransferSessionRef *pixelTransferSessionOut), (allocator, pixelTransferSessionOut))
+SOFT_LINK(VideoToolbox, VTPixelTransferSessionTransferImage, OSStatus, (VTPixelTransferSessionRef session, CVPixelBufferRef sourceBuffer, CVPixelBufferRef destinationBuffer), (session, sourceBuffer, destinationBuffer))
 
 SOFT_LINK_CLASS(AVFoundation, AVPlayer)
 SOFT_LINK_CLASS(AVFoundation, AVPlayerItem)
@@ -1000,8 +1008,12 @@ void MediaPlayerPrivateAVFoundationObjC::createVideoOutput()
     if (!m_avPlayerItem || m_videoOutput)
         return;
 
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
+    NSDictionary* attributes = @{ (NSString*)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_422YpCbCr8) };
+#else
     NSDictionary* attributes = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedInt:k32BGRAPixelFormat], kCVPixelBufferPixelFormatTypeKey,
                                 nil];
+#endif
     m_videoOutput.adoptNS([[AVPlayerItemVideoOutput alloc] initWithPixelBufferAttributes:attributes]);
     ASSERT(m_videoOutput);
 
@@ -1032,7 +1044,26 @@ RetainPtr<CVPixelBufferRef> MediaPlayerPrivateAVFoundationObjC::createPixelBuffe
     double start = WTF::currentTime();
 #endif
 
-    RetainPtr<CVPixelBufferRef> buffer = adoptCF([m_videoOutput.get() copyPixelBufferForItemTime:[m_avPlayerItem.get() currentTime] itemTimeForDisplay:nil]);
+    CMTime currentTime = [m_avPlayerItem.get() currentTime];
+
+    if (![m_videoOutput.get() hasNewPixelBufferForItemTime:currentTime])
+        return 0;
+
+    RetainPtr<CVPixelBufferRef> buffer = adoptCF([m_videoOutput.get() copyPixelBufferForItemTime:currentTime itemTimeForDisplay:nil]);
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
+    // Create a VTPixelTransferSession, if necessary, as we cannot guarantee timely delivery of ARGB pixels.
+    if (!m_pixelTransferSession) {
+        VTPixelTransferSessionRef session = 0;
+        VTPixelTransferSessionCreate(kCFAllocatorDefault, &session);
+        m_pixelTransferSession = adoptCF(session);
+    }
+
+    CVPixelBufferRef outputBuffer;
+    CVPixelBufferCreate(kCFAllocatorDefault, CVPixelBufferGetWidth(buffer.get()), CVPixelBufferGetHeight(buffer.get()), k32BGRAPixelFormat, 0, &outputBuffer);
+    VTPixelTransferSessionTransferImage(m_pixelTransferSession.get(), buffer.get(), outputBuffer);
+    buffer = adoptCF(outputBuffer);
+#endif
 
 #if !LOG_DISABLED
     double duration = WTF::currentTime() - start;