Title: [295555] trunk
Revision
295555
Author
[email protected]
Date
2022-06-15 04:10:25 -0700 (Wed, 15 Jun 2022)

Log Message

[GStreamer][WebRTC] canvas to PeerConnection improvements
https://bugs.webkit.org/show_bug.cgi?id=241330

Patch by Philippe Normand <[email protected]> on 2022-06-15
Reviewed by Miguel Gomez and Xabier Rodriguez-Calvar.

Video frames exported from the WebGL canvas need to be flipped on GStreamer ports and their format
should be RGBA. Frames coming from 2D canvas don't need to be flipped and have BGRA format.

Texture flipping is now handled in the player which is useful when painting canvas to a video
element. And flipping is also now handled in RTC outgoing video sources, which is useful when
exporting a canvas to a WebRTC PeerConnection.

The 30fps framerate is hardcoded, ideally should be inferred from the compositor refresh rate.
Having a framerate > 1 is specially needed for the canvas->WebRTC use-case, otherwise a 1/1
framerate would be set in caps, making the corresponding video stream slower than the actual refresh
rate.

* LayoutTests/platform/glib/TestExpectations:
* Source/WebCore/html/HTMLCanvasElement.cpp:
(WebCore::HTMLCanvasElement::toVideoFrame):
* Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
(WebCore::MediaPlayerPrivateGStreamer::updateTextureMapperFlags):
* Source/WebCore/platform/graphics/gstreamer/VideoFrameGStreamer.cpp:
(WebCore::VideoFrameGStreamer::createFromPixelBuffer):
* Source/WebCore/platform/graphics/gstreamer/VideoFrameGStreamer.h:
* Source/WebCore/platform/graphics/texmap/GraphicsContextGLTextureMapper.cpp:
(WebCore::GraphicsContextGLTextureMapper::paintCompositedResultsToVideoFrame):
* Source/WebCore/platform/mediastream/gstreamer/MockRealtimeVideoSourceGStreamer.cpp:
(WebCore::MockRealtimeVideoSourceGStreamer::updateSampleBuffer):
* Source/WebCore/platform/mediastream/gstreamer/RealtimeOutgoingVideoSourceGStreamer.cpp:
(WebCore::RealtimeOutgoingVideoSourceGStreamer::RealtimeOutgoingVideoSourceGStreamer):
(WebCore::RealtimeOutgoingVideoSourceGStreamer::setPayloadType):
* Source/WebCore/platform/mediastream/gstreamer/RealtimeOutgoingVideoSourceGStreamer.h:

Canonical link: https://commits.webkit.org/251560@main

Modified Paths

Diff

Modified: trunk/LayoutTests/platform/glib/TestExpectations (295554 => 295555)


--- trunk/LayoutTests/platform/glib/TestExpectations	2022-06-15 07:55:27 UTC (rev 295554)
+++ trunk/LayoutTests/platform/glib/TestExpectations	2022-06-15 11:10:25 UTC (rev 295555)
@@ -930,11 +930,8 @@
 webkit.org/b/235885 webrtc/audio-video-element-playing.html [ Timeout ]
 webkit.org/b/235885 webrtc/candidate-stats.html [ Failure ]
 webkit.org/b/235885 webrtc/canvas-to-peer-connection.html [ Failure ]
-webkit.org/b/235885 webrtc/canvas-to-peer-connection-2d.html [ Failure ]
-webkit.org/b/235885 webrtc/canvas-to-peer-connection-vp8-2d.html [ Failure ]
-webkit.org/b/235885 webrtc/canvas-to-peer-connection-vp8.html [ Failure ]
-webkit.org/b/235885 webrtc/captureCanvas-webrtc.html [ Timeout ]
-webkit.org/b/235885 webrtc/closing-peerconnection.html [ Timeout ]
+webkit.org/b/235885 webrtc/canvas-to-peer-connection-vp8-2d.html [ Timeout ]
+webkit.org/b/235885 webrtc/canvas-to-peer-connection-vp8.html [ Timeout ]
 webkit.org/b/235885 webrtc/direction-change.html [ Failure ]
 webkit.org/b/235885 webrtc/disable-encryption.html [ Failure ]
 webkit.org/b/235885 webrtc/ephemeral-certificates-and-cnames.html [ Failure ]
@@ -2351,7 +2348,6 @@
 webkit.org/b/187064 webkit.org/b/235885 webrtc/video-disabled-black.html [ Crash Timeout ]
 webkit.org/b/187064 webkit.org/b/235885 webrtc/video-remote-mute.html [ Crash Failure ]
 webkit.org/b/187064 webrtc/video-rotation.html [ Failure ]
