Title: [214806] trunk
Revision
214806
Author
commit-qu...@webkit.org
Date
2017-04-03 09:59:41 -0700 (Mon, 03 Apr 2017)

Log Message

captureStream is getting black frames with webgl canvas
https://bugs.webkit.org/show_bug.cgi?id=170325

Patch by Youenn Fablet <you...@apple.com> on 2017-04-03
Reviewed by Dean Jackson.

Source/WebCore:

Test: fast/mediastream/captureStream/canvas3d.html

Changing the webgl context to save buffers in case the canvas is captured.
Adding a canvas changed notification in case of clear.
In the future, we might want to change this notification and do it when endPaint or similar is called.

Adding an Internals API to grab the RGBA equivalent of the next track frame.
For that purpose, adding a bunch of WEBCORE_EXPORT.

* Modules/mediastream/CanvasCaptureMediaStreamTrack.cpp:
(WebCore::CanvasCaptureMediaStreamTrack::Source::Source): Adding constraints support so that track settings
getter actually transmits the width and height of the source.
(WebCore::CanvasCaptureMediaStreamTrack::Source::canvasChanged): ensuring webgl canvas context keep their drawing buffer.
* Modules/mediastream/MediaStreamTrack.h:
* bindings/js/JSDOMGuardedObject.h:
* bindings/js/JSDOMPromise.h:
(WebCore::DeferredPromise::resolve):
(WebCore::DeferredPromise::reject):
* dom/ActiveDOMCallback.h:
* html/HTMLCanvasElement.cpp:
(WebCore::HTMLCanvasElement::captureStream):
* html/ImageData.h:
* html/ImageData.idl:
* html/canvas/WebGLRenderingContext.cpp:
(WebCore::WebGLRenderingContext::clear): ensuring canvas observers get notified in case of clear calls.
* html/canvas/WebGLRenderingContextBase.h:
(WebCore::WebGLRenderingContextBase::preserveDrawingBuffer): Added to allow canvas capture to update this property.
* platform/MediaSample.h:
(WebCore::MediaSample::getRGBAImageData): Added for internals API.
* platform/graphics/avfoundation/MediaSampleAVFObjC.h:
* platform/graphics/avfoundation/objc/MediaSampleAVFObjC.mm:
(WebCore::MediaSampleAVFObjC::getRGBAImageData):
* platform/graphics/cv/PixelBufferConformerCV.cpp:
(WebCore::PixelBufferConformerCV::convert): Helper routine for getRGBAImageData.
* platform/graphics/cv/PixelBufferConformerCV.h:
* platform/mediastream/RealtimeMediaSourceSettings.h:
(WebCore::RealtimeMediaSourceSettings::setSupportedConstraints):
(WebCore::RealtimeMediaSourceSettings::setSupportedConstraits): Deleted.
* platform/mediastream/mac/AVMediaCaptureSource.mm:
(WebCore::AVMediaCaptureSource::initializeSettings):
* platform/mediastream/openwebrtc/RealtimeAudioSourceOwr.h:
* platform/mediastream/openwebrtc/RealtimeVideoSourceOwr.h:
* platform/mock/MockRealtimeMediaSource.cpp:
(WebCore::MockRealtimeMediaSource::initializeSettings):
* testing/Internals.cpp:
(WebCore::Internals::grabNextMediaStreamTrackFrame):
(WebCore::Internals::videoSampleAvailable):
* testing/Internals.h:
* testing/Internals.idl:

LayoutTests:

* fast/mediastream/captureStream/canvas3d-expected.txt: Added.
* fast/mediastream/captureStream/canvas3d.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (214805 => 214806)


--- trunk/LayoutTests/ChangeLog	2017-04-03 16:54:49 UTC (rev 214805)
+++ trunk/LayoutTests/ChangeLog	2017-04-03 16:59:41 UTC (rev 214806)
@@ -1,3 +1,13 @@
+2017-04-03  Youenn Fablet  <you...@apple.com>
+
+        captureStream is getting black frames with webgl canvas
+        https://bugs.webkit.org/show_bug.cgi?id=170325
+
+        Reviewed by Dean Jackson.
+
+        * fast/mediastream/captureStream/canvas3d-expected.txt: Added.
+        * fast/mediastream/captureStream/canvas3d.html: Added.
+
 2017-04-03  Per Arne Vollan  <pvol...@apple.com>
 
         Implement stroke-miterlimit.

Added: trunk/LayoutTests/fast/mediastream/captureStream/canvas3d-expected.txt (0 => 214806)


--- trunk/LayoutTests/fast/mediastream/captureStream/canvas3d-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/mediastream/captureStream/canvas3d-expected.txt	2017-04-03 16:59:41 UTC (rev 214806)
@@ -0,0 +1,7 @@
+CONSOLE MESSAGE: line 23: Turning drawing buffer preservation for the WebGL canvas being captured
+  
+ 
+
+PASS captureStream with 3d context drawing - not buffered initially 
+PASS captureStream with 3d context drawing - buffered initially 
+

