summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorGeorg Lippitsch <glippitsch@toolsonair.com>2017-05-12 14:39:54 +0200
committerSebastian Dröge <sebastian@centricular.com>2017-07-11 14:26:31 +0300
commitf0c7fbb371494bbe0721ef2abdff01b0fe7c7474 (patch)
tree309cfce7a6acd1c49d02ab6dac10e8d52cb3ebe1 /sys
parentdb36718ee4c54d4bf2478cbf561f06bb7b84dbcf (diff)
downloadgstreamer-plugins-bad-f0c7fbb371494bbe0721ef2abdff01b0fe7c7474.tar.gz
decklinkvideosrc: Add custom memory allocator
The default memory allocator of the decklink library allocates a fixed pool of buffers, and the number of buffers is unknown. This makes it impossible do useful queuing downstream. The new memory allocator can create an unlimited number of buffers, giving all queuing features one would expect from a live source. https://bugzilla.gnome.org/show_bug.cgi?id=782556
Diffstat (limited to 'sys')
-rw-r--r--sys/decklink/gstdecklink.cpp151
1 files changed, 151 insertions, 0 deletions
diff --git a/sys/decklink/gstdecklink.cpp b/sys/decklink/gstdecklink.cpp
index 08b49541a..49f3143df 100644
--- a/sys/decklink/gstdecklink.cpp
+++ b/sys/decklink/gstdecklink.cpp
@@ -856,6 +856,155 @@ public:
}
};
+class GStreamerDecklinkMemoryAllocator:public IDeckLinkMemoryAllocator
+{
+private:
+ GMutex m_mutex;
+ uint32_t m_lastBufferSize;
+ uint32_t m_nonEmptyCalls;
+ GstQueueArray * m_buffers;
+ gint m_refcount;
+
+ void _clearBufferPool()
+ {
+ uint8_t * buf;
+
+ if (!m_buffers)
+ return;
+
+ while ((buf = (uint8_t*)gst_queue_array_pop_head (m_buffers)))
+ g_free(buf - 128);
+ }
+
+public:
+ GStreamerDecklinkMemoryAllocator ()
+ : IDeckLinkMemoryAllocator (),
+ m_lastBufferSize (0),
+ m_nonEmptyCalls (0),
+ m_buffers (NULL),
+ m_refcount (1)
+ {
+ g_mutex_init (&m_mutex);
+
+ m_buffers = gst_queue_array_new (60);
+ }
+
+ virtual ~ GStreamerDecklinkMemoryAllocator ()
+ {
+ Decommit();
+
+ gst_queue_array_free (m_buffers);
+
+ g_mutex_clear (&m_mutex);
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface (REFIID, LPVOID *)
+ {
+ return E_NOINTERFACE;
+ }
+
+ virtual ULONG STDMETHODCALLTYPE AddRef (void)
+ {
+ ULONG ret;
+
+ g_mutex_lock (&m_mutex);
+ m_refcount++;
+ ret = m_refcount;
+ g_mutex_unlock (&m_mutex);
+
+ return ret;
+ }
+
+ virtual ULONG STDMETHODCALLTYPE Release (void)
+ {
+ ULONG ret;
+
+ g_mutex_lock (&m_mutex);
+ m_refcount--;
+ ret = m_refcount;
+ g_mutex_unlock (&m_mutex);
+
+
+ if (ret == 0) {
+ delete this;
+ }
+
+ return ret;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE
+ AllocateBuffer (uint32_t bufferSize, void **allocatedBuffer)
+ {
+ uint8_t * buf;
+
+ g_mutex_lock (&m_mutex);
+
+ /* If buffer size changed since last call, empty buffer pool */
+ if (bufferSize != m_lastBufferSize) {
+ _clearBufferPool();
+ m_lastBufferSize = bufferSize;
+ }
+
+ /* Look if there is a free buffer in the pool */
+ if (!(buf = (uint8_t*) gst_queue_array_pop_head (m_buffers))) {
+ /* If not, alloc a new one */
+ buf = (uint8_t*) g_malloc (bufferSize + 128);
+ *((uint32_t *) buf) = bufferSize;
+ buf += 128;
+ }
+ *allocatedBuffer = (void *) buf;
+
+ /* If there are still unused buffers in the pool
+ * remove one of them every fifth call */
+ if (gst_queue_array_get_length (m_buffers) > 0) {
+ if (++m_nonEmptyCalls >= 5) {
+ buf = (uint8_t*) gst_queue_array_pop_head (m_buffers) - 128;
+ g_free (buf);
+ m_nonEmptyCalls = 0;
+ }
+ } else {
+ m_nonEmptyCalls = 0;
+ }
+
+ g_mutex_unlock (&m_mutex);
+
+ return S_OK;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE
+ ReleaseBuffer (void * buffer)
+ {
+ g_mutex_lock (&m_mutex);
+
+ /* Put the buffer back to the pool if size matches with current pool */
+ uint32_t size = *(uint32_t *) ((uint8_t*)buffer - 128);
+ if (size == m_lastBufferSize) {
+ gst_queue_array_push_tail (m_buffers, buffer);
+ } else {
+ g_free (buffer);
+ }
+
+ g_mutex_unlock (&m_mutex);
+
+ return S_OK;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE
+ Commit ()
+ {
+ return S_OK;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE
+ Decommit ()
+ {
+ /* Clear all remaining pools */
+ _clearBufferPool();
+
+ return S_OK;
+ }
+};
+
#ifdef _MSC_VER
/* FIXME: We currently never deinit this */
@@ -1147,6 +1296,8 @@ gst_decklink_acquire_nth_input (gint n, GstElement * src, gboolean is_audio)
}
g_mutex_lock (&input->lock);
+ input->input->SetVideoInputFrameMemoryAllocator(
+ new GStreamerDecklinkMemoryAllocator);
if (is_audio && !input->audiosrc) {
input->audiosrc = GST_ELEMENT_CAST (gst_object_ref (src));
g_mutex_unlock (&input->lock);