[GStreamer] Add sharedBuffer utility to GstMappedBuffer, and a testsuite
authorcturner@igalia.com <cturner@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 14 Jan 2019 12:31:13 +0000 (12:31 +0000)
committercturner@igalia.com <cturner@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 14 Jan 2019 12:31:13 +0000 (12:31 +0000)
https://bugs.webkit.org/show_bug.cgi?id=192977

Reviewed by Carlos Garcia Campos.

Source/WebCore:

Add a utility method on GstMappedBuffer to return a SharedBuffer
view over the mapped data with no copies.

This patch also introduces a new gstreamer port API test
directory, and includes some tests for GstMappedBuffer.

New tests in the API section.

* platform/SharedBuffer.cpp: Add a new overload for
GstMappedBuffer that allows sharing the mapped GStreamer buffers
with zero copies.
(WebCore::SharedBuffer::create):
(WebCore::SharedBuffer::SharedBuffer):
(WebCore::SharedBuffer::DataSegment::data const):
(WebCore::SharedBuffer::DataSegment::size const):
* platform/SharedBuffer.h:
* platform/audio/gstreamer/WebKitWebAudioSourceGStreamer.cpp:
(webKitWebAudioSrcAllocateBuffersAndRenderAudio): Update to new
API.
* platform/graphics/gstreamer/GStreamerCommon.cpp:
(WebCore::GstMappedBuffer::createSharedBuffer): Return a shared
buffer sharing this mapped buffer. The buffer must be shareable to
use this method.
* platform/graphics/gstreamer/GStreamerCommon.h:
(WebCore::GstMappedBuffer::create): Make GstMappedBuffer RefCounted
(WebCore::GstMappedBuffer::~GstMappedBuffer):
(WebCore::GstMappedBuffer::data):
(WebCore::GstMappedBuffer::data const):
(WebCore::GstMappedBuffer::size const):
(WebCore::GstMappedBuffer::isSharable const): New predicate to
check whether this buffer can be shared (i.e., is not writable)
(WebCore::GstMappedBuffer::GstMappedBuffer):
(WebCore::GstMappedBuffer::operator bool const): Deleted.
* platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.cpp:
(WebCore::InbandTextTrackPrivateGStreamer::notifyTrackOfSample):
Update to use new API.
* platform/graphics/gstreamer/eme/GStreamerEMEUtilities.h:
(WebCore::InitData::InitData): Ditto.
* platform/graphics/gstreamer/eme/WebKitClearKeyDecryptorGStreamer.cpp:
(webKitMediaClearKeyDecryptorFindAndSetKey): Ditto.
(webKitMediaClearKeyDecryptorDecrypt): Ditto.
* platform/mediastream/gstreamer/MockGStreamerAudioCaptureSource.cpp:
(WebCore::WrappedMockRealtimeAudioSource::render): Ditto.
* platform/mediastream/gstreamer/RealtimeOutgoingAudioSourceLibWebRTC.cpp:
(WebCore::RealtimeOutgoingAudioSourceLibWebRTC::pullAudioData): Ditto.
* platform/mediastream/gstreamer/RealtimeOutgoingVideoSourceLibWebRTC.cpp:
(WebCore::RealtimeOutgoingVideoSourceLibWebRTC::createBlackFrame): Ditto.
* platform/mediastream/libwebrtc/GStreamerVideoEncoderFactory.cpp:
(WebCore::GStreamerVideoEncoder::Fragmentize): Ditto.

Tools:

* TestWebKitAPI/PlatformGTK.cmake: Build the new GStreamer test harness
* TestWebKitAPI/PlatformWPE.cmake: Ditto.
* TestWebKitAPI/Tests/WebCore/gstreamer/GStreamerTest.cpp: Added.
(TestWebKitAPI::GStreamerTest::SetUp):
(TestWebKitAPI::GStreamerTest::TearDown):
* TestWebKitAPI/Tests/WebCore/gstreamer/GStreamerTest.h: Added.
* TestWebKitAPI/Tests/WebCore/gstreamer/GstMappedBuffer.cpp: Added.
(TestWebKitAPI::TEST_F):

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

19 files changed:
Source/WebCore/ChangeLog
Source/WebCore/platform/SharedBuffer.cpp
Source/WebCore/platform/SharedBuffer.h
Source/WebCore/platform/audio/gstreamer/WebKitWebAudioSourceGStreamer.cpp
Source/WebCore/platform/graphics/gstreamer/GStreamerCommon.cpp
Source/WebCore/platform/graphics/gstreamer/GStreamerCommon.h
Source/WebCore/platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.cpp
Source/WebCore/platform/graphics/gstreamer/eme/GStreamerEMEUtilities.h
Source/WebCore/platform/graphics/gstreamer/eme/WebKitClearKeyDecryptorGStreamer.cpp
Source/WebCore/platform/mediastream/gstreamer/MockGStreamerAudioCaptureSource.cpp
Source/WebCore/platform/mediastream/gstreamer/RealtimeOutgoingAudioSourceLibWebRTC.cpp
Source/WebCore/platform/mediastream/gstreamer/RealtimeOutgoingVideoSourceLibWebRTC.cpp
Source/WebCore/platform/mediastream/libwebrtc/GStreamerVideoEncoderFactory.cpp
Tools/ChangeLog
Tools/TestWebKitAPI/PlatformGTK.cmake
Tools/TestWebKitAPI/PlatformWPE.cmake
Tools/TestWebKitAPI/Tests/WebCore/gstreamer/GStreamerTest.cpp [new file with mode: 0644]
Tools/TestWebKitAPI/Tests/WebCore/gstreamer/GStreamerTest.h [new file with mode: 0644]
Tools/TestWebKitAPI/Tests/WebCore/gstreamer/GstMappedBuffer.cpp [new file with mode: 0644]

index c6c9f61..e9b0e22 100644 (file)
@@ -1,3 +1,60 @@
+2019-01-14  Charlie Turner  <cturner@igalia.com>
+
+        [GStreamer] Add sharedBuffer utility to GstMappedBuffer, and a testsuite
+        https://bugs.webkit.org/show_bug.cgi?id=192977
+
+        Reviewed by Carlos Garcia Campos.
+
+        Add a utility method on GstMappedBuffer to return a SharedBuffer
+        view over the mapped data with no copies.
+
+        This patch also introduces a new gstreamer port API test
+        directory, and includes some tests for GstMappedBuffer.
+
+        New tests in the API section.
+
+        * platform/SharedBuffer.cpp: Add a new overload for
+        GstMappedBuffer that allows sharing the mapped GStreamer buffers
+        with zero copies.
+        (WebCore::SharedBuffer::create):
+        (WebCore::SharedBuffer::SharedBuffer):
+        (WebCore::SharedBuffer::DataSegment::data const):
+        (WebCore::SharedBuffer::DataSegment::size const):
+        * platform/SharedBuffer.h:
+        * platform/audio/gstreamer/WebKitWebAudioSourceGStreamer.cpp:
+        (webKitWebAudioSrcAllocateBuffersAndRenderAudio): Update to new
+        API.
+        * platform/graphics/gstreamer/GStreamerCommon.cpp:
+        (WebCore::GstMappedBuffer::createSharedBuffer): Return a shared
+        buffer sharing this mapped buffer. The buffer must be shareable to
+        use this method.
+        * platform/graphics/gstreamer/GStreamerCommon.h:
+        (WebCore::GstMappedBuffer::create): Make GstMappedBuffer RefCounted
+        (WebCore::GstMappedBuffer::~GstMappedBuffer):
+        (WebCore::GstMappedBuffer::data):
+        (WebCore::GstMappedBuffer::data const):
+        (WebCore::GstMappedBuffer::size const):
+        (WebCore::GstMappedBuffer::isSharable const): New predicate to
+        check whether this buffer can be shared (i.e., is not writable)
+        (WebCore::GstMappedBuffer::GstMappedBuffer):
+        (WebCore::GstMappedBuffer::operator bool const): Deleted.
+        * platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.cpp:
+        (WebCore::InbandTextTrackPrivateGStreamer::notifyTrackOfSample):
+        Update to use new API.
+        * platform/graphics/gstreamer/eme/GStreamerEMEUtilities.h:
+        (WebCore::InitData::InitData): Ditto.
+        * platform/graphics/gstreamer/eme/WebKitClearKeyDecryptorGStreamer.cpp:
+        (webKitMediaClearKeyDecryptorFindAndSetKey): Ditto.
+        (webKitMediaClearKeyDecryptorDecrypt): Ditto.
+        * platform/mediastream/gstreamer/MockGStreamerAudioCaptureSource.cpp:
+        (WebCore::WrappedMockRealtimeAudioSource::render): Ditto.
+        * platform/mediastream/gstreamer/RealtimeOutgoingAudioSourceLibWebRTC.cpp:
+        (WebCore::RealtimeOutgoingAudioSourceLibWebRTC::pullAudioData): Ditto.
+        * platform/mediastream/gstreamer/RealtimeOutgoingVideoSourceLibWebRTC.cpp:
+        (WebCore::RealtimeOutgoingVideoSourceLibWebRTC::createBlackFrame): Ditto.
+        * platform/mediastream/libwebrtc/GStreamerVideoEncoderFactory.cpp:
+        (WebCore::GStreamerVideoEncoder::Fragmentize): Ditto.
+
 2019-01-14  Karl Leplat  <karl.leplat_ext@softathome.com>
 
         [GTK][WPE] Graphic issue with invalidations on composited layers with subpixel positions
index 46fc811..26de1bb 100644 (file)
@@ -54,6 +54,20 @@ SharedBuffer::SharedBuffer(Vector<char>&& data)
     append(WTFMove(data));
 }
 
+#if USE(GSTREAMER)
+Ref<SharedBuffer> SharedBuffer::create(GstMappedBuffer& mappedBuffer)
+{
+    ASSERT(mappedBuffer.isSharable());
+    return adoptRef(*new SharedBuffer(mappedBuffer));
+}
+
+SharedBuffer::SharedBuffer(GstMappedBuffer& mappedBuffer)
+    : m_size(mappedBuffer.size())
+{
+    m_segments.append({0, DataSegment::create(&mappedBuffer)});
+}
+#endif
+
 RefPtr<SharedBuffer> SharedBuffer::createWithContentsOfFile(const String& filePath)
 {
     bool mappingSuccess;
@@ -211,6 +225,9 @@ const char* SharedBuffer::DataSegment::data() const
 #if USE(GLIB)
         [](const GRefPtr<GBytes>& data) { return reinterpret_cast<const char*>(g_bytes_get_data(data.get(), nullptr)); },
 #endif
+#if USE(GSTREAMER)
+        [](const RefPtr<GstMappedBuffer>& data) { return reinterpret_cast<const char*>(data->data()); },
+#endif
         [](const FileSystem::MappedFileData& data) { return reinterpret_cast<const char*>(data.data()); }
     );
     return WTF::visit(visitor, m_immutableData);
@@ -284,6 +301,9 @@ size_t SharedBuffer::DataSegment::size() const
 #if USE(GLIB)
         [](const GRefPtr<GBytes>& data) { return g_bytes_get_size(data.get()); },
 #endif
+#if USE(GSTREAMER)
+        [](const RefPtr<GstMappedBuffer>& data) { return data->size(); },
+#endif
         [](const FileSystem::MappedFileData& data) { return data.size(); }
     );
     return WTF::visit(visitor, m_immutableData);
index e2aae2f..81318e8 100644 (file)
 typedef struct _GBytes GBytes;
 #endif
 
+#if USE(GSTREAMER)
+#include "GStreamerCommon.h"
+#endif
+
 #if USE(FOUNDATION)
 OBJC_CLASS NSArray;
 OBJC_CLASS NSData;
@@ -88,6 +92,9 @@ public:
     static Ref<SharedBuffer> create(GBytes*);
 #endif
 