-webkit.org/b/187064 webkit.org/b/235885 webrtc/video-rotation-no-cvo.html [ Failure Crash ]
 webkit.org/b/187064 webrtc/video-with-data-channel.html [ Failure ]
 webkit.org/b/187064 imported/w3c/web-platform-tests/webrtc/RTCPeerConnection-getStats.https.html [ Failure Pass ]
 

Modified: trunk/Source/WebCore/html/HTMLCanvasElement.cpp (295554 => 295555)


--- trunk/Source/WebCore/html/HTMLCanvasElement.cpp	2022-06-15 07:55:27 UTC (rev 295554)
+++ trunk/Source/WebCore/html/HTMLCanvasElement.cpp	2022-06-15 11:10:25 UTC (rev 295555)
@@ -809,7 +809,8 @@
 #if PLATFORM(COCOA)
     return VideoFrameCV::createFromPixelBuffer(pixelBuffer.releaseNonNull());
 #elif USE(GSTREAMER)
-    return VideoFrameGStreamer::createFromPixelBuffer(pixelBuffer.releaseNonNull());
+    // FIXME: Hardcoding 30fps here is not great. Ideally we should get this from the compositor refresh rate, somehow.
+    return VideoFrameGStreamer::createFromPixelBuffer(pixelBuffer.releaseNonNull(), VideoFrameGStreamer::CanvasContentType::Canvas2D, VideoFrameGStreamer::Rotation::None, MediaTime::invalidTime(), { }, 30, false, { });
 #endif
 #else
     return nullptr;

Modified: trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp (295554 => 295555)


--- trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp	2022-06-15 07:55:27 UTC (rev 295554)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp	2022-06-15 11:10:25 UTC (rev 295555)
@@ -3741,8 +3741,11 @@
     case ImageOrientation::OriginLeftBottom:
         m_textureMapperFlags = TextureMapperGL::ShouldRotateTexture270;
         break;
+    case ImageOrientation::OriginBottomLeft:
+        m_textureMapperFlags = TextureMapperGL::ShouldFlipTexture;
+        break;
     default:
-        // FIXME: Handle OriginTopRight, OriginBottomLeft, OriginLeftTop and OriginRightBottom?
+        // FIXME: Handle OriginTopRight, OriginLeftTop and OriginRightBottom.
         m_textureMapperFlags = 0;
         break;
     }

Modified: trunk/Source/WebCore/platform/graphics/gstreamer/VideoFrameGStreamer.cpp (295554 => 295555)


