mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 19:51:11 +00:00
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
This commit is contained in:
parent
db36718ee4
commit
f0c7fbb371
1 changed files with 151 additions and 0 deletions
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue