Title: [213972] trunk
Revision
213972
Author
[email protected]
Date
2017-03-14 22:21:06 -0700 (Tue, 14 Mar 2017)

Log Message

CanvasCapture should not generate a frame per each canvas draw command
https://bugs.webkit.org/show_bug.cgi?id=169498

Patch by Youenn Fablet <[email protected]> on 2017-03-14
Reviewed by Simon Fraser & Eric Carlson.

Source/WebCore:

Test: fast/mediastream/captureStream/canvas2d-heavy-drawing.html

Making Canvas capture be asynchronous.
This ensures that one frame will be created for a set of synchronous draw commands.
In the future, we should find a better approach, like aligning with requestAnimationFrame.
Adding internals observer API for media stream tracks.

* Modules/mediastream/CanvasCaptureMediaStreamTrack.cpp:
(WebCore::CanvasCaptureMediaStreamTrack::Source::Source):
(WebCore::CanvasCaptureMediaStreamTrack::Source::canvasChanged):
* Modules/mediastream/CanvasCaptureMediaStreamTrack.h:
* Modules/mediastream/MediaStreamTrack.idl:
* platform/mediastream/RealtimeMediaSource.h:
* testing/Internals.cpp:
(WebCore::Internals::~Internals):
(WebCore::Internals::observeMediaStreamTrack):
* testing/Internals.h:
* testing/Internals.idl:

LayoutTests:

* fast/mediastream/captureStream/canvas2d-heavy-drawing-expected.txt: Added.
* fast/mediastream/captureStream/canvas2d-heavy-drawing.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (213971 => 213972)


--- trunk/LayoutTests/ChangeLog	2017-03-15 03:28:08 UTC (rev 213971)
+++ trunk/LayoutTests/ChangeLog	2017-03-15 05:21:06 UTC (rev 213972)
@@ -1,3 +1,13 @@
+2017-03-14  Youenn Fablet  <[email protected]>
+
+        CanvasCapture should not generate a frame per each canvas draw command
+        https://bugs.webkit.org/show_bug.cgi?id=169498
+
+        Reviewed by Simon Fraser & Eric Carlson.
+
+        * fast/mediastream/captureStream/canvas2d-heavy-drawing-expected.txt: Added.
+        * fast/mediastream/captureStream/canvas2d-heavy-drawing.html: Added.
+
 2017-03-14  Wenson Hsieh  <[email protected]>
 
         Unreviewed, skip fast/media/video-element-in-details-collapse.html on iOS

Added: trunk/LayoutTests/fast/mediastream/captureStream/canvas2d-heavy-drawing-expected.txt (0 => 213972)


--- trunk/LayoutTests/fast/mediastream/captureStream/canvas2d-heavy-drawing-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/mediastream/captureStream/canvas2d-heavy-drawing-expected.txt	2017-03-15 05:21:06 UTC (rev 213972)
@@ -0,0 +1,4 @@
+   
+
+PASS captureStream with 2d context drawing 
+

Added: trunk/LayoutTests/fast/mediastream/captureStream/canvas2d-heavy-drawing.html (0 => 213972)