Added: trunk/LayoutTests/fast/mediastream/captureStream/canvas3d.html (0 => 214806)


--- trunk/LayoutTests/fast/mediastream/captureStream/canvas3d.html	                        (rev 0)
+++ trunk/LayoutTests/fast/mediastream/captureStream/canvas3d.html	2017-04-03 16:59:41 UTC (rev 214806)
@@ -0,0 +1,81 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+    <body>
+        <canvas id="canvas1" width=400px height=400px></canvas>
+        <video id="video1" controls autoplay width=400px height=400px></video>
+        <br>
+        <canvas id="canvas2" width=400px height=400px></canvas>
+        <video id="video2" controls autoplay width=400px height=400px></video>
+        <script src=""
+        <script src=""
+        <script>
+
+var canvas1 = document.getElementById("canvas1");
+var canvas2 = document.getElementById("canvas2");
+var video1 = document.getElementById("video1");
+var video2 = document.getElementById("video2");
+var gl1 = canvas1.getContext('webgl', { preserveDrawingBuffer: false } );
+var gl2 = canvas2.getContext('webgl', { preserveDrawingBuffer: true } );
+
+function modifyCanvas(gl, green)
+{
+    gl.clearColor(0, green ? 1 : 0, 0, 1);
+    gl.clear(gl.COLOR_BUFFER_BIT);
+
+    setTimeout(() => { modifyCanvas(gl, !green) }, 500);
+}
+
+function checkGreenPixel(value, cptr)
+{
+    var index = cptr % 4;
+    if (index == 0)
+        return value == 0;
+    if (index == 1)
+        return value == 255;
+    if (index == 2)
+        return value == 0;
+    if (index == 3)
+        return value == 255;
+}
+
+promise_test((test) => {
+    var stream = canvas1.captureStream();
+    video1.srcObject = stream;
+
+    if (!window.internals)
+        var promise = Promise.resolve();
+    else {
+        internals.observeMediaStreamTrack(stream.getVideoTracks()[0]);
+        var promise = internals.grabNextMediaStreamTrackFrame().then((data) => {
+            data.data.forEach((value, cptr) => {
+                assert_true(checkGreenPixel(value, cptr), "expecting value " + cptr + " to be part of a green pixel");
+            });
+        })
+    }
+
+    modifyCanvas(gl1, true);
+    return promise;
+}, "captureStream with 3d context drawing - not buffered initially");
+
+promise_test((test) => {
+    var stream = canvas2.captureStream();
+    video2.srcObject = stream;
+
+    if (!window.internals)
+        var promise = Promise.resolve();
+    else {
+        internals.observeMediaStreamTrack(stream.getVideoTracks()[0]);
+        var promise = internals.grabNextMediaStreamTrackFrame().then((data) => {
+            data.data.forEach((value, cptr) => {
+                assert_true(checkGreenPixel(value, cptr), "expecting value " + cptr + " to be part of a green pixel");
+            });
+        })
+    }
+
+    modifyCanvas(gl2, true);
+    return promise;
+}, "captureStream with 3d context drawing - buffered initially");
+
+        </script>
+    </body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (214805 => 214806)


