[vlc-devel] [RFC PATCH 13/13] omxil: add android hw buffers support (zero copy)

Thomas Guillem guillem at archos.com
Thu Jun 26 14:06:01 CEST 2014


Activated if cfg "omxil-dr" is true. If extra android symbols are not found or
if HwBuffer_init() fails: fall back to non direct buffer mode
---
 modules/codec/omxil/omxil.c |  642 +++++++++++++++++++++++++++++++++++++++----
 modules/codec/omxil/omxil.h |   32 +++
 2 files changed, 614 insertions(+), 60 deletions(-)

diff --git a/modules/codec/omxil/omxil.c b/modules/codec/omxil/omxil.c
index f90ffc5..ac6e432 100644
--- a/modules/codec/omxil/omxil.c
+++ b/modules/codec/omxil/omxil.c
@@ -28,6 +28,9 @@
 # include "config.h"
 #endif
 
+#include <dlfcn.h>
+
+#include <jni.h>
 #include <limits.h>
 
 #include <vlc_common.h>
@@ -37,6 +40,7 @@
 #include <vlc_cpu.h>
 #include "../h264_nal.h"
 
+#include "android_opaque.h"
 #include "omxil.h"
 #include "omxil_core.h"
 #include "OMX_Broadcom.h"
@@ -55,6 +59,13 @@
 /* Defined in the broadcom version of OMX_Core.h */
 #define OMX_EventParamOrConfigChanged 0x7F000001
 
+/* JNI functions to get/set an Android Surface object. */
+extern JavaVM *myVm;
+extern jobject jni_LockAndGetAndroidJavaSurface();
+extern void jni_UnlockAndroidSurface();
+extern void jni_SetAndroidSurfaceSize(int width, int height, int visible_width, int visible_height, int sar_num, int sar_den);
+extern bool jni_IsVideoPlayerActivityCreated();
+
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
@@ -74,9 +85,23 @@ static OMX_ERRORTYPE OmxEmptyBufferDone( OMX_HANDLETYPE, OMX_PTR,
 static OMX_ERRORTYPE OmxFillBufferDone( OMX_HANDLETYPE, OMX_PTR,
                                         OMX_BUFFERHEADERTYPE * );
 
+static void *DequeueThread( void *data );
+static void InvalidateAllPictures(decoder_t *p_dec, OmxPort *p_port);
+static void HwBuffer_Init( decoder_t *p_dec, OmxPort *p_port );
+static void HwBuffer_Destroy( decoder_t *p_dec, OmxPort *p_port );
+static int  HwBuffer_AllocateBuffers( decoder_t *p_dec, OmxPort *p_port );
+static int  HwBuffer_FreeBuffers( decoder_t *p_dec, OmxPort *p_port );
+static void HwBuffer_ChangeState( decoder_t *p_dec, OmxPort *p_port,
+                                  int i_index, int i_state );
+
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
+#define DIRECTRENDERING_TEXT N_("OMX direct rendering")
+#define DIRECTRENDERING_LONGTEXT N_(\
+        "Enable OMX direct rendering using android native window buffers.")
+
+#define CFG_PREFIX "omxil-"
 vlc_module_begin ()
     set_description( N_("Audio/Video decoder (using OpenMAX IL)") )
     set_category( CAT_INPUT )
@@ -87,6 +112,8 @@ vlc_module_begin ()
      * enable it only via the --codec iomx command line parameter when
      * wanted. */
     set_capability( "decoder", 0 )
+    add_bool(CFG_PREFIX "dr", false,
+             DIRECTRENDERING_TEXT, DIRECTRENDERING_LONGTEXT, true)
 #else
     set_capability( "decoder", 80 )
 #endif
@@ -229,19 +256,38 @@ static OMX_ERRORTYPE SetPortDefinition(decoder_t *p_dec, OmxPort *p_port,
         }
         else
         {
-            if( !GetVlcChromaFormat( def->format.video.eColorFormat,
-                                     &p_fmt->i_codec, 0 ) )
+
+            if( p_port->p_hwbuf )
             {
-                omx_error = OMX_ErrorNotImplemented;
-                CHECK_ERROR(omx_error, "OMX color format %i not supported",
-                            (int)def->format.video.eColorFormat );
+                omx_error = pf_enable_graphic_buffers(p_port->omx_handle,
+                                                      p_port->i_port_index, OMX_TRUE);
+                CHECK_ERROR(omx_error, "can't enable graphic buffers");
+                omx_error =
+                    pf_get_graphic_buffer_usage(p_port->omx_handle,
+                                                p_port->i_port_index,
+                                                &p_port->p_hwbuf->i_hw_usage);
+                CHECK_ERROR(omx_error, "can't get graphic buffer usage");
+
+                omx_error = OMX_GetParameter(p_port->omx_handle,
+                                             OMX_IndexParamPortDefinition, def);
+                CHECK_ERROR(omx_error, "OMX_GetParameter failed (GraphicBuffers) (%x : %s)",
+                            omx_error, ErrorToString(omx_error));
+                p_fmt->i_codec = VLC_CODEC_ANDROID_OPAQUE;
+            } else {
+                if( !GetVlcChromaFormat( def->format.video.eColorFormat,
+                                         &p_fmt->i_codec, 0 ) )
+                {
+                    omx_error = OMX_ErrorNotImplemented;
+                    CHECK_ERROR(omx_error, "OMX color format %i not supported",
+                                (int)def->format.video.eColorFormat );
+                }
+                GetVlcChromaSizes( p_fmt->i_codec,
+                                   def->format.video.nFrameWidth,
+                                   def->format.video.nFrameHeight,
+                                   &p_port->i_frame_size, &p_port->i_frame_stride,
+                                   &p_port->i_frame_stride_chroma_div );
+                def->format.video.nStride = p_port->i_frame_stride;
             }
-            GetVlcChromaSizes( p_fmt->i_codec,
-                               def->format.video.nFrameWidth,
-                               def->format.video.nFrameHeight,
-                               &p_port->i_frame_size, &p_port->i_frame_stride,
-                               &p_port->i_frame_stride_chroma_div );
-            def->format.video.nStride = p_port->i_frame_stride;
             if (p_port->i_frame_size > def->nBufferSize)
                 def->nBufferSize = p_port->i_frame_size;
         }
@@ -314,7 +360,7 @@ static OMX_ERRORTYPE SetPortDefinition(decoder_t *p_dec, OmxPort *p_port,
         }
     }
     if (!strcmp(p_dec->p_sys->psz_component, "OMX.TI.DUCATI1.VIDEO.DECODER") &&
-                def->eDir == OMX_DirOutput)
+                def->eDir == OMX_DirOutput && !p_port->p_hwbuf)
     {
         /* When setting the output buffer size above, the decoder actually
          * sets the buffer size to a lower value than what was chosen. If
@@ -363,18 +409,29 @@ static OMX_ERRORTYPE AllocateBuffers(decoder_t *p_dec, OmxPort *p_port)
     decoder_sys_t *p_sys = p_dec->p_sys;
     OMX_ERRORTYPE omx_error = OMX_ErrorUndefined;
     OMX_PARAM_PORTDEFINITIONTYPE *def = &p_port->definition;
-    unsigned int i;
+    unsigned int i = 0;
 
 #ifdef OMXIL_EXTRA_DEBUG
     msg_Dbg( p_dec, "AllocateBuffers(%d)", def->eDir );
 #endif
 
-    p_port->i_buffers = p_port->definition.nBufferCountActual;
+    if( p_port->p_hwbuf )
+    {
+        if( HwBuffer_AllocateBuffers( p_dec, p_port ) != 0 )
+        {
+            omx_error = OMX_ErrorInsufficientResources;
+            goto error;
+        }
+        p_port->i_buffers = p_port->p_hwbuf->i_buffers;
+    }
+    else
+        p_port->i_buffers = p_port->definition.nBufferCountActual;
 
     p_port->pp_buffers = calloc(p_port->i_buffers, sizeof(OMX_BUFFERHEADERTYPE*));
     if( !p_port->pp_buffers )
     {
-        return OMX_ErrorInsufficientResources;
+        omx_error = OMX_ErrorInsufficientResources;
+        goto error;
     }
 
     for(i = 0; i < p_port->i_buffers; i++)
@@ -386,33 +443,53 @@ static OMX_ERRORTYPE AllocateBuffers(decoder_t *p_dec, OmxPort *p_port)
         p_port->pp_buffers[i] = (void *)ALIGN((uintptr_t)p_buf, p_port->definition.nBufferAlignment);
 #endif
 
-        if(p_port->b_direct)
+        if( p_port->p_hwbuf )
+        {
             omx_error =
                 OMX_UseBuffer( p_sys->omx_handle, &p_port->pp_buffers[i],
                                p_port->i_port_index, 0,
-                               p_port->definition.nBufferSize, (void*)1);
+                               def->nBufferSize, p_port->p_hwbuf->pp_handles[i] );
+            if( omx_error != OMX_ErrorNone ) break;
+#ifdef OMXIL_EXTRA_DEBUG
+            msg_Dbg( p_dec, "OMX_UseBuffer(%d) %p, %p", def->eDir,
+                     p_port->pp_buffers[i], p_port->p_hwbuf->pp_handles[i] );
+#endif
+            if( p_port->p_hwbuf->i_states[i] & BUF_STATE_OWNED )
+                OMX_FIFO_PUT( &p_port->p_hwbuf->fifo, p_port->pp_buffers[i] );
+        }
         else
-            omx_error =
-                OMX_AllocateBuffer( p_sys->omx_handle, &p_port->pp_buffers[i],
-                                    p_port->i_port_index, 0,
-                                    p_port->definition.nBufferSize);
-
-        if(omx_error != OMX_ErrorNone)
         {
-            p_port->i_buffers = i;
-            break;
+            if( p_port->b_direct )
+                omx_error =
+                    OMX_UseBuffer( p_sys->omx_handle, &p_port->pp_buffers[i],
+                                   p_port->i_port_index, 0,
+                                   p_port->definition.nBufferSize, (void*)1);
+            else
+                omx_error =
+                    OMX_AllocateBuffer( p_sys->omx_handle, &p_port->pp_buffers[i],
+                                        p_port->i_port_index, 0,
+                                        p_port->definition.nBufferSize);
+
+            if( omx_error != OMX_ErrorNone ) break;
+#ifdef OMXIL_EXTRA_DEBUG
+            msg_Dbg( p_dec, "OMX_AllocateBuffer(%d) %p, %p", def->eDir,
+                     p_port->pp_buffers[i], p_port->pp_buffers[i]->pBuffer );
+#endif
+            OMX_FIFO_PUT(&p_port->fifo, p_port->pp_buffers[i]);
         }
-        OMX_FIFO_PUT(&p_port->fifo, p_port->pp_buffers[i]);
     }
 
-    CHECK_ERROR(omx_error, "AllocateBuffers failed (%x, %i)",
-                omx_error, (int)p_port->i_port_index );
-
-
 #ifdef OMXIL_EXTRA_DEBUG
     msg_Dbg( p_dec, "AllocateBuffers(%d)::done", def->eDir );
 #endif
+
 error:
+    if( omx_error != OMX_ErrorNone )
+    {
+        p_port->i_buffers = i;
+        msg_Err( p_dec, "AllocateBuffer failed (%x : %s)",
+                 omx_error, ErrorToString(omx_error));
+    }
     return omx_error;
 }
 
@@ -459,10 +536,14 @@ static OMX_ERRORTYPE FreeBuffers(decoder_t *p_dec, OmxPort *p_port)
             if(omx_error != OMX_ErrorNone) break;
         }
     }
+
     if( omx_error != OMX_ErrorNone )
        msg_Err( p_dec, "OMX_FreeBuffer failed (%x, %i, %i)",
                 omx_error, (int)p_port->i_port_index, i );
 
+    if( p_port->p_hwbuf )
+        HwBuffer_FreeBuffers( p_dec, p_port );
+
     p_port->i_buffers = 0;
     free( p_port->pp_buffers );
     p_port->pp_buffers = NULL;
@@ -522,34 +603,37 @@ static OMX_ERRORTYPE GetPortDefinition(decoder_t *p_dec, OmxPort *p_port,
             omx_error = OMX_ErrorNone;
         }
 
-        /* Hack: Nexus One (stock firmware with binary OMX driver blob)
-         * claims to output 420Planar even though it in in practice is
-         * NV21. */
-        if(def->format.video.eColorFormat == OMX_COLOR_FormatYUV420Planar &&
-           !strncmp(p_sys->psz_component, "OMX.qcom.video.decoder",
-                    strlen("OMX.qcom.video.decoder")))
-            def->format.video.eColorFormat = OMX_QCOM_COLOR_FormatYVU420SemiPlanar;
-
-        if (IgnoreOmxDecoderPadding(p_sys->psz_component)) {
-            def->format.video.nSliceHeight = 0;
-            def->format.video.nStride = p_fmt->video.i_width;
-        }
-
-        if(!GetVlcVideoFormat( def->format.video.eCompressionFormat,
-                               &p_fmt->i_codec, 0 ) )
+        if( !p_port->p_hwbuf )
         {
-            if( !GetVlcChromaFormat( def->format.video.eColorFormat,
-                                     &p_fmt->i_codec, 0 ) )
+            /* Hack: Nexus One (stock firmware with binary OMX driver blob)
+             * claims to output 420Planar even though it in in practice is
+             * NV21. */
+            if(def->format.video.eColorFormat == OMX_COLOR_FormatYUV420Planar &&
+               !strncmp(p_sys->psz_component, "OMX.qcom.video.decoder",
+                        strlen("OMX.qcom.video.decoder")))
+                def->format.video.eColorFormat = OMX_QCOM_COLOR_FormatYVU420SemiPlanar;
+
+            if (IgnoreOmxDecoderPadding(p_sys->psz_component)) {
+                def->format.video.nSliceHeight = 0;
+                def->format.video.nStride = p_fmt->video.i_width;
+            }
+
+            if( !GetVlcVideoFormat( def->format.video.eCompressionFormat,
+                                   &p_fmt->i_codec, 0 ) )
             {
-                omx_error = OMX_ErrorNotImplemented;
-                CHECK_ERROR(omx_error, "OMX color format %i not supported",
-                            (int)def->format.video.eColorFormat );
+                if( !GetVlcChromaFormat( def->format.video.eColorFormat,
+                                         &p_fmt->i_codec, 0 ) )
+                {
+                    omx_error = OMX_ErrorNotImplemented;
+                    CHECK_ERROR(omx_error, "OMX color format %i not supported",
+                                (int)def->format.video.eColorFormat );
+                }
+                GetVlcChromaSizes( p_fmt->i_codec,
+                                   def->format.video.nFrameWidth,
+                                   def->format.video.nFrameHeight,
+                                   &p_port->i_frame_size, &p_port->i_frame_stride,
+                                   &p_port->i_frame_stride_chroma_div );
             }
-            GetVlcChromaSizes( p_fmt->i_codec,
-                               def->format.video.nFrameWidth,
-                               def->format.video.nFrameHeight,
-                               &p_port->i_frame_size, &p_port->i_frame_stride,
-                               &p_port->i_frame_stride_chroma_div );
         }
         if(p_port->i_frame_size > def->nBufferSize)
             def->nBufferSize = p_port->i_frame_size;
@@ -690,6 +774,7 @@ static OMX_ERRORTYPE DeinitialiseComponent(decoder_t *p_dec,
             }
             msg_Warn( p_dec, "Stray buffer left in fifo, %p", p_buffer );
         }
+        HwBuffer_Destroy( p_dec, p_port );
     }
     omx_error = pf_free_handle( omx_handle );
     return omx_error;
@@ -773,6 +858,7 @@ static OMX_ERRORTYPE InitialiseComponent(decoder_t *p_dec,
         p_port->i_port_index = definition.nPortIndex;
         p_port->definition = definition;
         p_port->omx_handle = omx_handle;
+        HwBuffer_Init( p_dec, p_port );
     }
 
     if(!p_sys->in.b_valid || !p_sys->out.b_valid)
@@ -959,7 +1045,7 @@ static int OpenGeneric( vlc_object_t *p_this, bool b_encode )
     p_sys->in.p_fmt = &p_dec->fmt_in;
     OMX_FIFO_INIT (&p_sys->out.fifo, pInputPortPrivate );
     OMX_BUFFER_COUNT_INIT( &p_sys->out.omx_count);
-    p_sys->out.b_direct = false;
+    p_sys->out.b_direct = jni_IsVideoPlayerActivityCreated() && var_InheritBool(p_dec, CFG_PREFIX "dr");
     p_sys->out.b_flushed = true;
     p_sys->out.p_fmt = &p_dec->fmt_out;
     p_sys->ports = 2;
@@ -1139,6 +1225,372 @@ static int OpenGeneric( vlc_object_t *p_this, bool b_encode )
     return VLC_EGENERIC;
 }
 
