diff options
author | Georg Lippitsch <glippitsch@toolsonair.com> | 2017-05-12 14:39:54 +0200 |
---|---|---|
committer | Sebastian Dröge <sebastian@centricular.com> | 2017-07-11 14:26:31 +0300 |
commit | f0c7fbb371494bbe0721ef2abdff01b0fe7c7474 (patch) | |
tree | 309cfce7a6acd1c49d02ab6dac10e8d52cb3ebe1 /sys | |
parent | db36718ee4c54d4bf2478cbf561f06bb7b84dbcf (diff) | |
download | gstreamer-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.cpp | 151 |
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); |