Title: [125318] trunk/Source/WebCore
Revision
125318
Author
[email protected]
Date
2012-08-10 13:13:02 -0700 (Fri, 10 Aug 2012)

Log Message

Use the new AVPlayerItemVideoOutput API in MediaPlayerPrivateAVFoundation.
https://bugs.webkit.org/show_bug.cgi?id=93591

Reviewed by Eric Carlson.

Support the new AVPlayerItemVideoOutput API from Mountain Lion, which has much increased performance over
AVAssetImageGenerator.

No new tests; Performance change only, no net change in functionality.

AVPlayerItemVideoOutput requires an attached CALayer for rendering to occur.  Make the rendering modes non-exclusive,
so layer-rendering and context-rendering can exist simultaneously:
* platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h: Make the MediaRenderingMode enum
    a bitfield.
* platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp:
(WebCore::MediaPlayerPrivateAVFoundation::currentRenderingModes): Renamed from currentRenderingMode().
(WebCore::MediaPlayerPrivateAVFoundation::setUpVideoRendering): Check for the presence of the MediaRenderingToLayer bit.
(WebCore::MediaPlayerPrivateAVFoundation::prepareForRendering): Ditto.
(WebCore::MediaPlayerPrivateAVFoundation::updateStates): Ditto.

Pull out existing the AVAssetImageGenerator into its own functions:
* platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
(WebCore::MediaPlayerPrivateAVFoundationObjC::createImageGenerator):
(WebCore::MediaPlayerPrivateAVFoundationObjC::destroyImageGenerator):
(WebCore::MediaPlayerPrivateAVFoundationObjC::paintWithImageGenerator):

Add new AVPlayerItemVideoOutput equivalent functions:
* platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
(WebCore::MediaPlayerPrivateAVFoundationObjC::createVideoOutput):
(WebCore::MediaPlayerPrivateAVFoundationObjC::destroyVideoOutput):
(WebCore::MediaPlayerPrivateAVFoundationObjC::createPixelBuffer):
(WebCore::MediaPlayerPrivateAVFoundationObjC::paintWithVideoOutput):

Switch between the AVAssetImageGenerator and AVPlayerItemVideoOutput functions from
within the original functions:
* platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
(WebCore::MediaPlayerPrivateAVFoundationObjC::createContextVideoRenderer):
(WebCore::MediaPlayerPrivateAVFoundationObjC::destroyContextVideoRenderer):
(WebCore::MediaPlayerPrivateAVFoundationObjC::hasContextRenderer):
(WebCore::MediaPlayerPrivateAVFoundationObjC::paint):

* platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
(WebCore::MediaPlayerPrivateAVFoundationObjC::createImageForTimeInRect): Call the
    AVAssetImageGenerator creation function directly.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (125317 => 125318)


--- trunk/Source/WebCore/ChangeLog	2012-08-10 20:10:57 UTC (rev 125317)
+++ trunk/Source/WebCore/ChangeLog	2012-08-10 20:13:02 UTC (rev 125318)
@@ -1,3 +1,50 @@
+2012-08-09  Jer Noble  <[email protected]>
+
+        Use the new AVPlayerItemVideoOutput API in MediaPlayerPrivateAVFoundation.
+        https://bugs.webkit.org/show_bug.cgi?id=93591
+
+        Reviewed by Eric Carlson.
+
+        Support the new AVPlayerItemVideoOutput API from Mountain Lion, which has much increased performance over
+        AVAssetImageGenerator.
+
+        No new tests; Performance change only, no net change in functionality.
+
+        AVPlayerItemVideoOutput requires an attached CALayer for rendering to occur.  Make the rendering modes non-exclusive, 
+        so layer-rendering and context-rendering can exist simultaneously:
+        * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h: Make the MediaRenderingMode enum
+            a bitfield.
+        * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp:
+        (WebCore::MediaPlayerPrivateAVFoundation::currentRenderingModes): Renamed from currentRenderingMode().
+        (WebCore::MediaPlayerPrivateAVFoundation::setUpVideoRendering): Check for the presence of the MediaRenderingToLayer bit.
+        (WebCore::MediaPlayerPrivateAVFoundation::prepareForRendering): Ditto.
+        (WebCore::MediaPlayerPrivateAVFoundation::updateStates): Ditto.
+
+        Pull out existing the AVAssetImageGenerator into its own functions:
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::createImageGenerator):
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::destroyImageGenerator):
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::paintWithImageGenerator):
+
+        Add new AVPlayerItemVideoOutput equivalent functions:
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::createVideoOutput):
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::destroyVideoOutput):
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::createPixelBuffer):
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::paintWithVideoOutput):
+
+        Switch between the AVAssetImageGenerator and AVPlayerItemVideoOutput functions from
+        within the original functions:
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::createContextVideoRenderer):
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::destroyContextVideoRenderer):
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::hasContextRenderer):
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::paint):
+
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::createImageForTimeInRect): Call the 
+            AVAssetImageGenerator creation function directly.
+
 2012-08-10  Abhishek Arya  <[email protected]>
 
         Crash on accessing a removed layout root in FrameView::scheduleRelayout.

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp (125317 => 125318)


--- trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp	2012-08-10 20:10:57 UTC (rev 125317)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp	2012-08-10 20:13:02 UTC (rev 125318)
@@ -116,6 +116,10 @@
 
     MediaRenderingMode currentMode = currentRenderingMode();
     MediaRenderingMode preferredMode = preferredRenderingMode();
+
+    if (preferredMode == MediaRenderingNone)
+        preferredMode = MediaRenderingToContext;
+
     if (currentMode == preferredMode && currentMode != MediaRenderingNone)
         return;
 

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h (125317 => 125318)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h	2012-08-10 20:10:57 UTC (rev 125317)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h	2012-08-10 20:13:02 UTC (rev 125318)
@@ -33,6 +33,7 @@
 OBJC_CLASS AVAsset;
 OBJC_CLASS AVPlayer;
 OBJC_CLASS AVPlayerItem;
+OBJC_CLASS AVPlayerItemVideoOutput;
 OBJC_CLASS AVPlayerLayer;
 OBJC_CLASS AVAssetImageGenerator;
 OBJC_CLASS WebCoreAVFMovieObserver;
@@ -42,6 +43,7 @@
 #endif
 
 typedef struct CGImage *CGImageRef;
+typedef struct __CVBuffer *CVPixelBufferRef;
 
 namespace WebCore {
 
@@ -110,7 +112,17 @@
 
     virtual bool hasSingleSecurityOrigin() const;
 
+#if __MAC_OS_X_VERSION_MIN_REQUIRED < 1080
+    void createImageGenerator();
+    void destroyImageGenerator();
     RetainPtr<CGImageRef> createImageForTimeInRect(float, const IntRect&);
+    void paintWithImageGenerator(GraphicsContext*, const IntRect&);
+#else
+    void createVideoOutput();
+    void destroyVideoOutput();
+    RetainPtr<CVPixelBufferRef> createPixelBuffer();
+    void paintWithVideoOutput(GraphicsContext*, const IntRect&);
+#endif
 
     MediaPlayer* m_player;
     RetainPtr<AVAsset> m_avAsset;
@@ -118,10 +130,16 @@
     RetainPtr<AVPlayerItem> m_avPlayerItem;
     RetainPtr<AVPlayerLayer> m_videoLayer;
     RetainPtr<WebCoreAVFMovieObserver> m_objcObserver;
-    RetainPtr<AVAssetImageGenerator> m_imageGenerator;
     RetainPtr<id> m_timeObserver;
     bool m_videoFrameHasDrawn;
     bool m_haveCheckedPlayability;
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED < 1080
+    RetainPtr<AVAssetImageGenerator> m_imageGenerator;
+#else
+    RetainPtr<AVPlayerItemVideoOutput> m_videoOutput;
+    RetainPtr<CVPixelBufferRef> m_lastImage;
+#endif
 };
 
 }

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm (125317 => 125318)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm	2012-08-10 20:10:57 UTC (rev 125317)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm	2012-08-10 20:13:02 UTC (rev 125318)
@@ -56,6 +56,7 @@
 
 SOFT_LINK_CLASS(AVFoundation, AVPlayer)
 SOFT_LINK_CLASS(AVFoundation, AVPlayerItem)