--- trunk/Source/WebCore/ChangeLog	2017-04-03 16:54:49 UTC (rev 214805)
+++ trunk/Source/WebCore/ChangeLog	2017-04-03 16:59:41 UTC (rev 214806)
@@ -1,3 +1,60 @@
+2017-04-03  Youenn Fablet  <you...@apple.com>
+
+        captureStream is getting black frames with webgl canvas
+        https://bugs.webkit.org/show_bug.cgi?id=170325
+
+        Reviewed by Dean Jackson.
+
+        Test: fast/mediastream/captureStream/canvas3d.html
+
+        Changing the webgl context to save buffers in case the canvas is captured.
+        Adding a canvas changed notification in case of clear.
+        In the future, we might want to change this notification and do it when endPaint or similar is called.
+
+        Adding an Internals API to grab the RGBA equivalent of the next track frame.
+        For that purpose, adding a bunch of WEBCORE_EXPORT.
+
+        * Modules/mediastream/CanvasCaptureMediaStreamTrack.cpp:
+        (WebCore::CanvasCaptureMediaStreamTrack::Source::Source): Adding constraints support so that track settings
+        getter actually transmits the width and height of the source.
+        (WebCore::CanvasCaptureMediaStreamTrack::Source::canvasChanged): ensuring webgl canvas context keep their drawing buffer.
+        * Modules/mediastream/MediaStreamTrack.h:
+        * bindings/js/JSDOMGuardedObject.h:
+        * bindings/js/JSDOMPromise.h:
+        (WebCore::DeferredPromise::resolve):
+        (WebCore::DeferredPromise::reject):
+        * dom/ActiveDOMCallback.h:
+        * html/HTMLCanvasElement.cpp:
+        (WebCore::HTMLCanvasElement::captureStream):
+        * html/ImageData.h:
+        * html/ImageData.idl:
+        * html/canvas/WebGLRenderingContext.cpp:
+        (WebCore::WebGLRenderingContext::clear): ensuring canvas observers get notified in case of clear calls.
+        * html/canvas/WebGLRenderingContextBase.h:
+        (WebCore::WebGLRenderingContextBase::preserveDrawingBuffer): Added to allow canvas capture to update this property.
+        * platform/MediaSample.h:
+        (WebCore::MediaSample::getRGBAImageData): Added for internals API.
+        * platform/graphics/avfoundation/MediaSampleAVFObjC.h:
+        * platform/graphics/avfoundation/objc/MediaSampleAVFObjC.mm:
+        (WebCore::MediaSampleAVFObjC::getRGBAImageData):
+        * platform/graphics/cv/PixelBufferConformerCV.cpp:
+        (WebCore::PixelBufferConformerCV::convert): Helper routine for getRGBAImageData.
+        * platform/graphics/cv/PixelBufferConformerCV.h:
+        * platform/mediastream/RealtimeMediaSourceSettings.h:
+        (WebCore::RealtimeMediaSourceSettings::setSupportedConstraints):
+        (WebCore::RealtimeMediaSourceSettings::setSupportedConstraits): Deleted.
+        * platform/mediastream/mac/AVMediaCaptureSource.mm:
+        (WebCore::AVMediaCaptureSource::initializeSettings):
+        * platform/mediastream/openwebrtc/RealtimeAudioSourceOwr.h:
+        * platform/mediastream/openwebrtc/RealtimeVideoSourceOwr.h:
+        * platform/mock/MockRealtimeMediaSource.cpp:
+        (WebCore::MockRealtimeMediaSource::initializeSettings):
+        * testing/Internals.cpp:
+        (WebCore::Internals::grabNextMediaStreamTrackFrame):
+        (WebCore::Internals::videoSampleAvailable):
+        * testing/Internals.h:
+        * testing/Internals.idl:
+
 2017-04-03  Per Arne Vollan  <pvol...@apple.com>
 
         Implement stroke-miterlimit.

Modified: trunk/Source/WebCore/Modules/mediastream/CanvasCaptureMediaStreamTrack.cpp (214805 => 214806)


--- trunk/Source/WebCore/Modules/mediastream/CanvasCaptureMediaStreamTrack.cpp	2017-04-03 16:54:49 UTC (rev 214805)
+++ trunk/Source/WebCore/Modules/mediastream/CanvasCaptureMediaStreamTrack.cpp	2017-04-03 16:59:41 UTC (rev 214806)
@@ -26,6 +26,7 @@
 #include "CanvasCaptureMediaStreamTrack.h"
 
 #include "GraphicsContext.h"
+#include "WebGLRenderingContextBase.h"
 
 #if ENABLE(MEDIA_STREAM)
 
@@ -67,6 +68,10 @@
 {
     m_settings.setWidth(canvas.width());
     m_settings.setHeight(canvas.height());
+    RealtimeMediaSourceSupportedConstraints constraints;
+    constraints.setSupportsWidth(true);
+    constraints.setSupportsHeight(true);
+    m_settings.setSupportedConstraints(constraints);
 }
 
 void CanvasCaptureMediaStreamTrack::Source::startProducingData()
@@ -124,6 +129,17 @@
 {
     ASSERT_UNUSED(canvas, m_canvas == &canvas);
 
+    // FIXME: We need to preserve drawing buffer as we are currently grabbing frames asynchronously.
+    // We should instead add an anchor point for both 2d and 3d contexts where canvas will actually paint.
+    // And call canvas observers from that point.
+    if (canvas.renderingContext() && canvas.renderingContext()->isWebGL()) {
+        auto& context = static_cast<WebGLRenderingContextBase&>(*canvas.renderingContext());
+        if (!context.isPreservingDrawingBuffer()) {
+            canvas.document().addConsoleMessage(MessageSource::JS, MessageLevel::Warning, ASCIILiteral("Turning drawing buffer preservation for the WebGL canvas being captured"));
+            context.setPreserveDrawingBuffer(true);
+        }
+    }
+
     // FIXME: We should try to generate the frame at the time the screen is being updated.
     if (m_canvasChangedTimer.isActive())
         return;

Modified: trunk/Source/WebCore/Modules/mediastream/MediaStreamTrack.h (214805 => 214806)


--- trunk/Source/WebCore/Modules/mediastream/MediaStreamTrack.h	2017-04-03 16:54:49 UTC (rev 214805)
+++ trunk/Source/WebCore/Modules/mediastream/MediaStreamTrack.h	2017-04-03 16:59:41 UTC (rev 214806)
@@ -89,7 +89,7 @@
         String deviceId;
         String groupId;
     };