--- trunk/Source/WebCore/platform/graphics/gstreamer/VideoFrameGStreamer.cpp	2022-06-15 07:55:27 UTC (rev 295554)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/VideoFrameGStreamer.cpp	2022-06-15 11:10:25 UTC (rev 295555)
@@ -30,7 +30,7 @@
 
 namespace WebCore {
 
-Ref<VideoFrameGStreamer> VideoFrameGStreamer::createFromPixelBuffer(Ref<PixelBuffer>&& pixelBuffer, const MediaTime& presentationTime, const IntSize& destinationSize, double frameRate, Rotation videoRotation, bool videoMirrored, std::optional<VideoFrameTimeMetadata>&& metadata)
+Ref<VideoFrameGStreamer> VideoFrameGStreamer::createFromPixelBuffer(Ref<PixelBuffer>&& pixelBuffer, CanvasContentType canvasContentType, Rotation videoRotation, const MediaTime& presentationTime, const IntSize& destinationSize, double frameRate, bool videoMirrored, std::optional<VideoFrameTimeMetadata>&& metadata)
 {
     ensureGStreamerInitialized();
 
@@ -46,8 +46,19 @@
 
     auto width = size.width();
     auto height = size.height();
-    gst_buffer_add_video_meta(buffer.get(), GST_VIDEO_FRAME_FLAG_NONE, GST_VIDEO_FORMAT_BGRA, width, height);
+    GstVideoFormat format;
 
+    switch (canvasContentType) {
+    case CanvasContentType::WebGL:
+        format = GST_VIDEO_FORMAT_RGBA;
+        break;
+    case CanvasContentType::Canvas2D:
+        format = GST_VIDEO_FORMAT_BGRA;
+        break;
+    }
+    const char* formatName = gst_video_format_to_string(format);
+    gst_buffer_add_video_meta(buffer.get(), GST_VIDEO_FRAME_FLAG_NONE, format, width, height);
+
     if (metadata)
         webkitGstBufferSetVideoFrameTimeMetadata(buffer.get(), *metadata);
 
@@ -54,7 +65,7 @@
     int frameRateNumerator, frameRateDenominator;
     gst_util_double_to_fraction(frameRate, &frameRateNumerator, &frameRateDenominator);
 
-    auto caps = adoptGRef(gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "BGRA", "width", G_TYPE_INT, width,
+    auto caps = adoptGRef(gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, formatName, "width", G_TYPE_INT, width,
         "height", G_TYPE_INT, height, "framerate", GST_TYPE_FRACTION, frameRateNumerator, frameRateDenominator, nullptr));
     auto sample = adoptGRef(gst_sample_new(buffer.get(), caps.get(), nullptr, nullptr));
 
@@ -67,7 +78,7 @@
 
         width = destinationSize.width();
         height = destinationSize.height();
-        auto outputCaps = adoptGRef(gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "BGRA", "width", G_TYPE_INT, width,
+        auto outputCaps = adoptGRef(gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, formatName, "width", G_TYPE_INT, width,
             "height", G_TYPE_INT, height, "framerate", GST_TYPE_FRACTION, frameRateNumerator, frameRateDenominator, nullptr));
         GstVideoInfo outputInfo;
         gst_video_info_from_caps(&outputInfo, outputCaps.get());

Modified: trunk/Source/WebCore/platform/graphics/gstreamer/VideoFrameGStreamer.h (295554 => 295555)


--- trunk/Source/WebCore/platform/graphics/gstreamer/VideoFrameGStreamer.h	2022-06-15 07:55:27 UTC (rev 295554)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/VideoFrameGStreamer.h	2022-06-15 11:10:25 UTC (rev 295555)
@@ -33,6 +33,12 @@
 
 class VideoFrameGStreamer final : public VideoFrame {
 public:
+
+    enum class CanvasContentType {
+        WebGL,
+        Canvas2D
+    };
+
     static Ref<VideoFrameGStreamer> create(GRefPtr<GstSample>&& sample, const FloatSize& presentationSize, const MediaTime& presentationTime = MediaTime::invalidTime(), Rotation videoRotation = Rotation::None, bool videoMirrored = false, std::optional<VideoFrameTimeMetadata>&& metadata = std::nullopt)
     {
         return adoptRef(*new VideoFrameGStreamer(WTFMove(sample), presentationSize, presentationTime, videoRotation, videoMirrored, WTFMove(metadata)));
@@ -43,7 +49,7 @@
         return adoptRef(*new VideoFrameGStreamer(sample, presentationTime, videoRotation));
     }
 
-    static Ref<VideoFrameGStreamer> createFromPixelBuffer(Ref<PixelBuffer>&&, const MediaTime& presentationTime = MediaTime::invalidTime(), const IntSize& destinationSize = { }, double frameRate = 1, Rotation videoRotation = Rotation::None, bool videoMirrored = false, std::optional<VideoFrameTimeMetadata>&& metadata = std::nullopt);
+    static Ref<VideoFrameGStreamer> createFromPixelBuffer(Ref<PixelBuffer>&&, CanvasContentType canvasContentType, Rotation videoRotation, const MediaTime& presentationTime = MediaTime::invalidTime(), const IntSize& destinationSize = { }, double frameRate = 1, bool videoMirrored = false, std::optional<VideoFrameTimeMetadata>&& metadata = std::nullopt);
 
     GstSample* sample() const { return m_sample.get(); }
     RefPtr<JSC::Uint8ClampedArray> computeRGBAImageData() const;

Modified: trunk/Source/WebCore/platform/graphics/texmap/GraphicsContextGLTextureMapper.cpp (295554 => 295555)


--- trunk/Source/WebCore/platform/graphics/texmap/GraphicsContextGLTextureMapper.cpp	2022-06-15 07:55:27 UTC (rev 295554)
+++ trunk/Source/WebCore/platform/graphics/texmap/GraphicsContextGLTextureMapper.cpp	2022-06-15 11:10:25 UTC (rev 295555)
@@ -120,8 +120,9 @@
 RefPtr<VideoFrame> GraphicsContextGLTextureMapper::paintCompositedResultsToVideoFrame()
 {
 #if USE(GSTREAMER)
+    // FIXME: Hardcoding 30fps here is not great. Ideally we should get this from the compositor refresh rate, somehow.
     if (auto pixelBuffer = readCompositedResults())
-        return VideoFrameGStreamer::createFromPixelBuffer(pixelBuffer.releaseNonNull());
+        return VideoFrameGStreamer::createFromPixelBuffer(pixelBuffer.releaseNonNull(), VideoFrameGStreamer::CanvasContentType::WebGL, VideoFrameGStreamer::Rotation::UpsideDown, MediaTime::invalidTime(), { }, 30, true, { });
 #endif
     return nullptr;
 }

Modified: trunk/Source/WebCore/platform/mediastream/gstreamer/MockRealtimeVideoSourceGStreamer.cpp (295554 => 295555)


--- trunk/Source/WebCore/platform/mediastream/gstreamer/MockRealtimeVideoSourceGStreamer.cpp	2022-06-15 07:55:27 UTC (rev 295554)
+++ trunk/Source/WebCore/platform/mediastream/gstreamer/MockRealtimeVideoSourceGStreamer.cpp	2022-06-15 11:10:25 UTC (rev 295555)
@@ -164,7 +164,7 @@
     std::optional<VideoFrameTimeMetadata> metadata;
     metadata->captureTime = MonotonicTime::now().secondsSinceEpoch();
     auto presentationTime = MediaTime::createWithDouble((elapsedTime() + 100_ms).seconds());
-    auto videoFrame = VideoFrameGStreamer::createFromPixelBuffer(pixelBuffer.releaseNonNull(), presentationTime, size(), frameRate(), videoFrameRotation(), false, WTFMove(metadata));
+    auto videoFrame = VideoFrameGStreamer::createFromPixelBuffer(pixelBuffer.releaseNonNull(), VideoFrameGStreamer::CanvasContentType::Canvas2D, videoFrameRotation(), presentationTime, size(), frameRate(), false, WTFMove(metadata));
     dispatchVideoFrameToObservers(videoFrame.get(), { });
 }
 

Modified: trunk/Source/WebCore/platform/mediastream/gstreamer/RealtimeOutgoingVideoSourceGStreamer.cpp (295554 => 295555)


--- trunk/Source/WebCore/platform/mediastream/gstreamer/RealtimeOutgoingVideoSourceGStreamer.cpp	2022-06-15 07:55:27 UTC (rev 295554)
+++ trunk/Source/WebCore/platform/mediastream/gstreamer/RealtimeOutgoingVideoSourceGStreamer.cpp	2022-06-15 11:10:25 UTC (rev 295555)
@@ -35,8 +35,12 @@
     registerWebKitGStreamerElements();
 
     m_videoConvert = gst_element_factory_make("videoconvert", nullptr);
+
+    m_videoFlip = gst_element_factory_make("videoflip", nullptr);
+    gst_util_set_object_arg(G_OBJECT(m_videoFlip.get()), "method", "automatic");
+
     m_encoder = gst_element_factory_make("webrtcvideoencoder", nullptr);
-    gst_bin_add_many(GST_BIN_CAST(m_bin.get()), m_videoConvert.get(), m_encoder.get(), nullptr);
+    gst_bin_add_many(GST_BIN_CAST(m_bin.get()), m_videoFlip.get(), m_videoConvert.get(), m_encoder.get(), nullptr);
 
     auto* padTemplate = gst_element_get_pad_template(m_encoder.get(), "src");
     auto caps = adoptGRef(gst_pad_template_get_caps(padTemplate));
@@ -102,7 +106,7 @@
     g_object_set(m_capsFilter.get(), "caps", filteredCaps.get(), nullptr);
 
     gst_bin_add(GST_BIN_CAST(m_bin.get()), m_payloader.get());
-    gst_element_link_many(m_outgoingSource.get(), m_valve.get(), m_videoConvert.get(), m_preEncoderQueue.get(),
+    gst_element_link_many(m_outgoingSource.get(), m_valve.get(), m_videoFlip.get(), m_videoConvert.get(), m_preEncoderQueue.get(),
         m_encoder.get(), m_payloader.get(), m_postEncoderQueue.get(), nullptr);
     return true;
 }

Modified: trunk/Source/WebCore/platform/mediastream/gstreamer/RealtimeOutgoingVideoSourceGStreamer.h (295554 => 295555)


--- trunk/Source/WebCore/platform/mediastream/gstreamer/RealtimeOutgoingVideoSourceGStreamer.h	2022-06-15 07:55:27 UTC (rev 295554)
+++ trunk/Source/WebCore/platform/mediastream/gstreamer/RealtimeOutgoingVideoSourceGStreamer.h	2022-06-15 11:10:25 UTC (rev 295555)
@@ -40,6 +40,7 @@
 
 private:
     GRefPtr<GstElement> m_videoConvert;
+    GRefPtr<GstElement> m_videoFlip;
 };
 
 } // namespace WebCore
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to