[GStreamer] video orientation support
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 21 Jun 2016 08:32:06 +0000 (08:32 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 21 Jun 2016 08:32:06 +0000 (08:32 +0000)
https://bugs.webkit.org/show_bug.cgi?id=148524

Patch by Miguel Gomez <magomez@igalia.com> on 2016-06-21
Reviewed by Philippe Normand.

Source/WebCore:

Rotate video frames to follow the orientation metadata in the video file.
When accelerated compositing is disabled, the rotation is performed by a videoflip element added
to the playbin.
When accelerated compositing is enabled, the rotation is peformed by the TextureMapper in response
to a rotation flag set on the frame buffers.

Test: media/video-orientation.html

* platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
(WebCore::MediaPlayerPrivateGStreamer::handleMessage):
Handle the GST_MESSAGE_TAG message from the bin.
(WebCore::MediaPlayerPrivateGStreamer::createGSTPlayBin):
Add the videflip element to the bin when accelerated compositing is disabled.
* platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp:
(WebCore::GstVideoFrameHolder::GstVideoFrameHolder):
Receive and use extra flags for the TextureMapper.
(WebCore::MediaPlayerPrivateGStreamerBase::MediaPlayerPrivateGStreamerBase):
(WebCore::MediaPlayerPrivateGStreamerBase::naturalSize):
When using accelerated compositing, transpose the video size if the rotation is 90 or 270 degrees.
(WebCore::MediaPlayerPrivateGStreamerBase::pushTextureToCompositor):
Add rotation flag to frame holder and layer buffer.
(WebCore::MediaPlayerPrivateGStreamerBase::paintToTextureMapper):
Use rotation flag when requesting the TextureMapper to draw.
(WebCore::MediaPlayerPrivateGStreamerBase::setVideoSourceRotation):
Function to store the video rotation.
* platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h:
Add bits to store the video rotation.
* platform/graphics/texmap/TextureMapperGL.cpp:
(WebCore::TextureMapperGL::drawTexturedQuadWithProgram):
Modify the patternTransform according to the rotation flag passed.
* platform/graphics/texmap/TextureMapperGL.h:
Add new flags to handle the video souce rotation.
* platform/graphics/texmap/TextureMapperPlatformLayerBuffer.cpp:
(WebCore::TextureMapperPlatformLayerBuffer::paintToTextureMapper):
Change the drawTexture method used so custom flags can be passed.
* platform/graphics/texmap/TextureMapperPlatformLayerBuffer.h:
(WebCore::TextureMapperPlatformLayerBuffer::setExtraFlags):
New method to set TextureMapper flags.

LayoutTests:

Test whether the video is properly being displayed by checking the video
element size.

* media/content/no-rotation.mp4: Added.
* media/content/rotation-180.mp4: Added.
* media/content/rotation-270.mp4: Added.
* media/content/rotation-90.mp4: Added.
* media/video-orientation-expected.txt: Added.
* media/video-orientation.html: Added.

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

15 files changed:
LayoutTests/ChangeLog
LayoutTests/media/content/no-rotation.mp4 [new file with mode: 0644]
LayoutTests/media/content/rotation-180.mp4 [new file with mode: 0644]
LayoutTests/media/content/rotation-270.mp4 [new file with mode: 0644]
LayoutTests/media/content/rotation-90.mp4 [new file with mode: 0644]
LayoutTests/media/video-orientation-expected.txt [new file with mode: 0644]
LayoutTests/media/video-orientation.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp
Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp
Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h
Source/WebCore/platform/graphics/texmap/TextureMapperGL.cpp
Source/WebCore/platform/graphics/texmap/TextureMapperGL.h
Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerBuffer.cpp
Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerBuffer.h

index c4cebdf..faeb75d 100644 (file)
@@ -1,3 +1,20 @@
+2016-06-21  Miguel Gomez  <magomez@igalia.com>
+
+        [GStreamer] video orientation support
+        https://bugs.webkit.org/show_bug.cgi?id=148524
+
+        Reviewed by Philippe Normand.
+
+        Test whether the video is properly being displayed by checking the video
+        element size.
+
+        * media/content/no-rotation.mp4: Added.
+        * media/content/rotation-180.mp4: Added.
+        * media/content/rotation-270.mp4: Added.
+        * media/content/rotation-90.mp4: Added.
+        * media/video-orientation-expected.txt: Added.
+        * media/video-orientation.html: Added.
+
 2016-06-20  Frederic Wang  <fwang@igalia.com>
 
         Use the MathOperator to handle some non-stretchy operators
diff --git a/LayoutTests/media/content/no-rotation.mp4 b/LayoutTests/media/content/no-rotation.mp4
new file mode 100644 (file)
index 0000000..f435352
Binary files /dev/null and b/LayoutTests/media/content/no-rotation.mp4 differ
diff --git a/LayoutTests/media/content/rotation-180.mp4 b/LayoutTests/media/content/rotation-180.mp4
new file mode 100644 (file)
index 0000000..373affc
Binary files /dev/null and b/LayoutTests/media/content/rotation-180.mp4 differ
diff --git a/LayoutTests/media/content/rotation-270.mp4 b/LayoutTests/media/content/rotation-270.mp4
new file mode 100644 (file)
index 0000000..81e8bda
Binary files /dev/null and b/LayoutTests/media/content/rotation-270.mp4 differ
diff --git a/LayoutTests/media/content/rotation-90.mp4 b/LayoutTests/media/content/rotation-90.mp4
new file mode 100644 (file)
index 0000000..f9c3043
Binary files /dev/null and b/LayoutTests/media/content/rotation-90.mp4 differ
diff --git a/LayoutTests/media/video-orientation-expected.txt b/LayoutTests/media/video-orientation-expected.txt
new file mode 100644 (file)
index 0000000..190a4ed
--- /dev/null
@@ -0,0 +1,35 @@
+
+Test size before movie is open:
+EXPECTED (video.videoWidth == '0') OK
+EXPECTED (video.videoHeight == '0') OK
+
+Loading "content/no-rotation.mp4". Movie video with no rotation tag set, size 352x288.
+EVENT(loadstart)
+EVENT(durationchange)
+EVENT(loadedmetadata)
+EXPECTED (video.videoWidth == '352') OK
+EXPECTED (video.videoHeight == '288') OK
+
+Loading "content/rotation-90.mp4". Movie video with rotation-90 tag set, size 352x288.
+EVENT(loadstart)
+EVENT(durationchange)
+EVENT(loadedmetadata)
+EXPECTED (video.videoWidth == '288') OK
+EXPECTED (video.videoHeight == '352') OK
+
+Loading "content/rotation-180.mp4". Movie video with rotation-180 tag set, size 352x288.
+EVENT(loadstart)
+EVENT(durationchange)
+EVENT(loadedmetadata)
+EXPECTED (video.videoWidth == '352') OK
+EXPECTED (video.videoHeight == '288') OK
+
+Loading "content/rotation-270.mp4". Movie video with rotation-270 tag set, size 352x288.
+EVENT(loadstart)
+EVENT(durationchange)
+EVENT(loadedmetadata)
+EXPECTED (video.videoWidth == '288') OK
+EXPECTED (video.videoHeight == '352') OK
+
+END OF TEST
+
diff --git a/LayoutTests/media/video-orientation.html b/LayoutTests/media/video-orientation.html
new file mode 100644 (file)
index 0000000..b60a1c9
--- /dev/null
@@ -0,0 +1,99 @@
+<html lang="en">
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+        <title>&lt;video&gt; rotation test</title>
+        <script src=video-test.js></script>
+
+        <script>
+
+            var movieInfo =
+            {
+                current:0,
+                movies:
+                [
+                    {
+                        url:"content/no-rotation.mp4",
+                        description:"video with no rotation tag set, size 352x288",
+                        width:352,
+                        height:288
+                    },
+                    {
+                        url:"content/rotation-90.mp4",
+                        description:"video with rotation-90 tag set, size 352x288",
+                        width:288,
+                        height:352
+                    },
+                    {
+                        url:"content/rotation-180.mp4",
+                        description:"video with rotation-180 tag set, size 352x288",
+                        width:352,
+                        height:288
+                    },
+                    {
+                        url:"content/rotation-270.mp4",
+                        description:"video with rotation-270 tag set, size 352x288",
+                        width:288,
+                        height:352
+                    },
+                ]
+            };
+
+            function testSize()
+            {
+                var movie = movieInfo.movies[movieInfo.current];
+
+                testExpected("video.videoWidth", movie.width);
+                testExpected("video.videoHeight", movie.height);
+
+                movieInfo.current++;
+                openNextMovie();
+            }
+
+            function openNextMovie()
+            {
+                consoleWrite("");
+                if (movieInfo.current >= movieInfo.movies.length)
+                {
+                    endTest();
+                    return;
+                }
+
+                var url = movieInfo.movies[movieInfo.current].url;
+                video.src = url;
+                var desc = "<b>Loading</b> <em>\""+ url + "\"</em>" +
+                            ". Movie " + movieInfo.movies[movieInfo.current].description + ".</em>";
+                consoleWrite(desc);
+                if (movieInfo.current > 0)
+                    video.load();
+            }
+
+            function start()
+            {
+                findMediaElement();
+
+                waitForEvent("error");
+                waitForEvent("loadstart");
+                waitForEvent("waiting");
+                waitForEvent("ratechange");
+                waitForEvent("durationchange");
+                waitForEvent("pause");
+                waitForEvent("play");
+                waitForEvent("playing");
+
+                waitForEvent('loadedmetadata', testSize);
+
+                consoleWrite("<b>Test size before movie is open:</b>");
+                testExpected("video.videoWidth", 0, "==");
+                testExpected("video.videoHeight", 0, "==");
+
+                openNextMovie();
+            }
+        </script>
+    </head>
+
+    <body onload="start()">
+
+        <video></video>
+
+    </body>
+</html>
index 2668d63..82e9f1f 100644 (file)
@@ -1,3 +1,49 @@
+2016-06-21  Miguel Gomez  <magomez@igalia.com>
+
+        [GStreamer] video orientation support
+        https://bugs.webkit.org/show_bug.cgi?id=148524
+
+        Reviewed by Philippe Normand.
+
+        Rotate video frames to follow the orientation metadata in the video file.
+        When accelerated compositing is disabled, the rotation is performed by a videoflip element added
+        to the playbin.
+        When accelerated compositing is enabled, the rotation is peformed by the TextureMapper in response
+        to a rotation flag set on the frame buffers.
+
+        Test: media/video-orientation.html
+
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
+        (WebCore::MediaPlayerPrivateGStreamer::handleMessage):
+        Handle the GST_MESSAGE_TAG message from the bin.
+        (WebCore::MediaPlayerPrivateGStreamer::createGSTPlayBin):
+        Add the videflip element to the bin when accelerated compositing is disabled.
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp:
+        (WebCore::GstVideoFrameHolder::GstVideoFrameHolder):
+        Receive and use extra flags for the TextureMapper.
+        (WebCore::MediaPlayerPrivateGStreamerBase::MediaPlayerPrivateGStreamerBase):
+        (WebCore::MediaPlayerPrivateGStreamerBase::naturalSize):
+        When using accelerated compositing, transpose the video size if the rotation is 90 or 270 degrees.
+        (WebCore::MediaPlayerPrivateGStreamerBase::pushTextureToCompositor):
+        Add rotation flag to frame holder and layer buffer.
+        (WebCore::MediaPlayerPrivateGStreamerBase::paintToTextureMapper):
+        Use rotation flag when requesting the TextureMapper to draw.
+        (WebCore::MediaPlayerPrivateGStreamerBase::setVideoSourceRotation):
+        Function to store the video rotation.
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h:
+        Add bits to store the video rotation.
+        * platform/graphics/texmap/TextureMapperGL.cpp:
+        (WebCore::TextureMapperGL::drawTexturedQuadWithProgram):
+        Modify the patternTransform according to the rotation flag passed.
+        * platform/graphics/texmap/TextureMapperGL.h:
+        Add new flags to handle the video souce rotation.
+        * platform/graphics/texmap/TextureMapperPlatformLayerBuffer.cpp:
+        (WebCore::TextureMapperPlatformLayerBuffer::paintToTextureMapper):
+        Change the drawTexture method used so custom flags can be passed.
+        * platform/graphics/texmap/TextureMapperPlatformLayerBuffer.h:
+        (WebCore::TextureMapperPlatformLayerBuffer::setExtraFlags):
+        New method to set TextureMapper flags.
+
 2016-06-20  Frederic Wang  <fwang@igalia.com>
 
         Use the MathOperator to handle some non-stretchy operators
index 05c3e41..3fde1ce 100644 (file)
@@ -1021,6 +1021,21 @@ void MediaPlayerPrivateGStreamer::handleMessage(GstMessage* message)
         processTableOfContents(message);
         break;
 #endif
+    case GST_MESSAGE_TAG: {
+        GstTagList* tags = nullptr;
+        GUniqueOutPtr<gchar> tag;
+        gst_message_parse_tag(message, &tags);
+        if (gst_tag_list_get_string(tags, GST_TAG_IMAGE_ORIENTATION, &tag.outPtr())) {
+            if (!g_strcmp0(tag.get(), "rotate-90"))
+                setVideoSourceRotation(VideoSourceRotation90);
+            else if (!g_strcmp0(tag.get(), "rotate-180"))
+                setVideoSourceRotation(VideoSourceRotation180);
+            else if (!g_strcmp0(tag.get(), "rotate-270"))
+                setVideoSourceRotation(VideoSourceRotation270);
+        }
+        gst_tag_list_unref(tags);
+        break;
+    }
     default:
         LOG_MEDIA_MESSAGE("Unhandled GStreamer message type: %s",
                     GST_MESSAGE_TYPE_NAME(message));
@@ -1983,6 +1998,14 @@ void MediaPlayerPrivateGStreamer::createGSTPlayBin()
             g_object_set(m_pipeline.get(), "audio-filter", scale, nullptr);
     }
 