+#if USE(GSTREAMER)
+    static Ref<SharedBuffer> create(GstMappedBuffer&);
+#endif
     // Calling data() causes all the data segments to be copied into one segment if they are not already.
     // Iterate the segments using begin() and end() instead.
     // FIXME: Audit the call sites of this function and replace them with iteration if possible.
@@ -126,6 +133,9 @@ public:
 #if USE(GLIB)
         static Ref<DataSegment> create(GRefPtr<GBytes>&& data) { return adoptRef(*new DataSegment(WTFMove(data))); }
 #endif
+#if USE(GSTREAMER)
+        static Ref<DataSegment> create(RefPtr<GstMappedBuffer>&& data) { return adoptRef(*new DataSegment(WTFMove(data))); }
+#endif
         static Ref<DataSegment> create(FileSystem::MappedFileData&& data) { return adoptRef(*new DataSegment(WTFMove(data))); }
 
     private:
@@ -143,6 +153,10 @@ public:
         DataSegment(GRefPtr<GBytes>&& data)
             : m_immutableData(WTFMove(data)) { }
 #endif
+#if USE(GSTREAMER)
+        DataSegment(RefPtr<GstMappedBuffer>&& data)
+            : m_immutableData(WTFMove(data)) { }
+#endif
         DataSegment(FileSystem::MappedFileData&& data)
             : m_immutableData(WTFMove(data)) { }
 
@@ -156,6 +170,9 @@ public:
 #if USE(GLIB)
             GRefPtr<GBytes>,
 #endif
+#if USE(GSTREAMER)
+            RefPtr<GstMappedBuffer>,
+#endif
             FileSystem::MappedFileData> m_immutableData;
         friend class SharedBuffer;
     };
@@ -191,6 +208,9 @@ private:
 #if USE(GLIB)
     explicit SharedBuffer(GBytes*);
 #endif
+#if USE(GSTREAMER)
+    explicit SharedBuffer(GstMappedBuffer&);
+#endif
 
     void combineIntoOneSegment() const;
     
index 0210352..2f937f6 100644 (file)
@@ -327,7 +327,7 @@ static Optional<Vector<GRefPtr<GstBuffer>>> webKitWebAudioSrcAllocateBuffersAndR
 
     Vector<GRefPtr<GstBuffer>> channelBufferList;
     channelBufferList.reserveInitialCapacity(priv->sources.size());
-    Vector<GstMappedBuffer> mappedBuffers;
+    Vector<RefPtr<GstMappedBuffer>> mappedBuffers;
     mappedBuffers.reserveInitialCapacity(priv->sources.size());
     for (unsigned i = 0; i < priv->sources.size(); ++i) {
         GRefPtr<GstBuffer> buffer;
@@ -342,10 +342,10 @@ static Optional<Vector<GRefPtr<GstBuffer>>> webKitWebAudioSrcAllocateBuffersAndR
         ASSERT(buffer);
         GST_BUFFER_TIMESTAMP(buffer.get()) = timestamp;
         GST_BUFFER_DURATION(buffer.get()) = duration;
-        GstMappedBuffer mappedBuffer(buffer.get(), GST_MAP_READWRITE);
+        auto mappedBuffer = GstMappedBuffer::create(buffer.get(), GST_MAP_READWRITE);
         ASSERT(mappedBuffer);
         mappedBuffers.uncheckedAppend(WTFMove(mappedBuffer));
-        priv->bus->setChannelMemory(i, reinterpret_cast<float*>(mappedBuffers[i].data()), priv->framesToPull);
+        priv->bus->setChannelMemory(i, reinterpret_cast<float*>(mappedBuffers[i]->data()), priv->framesToPull);
         channelBufferList.uncheckedAppend(WTFMove(buffer));
     }
 
index 0ba4739..c32539b 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "GstAllocatorFastMalloc.h"
 #include "IntSize.h"
+#include "SharedBuffer.h"
 #include <gst/audio/audio-info.h>
 #include <gst/gst.h>
 #include <mutex>
@@ -357,6 +358,15 @@ void connectSimpleBusMessageCallback(GstElement* pipeline)
     g_signal_connect(bus.get(), "message", G_CALLBACK(simpleBusMessageCallback), pipeline);
 }
 
+Ref<SharedBuffer> GstMappedBuffer::createSharedBuffer()
+{
+    // SharedBuffer provides a read-only view on what it expects are
+    // immutable data. Do not create one is writable and hence mutable.
+    RELEASE_ASSERT(isSharable());
+
+    return SharedBuffer::create(*this);
+}
+
 }
 
 #endif // USE(GSTREAMER)
index 2ef1550..5cb717d 100644 (file)
 #include <gst/video/video-format.h>
 #include <gst/video/video-info.h>
 #include <wtf/MediaTime.h>
