[vlc-devel] [RFC PATCH 3/6] omxil/mediacodec: add QueueThread
Thomas Guillem
thomas at gllm.fr
Mon Nov 3 19:41:19 CET 2014
QueueThread is an object that queue input or output buffers in a seperate
thread. It will be used by omxil and mediacodec.
---
modules/codec/Makefile.am | 2 +
modules/codec/omxil/queue_thread.c | 383 +++++++++++++++++++++++++++++++++++++
modules/codec/omxil/queue_thread.h | 66 +++++++
3 files changed, 451 insertions(+)
create mode 100644 modules/codec/omxil/queue_thread.c
create mode 100644 modules/codec/omxil/queue_thread.h
diff --git a/modules/codec/Makefile.am b/modules/codec/Makefile.am
index 0dc451d..9dcbb94 100644
--- a/modules/codec/Makefile.am
+++ b/modules/codec/Makefile.am
@@ -356,6 +356,7 @@ libomxil_plugin_la_SOURCES = \
codec/hevc_nal.c codec/hevc_nal.h \
codec/omxil/qcom.c codec/omxil/qcom.h \
codec/omxil/omxil.c codec/omxil/omxil.h codec/omxil/omxil_core.c codec/omxil/omxil_core.h \
+ codec/omxil/queue_thread.c codec/omxil/queue_thread.h \
video_chroma/copy.c
libomxil_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/codec/omxil $(CFLAGS_omxil)
libomxil_plugin_la_LIBADD = $(LIBDL)
@@ -372,6 +373,7 @@ libiomx_plugin_la_LIBADD = $(libomxil_plugin_la_LIBADD)
libmediacodec_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/codec/omxil
libmediacodec_plugin_la_SOURCES = codec/omxil/android_mediacodec.c codec/omxil/utils.c \
+ codec/omxil/queue_thread.c codec/omxil/queue_thread.h \
video_chroma/copy.c codec/omxil/android_opaque.c codec/omxil/android_opaque.h \
codec/h264_nal.c codec/h264_nal.h codec/hevc_nal.c codec/hevc_nal.h
diff --git a/modules/codec/omxil/queue_thread.c b/modules/codec/omxil/queue_thread.c
new file mode 100644
index 0000000..b391a2b
--- /dev/null
+++ b/modules/codec/omxil/queue_thread.c
@@ -0,0 +1,383 @@
+/*****************************************************************************
+ * queue_thread.c: queue input/output buffers in a separate thread
+ *****************************************************************************
+ * Copyright (C) 2014 Thomas Guillem
+ *
+ * Authors: Thomas Guillem <thomas at gllm.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include "queue_thread.h"
+
+#include <vlc_picture_fifo.h>
+
+typedef struct queue_thread_elm_priv queue_thread_elm_priv;
+struct queue_thread_elm_priv
+{
+ queue_thread_elm *p_elm;
+ queue_thread_elm_priv *p_next;
+};
+
+typedef struct queue_thread_fifo queue_thread_fifo;
+struct queue_thread_fifo
+{
+ queue_thread_elm_priv *p_first;
+ queue_thread_elm_priv **pp_last;
+};
+
+
+struct queue_thread_sys {
+ vlc_mutex_t mutex;
+ vlc_cond_t cond;
+ vlc_thread_t thread;
+ queue_thread_fifo *p_fifo;
+ enum {
+ STATE_STOP,
+ STATE_RUNNING,
+ STATE_PAUSING,
+ STATE_FLUSHING,
+ STATE_PAUSED,
+ STATE_STOPPING,
+ STATE_ERROR,
+ } state;
+};
+
+/*****************************************************************************
+ * QueueThread_Fifo
+ *****************************************************************************/
+int QueueThread_FifoPush( queue_thread *p_qthread, queue_thread_elm *p_elm )
+{
+ queue_thread_sys *p_sys = p_qthread->p_sys;
+ queue_thread_fifo *p_fifo = p_sys->p_fifo;
+ queue_thread_elm_priv *p_priv;
+
+ vlc_mutex_lock( &p_sys->mutex );
+
+ p_priv = calloc( 1, sizeof(queue_thread_elm_priv) );
+ if( !p_priv )
+ {
+ vlc_mutex_unlock( &p_sys->mutex );
+ return -1;
+ }
+
+ p_priv->p_elm = p_elm;
+ *p_fifo->pp_last = p_priv;
+ p_fifo->pp_last = &p_priv->p_next;
+
+ vlc_cond_signal( &p_sys->cond );
+ vlc_mutex_unlock( &p_sys->mutex );
+
+ return 0;
+}
+
+queue_thread_elm *QueueThread_FifoPop( queue_thread *p_qthread )
+{
+ queue_thread_sys *p_sys = p_qthread->p_sys;
+ queue_thread_fifo *p_fifo = p_sys->p_fifo;
+ queue_thread_elm *p_elm;
+ queue_thread_elm_priv *p_priv;
+
+ vlc_mutex_lock( &p_sys->mutex );
+ p_priv = p_fifo->p_first;
+
+ if( !p_priv )
+ {
+ vlc_mutex_unlock( &p_sys->mutex );
+ return NULL;
+ }
+
+ p_elm = p_priv->p_elm;
+ p_fifo->p_first = p_priv->p_next;
+ free(p_priv);
+
+ if( !p_fifo->p_first )
+ p_fifo->pp_last = &p_fifo->p_first;
+
+ vlc_mutex_unlock( &p_sys->mutex );
+
+ return p_elm;
+}
+
+queue_thread_elm *QueueThread_FifoPeek( queue_thread *p_qthread )
+{
+ queue_thread_sys *p_sys = p_qthread->p_sys;
+ queue_thread_fifo *p_fifo = p_sys->p_fifo;
+ queue_thread_elm *p_elm = NULL;
+
+ vlc_mutex_lock( &p_sys->mutex );
+ if( p_fifo->p_first != NULL )
+ p_elm = p_fifo->p_first->p_elm;
+ vlc_mutex_unlock( &p_sys->mutex );
+
+ return p_elm;
+}
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static int QueueThread_FifoNew( queue_thread *p_qthread )
+{
+ queue_thread_sys *p_sys = p_qthread->p_sys;
+ queue_thread_fifo *p_fifo;
+
+ p_sys->p_fifo = p_fifo = calloc( 1, sizeof(queue_thread_fifo) );
+ if( !p_fifo )
+ return -1;
+ p_fifo->pp_last = &p_fifo->p_first;
+
+ return 0;
+}
+
+static void QueueThread_FifoRelease( queue_thread *p_qthread )
+{
+ queue_thread_sys *p_sys = p_qthread->p_sys;
+
+ if( p_sys->p_fifo == NULL )
+ return;
+
+ while( ( QueueThread_FifoPop( p_qthread ) ) )
+ msg_Warn(p_qthread, "stray elm in FIFO, Shouldn't not happen");
+ free( p_sys->p_fifo );
+ p_sys->p_fifo = NULL;
+}
+
+static void QueueThread_SetStateWait( queue_thread *p_qthread,
+ unsigned int state,
+ unsigned int waiting_state )
+{
+ queue_thread_sys *p_sys = p_qthread->p_sys;
+
+ vlc_mutex_lock( &p_sys->mutex);
+ if( p_sys->state == STATE_ERROR )
+ {
+ vlc_mutex_unlock( &p_sys->mutex );
+ return;
+ }
+ p_sys->state = state;
+ vlc_cond_signal( &p_sys->cond );
+
+ while( p_sys->state != waiting_state )
+ vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
+
+ vlc_mutex_unlock( &p_sys->mutex );
+}
+
+static void *QueueThread( void *data )
+{
+ queue_thread *p_qthread = data;
+ queue_thread_sys *p_sys = p_qthread->p_sys;
+ bool b_wait = false;
+ bool b_flush = false;
+
+ if( p_qthread->pf_init != NULL &&
+ p_qthread->pf_init( p_qthread ) != 0 )
+ goto error;
+
+ vlc_mutex_lock( &p_sys->mutex );
+ while( p_sys->state != STATE_STOP && p_sys->state != STATE_ERROR )
+ {
+ int ret;
+
+ while( p_sys->state == STATE_PAUSED )
+ vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
+
+ if( p_sys->state == STATE_RUNNING && b_wait )
+ {
+ vlc_cond_timedwait( &p_sys->cond, &p_sys->mutex,
+ mdate() + 100000 );
+ b_wait = false;
+ }
+
+ if( p_sys->state == STATE_PAUSING )
+ {
+ b_wait = false;
+ p_sys->state = STATE_PAUSED;
+ vlc_cond_signal( &p_sys->cond );
+ continue;
+ }
+ else if( p_sys->state == STATE_FLUSHING || p_sys->state == STATE_STOPPING )
+ {
+ if( !b_flush ) {
+ b_flush = true;
+ }
+ else
+ {
+ b_flush = false;
+ if( p_sys->state == STATE_FLUSHING )
+ {
+ p_sys->state = STATE_PAUSED;
+ vlc_cond_signal( &p_sys->cond );
+ continue;
+ }
+ else
+ {
+ p_sys->state = STATE_STOP;
+ continue;
+ }
+ }
+ }
+ else if( p_sys->state != STATE_RUNNING )
+ {
+ p_sys->state = STATE_ERROR;
+ continue;
+ }
+ vlc_mutex_unlock( &p_sys->mutex );
+
+ ret = p_qthread->pf_run( p_qthread, b_flush );
+ if( !b_flush && ret == 0
+ && QueueThread_FifoPeek( p_qthread ) == NULL )
+ b_wait = true;
+
+ vlc_mutex_lock( &p_sys->mutex );
+ if( ret == -1 )
+ p_sys->state = STATE_ERROR;
+ }
+ vlc_mutex_unlock( &p_sys->mutex );
+
+error:
+ if( p_qthread->pf_destroy )
+ p_qthread->pf_destroy( p_qthread );
+
+ return NULL;
+}
+
+
+queue_thread *QueueThread_New( vlc_object_t *obj )
+{
+ queue_thread *p_qthread = vlc_object_create( obj, sizeof(queue_thread) );
+ queue_thread_sys *p_sys;
+
+ if( p_qthread == NULL )
+ return NULL;
+
+ p_qthread->p_sys = p_sys = calloc( 1, sizeof(queue_thread_sys) );
+ if( p_sys == NULL )
+ goto error;
+
+ vlc_mutex_init( &p_sys->mutex );
+ vlc_cond_init( &p_sys->cond );
+
+ if( QueueThread_FifoNew( p_qthread ) != 0 )
+ goto error;
+
+ p_sys->state = STATE_STOP;
+
+ return p_qthread;
+
+error:
+ QueueThread_Delete( p_qthread );
+ return NULL;
+}
+
+void QueueThread_Delete( queue_thread *p_qthread )
+{
+ queue_thread_sys *p_sys = p_qthread->p_sys;
+
+ if( p_sys )
+ {
+ if( p_sys->thread )
+ {
+ QueueThread_SetStateWait( p_qthread, STATE_STOPPING,
+ STATE_STOPPING );
+ vlc_join( p_sys->thread, NULL );
+
+ }
+ QueueThread_FifoRelease( p_qthread );
+
+ vlc_mutex_destroy( &p_sys->mutex );
+ vlc_cond_destroy( &p_sys->cond );
+
+ free( p_sys );
+ }
+ vlc_object_release( p_qthread );
+}
+
+int QueueThread_Start( queue_thread *p_qthread )
+{
+ queue_thread_sys *p_sys = p_qthread->p_sys;
+
+ vlc_mutex_lock( &p_sys->mutex );
+
+ if( p_sys->state == STATE_PAUSED )
+ {
+ p_sys->state = STATE_RUNNING;
+ vlc_cond_signal( &p_sys->cond );
+ vlc_mutex_unlock( &p_sys->mutex );
+ return 0;
+ }
+ else if( p_sys->state != STATE_STOP )
+ {
+ msg_Err( p_qthread, "QueueThread_Start failed: invalid state" );
+ goto error;
+ }
+
+ if( !p_qthread->p_owner && !p_qthread->pf_run )
+ {
+ msg_Err( p_qthread, "QueueThread_Start failed: callbacks not set" );
+ goto error;
+ }
+
+ p_sys->state = STATE_RUNNING;
+ if( vlc_clone( &p_sys->thread,
+ QueueThread, p_qthread, VLC_THREAD_PRIORITY_LOW ) )
+ {
+ msg_Err( p_qthread, "QueueThread_Start failed: clone failed" );
+ goto error;
+ }
+
+ vlc_mutex_unlock( &p_sys->mutex );
+ return 0;
+error:
+ vlc_mutex_unlock( &p_sys->mutex );
+ return -1;
+}
+
+int QueueThread_Pause( queue_thread *p_qthread )
+{
+ QueueThread_SetStateWait( p_qthread, STATE_PAUSING,
+ STATE_PAUSED );
+ return 0;
+}
+
+bool QueueThread_GetErrorState( queue_thread *p_qthread )
+{
+ queue_thread_sys *p_sys = p_qthread->p_sys;
+ bool ret;
+
+ vlc_mutex_lock( &p_sys->mutex );
+ ret = p_sys->state == STATE_ERROR;
+ vlc_mutex_unlock( &p_sys->mutex );
+
+ return ret;
+}
+
+void QueueThread_Flush( queue_thread *p_qthread )
+{
+ QueueThread_SetStateWait( p_qthread, STATE_FLUSHING,
+ STATE_PAUSED );
+}
+
+void QueueThread_Wake( queue_thread *p_qthread )
+{
+ queue_thread_sys *p_sys = p_qthread->p_sys;
+
+ vlc_mutex_lock( &p_sys->mutex );
+ vlc_cond_signal( &p_sys->cond );
+ vlc_mutex_unlock( &p_sys->mutex );
+}
diff --git a/modules/codec/omxil/queue_thread.h b/modules/codec/omxil/queue_thread.h
new file mode 100644
index 0000000..c108328
--- /dev/null
+++ b/modules/codec/omxil/queue_thread.h
@@ -0,0 +1,66 @@
+/*****************************************************************************
+ * queue_thread.c: queue input/output buffers in a separate thread
+ *****************************************************************************
+ * Copyright (C) 2014 Thomas Guillem
+ *
+ * Authors: Thomas Guillem <thomas at gllm.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_block.h>
+
+typedef struct queue_thread_sys queue_thread_sys;
+typedef struct queue_thread_owner_sys queue_thread_owner_sys;
+typedef struct queue_thread queue_thread;
+typedef struct queue_thread_elm queue_thread_elm;
+
+struct queue_thread
+{
+ VLC_COMMON_MEMBERS
+
+ queue_thread_sys *p_sys;
+ queue_thread_owner_sys *p_owner;
+
+ /* All callbacks are called from the queue thread.
+ * return -1 in case of error */
+
+ /* pf_run
+ * return 0 if queue thread should wait before calling pf_run again, and 1
+ * otherwise */
+ int ( * pf_run )( queue_thread *p_qthread, bool b_flushing );
+
+ /* pf_init */
+ int ( * pf_init )( queue_thread *p_qthread );
+
+ /* pf_destroy */
+ int ( * pf_destroy )( queue_thread *p_qthread );
+};
+
+queue_thread* QueueThread_New( vlc_object_t * );
+void QueueThread_Delete( queue_thread * );
+int QueueThread_Start( queue_thread * );
+int QueueThread_Pause( queue_thread * );
+void QueueThread_Flush( queue_thread * );
+void QueueThread_Wake( queue_thread * );
+bool QueueThread_GetErrorState( queue_thread * );
+
+int QueueThread_FifoPush( queue_thread *, queue_thread_elm * );
+queue_thread_elm *QueueThread_FifoPop( queue_thread * );
+queue_thread_elm *QueueThread_FifoPeek( queue_thread * );
--
2.1.1
More information about the vlc-devel
mailing list