+SOFT_LINK_CLASS(AVFoundation, AVPlayerItemVideoOutput)
 SOFT_LINK_CLASS(AVFoundation, AVPlayerLayer)
 SOFT_LINK_CLASS(AVFoundation, AVURLAsset)
 SOFT_LINK_CLASS(AVFoundation, AVAssetImageGenerator)
@@ -73,6 +74,7 @@
 
 #define AVPlayer getAVPlayerClass()
 #define AVPlayerItem getAVPlayerItemClass()
+#define AVPlayerItemVideoOutput getAVPlayerItemVideoOutputClass()
 #define AVPlayerLayer getAVPlayerLayerClass()
 #define AVURLAsset getAVURLAssetClass()
 #define AVAssetImageGenerator getAVAssetImageGeneratorClass()
@@ -183,13 +185,27 @@
 
 bool MediaPlayerPrivateAVFoundationObjC::hasContextRenderer() const
 {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
+    return m_videoOutput;
+#else
     return m_imageGenerator;
+#endif
 }
 
 void MediaPlayerPrivateAVFoundationObjC::createContextVideoRenderer()
 {
-    LOG(Media, "MediaPlayerPrivateAVFoundationObjC::createContextVideoRenderer(%p)", this);
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
+    createVideoOutput();
+#else
+    createImageGenerator();
+#endif
+}
 
+#if __MAC_OS_X_VERSION_MIN_REQUIRED < 1080
+void MediaPlayerPrivateAVFoundationObjC::createImageGenerator()
+{
+    LOG(Media, "MediaPlayerPrivateAVFoundationObjC::createImageGenerator(%p)", this);
+
     if (!m_avAsset || m_imageGenerator)
         return;
 
@@ -202,16 +218,28 @@
 
     LOG(Media, "MediaPlayerPrivateAVFoundationObjC::createImageGenerator(%p) - returning %p", this, m_imageGenerator.get());
 }
+#endif
 
 void MediaPlayerPrivateAVFoundationObjC::destroyContextVideoRenderer()
 {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
+    destroyVideoOutput();
+#else
+    destroyImageGenerator();
+#endif
+}
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED < 1080
+void MediaPlayerPrivateAVFoundationObjC::destroyImageGenerator()
+{
     if (!m_imageGenerator)
         return;
 
-    LOG(Media, "MediaPlayerPrivateAVFoundationObjC::destroyContextVideoRenderer(%p) - destroying  %p", this, m_imageGenerator.get());
+    LOG(Media, "MediaPlayerPrivateAVFoundationObjC::destroyImageGenerator(%p) - destroying  %p", this, m_imageGenerator.get());
 
     m_imageGenerator = 0;
 }
+#endif
 
 void MediaPlayerPrivateAVFoundationObjC::createVideoLayer()
 {
@@ -611,6 +639,21 @@
     setDelayCallbacks(true);
     BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
+    paintWithVideoOutput(context, rect);
+#else
+    paintWithImageGenerator(context, rect);
+#endif
+
+    END_BLOCK_OBJC_EXCEPTIONS;
+    setDelayCallbacks(false);
+
+    m_videoFrameHasDrawn = true;
+}
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED < 1080
+void MediaPlayerPrivateAVFoundationObjC::paintWithImageGenerator(GraphicsContext* context, const IntRect& rect)
+{
     RetainPtr<CGImageRef> image = createImageForTimeInRect(currentTime(), rect);
     if (image) {
         GraphicsContextStateSaver stateSaver(*context);
@@ -621,12 +664,8 @@
         CGContextDrawImage(context->platformContext(), CGRectMake(0, 0, paintRect.width(), paintRect.height()), image.get());
         image = 0;
     }
-
-    END_BLOCK_OBJC_EXCEPTIONS;
-    setDelayCallbacks(false);
-
-    m_videoFrameHasDrawn = true;
 }
+#endif
 
 static HashSet<String> mimeTypeCache()
 {
@@ -644,10 +683,11 @@
     return cache;
 } 
 