+static void HwBuffer_ChangeState( decoder_t *p_dec, OmxPort *p_port,
+                                  int i_index, int i_state )
+{
+    p_port->p_hwbuf->i_states[i_index] = i_state;
+    if( i_state == BUF_STATE_OWNED )
+        p_port->p_hwbuf->i_owned++;
+    else
+        p_port->p_hwbuf->i_owned--;
+
+#ifdef OMXIL_EXTRA_DEBUG
+    msg_Dbg( p_dec, "buffer[%d]: state -> %d, owned buffers: %u",
+             i_index, i_state, p_port->p_hwbuf->i_owned );
+#endif
+}
+
+static void HwBuffer_Init( decoder_t *p_dec, OmxPort *p_port )
+{
+    VLC_UNUSED( p_dec );
+
+    if( !p_port->b_direct )
+        return;
+
+    msg_Dbg( p_dec, "HwBuffer_Init");
+
+    p_port->p_hwbuf = calloc(1, sizeof(HwBuffer));
+    if( !p_port->p_hwbuf )
+    {
+        goto error;
+    }
+    OMX_FIFO_INIT (&p_port->p_hwbuf->fifo, pOutputPortPrivate );
+    vlc_cond_init (&p_port->p_hwbuf->wait);
+    p_port->p_hwbuf->p_library = LoadNativeWindowAPI(&p_port->p_hwbuf->native_window);
+    if( p_port->p_hwbuf->p_library )
+    {
+        void *surf = jni_LockAndGetAndroidJavaSurface();
+
+        if( surf ) {
+            JNIEnv *p_env;
+
+            (*myVm)->AttachCurrentThread(myVm, &p_env, NULL);
+            p_port->p_hwbuf->window = p_port->p_hwbuf->native_window.winFromSurface(p_env, surf);
+            (*myVm)->DetachCurrentThread(myVm);
+            pf_omx_hwbuffer_connect(p_port->p_hwbuf->window);
+        }
+        jni_UnlockAndroidSurface();
+    }
+    if( !(pf_enable_graphic_buffers && pf_get_graphic_buffer_usage &&
+          pf_omx_hwbuffer_connect && pf_omx_hwbuffer_disconnect &&
+          pf_omx_hwbuffer_setup && pf_omx_hwbuffer_setcrop &&
+          pf_omx_hwbuffer_dequeue && pf_omx_hwbuffer_queue &&
+          pf_omx_hwbuffer_cancel) ||
+        !((OMX_COMPONENTTYPE*)p_port->omx_handle)->UseBuffer ||
+        !p_port->p_hwbuf->window )
+    {
+        msg_Warn( p_dec, "direct output port enabled but can't found "
+                          "extra symbols, switch back to non direct" );
+        goto error;
+    }
+
+    msg_Dbg( p_dec, "direct output port enabled" );
+    return;
+error:
+    /* if HwBuffer_Init fails, we can fall back to non direct buffers */
+    HwBuffer_Destroy( p_dec, p_port );
+}
+
+static void HwBuffer_Destroy( decoder_t *p_dec, OmxPort *p_port )
+{
+    if( p_port->p_hwbuf )
+    {
+        if( p_port->p_hwbuf->p_library )
+        {
+            if( p_port->p_hwbuf->window )
+            {
+                HwBuffer_FreeBuffers( p_dec, p_port );
+                pf_omx_hwbuffer_disconnect(p_port->p_hwbuf->window);
+                p_port->p_hwbuf->native_window.winRelease( p_port->p_hwbuf->window );
+            }
+            dlclose( p_port->p_hwbuf->p_library );
+        }
+
+        vlc_cond_destroy( &p_port->p_hwbuf->wait );
+        OMX_FIFO_DESTROY( &p_port->p_hwbuf->fifo );
+        free( p_port->p_hwbuf );
+        p_port->p_hwbuf = NULL;
+    }
+    p_port->b_direct = false;
+}
+
+static int HwBuffer_AllocateBuffers( decoder_t *p_dec, OmxPort *p_port )
+{
+    OMX_PARAM_PORTDEFINITIONTYPE *def = &p_port->definition;
+    unsigned int min_undequeued = 0;
+    unsigned int num_frames = p_port->definition.nBufferCountActual;
+
+    if( !p_port->p_hwbuf )
+        return 0;
+
+    if( pf_omx_hwbuffer_setup(p_port->p_hwbuf->window,
+                          def->format.video.nFrameWidth,
+                          def->format.video.nFrameHeight,
+                          def->format.video.eColorFormat,
+                          (int) p_port->p_hwbuf->i_hw_usage,
+                          &num_frames, &min_undequeued) != 0 )
+    {
+        msg_Err( p_dec, "can't setup OMXHWBuffer" );
+        goto error;
+    }
+
+    if( num_frames != p_port->definition.nBufferCountActual )
+    {
+        OMX_ERRORTYPE omx_error;
+#ifdef OMXIL_EXTRA_DEBUG
+        msg_Dbg( p_dec, "AllocateBuffers: video out wants more frames: %lu vs %u",
+                 p_port->definition.nBufferCountActual, num_frames);
+#endif
+        p_port->definition.nBufferCountActual = num_frames;
+
+        omx_error = OMX_SetParameter(p_dec->p_sys->omx_handle, OMX_IndexParamPortDefinition,
+                         &p_port->definition);
+        CHECK_ERROR(omx_error, "OMX_SetParameter failed (%x : %s)",
+                omx_error, ErrorToString(omx_error));
+    }
+
+    jni_SetAndroidSurfaceSize(def->format.video.nFrameWidth,
+                              def->format.video.nFrameHeight,
+                              def->format.video.nFrameWidth,
+                              def->format.video.nFrameHeight,
+                              p_dec->fmt_out.video.i_sar_num,
+                              p_dec->fmt_out.video.i_sar_den);
+
+    p_port->p_hwbuf->i_buffers = p_port->definition.nBufferCountActual;
+    p_port->p_hwbuf->i_max_owned = p_port->p_hwbuf->i_buffers - min_undequeued;
+
+    p_port->p_hwbuf->pp_handles = calloc( p_port->p_hwbuf->i_buffers,
+                                          sizeof(void *) );
+    if( !p_port->p_hwbuf->pp_handles )
+        goto error;
+
+    p_port->p_hwbuf->i_states = calloc( p_port->p_hwbuf->i_buffers, sizeof(int) );
+    if( !p_port->p_hwbuf->i_states )
+        goto error;
+
+    p_port->p_hwbuf->inflight_picture = calloc( p_port->p_hwbuf->i_buffers,
+                                                sizeof(picture_t*) );
+    if( !p_port->p_hwbuf->inflight_picture )
+        goto error;
+
+    for(unsigned int i = 0; i < p_port->p_hwbuf->i_buffers; i++)
+    {
+        void *p_handle = NULL;
+
+        if( pf_omx_hwbuffer_dequeue(p_port->p_hwbuf->window, &p_handle) != 0)
+        {
+            msg_Err( p_dec, "OMXHWBuffer_dequeue Fail" );
+            goto error;
+        }
+        p_port->p_hwbuf->pp_handles[i] = p_handle;
+        if( i < p_port->p_hwbuf->i_max_owned )
+        {
+            HwBuffer_ChangeState( p_dec, p_port, i, BUF_STATE_OWNED );
+        }
+        else
+        {
+            msg_Dbg( p_dec, "canceling buffer(%d)", i );
+            pf_omx_hwbuffer_cancel( p_port->p_hwbuf->window, p_handle );
+        }
+    }
+
+    p_port->p_hwbuf->b_run = true;
+    if( vlc_clone( &p_port->p_hwbuf->dequeue_thread, DequeueThread, p_dec, VLC_THREAD_PRIORITY_LOW ) )
+        goto error;
+
+    return 0;
+
+error:
+
+    msg_Err( p_dec, "HwBuffer_AllocateBuffers(%d) failed", def->eDir );
+    return -1;
+}
+
+static int HwBuffer_FreeBuffers( decoder_t *p_dec, OmxPort *p_port )
+{
+    bool join;
+    OMX_BUFFERHEADERTYPE *p_buffer;
+
+    msg_Dbg( p_dec, "HwBuffer_FreeBuffers");
+
+    vlc_mutex_lock( get_android_opaque_mutex() );
+    InvalidateAllPictures( p_dec, p_port );
+
+    join = p_port->p_hwbuf->b_run;
+
+    p_port->p_hwbuf->b_run = false;
+
+    if( p_port->p_hwbuf->pp_handles )
+    {
+        for(unsigned int i = 0; i < p_port->p_hwbuf->i_buffers; i++)
+        {
+            void *p_handle = p_port->p_hwbuf->pp_handles[i];
+
+            if( p_handle && p_port->p_hwbuf->i_states[i] == BUF_STATE_OWNED )
+            {
+                pf_omx_hwbuffer_cancel(p_port->p_hwbuf->window, p_handle );
+                HwBuffer_ChangeState( p_dec, p_port, i, BUF_STATE_NOT_OWNED );
+            }
+        }
+    }
+    vlc_cond_signal( &p_port->p_hwbuf->wait );
+
+    vlc_mutex_unlock( get_android_opaque_mutex() );
+
+    if( join )
+        vlc_join( p_port->p_hwbuf->dequeue_thread, NULL );
+
+    /* empty the OMX_FIFO */
+    while (1) {
+        OMX_FIFO_PEEK(&p_port->p_hwbuf->fifo, p_buffer);
+        if (!p_buffer) break;
+
+        OMX_FIFO_GET(&p_port->p_hwbuf->fifo, p_buffer);
+    }
+
+    p_port->p_hwbuf->i_buffers = 0;
+
+    free( p_port->p_hwbuf->pp_handles );
+    p_port->p_hwbuf->pp_handles = NULL;
+
+    free( p_port->p_hwbuf->i_states );
+    p_port->p_hwbuf->i_states = NULL;
+
+    free( p_port->p_hwbuf->inflight_picture );
+    p_port->p_hwbuf->inflight_picture = NULL;
+
+    return 0;
+}
+
+static void *DequeueThread( void *data )
+{
+    decoder_t *p_dec = data;
+    decoder_sys_t *p_sys = p_dec->p_sys;;
+    OmxPort *p_port = &p_sys->out;
+    unsigned int i;
+    int i_index = -1;
+    void *p_handle = NULL;
+
+    msg_Dbg( p_dec, "DequeueThread running");
+    vlc_mutex_lock( get_android_opaque_mutex() );
+    while( p_port->p_hwbuf->b_run )
+    {
+        while( p_port->p_hwbuf->i_owned >= p_port->p_hwbuf->i_max_owned &&
+               p_port->p_hwbuf->b_run)
+            vlc_cond_wait( &p_port->p_hwbuf->wait, get_android_opaque_mutex() );
+
+        if( !p_port->p_hwbuf->b_run ) continue;
+
+        vlc_mutex_unlock( get_android_opaque_mutex() );
+
+        pf_omx_hwbuffer_dequeue(p_port->p_hwbuf->window, &p_handle);
+
+        vlc_mutex_lock( get_android_opaque_mutex() );
+
+        if( !p_port->p_hwbuf->b_run )
+        {
+            pf_omx_hwbuffer_cancel(p_port->p_hwbuf->window, p_handle);
+            continue;
+        }
+
+        for(i = 0; i < p_port->i_buffers; i++)
+        {
+            if( p_port->pp_buffers[i]->pBuffer == p_handle )
+            {
+                i_index = i;
+                break;
+            }
+        }
+        if( i_index == -1 )
+        {
+            msg_Err( p_dec, "pf_omx_hwbuffer_dequeue returned unknown handle" );
+            continue;
+        }
+
+        HwBuffer_ChangeState( p_dec, p_port, i_index, BUF_STATE_OWNED );
+
+        OMX_FIFO_PUT(&p_port->p_hwbuf->fifo, p_port->pp_buffers[i_index]);
+    }
+    vlc_mutex_unlock( get_android_opaque_mutex() );
+
+    msg_Dbg( p_dec, "DequeueThread stopped");
+    return NULL;
+}
+
+/*****************************************************************************
+ * vout callbacks
+ *****************************************************************************/
+static void DisplayBuffer(picture_sys_t* p_picsys, bool b_render)
+{
+    decoder_t *p_dec = p_picsys->p_dec;
+    decoder_sys_t *p_sys = p_dec->p_sys;
+    OmxPort *p_port = &p_sys->out;
+    void *p_handle;
+
+    if( !p_picsys->b_valid ) return;
+
+    vlc_mutex_lock( get_android_opaque_mutex() );
+
+    /* Picture might have been invalidated while waiting on the mutex. */
+    if (!p_picsys->b_valid) {
+        vlc_mutex_unlock( get_android_opaque_mutex() );
+        return;
+    }
+
+    p_handle = p_port->pp_buffers[p_picsys->i_index]->pBuffer;
+
+#ifdef OMXIL_EXTRA_DEBUG
+    msg_Dbg( p_dec, "DisplayBuffer: %s %p",
+             b_render ? "render" : "cancel", p_handle );
+#endif
+
+    if( !p_handle )
+    {
+        msg_Err( p_dec, "DisplayBuffer: buffer handle invalid" );
+        goto end;
+    }
+
+    if( b_render )
+        pf_omx_hwbuffer_queue(p_port->p_hwbuf->window, p_handle);
+    else
+        pf_omx_hwbuffer_cancel(p_port->p_hwbuf->window, p_handle);
+
+    HwBuffer_ChangeState( p_dec, p_port, p_picsys->i_index, BUF_STATE_NOT_OWNED );
+    vlc_cond_signal( &p_port->p_hwbuf->wait );
+
+    p_port->p_hwbuf->inflight_picture[p_picsys->i_index] = NULL;
+
+end:
+    p_picsys->b_valid = false;
+    p_picsys->i_index = -1;
+
+    vlc_mutex_unlock( get_android_opaque_mutex() );
+}
+
+static void UnlockCallback(picture_sys_t* p_picsys)
+{
+    DisplayBuffer(p_picsys, false);
+}
+
+static void DisplayCallback(picture_sys_t* p_picsys)
+{
+    DisplayBuffer(p_picsys, true);
+}
+
+static void InvalidateAllPictures(decoder_t *p_dec, OmxPort *p_port)
+{
+    VLC_UNUSED( p_dec );
+    if( p_port->p_hwbuf->inflight_picture ) {
+        for (unsigned int i = 0; i < p_port->i_buffers; ++i) {
+            picture_t *p_pic = p_port->p_hwbuf->inflight_picture[i];
+            if (p_pic) {
+                p_pic->p_sys->b_valid = false;
+                p_port->p_hwbuf->inflight_picture[i] = NULL;
+            }
+        }
+    }
+}
+
 /*****************************************************************************
  * PortReconfigure
  *****************************************************************************/
@@ -1148,10 +1600,14 @@ static OMX_ERRORTYPE PortReconfigure(decoder_t *p_dec, OmxPort *p_port)
     OMX_PARAM_PORTDEFINITIONTYPE definition;
     OMX_ERRORTYPE omx_error;
 
+#ifdef OMXIL_EXTRA_DEBUG
+    msg_Dbg( p_dec, "PortReconfigure(%d)",  p_port->definition.eDir );
+#endif
+
     /* Sanity checking */
     OMX_INIT_STRUCTURE(definition);
     definition.nPortIndex = p_port->i_port_index;
-    omx_error = OMX_GetParameter(p_dec->p_sys->omx_handle, OMX_IndexParamPortDefinition,
+    omx_error = OMX_GetParameter(p_sys->omx_handle, OMX_IndexParamPortDefinition,
                                  &definition);
     if(omx_error != OMX_ErrorNone || (p_dec->fmt_in.i_cat == VIDEO_ES &&
        (!definition.format.video.nFrameWidth ||
@@ -1188,7 +1644,7 @@ static OMX_ERRORTYPE PortReconfigure(decoder_t *p_dec, OmxPort *p_port)
          * change for current working configurations for video.
          */
         omx_error = OMX_SetParameter(p_dec->p_sys->omx_handle, OMX_IndexParamPortDefinition,
-                                     &definition);
+                                     &p_port->definition);
         CHECK_ERROR(omx_error, "OMX_SetParameter failed (%x : %s)",
                     omx_error, ErrorToString(omx_error));
     }
@@ -1209,6 +1665,10 @@ static OMX_ERRORTYPE PortReconfigure(decoder_t *p_dec, OmxPort *p_port)
     PrintOmx(p_dec, p_sys->omx_handle, p_dec->p_sys->out.i_port_index);
 
  error:
+
+#ifdef OMXIL_EXTRA_DEBUG
+    msg_Dbg( p_dec, "PortReconfigure(%d)::done",  p_port->definition.eDir );
+#endif
     return omx_error;
 }
 
@@ -1266,6 +1726,20 @@ static picture_t *DecodeVideo( decoder_t *p_dec, block_t **pp_block )
         p_dec->fmt_out.video.i_sar_den = p_dec->fmt_in.video.i_sar_den;
     }
 
+    /* send all buffers dequeued by DequeueThread to omx */
+    if( p_sys->out.p_hwbuf )
+    {
+        while (1) {
+            OMX_FIFO_PEEK(&p_sys->out.p_hwbuf->fifo, p_header);
+            if (!p_header) break;
+
+            OMX_FIFO_GET(&p_sys->out.p_hwbuf->fifo, p_header);
+            p_header->nFilledLen = 0;
+            OMX_BUFFER_COUNT_INC( &p_sys->out.omx_count );
+            OMX_FillThisBuffer(p_sys->omx_handle, p_header);
+        }
+    }
+
     /* Take care of decoded frames first */
     while(!p_pic)
     {
@@ -1276,7 +1750,54 @@ static picture_t *DecodeVideo( decoder_t *p_dec, block_t **pp_block )
         {
             omx_error = GetPortDefinition(p_dec, &p_sys->out, p_sys->out.p_fmt);
             p_sys->out.b_update_def = 0;
-            CHECK_ERROR(omx_error, "GetPortDefinition failed");
+        }
+
+        if( p_sys->out.p_hwbuf )
+        {
+            int i_index = -1;
+            picture_sys_t *p_picsys;
+            OmxPort *p_port = &p_sys->out;
+
+            if( !p_header->nFilledLen )
+            {
+                msg_Err( p_dec, "omx buffer should be filled at that point" );
+                goto error;
+            }
+
+            for(i = 0; i < p_port->i_buffers; i++)
+            {
+                if( p_port->pp_buffers[i] == p_header )
+                {
+                    i_index = i;
+                    break;
+                }
+            }
+            if( i_index == -1 )
+            {
+                msg_Err( p_dec, "output buffer not found" );
+                goto error;
+            }
+
+            p_pic = decoder_NewPicture( p_dec );
+            if(!p_pic)
+            {
+                msg_Err( p_dec, "decoder_NewPicture failed" );
+                goto error;
+            }
+            p_pic->date = FromOmxTicks( p_header->nTimeStamp );
+
+            p_picsys = p_pic->p_sys;
+            p_picsys->pf_display_callback = DisplayCallback;
+            p_picsys->pf_unlock_callback = UnlockCallback;
+            p_picsys->p_dec = p_dec;
+            p_picsys->i_index = i_index;
+            p_picsys->b_valid = true;
+
+            vlc_mutex_lock( get_android_opaque_mutex() );
+            p_sys->out.p_hwbuf->inflight_picture[i_index] = p_pic;
+            vlc_mutex_unlock( get_android_opaque_mutex() );
+            OMX_FIFO_GET(&p_sys->out.fifo, p_header);
+            continue;
         }
 
         if(p_header->nFilledLen)
@@ -1782,10 +2303,11 @@ static OMX_ERRORTYPE OmxFillBufferDone( OMX_HANDLETYPE omx_handle,
              (int)omx_header->nFilledLen, FromOmxTicks(omx_header->nTimeStamp) );
 #endif
 
-    if(omx_header->pOutputPortPrivate)
+    if( !p_sys->out.p_hwbuf && omx_header->pOutputPortPrivate )
     {
         omx_header->pBuffer = omx_header->pOutputPortPrivate;
     }
+
     OMX_FIFO_PUT(&p_sys->out.fifo, omx_header);
     OMX_BUFFER_COUNT_DEC( &p_sys->out.omx_count );
 
diff --git a/modules/codec/omxil/omxil.h b/modules/codec/omxil/omxil.h
index 2921e90..110c116 100644
--- a/modules/codec/omxil/omxil.h
+++ b/modules/codec/omxil/omxil.h
@@ -36,6 +36,14 @@
 #include "omxil_utils.h"
 #include "omxil_core.h"
 
+#include "../../video_output/android/utils.h"
+
+enum
+{
+    BUF_STATE_NOT_OWNED = 0,
+    BUF_STATE_OWNED,
+};
+
 /*****************************************************************************
  * decoder_sys_t : omxil decoder descriptor
  *****************************************************************************/
@@ -59,6 +67,28 @@ typedef struct OmxBufferCount
 
 } OmxBufferCount;
 
+typedef struct HwBuffer
+{
+    vlc_thread_t    dequeue_thread;
+    bool            b_run;
+    vlc_cond_t      wait;
+    picture_t**     inflight_picture; /**< stores the inflight picture for each output buffer or NULL */
+
+    unsigned int    i_buffers;
+    void            **pp_handles;
+    int             *i_states;
+    unsigned int    i_max_owned;
+    unsigned int    i_owned;
+
+    OmxFifo         fifo;
+
+    void            *p_library;
+    void            *window;
+    native_window_api_t native_window;
+    OMX_U32         i_hw_usage;
+
+} HwBuffer;
+
 typedef struct OmxPort
 {
     bool b_valid;
@@ -84,6 +114,8 @@ typedef struct OmxPort
     OMX_BOOL b_direct;
     OMX_BOOL b_flushed;
 
+    HwBuffer *p_hwbuf;
+
 } OmxPort;
 
 struct decoder_sys_t
-- 
1.7.10.4


-- 


This email and any files transmitted with it are confidential and are 
intended solely for the use of the individual or entity to which they are 
addressed. Access to this e-mail by anyone else is unauthorised. If you are 
not the intended recipient, any disclosure, copying, distribution or any 
action taken or omitted to be taken in reliance on it, is prohibited. 
E-mail messages are not necessarily secure. Archos does not accept 
responsibility for any changes made to this message after it was sent.



More information about the vlc-devel mailing list