+#include <wtf/ThreadSafeRefCounted.h>
 
 namespace WebCore {
 
 class IntSize;
+class SharedBuffer;
 
 inline bool webkitGstCheckVersion(guint major, guint minor, guint micro)
 {
@@ -77,51 +79,47 @@ inline GstClockTime toGstClockTime(const MediaTime &mediaTime)
     return static_cast<GstClockTime>(toGstUnsigned64Time(mediaTime));
 }
 
-class GstMappedBuffer {
-    WTF_MAKE_NONCOPYABLE(GstMappedBuffer);
+class GstMappedBuffer : public ThreadSafeRefCounted<GstMappedBuffer> {
 public:
-
-    GstMappedBuffer(GstMappedBuffer&& other)
-        : m_buffer(other.m_buffer)
-        , m_info(other.m_info)
-        , m_isValid(other.m_isValid)
-    {
-        other.m_isValid = false;
-    }
-
-    GstMappedBuffer(GstBuffer* buffer, GstMapFlags flags)
-        : m_buffer(buffer)
+    static RefPtr<GstMappedBuffer> create(GstBuffer* buffer, GstMapFlags flags)
     {
-        m_isValid = gst_buffer_map(m_buffer, &m_info, flags);
+        GstMapInfo info;
+        if (!gst_buffer_map(buffer, &info, flags))
+            return nullptr;
+        return adoptRef(new GstMappedBuffer(buffer, WTFMove(info)));
     }
 
     // Unfortunately, GST_MAP_READWRITE is defined out of line from the MapFlags
     // enum as an int, and C++ is careful to not implicity convert it to an enum.
-    GstMappedBuffer(GstBuffer* buffer, int flags)
-        : GstMappedBuffer(buffer, static_cast<GstMapFlags>(flags)) { }
+    static RefPtr<GstMappedBuffer> create(GstBuffer* buffer, int flags)
+    {
+        return GstMappedBuffer::create(buffer, static_cast<GstMapFlags>(flags));
+    }
 
     ~GstMappedBuffer()
     {
-        if (m_isValid)
-            gst_buffer_unmap(m_buffer, &m_info);
-        m_isValid = false;
+        gst_buffer_unmap(m_buffer, &m_info);
     }
 
-    uint8_t* data() { ASSERT(m_isValid); return static_cast<uint8_t*>(m_info.data); }
-    const uint8_t* data() const { ASSERT(m_isValid); return static_cast<uint8_t*>(m_info.data); }
-
-    size_t size() const { ASSERT(m_isValid); return static_cast<size_t>(m_info.size); }
-
-    explicit operator bool() const { return m_isValid; }
+    uint8_t* data() { return static_cast<uint8_t*>(m_info.data); }
+    const uint8_t* data() const { return static_cast<uint8_t*>(m_info.data); }
+    size_t size() const { return static_cast<size_t>(m_info.size); }
+    bool isSharable() const { return !(m_info.flags & GST_MAP_WRITE); }
+    Ref<SharedBuffer> createSharedBuffer();
 
 private:
+    GstMappedBuffer(GstBuffer* buffer, GstMapInfo&& info)
+        : m_buffer(buffer)
+        , m_info(WTFMove(info))
+    {
+    }
+
     friend bool operator==(const GstMappedBuffer&, const GstMappedBuffer&);
     friend bool operator==(const GstMappedBuffer&, const GstBuffer*);
     friend bool operator==(const GstBuffer* a, const GstMappedBuffer& b) { return operator==(b, a); }
 
     GstBuffer* m_buffer { nullptr };
     GstMapInfo m_info;
-    bool m_isValid { false };
 };
 
 inline bool operator==(const GstMappedBuffer& a, const GstMappedBuffer& b)
index c2dd123..fbffee6 100644 (file)
@@ -112,16 +112,16 @@ void InbandTextTrackPrivateGStreamer::notifyTrackOfSample()
             GST_WARNING("Track %d got sample with no buffer.", m_index);
             continue;
         }
-        GstMappedBuffer mappedBuffer(buffer, GST_MAP_READ);
+        auto mappedBuffer = GstMappedBuffer::create(buffer, GST_MAP_READ);
         ASSERT(mappedBuffer);
         if (!mappedBuffer) {
             GST_WARNING("Track %d unable to map buffer.", m_index);
             continue;
         }
 
-        GST_INFO("Track %d parsing sample: %.*s", m_index, static_cast<int>(mappedBuffer.size()),
-            reinterpret_cast<char*>(mappedBuffer.data()));
-        client()->parseWebVTTCueData(reinterpret_cast<char*>(mappedBuffer.data()), mappedBuffer.size());
+        GST_INFO("Track %d parsing sample: %.*s", m_index, static_cast<int>(mappedBuffer->size()),
+            reinterpret_cast<char*>(mappedBuffer->data()));
+        client()->parseWebVTTCueData(reinterpret_cast<char*>(mappedBuffer->data()), mappedBuffer->size());
     }
 }
 
index beff76a..8a92ca3 100644 (file)
@@ -40,12 +40,12 @@ public:
     InitData(const String& systemId, GstBuffer* initData)
         : m_systemId(systemId)
     {
-        GstMappedBuffer mappedInitData(initData, GST_MAP_READ);
+        auto mappedInitData = GstMappedBuffer::create(initData, GST_MAP_READ);
         if (!mappedInitData) {
             GST_ERROR("cannot map %s protection data", systemId.utf8().data());
             ASSERT_NOT_REACHED();
         }
-        m_payload = SharedBuffer::create(mappedInitData.data(), mappedInitData.size());
+        m_payload = mappedInitData->createSharedBuffer();
     }
 
     void append(InitData&& initData)
index f941e52..14eecc0 100644 (file)
@@ -150,11 +150,11 @@ static gboolean webKitMediaClearKeyDecryptorHandleKeyResponse(WebKitMediaCommonE
     return TRUE;
 }
 
