[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