+#if __MAC_OS_X_VERSION_MIN_REQUIRED < 1080
 RetainPtr<CGImageRef> MediaPlayerPrivateAVFoundationObjC::createImageForTimeInRect(float time, const IntRect& rect)
 {
     if (!m_imageGenerator)
-        createContextVideoRenderer();
+        createImageGenerator();
     ASSERT(m_imageGenerator);
 
 #if !LOG_DISABLED
@@ -664,6 +704,7 @@
 
     return image;
 }
+#endif
 
 void MediaPlayerPrivateAVFoundationObjC::getSupportedTypes(HashSet<String>& supportedTypes)
 {
@@ -781,6 +822,81 @@
     return resolvedOrigin->isSameSchemeHostPort(requestedOrigin.get());
 }
 
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
+void MediaPlayerPrivateAVFoundationObjC::createVideoOutput()
+{
+    LOG(Media, "MediaPlayerPrivateAVFoundationObjC::createVideoOutput(%p)", this);
+
+    if (!m_avPlayerItem || m_videoOutput)
+        return;
+
+    NSDictionary* attributes = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedInt:k32BGRAPixelFormat], kCVPixelBufferPixelFormatTypeKey,
+                                nil];
+    m_videoOutput.adoptNS([[AVPlayerItemVideoOutput alloc] initWithPixelBufferAttributes:attributes]);
+    ASSERT(m_videoOutput);
+
+    [m_avPlayerItem.get() addOutput:m_videoOutput.get()];
+
+    LOG(Media, "MediaPlayerPrivateAVFoundationObjC::createVideoOutput(%p) - returning %p", this, m_videoOutput.get());
+}
+
+void MediaPlayerPrivateAVFoundationObjC::destroyVideoOutput()
+{
+    if (!m_videoOutput)
+        return;
+
+    if (m_avPlayerItem)
+        [m_avPlayerItem.get() removeOutput:m_videoOutput.get()];
+    LOG(Media, "MediaPlayerPrivateAVFoundationObjC::destroyVideoOutput(%p) - destroying  %p", this, m_videoOutput.get());
+
+    m_videoOutput = 0;
+}
+
+RetainPtr<CVPixelBufferRef> MediaPlayerPrivateAVFoundationObjC::createPixelBuffer()
+{
+    if (!m_videoOutput)
+        createVideoOutput();
+    ASSERT(m_videoOutput);
+
+#if !LOG_DISABLED
+    double start = WTF::currentTime();
+#endif
+
+    RetainPtr<CVPixelBufferRef> buffer = adoptCF([m_videoOutput.get() copyPixelBufferForItemTime:[m_avPlayerItem.get() currentTime] itemTimeForDisplay:nil]);
+
+#if !LOG_DISABLED
+    double duration = WTF::currentTime() - start;
+    LOG(Media, "MediaPlayerPrivateAVFoundationObjC::createPixelBuffer() - creating buffer took %.4f", this, narrowPrecisionToFloat(duration));
+#endif
+
+    return buffer;
+}
+
+void MediaPlayerPrivateAVFoundationObjC::paintWithVideoOutput(GraphicsContext* context, const IntRect& rect)
+{
+    RetainPtr<CVPixelBufferRef> pixelBuffer = createPixelBuffer();
+
+    // Calls to copyPixelBufferForItemTime:itemTimeForDisplay: may return nil if the pixel buffer
+    // for the requested time has already been retrieved. In this case, the last valid image (if any)
+    // should be displayed.
+    if (pixelBuffer)
+        m_lastImage = pixelBuffer;
+
+    if (m_lastImage) {
+        GraphicsContextStateSaver stateSaver(*context);
+        context->translate(rect.x(), rect.y() + rect.height());
+        context->scale(FloatSize(1.0f, -1.0f));
+        RetainPtr<CIImage> image(AdoptNS, [[CIImage alloc] initWithCVImageBuffer:m_lastImage.get()]);
+
+        // ciContext does not use a RetainPtr for results of contextWithCGContext:, as the returned value
+        // is autoreleased, and there is no non-autoreleased version of that function.
+        CIContext* ciContext = [CIContext contextWithCGContext:context->platformContext() options:nil];
+        [ciContext drawImage:image.get() inRect:rect fromRect:rect];
+    }
+}
+
+#endif
+
 NSArray* assetMetadataKeyNames()
 {
     static NSArray* keys;
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to