-    TrackSettings getSettings() const;
+    WEBCORE_EXPORT TrackSettings getSettings() const;
 
     struct TrackCapabilities {
         std::optional<LongRange> width;

Modified: trunk/Source/WebCore/bindings/js/JSDOMGuardedObject.h (214805 => 214806)


--- trunk/Source/WebCore/bindings/js/JSDOMGuardedObject.h	2017-04-03 16:54:49 UTC (rev 214805)
+++ trunk/Source/WebCore/bindings/js/JSDOMGuardedObject.h	2017-04-03 16:59:41 UTC (rev 214806)
@@ -33,7 +33,7 @@
 
 namespace WebCore {
 
-class DOMGuardedObject : public RefCounted<DOMGuardedObject>, public ActiveDOMCallback {
+class WEBCORE_EXPORT DOMGuardedObject : public RefCounted<DOMGuardedObject>, public ActiveDOMCallback {
 public:
     ~DOMGuardedObject();
 

Modified: trunk/Source/WebCore/bindings/js/JSDOMPromise.h (214805 => 214806)


--- trunk/Source/WebCore/bindings/js/JSDOMPromise.h	2017-04-03 16:54:49 UTC (rev 214805)
+++ trunk/Source/WebCore/bindings/js/JSDOMPromise.h	2017-04-03 16:59:41 UTC (rev 214806)
@@ -88,7 +88,7 @@
     void reject();
     void reject(std::nullptr_t);
     void reject(Exception&&);
-    void reject(ExceptionCode, const String& = { });
+    WEBCORE_EXPORT void reject(ExceptionCode, const String& = { });
     void reject(const JSC::PrivateName&);
 
     template<typename Callback>
@@ -122,7 +122,7 @@
 
     JSC::JSPromiseDeferred* deferred() const { return guarded(); }
 
-    void callFunction(JSC::ExecState&, JSC::JSValue function, JSC::JSValue resolution);
+    WEBCORE_EXPORT void callFunction(JSC::ExecState&, JSC::JSValue function, JSC::JSValue resolution);
     void resolve(JSC::ExecState& state, JSC::JSValue resolution) { callFunction(state, deferred()->resolve(), resolution); }
     void reject(JSC::ExecState& state, JSC::JSValue resolution) { callFunction(state, deferred()->reject(), resolution); }
 };
@@ -212,7 +212,7 @@
 void fulfillPromiseWithJSON(Ref<DeferredPromise>&&, const String&);
 void fulfillPromiseWithArrayBuffer(Ref<DeferredPromise>&&, ArrayBuffer*);
 void fulfillPromiseWithArrayBuffer(Ref<DeferredPromise>&&, const void*, size_t);
-void rejectPromiseWithExceptionIfAny(JSC::ExecState&, JSDOMGlobalObject&, JSC::JSPromiseDeferred&);
+WEBCORE_EXPORT void rejectPromiseWithExceptionIfAny(JSC::ExecState&, JSDOMGlobalObject&, JSC::JSPromiseDeferred&);
 JSC::EncodedJSValue createRejectedPromiseWithTypeError(JSC::ExecState&, const String&);
 
 using PromiseFunction = void(JSC::ExecState&, Ref<DeferredPromise>&&);

Modified: trunk/Source/WebCore/dom/ActiveDOMCallback.h (214805 => 214806)


--- trunk/Source/WebCore/dom/ActiveDOMCallback.h	2017-04-03 16:54:49 UTC (rev 214805)
+++ trunk/Source/WebCore/dom/ActiveDOMCallback.h	2017-04-03 16:59:41 UTC (rev 214806)
@@ -46,7 +46,7 @@
     ActiveDOMCallback(ScriptExecutionContext* context);
     virtual ~ActiveDOMCallback();
 
-    bool canInvokeCallback() const;
+    WEBCORE_EXPORT bool canInvokeCallback() const;
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/html/HTMLCanvasElement.cpp (214805 => 214806)


--- trunk/Source/WebCore/html/HTMLCanvasElement.cpp	2017-04-03 16:54:49 UTC (rev 214805)
+++ trunk/Source/WebCore/html/HTMLCanvasElement.cpp	2017-04-03 16:59:41 UTC (rev 214806)
@@ -603,7 +603,7 @@
 
     if (frameRequestRate && frameRequestRate.value() < 0)
         return Exception(NOT_SUPPORTED_ERR, ASCIILiteral("frameRequestRate is negative"));
-    
+
     auto track = CanvasCaptureMediaStreamTrack::create(context, *this, WTFMove(frameRequestRate));
     auto stream =  MediaStream::create(context);
     stream->addTrack(track);

Modified: trunk/Source/WebCore/html/ImageData.h (214805 => 214806)


--- trunk/Source/WebCore/html/ImageData.h	2017-04-03 16:54:49 UTC (rev 214805)
+++ trunk/Source/WebCore/html/ImageData.h	2017-04-03 16:59:41 UTC (rev 214806)
@@ -34,7 +34,7 @@
 
 namespace WebCore {
 
-class ImageData : public RefCounted<ImageData> {
+class WEBCORE_EXPORT ImageData : public RefCounted<ImageData> {
 public:
     static ExceptionOr<Ref<ImageData>> create(unsigned sw, unsigned sh);
     static RefPtr<ImageData> create(const IntSize&);

Modified: trunk/Source/WebCore/html/ImageData.idl (214805 => 214806)


--- trunk/Source/WebCore/html/ImageData.idl	2017-04-03 16:54:49 UTC (rev 214805)
+++ trunk/Source/WebCore/html/ImageData.idl	2017-04-03 16:59:41 UTC (rev 214806)
@@ -31,6 +31,7 @@
     Constructor(unsigned long sw, unsigned long sh),
     ConstructorMayThrowException,
     CustomToJSObject,
+    ExportMacro=WEBCORE_EXPORT,
     Exposed=(Window,Worker),
     ImplementationLacksVTable,
 ] interface ImageData {

Modified: trunk/Source/WebCore/html/canvas/WebGLRenderingContext.cpp (214805 => 214806)


--- trunk/Source/WebCore/html/canvas/WebGLRenderingContext.cpp	2017-04-03 16:54:49 UTC (rev 214805)
+++ trunk/Source/WebCore/html/canvas/WebGLRenderingContext.cpp	2017-04-03 16:59:41 UTC (rev 214806)
@@ -470,7 +470,7 @@
     }
     if (!clearIfComposited(mask))
         m_context->clear(mask);
-    markContextChanged();
+    markContextChangedAndNotifyCanvasObserver();
 }
 
 WebGLAny WebGLRenderingContext::getParameter(GC3Denum pname)

Modified: trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.h (214805 => 214806)


--- trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.h	2017-04-03 16:54:49 UTC (rev 214805)
+++ trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.h	2017-04-03 16:59:41 UTC (rev 214806)
@@ -207,6 +207,9 @@
     WebGLAny getVertexAttrib(GC3Duint index, GC3Denum pname);
     long long getVertexAttribOffset(GC3Duint index, GC3Denum pname);
 
+    bool isPreservingDrawingBuffer() const { return m_attributes.preserveDrawingBuffer; }
+    void setPreserveDrawingBuffer(bool value) { m_attributes.preserveDrawingBuffer = value; }
+
     virtual void hint(GC3Denum target, GC3Denum mode) = 0;
     GC3Dboolean isBuffer(WebGLBuffer*);
     bool isContextLost() const;

Modified: trunk/Source/WebCore/platform/MediaSample.h (214805 => 214806)


--- trunk/Source/WebCore/platform/MediaSample.h	2017-04-03 16:54:49 UTC (rev 214805)
+++ trunk/Source/WebCore/platform/MediaSample.h	2017-04-03 16:59:41 UTC (rev 214806)
@@ -27,6 +27,7 @@
 #define MediaSample_h
 
 #include "FloatSize.h"
+#include <runtime/TypedArrays.h>
 #include <wtf/MediaTime.h>
 #include <wtf/RefCounted.h>
 #include <wtf/text/AtomicString.h>
@@ -69,6 +70,8 @@
     virtual std::pair<RefPtr<MediaSample>, RefPtr<MediaSample>> divide(const MediaTime& presentationTime) = 0;
     virtual Ref<MediaSample> createNonDisplayingCopy() const = 0;
 
+    virtual RefPtr<JSC::Uint8ClampedArray> getRGBAImageData() const { return nullptr; }
+
     enum SampleFlags {
         None = 0,
         IsSync = 1 << 0,

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/MediaSampleAVFObjC.h (214805 => 214806)


--- trunk/Source/WebCore/platform/graphics/avfoundation/MediaSampleAVFObjC.h	2017-04-03 16:54:49 UTC (rev 214805)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/MediaSampleAVFObjC.h	2017-04-03 16:59:41 UTC (rev 214806)
@@ -41,6 +41,8 @@
     static RefPtr<MediaSampleAVFObjC> createImageSample(Ref<JSC::Uint8ClampedArray>&&, unsigned long width, unsigned long height);
     static RefPtr<MediaSampleAVFObjC> createImageSample(Vector<uint8_t>&&, unsigned long width, unsigned long height);
 
+    RefPtr<JSC::Uint8ClampedArray> getRGBAImageData() const final;
+
 private:
     MediaSampleAVFObjC(CMSampleBufferRef sample)
         : m_sample(sample)

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSampleAVFObjC.mm (214805 => 214806)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSampleAVFObjC.mm	2017-04-03 16:54:49 UTC (rev 214805)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSampleAVFObjC.mm	2017-04-03 16:59:41 UTC (rev 214806)
@@ -26,6 +26,8 @@
 #import "config.h"
 #import "MediaSampleAVFObjC.h"
 
+#import "PixelBufferConformerCV.h"
+#import <runtime/TypedArrayInlines.h>
 #import <wtf/PrintStream.h>
 
 #import "CoreMediaSoftLink.h"
@@ -265,4 +267,28 @@
     return MediaSampleAVFObjC::create(adoptCF(newSampleBuffer).get(), m_id);
 }
 
+RefPtr<JSC::Uint8ClampedArray> MediaSampleAVFObjC::getRGBAImageData() const
+{
+    const OSType imageFormat = kCVPixelFormatType_32RGBA;
+    RetainPtr<CFNumberRef> imageFormatNumber = adoptCF(CFNumberCreate(nullptr,  kCFNumberIntType,  &imageFormat));
+
+    RetainPtr<CFMutableDictionaryRef> conformerOptions = adoptCF(CFDictionaryCreateMutable(0, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
+    CFDictionarySetValue(conformerOptions.get(), kCVPixelBufferPixelFormatTypeKey, imageFormatNumber.get());
+    PixelBufferConformerCV pixelBufferConformer(conformerOptions.get());
+
+    auto pixelBuffer = static_cast<CVPixelBufferRef>(CMSampleBufferGetImageBuffer(m_sample.get()));
+    auto rgbaPixelBuffer = pixelBufferConformer.convert(pixelBuffer);
+    auto status = CVPixelBufferLockBaseAddress(rgbaPixelBuffer.get(), kCVPixelBufferLock_ReadOnly);
+    ASSERT(status == noErr);
+
+    void* data = "" 0);
+    size_t byteLength = CVPixelBufferGetHeight(pixelBuffer) * CVPixelBufferGetWidth(pixelBuffer) * 4;
+    auto result = JSC::Uint8ClampedArray::create(JSC::ArrayBuffer::create(data, byteLength), 0, byteLength);
+
+    status = CVPixelBufferUnlockBaseAddress(rgbaPixelBuffer.get(), kCVPixelBufferLock_ReadOnly);
+    ASSERT(status == noErr);
+
+    return result;
 }
+
+}

Modified: trunk/Source/WebCore/platform/graphics/cv/PixelBufferConformerCV.cpp (214805 => 214806)


--- trunk/Source/WebCore/platform/graphics/cv/PixelBufferConformerCV.cpp	2017-04-03 16:54:49 UTC (rev 214805)
+++ trunk/Source/WebCore/platform/graphics/cv/PixelBufferConformerCV.cpp	2017-04-03 16:59:41 UTC (rev 214806)
@@ -72,6 +72,24 @@
     CFRelease(pixelBuffer);
 }
 
+RetainPtr<CVPixelBufferRef> PixelBufferConformerCV::convert(CVPixelBufferRef rawBuffer)
+{
+#if USE(VIDEOTOOLBOX)
+    RetainPtr<CVPixelBufferRef> buffer { rawBuffer };
+
+    if (!VTPixelBufferConformerIsConformantPixelBuffer(m_pixelConformer.get(), buffer.get())) {
+        CVPixelBufferRef outputBuffer = nullptr;
+        OSStatus status = VTPixelBufferConformerCopyConformedPixelBuffer(m_pixelConformer.get(), buffer.get(), false, &outputBuffer);
+        if (status != noErr || !outputBuffer)
+            return nullptr;
+        return adoptCF(outputBuffer);
+    }
+#else
+    UNUSED_PARAM(rawBuffer);
+#endif
+    return nullptr;
+}
+
 RetainPtr<CGImageRef> PixelBufferConformerCV::createImageFromPixelBuffer(CVPixelBufferRef rawBuffer)
 {
     RetainPtr<CVPixelBufferRef> buffer { rawBuffer };

Modified: trunk/Source/WebCore/platform/graphics/cv/PixelBufferConformerCV.h (214805 => 214806)


--- trunk/Source/WebCore/platform/graphics/cv/PixelBufferConformerCV.h	2017-04-03 16:54:49 UTC (rev 214805)
+++ trunk/Source/WebCore/platform/graphics/cv/PixelBufferConformerCV.h	2017-04-03 16:59:41 UTC (rev 214806)
@@ -37,6 +37,7 @@
 class PixelBufferConformerCV {
 public:
     PixelBufferConformerCV(CFDictionaryRef attributes);
+    RetainPtr<CVPixelBufferRef> convert(CVPixelBufferRef);
     RetainPtr<CGImageRef> createImageFromPixelBuffer(CVPixelBufferRef);
 
 private:

Modified: trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceSettings.h (214805 => 214806)


--- trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceSettings.h	2017-04-03 16:54:49 UTC (rev 214805)
+++ trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceSettings.h	2017-04-03 16:59:41 UTC (rev 214806)
@@ -92,7 +92,7 @@
     const AtomicString& groupId() const { return m_groupId; }
     void setGroupId(const AtomicString& groupId) { m_groupId = groupId; }
 
-    void setSupportedConstraits(const RealtimeMediaSourceSupportedConstraints& supportedConstraints) { m_supportedConstraints = supportedConstraints; }
+    void setSupportedConstraints(const RealtimeMediaSourceSupportedConstraints& supportedConstraints) { m_supportedConstraints = supportedConstraints; }
 
     template<class Encoder> void encode(Encoder&) const;
     template<class Decoder> static bool decode(Decoder&, RealtimeMediaSourceSettings&);

Modified: trunk/Source/WebCore/platform/mediastream/mac/AVMediaCaptureSource.mm (214805 => 214806)


--- trunk/Source/WebCore/platform/mediastream/mac/AVMediaCaptureSource.mm	2017-04-03 16:54:49 UTC (rev 214805)
+++ trunk/Source/WebCore/platform/mediastream/mac/AVMediaCaptureSource.mm	2017-04-03 16:59:41 UTC (rev 214806)
@@ -204,7 +204,7 @@
 void AVMediaCaptureSource::initializeSettings()
 {
     if (m_currentSettings.deviceId().isEmpty())
-        m_currentSettings.setSupportedConstraits(supportedConstraints());
+        m_currentSettings.setSupportedConstraints(supportedConstraints());
 
     m_currentSettings.setDeviceId(id());
     updateSettings(m_currentSettings);

Modified: trunk/Source/WebCore/platform/mediastream/openwebrtc/RealtimeAudioSourceOwr.h (214805 => 214806)


--- trunk/Source/WebCore/platform/mediastream/openwebrtc/RealtimeAudioSourceOwr.h	2017-04-03 16:54:49 UTC (rev 214805)
+++ trunk/Source/WebCore/platform/mediastream/openwebrtc/RealtimeAudioSourceOwr.h	2017-04-03 16:59:41 UTC (rev 214806)
@@ -59,7 +59,7 @@
 protected:
     void initializeSettings() final {
         if (m_currentSettings.deviceId().isEmpty())
-            m_currentSettings.setSupportedConstraits(supportedConstraints());
+            m_currentSettings.setSupportedConstraints(supportedConstraints());
 
         m_currentSettings.setDeviceId(id());
     }

Modified: trunk/Source/WebCore/platform/mediastream/openwebrtc/RealtimeVideoSourceOwr.h (214805 => 214806)


--- trunk/Source/WebCore/platform/mediastream/openwebrtc/RealtimeVideoSourceOwr.h	2017-04-03 16:54:49 UTC (rev 214805)
+++ trunk/Source/WebCore/platform/mediastream/openwebrtc/RealtimeVideoSourceOwr.h	2017-04-03 16:59:41 UTC (rev 214806)
@@ -59,7 +59,7 @@
 protected:
     void initializeSettings() final {
         if (m_currentSettings.deviceId().isEmpty())
-            m_currentSettings.setSupportedConstraits(supportedConstraints());
+            m_currentSettings.setSupportedConstraints(supportedConstraints());
 
         m_currentSettings.setDeviceId(id());
 

Modified: trunk/Source/WebCore/platform/mock/MockRealtimeMediaSource.cpp (214805 => 214806)


--- trunk/Source/WebCore/platform/mock/MockRealtimeMediaSource.cpp	2017-04-03 16:54:49 UTC (rev 214805)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeMediaSource.cpp	2017-04-03 16:59:41 UTC (rev 214806)
@@ -98,7 +98,7 @@
 void MockRealtimeMediaSource::initializeSettings()
 {
     if (m_currentSettings.deviceId().isEmpty()) {
-        m_currentSettings.setSupportedConstraits(supportedConstraints());
+        m_currentSettings.setSupportedConstraints(supportedConstraints());
         m_currentSettings.setDeviceId(id());
     }
 

Modified: trunk/Source/WebCore/testing/Internals.cpp (214805 => 214806)


--- trunk/Source/WebCore/testing/Internals.cpp	2017-04-03 16:54:49 UTC (rev 214805)
+++ trunk/Source/WebCore/testing/Internals.cpp	2017-04-03 16:59:41 UTC (rev 214806)
@@ -85,6 +85,7 @@
 #include "InstrumentingAgents.h"
 #include "IntRect.h"
 #include "InternalSettings.h"
+#include "JSImageData.h"
 #include "Language.h"
 #include "LibWebRTCProvider.h"
 #include "MainFrame.h"
@@ -3895,6 +3896,33 @@
     m_track = &track;
     m_track->source().addObserver(*this);
 }
+
+void Internals::grabNextMediaStreamTrackFrame(TrackFramePromise&& promise)
+{
+    m_nextTrackFramePromise = WTFMove(promise);
+}
+
+void Internals::videoSampleAvailable(MediaSample& sample)
+{
+    m_trackVideoSampleCount++;
+    if (!m_nextTrackFramePromise)
+        return;
+
+    auto videoSettings = m_track->getSettings();
+    if (!videoSettings.width || !videoSettings.height)
+        return;
+
+    auto rgba = sample.getRGBAImageData();
+    if (!rgba)
+        return;
+    auto imageData = ImageData::create(rgba.releaseNonNull(), *videoSettings.width, *videoSettings.height);
+    if (!imageData.hasException())
+        m_nextTrackFramePromise->resolve(imageData.releaseReturnValue().releaseNonNull());
+    else
+        m_nextTrackFramePromise->reject(imageData.exception().code());
+    m_nextTrackFramePromise = std::nullopt;
+}
+
 #endif
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/testing/Internals.h (214805 => 214806)


--- trunk/Source/WebCore/testing/Internals.h	2017-04-03 16:54:49 UTC (rev 214805)
+++ trunk/Source/WebCore/testing/Internals.h	2017-04-03 16:59:41 UTC (rev 214806)
@@ -29,9 +29,11 @@
 #include "CSSComputedStyleDeclaration.h"
 #include "ContextDestructionObserver.h"
 #include "ExceptionOr.h"
+#include "JSDOMPromise.h"
 #include "PageConsoleClient.h"
 #include "RealtimeMediaSource.h"
 #include <runtime/Float32Array.h>
+#include <wtf/Optional.h>
 
 #if ENABLE(MEDIA_SESSION)
 #include "MediaSessionInterruptionProvider.h"
@@ -54,6 +56,7 @@
 class HTMLLinkElement;
 class HTMLMediaElement;
 class HTMLSelectElement;
+class ImageData;
 class InspectorStubFrontend;
 class InternalSettings;
 class MallocStatistics;
@@ -562,6 +565,8 @@
     unsigned long trackAudioSampleCount() const { return m_trackAudioSampleCount; }
     unsigned long trackVideoSampleCount() const { return m_trackVideoSampleCount; }
     void observeMediaStreamTrack(MediaStreamTrack&);
+    using TrackFramePromise = DOMPromise<IDLInterface<ImageData>>;
+    void grabNextMediaStreamTrackFrame(TrackFramePromise&&);
 #endif
 
 private:
@@ -573,12 +578,13 @@
 
     // RealtimeMediaSource::Observer API
 #if ENABLE(MEDIA_STREAM)
-    void videoSampleAvailable(MediaSample&) final { m_trackVideoSampleCount++; }
+    void videoSampleAvailable(MediaSample&) final;
     void audioSamplesAvailable(const MediaTime&, const PlatformAudioData&, const AudioStreamDescription&, size_t) final { m_trackAudioSampleCount++; }
 
     unsigned long m_trackVideoSampleCount { 0 };
     unsigned long m_trackAudioSampleCount { 0 };
     RefPtr<MediaStreamTrack> m_track;
+    std::optional<TrackFramePromise> m_nextTrackFramePromise;
 #endif
 
     std::unique_ptr<InspectorStubFrontend> m_inspectorFrontend;

Modified: trunk/Source/WebCore/testing/Internals.idl (214805 => 214806)


--- trunk/Source/WebCore/testing/Internals.idl	2017-04-03 16:54:49 UTC (rev 214805)
+++ trunk/Source/WebCore/testing/Internals.idl	2017-04-03 16:59:41 UTC (rev 214806)
@@ -526,6 +526,7 @@
     [Conditional=WEBGL] void simulateWebGLContextChanged(WebGLRenderingContextBase context);
 
     [Conditional=MEDIA_STREAM] void observeMediaStreamTrack(MediaStreamTrack track);
+    [Conditional=MEDIA_STREAM] Promise<ImageData> grabNextMediaStreamTrackFrame();
     [Conditional=MEDIA_STREAM] readonly attribute unsigned long trackAudioSampleCount;
     [Conditional=MEDIA_STREAM] readonly attribute unsigned long trackVideoSampleCount;
 };
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to