-static gboolean webKitMediaClearKeyDecryptorFindAndSetKey(WebKitMediaClearKeyDecryptPrivate* priv, const WebCore::GstMappedBuffer& keyIDBuffer)
+static gboolean webKitMediaClearKeyDecryptorFindAndSetKey(WebKitMediaClearKeyDecryptPrivate* priv, RefPtr<WebCore::GstMappedBuffer>&& keyIDBuffer)
 {
     GRefPtr<GstBuffer> keyBuffer;
     for (auto& key : priv->keys) {
-        if (key.keyID.get() == keyIDBuffer) {
+        if (key.keyID.get() == *keyIDBuffer) {
             keyBuffer = key.keyValue;
             break;
         }
@@ -165,14 +165,14 @@ static gboolean webKitMediaClearKeyDecryptorFindAndSetKey(WebKitMediaClearKeyDec
         return false;
     }
 
-    WebCore::GstMappedBuffer mappedKeyValueBuffer(keyBuffer.get(), GST_MAP_READ);
+    auto mappedKeyValueBuffer = WebCore::GstMappedBuffer::create(keyBuffer.get(), GST_MAP_READ);
     if (!mappedKeyValueBuffer) {
         GST_ERROR_OBJECT(priv, "Failed to map decryption key");
         return false;
     }
 
-    ASSERT(mappedKeyValueBuffer.size() == CLEARKEY_SIZE);
-    if (gcry_error_t error = gcry_cipher_setkey(priv->handle, mappedKeyValueBuffer.data(), mappedKeyValueBuffer.size())) {
+    ASSERT(mappedKeyValueBuffer->size() == CLEARKEY_SIZE);
+    if (gcry_error_t error = gcry_cipher_setkey(priv->handle, mappedKeyValueBuffer->data(), mappedKeyValueBuffer->size())) {
         GST_ERROR_OBJECT(priv, "gcry_cipher_setkey failed: %s", gpg_strerror(error));
         return false;
     }
@@ -188,19 +188,19 @@ static gboolean webKitMediaClearKeyDecryptorDecrypt(WebKitMediaCommonEncryptionD
         return false;
     }
 
-    WebCore::GstMappedBuffer mappedIVBuffer(ivBuffer, GST_MAP_READ);
+    auto mappedIVBuffer = WebCore::GstMappedBuffer::create(ivBuffer, GST_MAP_READ);
     if (!mappedIVBuffer) {
         GST_ERROR_OBJECT(self, "Failed to map IV");
         return false;
     }
 
     uint8_t ctr[CLEARKEY_SIZE];
-    if (mappedIVBuffer.size() == 8) {
+    if (mappedIVBuffer->size() == 8) {
         memset(ctr + 8, 0, 8);
-        memcpy(ctr, mappedIVBuffer.data(), 8);
+        memcpy(ctr, mappedIVBuffer->data(), 8);
     } else {
         ASSERT(mappedIVBuffer.size() == CLEARKEY_SIZE);
-        memcpy(ctr, mappedIVBuffer.data(), CLEARKEY_SIZE);
+        memcpy(ctr, mappedIVBuffer->data(), CLEARKEY_SIZE);
     }
 
     WebKitMediaClearKeyDecryptPrivate* priv = WEBKIT_MEDIA_CK_DECRYPT_GET_PRIVATE(WEBKIT_MEDIA_CK_DECRYPT(self));
@@ -216,30 +216,30 @@ static gboolean webKitMediaClearKeyDecryptorDecrypt(WebKitMediaCommonEncryptionD
         return false;
     }
 
-    WebCore::GstMappedBuffer mappedKeyIdBuffer(keyIDBuffer, GST_MAP_READ);
+    auto mappedKeyIdBuffer = WebCore::GstMappedBuffer::create(keyIDBuffer, GST_MAP_READ);
     if (!mappedKeyIdBuffer) {
         GST_ERROR_OBJECT(self, "Failed to map key id buffer");
         return false;
     }
 
-    WebCore::GstMappedBuffer mappedBuffer(buffer, GST_MAP_READWRITE);
+    auto mappedBuffer = WebCore::GstMappedBuffer::create(buffer, GST_MAP_READWRITE);
     if (!mappedBuffer) {
         GST_ERROR_OBJECT(self, "Failed to map buffer");
         return false;
     }
 
-    webKitMediaClearKeyDecryptorFindAndSetKey(priv, mappedKeyIdBuffer);
+    webKitMediaClearKeyDecryptorFindAndSetKey(priv, WTFMove(mappedKeyIdBuffer));
 
     unsigned position = 0;
     unsigned sampleIndex = 0;
 
     if (!subSampleCount) {
         // Full sample encryption.
-        GST_TRACE_OBJECT(self, "full sample encryption: %zu encrypted bytes", mappedBuffer.size());
+        GST_TRACE_OBJECT(self, "full sample encryption: %zu encrypted bytes", mappedBuffer->size());
 
         // Check if the buffer is empty.
-        if (mappedBuffer.size()) {
-            cipherError = gcry_cipher_decrypt(priv->handle, mappedBuffer.data(), mappedBuffer.size(), 0, 0);
+        if (mappedBuffer->size()) {
+            cipherError = gcry_cipher_decrypt(priv->handle, mappedBuffer->data(), mappedBuffer->size(), 0, 0);
             if (cipherError) {
                 GST_ERROR_OBJECT(self, "full sample decryption failed: %s", gpg_strerror(cipherError));
                 return false;
@@ -255,16 +255,16 @@ static gboolean webKitMediaClearKeyDecryptorDecrypt(WebKitMediaCommonEncryptionD
     }
 
     // Subsample encryption.
-    WebCore::GstMappedBuffer mappedSubSamplesBuffer(subSamplesBuffer, GST_MAP_READ);
+    auto mappedSubSamplesBuffer = WebCore::GstMappedBuffer::create(subSamplesBuffer, GST_MAP_READ);
     if (!mappedSubSamplesBuffer) {
         GST_ERROR_OBJECT(self, "Failed to map subsample buffer");
         return false;
     }
 
-    GUniquePtr<GstByteReader> reader(gst_byte_reader_new(mappedSubSamplesBuffer.data(), mappedSubSamplesBuffer.size()));
-    GST_DEBUG_OBJECT(self, "position: %d, size: %zu", position, mappedBuffer.size());
+    GUniquePtr<GstByteReader> reader(gst_byte_reader_new(mappedSubSamplesBuffer->data(), mappedSubSamplesBuffer->size()));
+    GST_DEBUG_OBJECT(self, "position: %d, size: %zu", position, mappedBuffer->size());
 
-    while (position < mappedBuffer.size()) {
+    while (position < mappedBuffer->size()) {
         guint16 nBytesClear = 0;
         guint32 nBytesEncrypted = 0;
 
@@ -277,14 +277,14 @@ static gboolean webKitMediaClearKeyDecryptorDecrypt(WebKitMediaCommonEncryptionD
             sampleIndex++;
         } else {
             nBytesClear = 0;
-            nBytesEncrypted = mappedBuffer.size() - position;
+            nBytesEncrypted = mappedBuffer->size() - position;
         }
 
-        GST_TRACE_OBJECT(self, "subsample index %u - %hu bytes clear (todo=%zu)", sampleIndex, nBytesClear, mappedBuffer.size() - position);
+        GST_TRACE_OBJECT(self, "subsample index %u - %hu bytes clear (todo=%zu)", sampleIndex, nBytesClear, mappedBuffer->size() - position);
         position += nBytesClear;
         if (nBytesEncrypted) {
-            GST_TRACE_OBJECT(self, "subsample index %u - %u bytes encrypted (todo=%zu)", sampleIndex, nBytesEncrypted, mappedBuffer.size() - position);
-            cipherError = gcry_cipher_decrypt(priv->handle, mappedBuffer.data() + position, nBytesEncrypted, 0, 0);
+            GST_TRACE_OBJECT(self, "subsample index %u - %u bytes encrypted (todo=%zu)", sampleIndex, nBytesEncrypted, mappedBuffer->size() - position);
+            cipherError = gcry_cipher_decrypt(priv->handle, mappedBuffer->data() + position, nBytesEncrypted, 0, 0);
             if (cipherError) {
                 GST_ERROR_OBJECT(self, "sub sample index %u decryption failed: %s", sampleIndex, gpg_strerror(cipherError));
                 return false;
index dedc079..5338eb3 100644 (file)
@@ -78,13 +78,13 @@ public:
 
             GstBuffer* buffer = gst_buffer_new_allocate(nullptr, bipBopCount * m_streamFormat->bytesPerFrame(), nullptr);
             {
-                GstMappedBuffer map(buffer, GST_MAP_WRITE);
+                auto map = GstMappedBuffer::create(buffer, GST_MAP_WRITE);
 
                 if (!muted()) {
-                    memcpy(map.data(), &m_bipBopBuffer[bipBopStart], sizeof(float) * bipBopCount);
-                    addHum(s_HumVolume, s_HumFrequency, sampleRate(), m_samplesRendered, (float*)map.data(), bipBopCount);
+                    memcpy(map->data(), &m_bipBopBuffer[bipBopStart], sizeof(float) * bipBopCount);
+                    addHum(s_HumVolume, s_HumFrequency, sampleRate(), m_samplesRendered, (float*)map->data(), bipBopCount);
                 } else
-                    memset(map.data(), 0, sizeof(float) * bipBopCount);
+                    memset(map->data(), 0, sizeof(float) * bipBopCount);
             }
 
             gst_app_src_push_buffer(GST_APP_SRC(m_src.get()), buffer);
index 5e7f977..7203d7d 100644 (file)
@@ -114,9 +114,9 @@ void RealtimeOutgoingAudioSourceLibWebRTC::pullAudioData()
         if (isSilenced())
             gst_audio_format_fill_silence(m_outputStreamDescription->getInfo()->finfo, m_audioBuffer.data(), outBufferSize);
         else {
-            GstMappedBuffer inMap(inBuffer.get(), GST_MAP_READ);
+            auto inMap = GstMappedBuffer::create(inBuffer.get(), GST_MAP_READ);
 
-            gpointer in[1] = { inMap.data() };
+            gpointer in[1] = { inMap->data() };
             gpointer out[1] = { m_audioBuffer.data() };
             if (!gst_audio_converter_samples(m_sampleConverter.get(), static_cast<GstAudioConverterFlags>(0), in, inChunkSampleCount, out, outChunkSampleCount)) {
                 GST_ERROR("Could not convert samples.");
index 9e396d9..69be9b5 100644 (file)
@@ -86,8 +86,8 @@ rtc::scoped_refptr<webrtc::VideoFrameBuffer> RealtimeOutgoingVideoSourceLibWebRT
     GRefPtr<GstBuffer> buffer = adoptGRef(gst_buffer_new_allocate(nullptr, info.size, nullptr));
     GRefPtr<GstCaps> caps = adoptGRef(gst_video_info_to_caps(&info));
 
-    GstMappedBuffer map(buffer.get(), GST_MAP_WRITE);
-    memset(map.data(), 0, info.size);
+    auto map = GstMappedBuffer::create(buffer.get(), GST_MAP_WRITE);
+    memset(map->data(), 0, info.size);
 
     return GStreamerVideoFrameLibWebRTC::create(gst_sample_new(buffer.get(), caps.get(), NULL, NULL));
 }
index bc12b6c..ee740b4 100644 (file)
@@ -342,22 +342,22 @@ public:
     virtual void Fragmentize(webrtc::EncodedImage* encodedImage, std::unique_ptr<uint8_t[]>* encodedImageBuffer,
         size_t* bufferSize, GstBuffer* buffer, webrtc::RTPFragmentationHeader* fragmentationInfo)
     {
-        GstMappedBuffer map(buffer, GST_MAP_READ);
+        auto map = GstMappedBuffer::create(buffer, GST_MAP_READ);
 
-        if (*bufferSize < map.size()) {
-            encodedImage->_size = map.size();
+        if (*bufferSize < map->size()) {
+            encodedImage->_size = map->size();
             encodedImage->_buffer = new uint8_t[encodedImage->_size];
             encodedImageBuffer->reset(encodedImage->_buffer);
-            *bufferSize = map.size();
+            *bufferSize = map->size();
         }
 
-        memcpy(encodedImage->_buffer, map.data(), map.size());
-        encodedImage->_length = map.size();
-        encodedImage->_size = map.size();
+        memcpy(encodedImage->_buffer, map->data(), map->size());
+        encodedImage->_length = map->size();
+        encodedImage->_size = map->size();
 
         fragmentationInfo->VerifyAndAllocateFragmentationHeader(1);
         fragmentationInfo->fragmentationOffset[0] = 0;
-        fragmentationInfo->fragmentationLength[0] = map.size();
+        fragmentationInfo->fragmentationLength[0] = map->size();
         fragmentationInfo->fragmentationPlType[0] = 0;
         fragmentationInfo->fragmentationTimeDiff[0] = 0;
     }
@@ -438,9 +438,9 @@ public:
         std::vector<GstH264NalUnit> nals;
 
         const uint8_t startCode[4] = { 0, 0, 0, 1 };
-        GstMappedBuffer map(gstbuffer, GST_MAP_READ);
+        auto map = GstMappedBuffer::create(gstbuffer, GST_MAP_READ);
         while (parserResult == GST_H264_PARSER_OK) {
-            parserResult = gst_h264_parser_identify_nalu(m_parser, map.data(), offset, map.size(), &nalu);
+            parserResult = gst_h264_parser_identify_nalu(m_parser, map->data(), offset, map->size(), &nalu);
 
             nalu.sc_offset = offset;
             nalu.offset = offset + sizeof(startCode);
@@ -456,7 +456,7 @@ public:
             encodedImage->_size = requiredSize;
             encodedImage->_buffer = new uint8_t[encodedImage->_size];
             encodedImageBuffer->reset(encodedImage->_buffer);
-            *bufferSize = map.size();
+            *bufferSize = map->size();
         }
 
         // Iterate nal units and fill the Fragmentation info.
@@ -465,15 +465,15 @@ public:
         encodedImage->_length = 0;
         for (std::vector<GstH264NalUnit>::iterator nal = nals.begin(); nal != nals.end(); ++nal, fragmentIndex++) {
 
-            ASSERT(map.data()[nal->sc_offset + 0] == startCode[0]);
-            ASSERT(map.data()[nal->sc_offset + 1] == startCode[1]);
-            ASSERT(map.data()[nal->sc_offset + 2] == startCode[2]);
-            ASSERT(map.data()[nal->sc_offset + 3] == startCode[3]);
+            ASSERT(map->data()[nal->sc_offset + 0] == startCode[0]);
+            ASSERT(map->data()[nal->sc_offset + 1] == startCode[1]);
+            ASSERT(map->data()[nal->sc_offset + 2] == startCode[2]);
+            ASSERT(map->data()[nal->sc_offset + 3] == startCode[3]);
 
             fragmentationHeader->fragmentationOffset[fragmentIndex] = nal->offset;
             fragmentationHeader->fragmentationLength[fragmentIndex] = nal->size;
 
-            memcpy(encodedImage->_buffer + encodedImage->_length, &map.data()[nal->sc_offset],
+            memcpy(encodedImage->_buffer + encodedImage->_length, &map->data()[nal->sc_offset],
                 sizeof(startCode) + nal->size);
             encodedImage->_length += nal->size + sizeof(startCode);
         }
index 22e5516..284cfda 100644 (file)
@@ -1,5 +1,21 @@
 2019-01-14  Charlie Turner  <cturner@igalia.com>
 
+        [GStreamer] Add sharedBuffer utility to GstMappedBuffer, and a testsuite
+        https://bugs.webkit.org/show_bug.cgi?id=192977
+
+        Reviewed by Carlos Garcia Campos.
+
+        * TestWebKitAPI/PlatformGTK.cmake: Build the new GStreamer test harness
+        * TestWebKitAPI/PlatformWPE.cmake: Ditto.
+        * TestWebKitAPI/Tests/WebCore/gstreamer/GStreamerTest.cpp: Added.
+        (TestWebKitAPI::GStreamerTest::SetUp):
+        (TestWebKitAPI::GStreamerTest::TearDown):
+        * TestWebKitAPI/Tests/WebCore/gstreamer/GStreamerTest.h: Added.
+        * TestWebKitAPI/Tests/WebCore/gstreamer/GstMappedBuffer.cpp: Added.
+        (TestWebKitAPI::TEST_F):
+
+2019-01-14  Charlie Turner  <cturner@igalia.com>
+
         [WPE] Workaround for incorrect template specialization being selected when UChar=char16_t
         https://bugs.webkit.org/show_bug.cgi?id=193332
 
index 84499de..c34fae0 100644 (file)
@@ -25,6 +25,7 @@ include_directories(
 include_directories(SYSTEM
     ${GDK3_INCLUDE_DIRS}
     ${GLIB_INCLUDE_DIRS}
+    ${GSTREAMER_INCLUDE_DIRS}
     ${GTK3_INCLUDE_DIRS}
     ${LIBSOUP_INCLUDE_DIRS}
 )
@@ -93,6 +94,8 @@ add_executable(TestWebCore
     ${TESTWEBKITAPI_DIR}/Tests/WebCore/DNS.cpp
     ${TESTWEBKITAPI_DIR}/Tests/WebCore/FileMonitor.cpp
     ${TESTWEBKITAPI_DIR}/Tests/WebCore/FileSystem.cpp
+    ${TESTWEBKITAPI_DIR}/Tests/WebCore/gstreamer/GstMappedBuffer.cpp
+    ${TESTWEBKITAPI_DIR}/Tests/WebCore/gstreamer/GStreamerTest.cpp
     ${TESTWEBKITAPI_DIR}/Tests/WebCore/GridPosition.cpp
     ${TESTWEBKITAPI_DIR}/Tests/WebCore/HTMLParserIdioms.cpp
     ${TESTWEBKITAPI_DIR}/Tests/WebCore/LayoutUnit.cpp
index fb1b6b5..b687759 100644 (file)
@@ -23,6 +23,7 @@ include_directories(
 include_directories(SYSTEM
     ${CAIRO_INCLUDE_DIRS}
     ${GLIB_INCLUDE_DIRS}
+    ${GSTREAMER_INCLUDE_DIRS}
     ${LIBSOUP_INCLUDE_DIRS}
     ${WPE_INCLUDE_DIRS}
     ${WPEBACKEND_FDO_INCLUDE_DIRS}
@@ -60,6 +61,8 @@ add_executable(TestWebCore
     ${TESTWEBKITAPI_DIR}/TestsController.cpp
     ${TESTWEBKITAPI_DIR}/Tests/WebCore/FileMonitor.cpp
     ${TESTWEBKITAPI_DIR}/Tests/WebCore/FileSystem.cpp
+    ${TESTWEBKITAPI_DIR}/Tests/WebCore/gstreamer/GstMappedBuffer.cpp
+    ${TESTWEBKITAPI_DIR}/Tests/WebCore/gstreamer/GStreamerTest.cpp
     ${TESTWEBKITAPI_DIR}/Tests/WebCore/HTMLParserIdioms.cpp
     ${TESTWEBKITAPI_DIR}/Tests/WebCore/LayoutUnit.cpp
     ${TESTWEBKITAPI_DIR}/Tests/WebCore/MIMETypeRegistry.cpp
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/gstreamer/GStreamerTest.cpp b/Tools/TestWebKitAPI/Tests/WebCore/gstreamer/GStreamerTest.cpp
new file mode 100644 (file)
index 0000000..3d7f94d
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 Igalia, S.L.
+ * Copyright (C) 2018 Metrological Group B.V.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if USE(GSTREAMER)
+#include "GStreamerTest.h"
+
+#include <WebCore/GStreamerCommon.h>
+#include <gst/gst.h>
+
+using namespace WebCore;
+
+namespace TestWebKitAPI {
+
+void GStreamerTest::SetUp()
+{
+    if (!gst_is_initialized())
+        gst_init(nullptr, nullptr);
+}
+
+void GStreamerTest::TearDown()
+{
+    // It might be tempting to call gst_deinit() here. However, that
+    // will tear down the whole process from the GStreamer POV, and the
+    // seemingly symmetrical call to gst_init() will fail to
+    // initialize GStreamer correctly.
+}
+
+} // namespace TestWebKitAPI
+
+#endif // USE(GSTREAMER)
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/gstreamer/GStreamerTest.h b/Tools/TestWebKitAPI/Tests/WebCore/gstreamer/GStreamerTest.h
new file mode 100644 (file)
index 0000000..6b2cbae
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 Igalia, S.L.
+ * Copyright (C) 2018 Metrological Group B.V.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if USE(GSTREAMER)
+
+namespace TestWebKitAPI {
+
+class GStreamerTest : public testing::Test {
+public:
+    void SetUp() override;
+    void TearDown() override;
+};
+
+} // namespace TestWebKitAPI
+
+#endif // USE(GSTREAMER)
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/gstreamer/GstMappedBuffer.cpp b/Tools/TestWebKitAPI/Tests/WebCore/gstreamer/GstMappedBuffer.cpp
new file mode 100644 (file)
index 0000000..df572ae
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2018 Igalia, S.L.
+ * Copyright (C) 2018 Metrological Group B.V.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if USE(GSTREAMER)
+
+#include "GStreamerTest.h"
+#include "SharedBuffer.h"
+#include "Test.h"
+#include <WebCore/GStreamerCommon.h>
+
+using namespace WebCore;
+
+namespace TestWebKitAPI {
+
+TEST_F(GStreamerTest, mappedBufferBasics)
+{
+    GRefPtr<GstBuffer> buf = adoptGRef(gst_buffer_new_allocate(nullptr, 64, nullptr));
+    auto mappedBuf = GstMappedBuffer::create(buf.get(), GST_MAP_READ);
+    ASSERT_TRUE(mappedBuf);
+    EXPECT_EQ(mappedBuf->size(), 64);
+
+    auto mappedBuf2 = GstMappedBuffer::create(buf.get(), GST_MAP_READ);
+    ASSERT_TRUE(mappedBuf2);
+    EXPECT_EQ(*mappedBuf, *mappedBuf2);
+    EXPECT_EQ(buf.get(), *mappedBuf);
+    EXPECT_EQ(*mappedBuf2, buf.get());
+}
+
+TEST_F(GStreamerTest, mappedBufferReadSanity)
+{
+    gpointer memory = g_malloc(16);
+    memset(memory, 'x', 16);
+    GRefPtr<GstBuffer> buf = adoptGRef(gst_buffer_new_wrapped(memory, 16));
+    auto mappedBuf = GstMappedBuffer::create(buf.get(), GST_MAP_READ);
+    ASSERT_TRUE(mappedBuf);
+    EXPECT_EQ(mappedBuf->size(), 16);
+    EXPECT_EQ(memcmp(memory, mappedBuf->data(), 16), 0);
+    EXPECT_EQ(memcmp(memory, mappedBuf->createSharedBuffer()->data(), 16), 0);
+}
+
+TEST_F(GStreamerTest, mappedBufferWriteSanity)
+{
+    gpointer memory = g_malloc(16);
+    memset(memory, 'x', 16);
+    GRefPtr<GstBuffer> buf = adoptGRef(gst_buffer_new_wrapped(memory, 16));
+
+    auto mappedBuf = GstMappedBuffer::create(buf.get(), GST_MAP_WRITE);
+    ASSERT_TRUE(mappedBuf);
+    EXPECT_EQ(mappedBuf->size(), 16);
+    memset(mappedBuf->data(), 'y', mappedBuf->size());
+
+    EXPECT_EQ(memcmp(memory, mappedBuf->data(), 16), 0);
+}
+
+TEST_F(GStreamerTest, mappedBufferCachesSharedBuffers)
+{
+    GRefPtr<GstBuffer> buf = adoptGRef(gst_buffer_new_allocate(nullptr, 64, nullptr));
+    auto mappedBuf = GstMappedBuffer::create(buf.get(), GST_MAP_READ);
+    ASSERT_TRUE(mappedBuf);
+    auto sharedBuf = mappedBuf->createSharedBuffer();
+    // We expect the same data pointer wrapped by shared buffer, no
+    // copies need to be made.
+    EXPECT_EQ(sharedBuf->data(), mappedBuf->createSharedBuffer()->data());
+}
+
+TEST_F(GStreamerTest, mappedBufferDoesNotAddExtraRefs)
+{
+    // It is important not to ref the passed GStreamer buffers, if we
+    // do so, then in the case of writable buffers, they can become
+    // unwritable, even though we are the sole owners. We also don't
+    // want to take ownership of the buffer from the user-code, since
+    // for transformInPlace use-cases, that would break.
+    GRefPtr<GstBuffer> buf = adoptGRef(gst_buffer_new());
+
+    ASSERT_EQ(GST_OBJECT_REFCOUNT(buf.get()), 1);
+
+    auto mappedBuf = GstMappedBuffer::create(buf.get(), GST_MAP_READWRITE);
+    ASSERT_TRUE(mappedBuf);
+
+    ASSERT_EQ(GST_OBJECT_REFCOUNT(buf.get()), 1);
+}
+
+} // namespace TestWebKitAPI
+
+#endif // USE(GSTREAMER)