--- trunk/LayoutTests/fast/mediastream/captureStream/canvas2d-heavy-drawing.html	                        (rev 0)
+++ trunk/LayoutTests/fast/mediastream/captureStream/canvas2d-heavy-drawing.html	2017-03-15 05:21:06 UTC (rev 213972)
@@ -0,0 +1,78 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+    <body>
+        <canvas id="canvas1" width=100px height=100px></canvas>
+        <video id="video" autoplay width=100px height=100px></video>
+        <canvas id="canvas2" width=100px height=100px></canvas>
+        <script src=""
+        <script src=""
+        <script>
+
+var canvas1 = document.getElementById("canvas1");
+var canvas2 = document.getElementById("canvas2");
+var video = document.getElementById("video");
+
+var previousTrackSampleCount = 0
+function validateCanvas(resolve, reject)
+{
+    try {
+        if (window.internals) {
+             assert_true((internals.trackVideoSampleCount - previousTrackSampleCount) <= 1, "got too much internals.trackVideoSampleCount");
+             previousTrackSampleCount = internals.trackVideoSampleCount;
+        }
+        canvas2.getContext("2d").drawImage(video, 0 ,0);
+        assert_array_equals(canvas2.getContext("2d").getImageData(0 ,0, 100, 100), canvas2.getContext("2d").getImageData(0, 0, 100, 100));
+    } catch(e) {
+        reject(e);
+        return;
+    }
+    setTimeout(() => { validateCanvas(reject, resolve); }, 5);
+}
+
+function checkCanvas(canvas, stream)
+{
+    return new Promise((resolve, reject) => {
+        video.srcObject = stream;
+        video._onplay_ = () => {
+            if (window.internals)
+                previousTrackSampleCount = internals.trackVideoSampleCount;
+            validateCanvas(resolve, reject);
+            setTimeout(resolve, 500);
+        }
+    });
+}
+
+var cptr = 0;
+function printLine()
+{
+    var context = canvas1.getContext("2d");
+    context.fillStyle = "red";
+    for (var i = 0 ; i < 100; ++i)
+        context.fillRect(0, 0, 100, 100);
+
+    cptr += 5;
+    if (cptr > 255)
+        cptr = 0;
+    context.fillStyle="rgb(0, " + cptr + ", 0)";
+    context.fillRect(0, 0, 100, 100);
+    setTimeout(printLine, 100);
+}
+
+promise_test((test) => {
+    var stream = canvas1.captureStream();
+
+    assert_false(!!stream.getAudioTracks().length);
+    assert_true(stream.getVideoTracks().length == 1);
+
+    if (window.internals)
+        internals.observeMediaStreamTrack(stream.getVideoTracks()[0]);
+
+    promise = checkCanvas(canvas1, stream);
+
+    printLine();
+
+    return promise;
+}, "captureStream with 2d context drawing");
+        </script>
+    </body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (213971 => 213972)


--- trunk/Source/WebCore/ChangeLog	2017-03-15 03:28:08 UTC (rev 213971)
+++ trunk/Source/WebCore/ChangeLog	2017-03-15 05:21:06 UTC (rev 213972)
@@ -1,3 +1,29 @@
+2017-03-14  Youenn Fablet  <[email protected]>
+
+        CanvasCapture should not generate a frame per each canvas draw command
+        https://bugs.webkit.org/show_bug.cgi?id=169498
+
+        Reviewed by Simon Fraser & Eric Carlson.
+
+        Test: fast/mediastream/captureStream/canvas2d-heavy-drawing.html
+
+        Making Canvas capture be asynchronous.
+        This ensures that one frame will be created for a set of synchronous draw commands.
+        In the future, we should find a better approach, like aligning with requestAnimationFrame.
+        Adding internals observer API for media stream tracks.
+
+        * Modules/mediastream/CanvasCaptureMediaStreamTrack.cpp:
+        (WebCore::CanvasCaptureMediaStreamTrack::Source::Source):
+        (WebCore::CanvasCaptureMediaStreamTrack::Source::canvasChanged):
+        * Modules/mediastream/CanvasCaptureMediaStreamTrack.h:
+        * Modules/mediastream/MediaStreamTrack.idl:
+        * platform/mediastream/RealtimeMediaSource.h:
+        * testing/Internals.cpp:
+        (WebCore::Internals::~Internals):
+        (WebCore::Internals::observeMediaStreamTrack):
+        * testing/Internals.h:
+        * testing/Internals.idl:
+
 2017-03-14  Wenson Hsieh  <[email protected]>
 
         RenderElements should unregister for viewport visibility callbacks when they are destroyed

Modified: trunk/Source/WebCore/Modules/mediastream/CanvasCaptureMediaStreamTrack.cpp (213971 => 213972)


--- trunk/Source/WebCore/Modules/mediastream/CanvasCaptureMediaStreamTrack.cpp	2017-03-15 03:28:08 UTC (rev 213971)
+++ trunk/Source/WebCore/Modules/mediastream/CanvasCaptureMediaStreamTrack.cpp	2017-03-15 05:21:06 UTC (rev 213972)
@@ -62,6 +62,7 @@
     : RealtimeMediaSource(String(), Type::Video, String())
     , m_frameRequestRate(WTFMove(frameRequestRate))
     , m_requestFrameTimer(*this, &Source::requestFrameTimerFired)
+    , m_canvasChangedTimer(*this, &Source::captureCanvas)
     , m_canvas(&canvas)
 {
     m_settings.setWidth(canvas.width());
@@ -123,7 +124,10 @@
 {
     ASSERT_UNUSED(canvas, m_canvas == &canvas);
 
-    captureCanvas();
+    // FIXME: We should try to generate the frame at the time the screen is being updated.
+    if (m_canvasChangedTimer.isActive())
+        return;
+    m_canvasChangedTimer.startOneShot(0);
 }
 
 void CanvasCaptureMediaStreamTrack::Source::captureCanvas()

Modified: trunk/Source/WebCore/Modules/mediastream/CanvasCaptureMediaStreamTrack.h (213971 => 213972)


--- trunk/Source/WebCore/Modules/mediastream/CanvasCaptureMediaStreamTrack.h	2017-03-15 03:28:08 UTC (rev 213971)
+++ trunk/Source/WebCore/Modules/mediastream/CanvasCaptureMediaStreamTrack.h	2017-03-15 05:21:06 UTC (rev 213972)
@@ -28,6 +28,7 @@
 
 #include "HTMLCanvasElement.h"
 #include "MediaStreamTrack.h"
+#include "Timer.h"
 #include <wtf/TypeCasts.h>
 
 namespace WebCore {
@@ -73,6 +74,7 @@
         bool m_shouldEmitFrame { true };
         std::optional<double> m_frameRequestRate;
         Timer m_requestFrameTimer;
+        Timer m_canvasChangedTimer;
         RealtimeMediaSourceSettings m_settings;
         HTMLCanvasElement* m_canvas;
         RefPtr<Image> m_currentImage;

Modified: trunk/Source/WebCore/Modules/mediastream/MediaStreamTrack.idl (213971 => 213972)


--- trunk/Source/WebCore/Modules/mediastream/MediaStreamTrack.idl	2017-03-15 03:28:08 UTC (rev 213971)
+++ trunk/Source/WebCore/Modules/mediastream/MediaStreamTrack.idl	2017-03-15 05:21:06 UTC (rev 213972)
@@ -29,6 +29,7 @@
     ActiveDOMObject,
     Conditional=MEDIA_STREAM,
     CustomToJSObject,
+    ExportToWrappedFunction,
     PrivateIdentifier,
     PublicIdentifier,
 ] interface MediaStreamTrack : EventTarget {

Modified: trunk/Source/WebCore/platform/mediastream/RealtimeMediaSource.h (213971 => 213972)


--- trunk/Source/WebCore/platform/mediastream/RealtimeMediaSource.h	2017-03-15 03:28:08 UTC (rev 213971)
+++ trunk/Source/WebCore/platform/mediastream/RealtimeMediaSource.h	2017-03-15 05:21:06 UTC (rev 213972)
@@ -137,8 +137,8 @@
     virtual bool remote() const { return m_remote; }
     virtual void setRemote(bool remote) { m_remote = remote; }
 
-    void addObserver(Observer&);
-    void removeObserver(Observer&);
+    WEBCORE_EXPORT void addObserver(Observer&);
+    WEBCORE_EXPORT void removeObserver(Observer&);
 
     virtual void startProducingData() { }
     virtual void stopProducingData() { }

Modified: trunk/Source/WebCore/testing/Internals.cpp (213971 => 213972)


--- trunk/Source/WebCore/testing/Internals.cpp	2017-03-15 03:28:08 UTC (rev 213971)
+++ trunk/Source/WebCore/testing/Internals.cpp	2017-03-15 05:21:06 UTC (rev 213972)
@@ -90,6 +90,7 @@
 #include "MallocStatistics.h"
 #include "MediaPlayer.h"
 #include "MediaProducer.h"
+#include "MediaStreamTrack.h"
 #include "MemoryCache.h"
 #include "MemoryInfo.h"
 #include "MockLibWebRTCPeerConnection.h"
@@ -376,6 +377,8 @@
 
 Internals::~Internals()
 {
+    if (m_track)
+        m_track->source().removeObserver(*this);
 }
 
 void Internals::resetToConsistentState(Page& page)
@@ -3825,4 +3828,10 @@
 #endif
 
 
+void Internals::observeMediaStreamTrack(MediaStreamTrack& track)
+{
+    m_track = &track;
+    m_track->source().addObserver(*this);
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/testing/Internals.h (213971 => 213972)


--- trunk/Source/WebCore/testing/Internals.h	2017-03-15 03:28:08 UTC (rev 213971)
+++ trunk/Source/WebCore/testing/Internals.h	2017-03-15 05:21:06 UTC (rev 213972)
@@ -30,6 +30,7 @@
 #include "ContextDestructionObserver.h"
 #include "ExceptionOr.h"
 #include "PageConsoleClient.h"
+#include "RealtimeMediaSource.h"
 #include <runtime/Float32Array.h>
 
 #if ENABLE(MEDIA_SESSION)
@@ -57,6 +58,7 @@
 class InternalSettings;
 class MallocStatistics;
 class MediaSession;
+class MediaStreamTrack;
 class MemoryInfo;
 class MockCDMFactory;
 class MockContentFilterSettings;
@@ -75,7 +77,7 @@
 class WebGLRenderingContextBase;
 class XMLHttpRequest;
 
-class Internals final : public RefCounted<Internals>, private ContextDestructionObserver {
+class Internals final : public RefCounted<Internals>,  private ContextDestructionObserver, private RealtimeMediaSource::Observer {
 public:
     static Ref<Internals> create(Document&);
     virtual ~Internals();
@@ -544,6 +546,10 @@
     void simulateWebGLContextChanged(WebGLRenderingContextBase&);
 #endif
 
+    unsigned long trackAudioSampleCount() const { return m_trackAudioSampleCount; }
+    unsigned long trackVideoSampleCount() const { return m_trackVideoSampleCount; }
+    void observeMediaStreamTrack(MediaStreamTrack&);
+
 private:
     explicit Internals(Document&);
     Document* contextDocument() const;
@@ -551,7 +557,15 @@
 
     ExceptionOr<RenderedDocumentMarker*> markerAt(Node&, const String& markerType, unsigned index);
 
+    // RealtimeMediaSource::Observer API
+    void videoSampleAvailable(MediaSample&) final { m_trackVideoSampleCount++; }
+    void audioSamplesAvailable(const MediaTime&, const PlatformAudioData&, const AudioStreamDescription&, size_t) final { m_trackAudioSampleCount++; }
+
     std::unique_ptr<InspectorStubFrontend> m_inspectorFrontend;
+
+    unsigned long m_trackVideoSampleCount { 0 };
+    unsigned long m_trackAudioSampleCount { 0 };
+    RefPtr<MediaStreamTrack> m_track;
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/testing/Internals.idl (213971 => 213972)


--- trunk/Source/WebCore/testing/Internals.idl	2017-03-15 03:28:08 UTC (rev 213971)
+++ trunk/Source/WebCore/testing/Internals.idl	2017-03-15 05:21:06 UTC (rev 213972)
@@ -516,4 +516,8 @@
     void disableTileSizeUpdateDelay();
 
     [Conditional=WEBGL] void simulateWebGLContextChanged(WebGLRenderingContextBase context);
+
+    void observeMediaStreamTrack(MediaStreamTrack track);
+    readonly attribute unsigned long trackAudioSampleCount;
+    readonly attribute unsigned long trackVideoSampleCount;
 };
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to