+    if (!m_player->client().mediaPlayerRenderingCanBeAccelerated(m_player)) {
+        // If not using accelerated compositing, let GStreamer handle
+        // the image-orientation tag.
+        GstElement* videoFlip = gst_element_factory_make("videoflip", nullptr);
+        g_object_set(videoFlip, "method", 8, nullptr);
+        g_object_set(m_pipeline.get(), "video-filter", videoFlip, nullptr);
+    }
+
     GRefPtr<GstPad> videoSinkPad = adoptGRef(gst_element_get_static_pad(m_videoSink.get(), "sink"));
     if (videoSinkPad)
         g_signal_connect_swapped(videoSinkPad.get(), "notify::caps", G_CALLBACK(videoSinkCapsChangedCallback), this);
index 56a8b08..0dd5656 100644 (file)
@@ -105,14 +105,14 @@ static int greatestCommonDivisor(int a, int b)
 #if USE(COORDINATED_GRAPHICS_THREADED) && USE(GSTREAMER_GL)
 class GstVideoFrameHolder : public TextureMapperPlatformLayerBuffer::UnmanagedBufferDataHolder {
 public:
-    explicit GstVideoFrameHolder(GstSample* sample)
+    explicit GstVideoFrameHolder(GstSample* sample, TextureMapperGL::Flags flags)
     {
         GstVideoInfo videoInfo;
         if (UNLIKELY(!getSampleVideoInfo(sample, videoInfo)))
             return;
 
         m_size = IntSize(GST_VIDEO_INFO_WIDTH(&videoInfo), GST_VIDEO_INFO_HEIGHT(&videoInfo));
-        m_flags = GST_VIDEO_INFO_HAS_ALPHA(&videoInfo) ? TextureMapperGL::ShouldBlend : 0;
+        m_flags = flags | (GST_VIDEO_INFO_HAS_ALPHA(&videoInfo) ? TextureMapperGL::ShouldBlend : 0);
 
         GstBuffer* buffer = gst_sample_get_buffer(sample);
         if (UNLIKELY(!gst_video_frame_map(&m_videoFrame, &videoInfo, buffer, static_cast<GstMapFlags>(GST_MAP_READ | GST_MAP_GL))))
@@ -153,6 +153,10 @@ MediaPlayerPrivateGStreamerBase::MediaPlayerPrivateGStreamerBase(MediaPlayer* pl
     , m_drawTimer(RunLoop::main(), this, &MediaPlayerPrivateGStreamerBase::repaint)
 #endif
     , m_usingFallbackVideoSink(false)
+    , m_videoSourceRotation(NoVideoSourceRotation)
+#if USE(TEXTURE_MAPPER_GL)
+    , m_textureMapperRotationFlag(0)
+#endif
 {
     g_mutex_init(&m_sampleMutex);
 #if USE(COORDINATED_GRAPHICS_THREADED)
@@ -286,6 +290,14 @@ FloatSize MediaPlayerPrivateGStreamerBase::naturalSize() const
     if (!getVideoSizeAndFormatFromCaps(caps, originalSize, format, pixelAspectRatioNumerator, pixelAspectRatioDenominator, stride))
         return FloatSize();
 
+#if USE(TEXTURE_MAPPER_GL)
+    // When using accelerated compositing, if the video is tagged as rotated 90 or 270 degrees, swap width and height.
+    if (m_player->client().mediaPlayerRenderingCanBeAccelerated(m_player)) {
+        if (m_videoSourceRotation == VideoSourceRotation90 || m_videoSourceRotation == VideoSourceRotation270)
+            originalSize = originalSize.transposedSize();
+    }
+#endif
+
     LOG_MEDIA_MESSAGE("Original video size: %dx%d", originalSize.width(), originalSize.height());
     LOG_MEDIA_MESSAGE("Pixel aspect ratio: %d/%d", pixelAspectRatioNumerator, pixelAspectRatioDenominator);
 
@@ -469,7 +481,7 @@ void MediaPlayerPrivateGStreamerBase::pushTextureToCompositor()
         return;
 
 #if USE(GSTREAMER_GL)
-    std::unique_ptr<GstVideoFrameHolder> frameHolder = std::make_unique<GstVideoFrameHolder>(m_sample.get());
+    std::unique_ptr<GstVideoFrameHolder> frameHolder = std::make_unique<GstVideoFrameHolder>(m_sample.get(), m_textureMapperRotationFlag);
     if (UNLIKELY(!frameHolder->isValid()))
         return;
 
@@ -482,7 +494,6 @@ void MediaPlayerPrivateGStreamerBase::pushTextureToCompositor()
         return;
 
     IntSize size = IntSize(GST_VIDEO_INFO_WIDTH(&videoInfo), GST_VIDEO_INFO_HEIGHT(&videoInfo));
-
     std::unique_ptr<TextureMapperPlatformLayerBuffer> buffer = m_platformLayerProxy->getAvailableBuffer(size, GraphicsContext3D::DONT_CARE);
     if (UNLIKELY(!buffer)) {
         if (UNLIKELY(!m_context3D))
@@ -493,6 +504,7 @@ void MediaPlayerPrivateGStreamerBase::pushTextureToCompositor()
         buffer = std::make_unique<TextureMapperPlatformLayerBuffer>(WTFMove(texture));
     }
     updateTexture(buffer->textureGL(), videoInfo);
+    buffer->setExtraFlags(m_textureMapperRotationFlag | (GST_VIDEO_INFO_HAS_ALPHA(&videoInfo) ? TextureMapperGL::ShouldBlend : 0));
     m_platformLayerProxy->pushNextBuffer(WTFMove(buffer));
 #endif
 }
@@ -611,6 +623,8 @@ void MediaPlayerPrivateGStreamerBase::paintToTextureMapper(TextureMapper& textur
 
     if (m_usingFallbackVideoSink) {
         RefPtr<BitmapTexture> texture;
+        IntSize size;
+        TextureMapperGL::Flags flags;
         {
             WTF::GMutexLocker<GMutex> lock(m_sampleMutex);
 
@@ -618,11 +632,14 @@ void MediaPlayerPrivateGStreamerBase::paintToTextureMapper(TextureMapper& textur
             if (UNLIKELY(!getSampleVideoInfo(m_sample.get(), videoInfo)))
                 return;
 
-            IntSize size = IntSize(GST_VIDEO_INFO_WIDTH(&videoInfo), GST_VIDEO_INFO_HEIGHT(&videoInfo));
+            size = IntSize(GST_VIDEO_INFO_WIDTH(&videoInfo), GST_VIDEO_INFO_HEIGHT(&videoInfo));
+            flags = m_textureMapperRotationFlag | (GST_VIDEO_INFO_HAS_ALPHA(&videoInfo) ? TextureMapperGL::ShouldBlend : 0);
             texture = textureMapper.acquireTextureFromPool(size, GST_VIDEO_INFO_HAS_ALPHA(&videoInfo) ? BitmapTexture::SupportsAlpha : BitmapTexture::NoFlag);
             updateTexture(static_cast<BitmapTextureGL&>(*texture), videoInfo);
         }
-        textureMapper.drawTexture(*texture, targetRect, matrix, opacity);
+        TextureMapperGL& texmapGL = reinterpret_cast<TextureMapperGL&>(textureMapper);
+        BitmapTextureGL* textureGL = static_cast<BitmapTextureGL*>(texture.get());
+        texmapGL.drawTexture(textureGL->id(), flags, textureGL->size(), targetRect, matrix, opacity);
         return;
     }
 
@@ -637,7 +654,7 @@ void MediaPlayerPrivateGStreamerBase::paintToTextureMapper(TextureMapper& textur
         return;
 
     unsigned textureID = *reinterpret_cast<unsigned*>(videoFrame.data[0]);
-    TextureMapperGL::Flags flags = GST_VIDEO_INFO_HAS_ALPHA(&videoInfo) ? TextureMapperGL::ShouldBlend : 0;
+    TextureMapperGL::Flags flags = m_textureMapperRotationFlag | (GST_VIDEO_INFO_HAS_ALPHA(&videoInfo) ? TextureMapperGL::ShouldBlend : 0);
 
     IntSize size = IntSize(GST_VIDEO_INFO_WIDTH(&videoInfo), GST_VIDEO_INFO_HEIGHT(&videoInfo));
     TextureMapperGL& textureMapperGL = reinterpret_cast<TextureMapperGL&>(textureMapper);
@@ -684,6 +701,34 @@ NativeImagePtr MediaPlayerPrivateGStreamerBase::nativeImageForCurrentTime()
 }
 #endif
 
+void MediaPlayerPrivateGStreamerBase::setVideoSourceRotation(VideoSourceRotation rotation)
+{
+    if (m_videoSourceRotation == rotation)
+        return;
+
+    m_videoSourceRotation = rotation;
+
+#if USE(TEXTURE_MAPPER_GL)
+    switch (m_videoSourceRotation) {
+    case NoVideoSourceRotation:
+        m_textureMapperRotationFlag = 0;
+        break;
+    case VideoSourceRotation90:
+        m_textureMapperRotationFlag = TextureMapperGL::ShouldRotateTexture90;
+        break;
+    case VideoSourceRotation180:
+        m_textureMapperRotationFlag = TextureMapperGL::ShouldRotateTexture180;
+        break;
+    case VideoSourceRotation270:
+        m_textureMapperRotationFlag = TextureMapperGL::ShouldRotateTexture270;
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+        break;
+    }
+#endif
+}
+
 bool MediaPlayerPrivateGStreamerBase::supportsFullscreen() const
 {
     return true;
index b50aa01..d6bd904 100644 (file)
@@ -34,6 +34,9 @@
 #include <wtf/Condition.h>
 #include <wtf/Forward.h>
 #include <wtf/RunLoop.h>
+#if USE(TEXTURE_MAPPER_GL)
+#include "TextureMapperGL.h"
+#endif
 
 typedef struct _GstBaseSink GstBaseSink;
 typedef struct _GstMessage GstMessage;
@@ -57,6 +60,13 @@ class MediaPlayerPrivateGStreamerBase : public MediaPlayerPrivateInterface
 {
 
 public:
+    enum VideoSourceRotation {
+        NoVideoSourceRotation,
+        VideoSourceRotation90,
+        VideoSourceRotation180,
+        VideoSourceRotation270
+    };
+
     virtual ~MediaPlayerPrivateGStreamerBase();
 
     FloatSize naturalSize() const override;
@@ -117,6 +127,8 @@ public:
     NativeImagePtr nativeImageForCurrentTime() override;
 #endif
 
+    void setVideoSourceRotation(VideoSourceRotation);
+
 protected:
     MediaPlayerPrivateGStreamerBase(MediaPlayer*);
     virtual GstElement* createVideoSink();
@@ -194,6 +206,11 @@ protected:
     Condition m_drawCondition;
     Lock m_drawMutex;
 #endif
+
+    VideoSourceRotation m_videoSourceRotation;
+#if USE(TEXTURE_MAPPER_GL)
+    TextureMapperGL::Flags m_textureMapperRotationFlag;
+#endif
 };
 }
 
index 868f877..f4a27d6 100644 (file)
@@ -560,6 +560,18 @@ void TextureMapperGL::drawTexturedQuadWithProgram(TextureMapperShaderProgram& pr
     }
 
     TransformationMatrix patternTransform = this->patternTransform();
+    if (flags & ShouldRotateTexture90) {
+        patternTransform.rotate(-90);
+        patternTransform.translate(-1, 0);
+    }
+    if (flags & ShouldRotateTexture180) {
+        patternTransform.rotate(180);
+        patternTransform.translate(-1, -1);
+    }
+    if (flags & ShouldRotateTexture270) {
+        patternTransform.rotate(-270);
+        patternTransform.translate(0, -1);
+    }
     if (flags & ShouldFlipTexture)
         patternTransform.flipY();
     if (flags & ShouldUseARBTextureRect)
index 38380a6..acc78e8 100644 (file)
@@ -47,7 +47,10 @@ public:
         ShouldBlend = 0x01,
         ShouldFlipTexture = 0x02,
         ShouldUseARBTextureRect = 0x04,
-        ShouldAntialias = 0x08
+        ShouldAntialias = 0x08,
+        ShouldRotateTexture90 = 0x10,
+        ShouldRotateTexture180 = 0x20,
+        ShouldRotateTexture270 = 0x40
     };
 
     typedef int Flags;
index 06f1b87..88851fe 100644 (file)
@@ -51,14 +51,16 @@ bool TextureMapperPlatformLayerBuffer::canReuseWithoutReset(const IntSize& size,
 
 void TextureMapperPlatformLayerBuffer::paintToTextureMapper(TextureMapper& textureMapper, const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix, float opacity)
 {
+    TextureMapperGL& texmapGL = static_cast<TextureMapperGL&>(textureMapper);
+
     if (m_hasManagedTexture) {
         ASSERT(m_texture);
-        textureMapper.drawTexture(*m_texture, targetRect, modelViewMatrix, opacity);
+        BitmapTextureGL* textureGL = static_cast<BitmapTextureGL*>(m_texture.get());
+        texmapGL.drawTexture(textureGL->id(), m_extraFlags, textureGL->size(), targetRect, modelViewMatrix, opacity);
         return;
     }
 
     ASSERT(m_textureID);
-    TextureMapperGL& texmapGL = static_cast<TextureMapperGL&>(textureMapper);
     texmapGL.drawTexture(m_textureID, m_extraFlags, m_size, targetRect, modelViewMatrix, opacity);
 }
 
index d3651fb..f8c1d60 100644 (file)
@@ -60,6 +60,7 @@ public:
 
     bool hasManagedTexture() const { return m_hasManagedTexture; }
     void setUnmanagedBufferDataHolder(std::unique_ptr<UnmanagedBufferDataHolder> holder) { m_unmanagedBufferDataHolder = WTFMove(holder); }
+    void setExtraFlags(TextureMapperGL::Flags flags) { m_extraFlags = flags; }
 
 private: