[vlc-devel] [PATCH 4/4] mediacodec: add an output thread, remove polling

Thomas Guillem thomas at gllm.fr
Thu Dec 3 10:51:26 CET 2015


This commit improve MediaCodec performances and remove polling every 10 msecs
when DecodeCommon is waiting for an input or an output buffer.

One new thread is used for output: once an input buffer is queued, this thread
will wait indefinitely for a MediaCodec output buffer (this can be cancelled by
a flush).  This buffer will be queued to the video or audio output via
decoder_QueueVideo or decoder_QueueAudio.

This thread, and pf_decode call are locked by the same mutex. Only
mc->dequeue_in/mc->dequeue_out are not locked since these functions can block.

Fixes #15079
---
 modules/codec/omxil/mediacodec.c | 526 ++++++++++++++++++++++++---------------
 1 file changed, 329 insertions(+), 197 deletions(-)

diff --git a/modules/codec/omxil/mediacodec.c b/modules/codec/omxil/mediacodec.c
index 4507b65..0566f5d 100644
--- a/modules/codec/omxil/mediacodec.c
+++ b/modules/codec/omxil/mediacodec.c
@@ -83,7 +83,7 @@ struct decoder_sys_t
 {
     mc_api *api;
 
-    /* Codec Specific Data buffer: sent in PutInput after a start or a flush
+    /* Codec Specific Data buffer: sent in DecodeCommon after a start or a flush
      * with the BUFFER_FLAG_CODEC_CONFIG flag.*/
     block_t **pp_csd;
     size_t i_csd_count;
@@ -92,9 +92,6 @@ struct decoder_sys_t
     bool b_update_format;
     bool b_has_format;
 
-    bool decoded;
-    bool error_state;
-    bool b_new_block;
     int64_t i_preroll_end;
     int     i_quirks;
 
@@ -103,6 +100,17 @@ struct decoder_sys_t
     dec_on_flush_cb         pf_on_flush;
     dec_process_output_cb   pf_process_output;
 
+    vlc_mutex_t     lock;
+    vlc_cond_t      cond;
+    vlc_cond_t      dec_cond;
+    vlc_thread_t    out_thread;
+    bool            b_out_thread_running;
+    bool            b_flush_out;
+    bool            b_output_ready;
+    bool            b_mc_running;
+    bool            b_error;
+    bool            b_error_signaled; // TODO remove
+
     union
     {
         struct
@@ -145,6 +153,10 @@ static void Audio_OnFlush(decoder_t *);
 static int Audio_ProcessOutput(decoder_t *, mc_api_out *, picture_t **, block_t **);
 static block_t *DecodeAudio(decoder_t *, block_t **);
 
+static int DecodeFlush(decoder_t *);
+static void StopMediaCodec(decoder_t *);
+static void *OutThread(void *);
+
 static void InvalidateAllPictures(decoder_t *);
 static void RemoveInflightPictures(decoder_t *);
 
@@ -179,7 +191,6 @@ vlc_module_begin ()
         add_shortcut( "mediacodec_jni" )
 vlc_module_end ()
 
-
 static void CSDFree(decoder_t *p_dec)
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
@@ -194,7 +205,7 @@ static void CSDFree(decoder_t *p_dec)
     p_sys->i_csd_count = 0;
 }
 
-/* Create the p_sys->p_csd that will be sent via PutInput */
+/* Create the p_sys->p_csd that will be sent from DecodeCommon */
 static int CSDDup(decoder_t *p_dec, const struct csd *p_csd, size_t i_count)
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
@@ -468,6 +479,7 @@ static int OpenDecoder(vlc_object_t *p_this, pf_MediaCodecApi_init pf_init)
     decoder_sys_t *p_sys;
     mc_api *api;
     const char *mime = NULL;
+    bool b_late_opening = false;
 
     /* Video or Audio if "mediacodec-audio" bool is true */
     if (p_dec->fmt_in.i_cat != VIDEO_ES && (p_dec->fmt_in.i_cat != AUDIO_ES
@@ -557,9 +569,13 @@ static int OpenDecoder(vlc_object_t *p_this, pf_MediaCodecApi_init pf_init)
     p_dec->fmt_out.i_cat = p_dec->fmt_in.i_cat;
     p_dec->fmt_out.video = p_dec->fmt_in.video;
     p_dec->fmt_out.audio = p_dec->fmt_in.audio;
-    p_sys->b_new_block = true;
     p_sys->api->psz_mime = mime;
 
+    vlc_mutex_init(&p_sys->lock);
+    vlc_cond_init(&p_sys->cond);
+    vlc_cond_init(&p_sys->dec_cond);
+    vlc_cond_init(&p_sys->dec_cond);
+
     if (p_dec->fmt_in.i_cat == VIDEO_ES)
     {
         p_sys->pf_on_new_block = Video_OnNewBlock;
@@ -594,7 +610,7 @@ static int OpenDecoder(vlc_object_t *p_this, pf_MediaCodecApi_init pf_init)
         {
             msg_Warn(p_dec, "waiting for a valid video size for codec %4.4s",
                      (const char *)&p_dec->fmt_in.i_codec);
-            return VLC_SUCCESS;
+            b_late_opening = true;
         }
     }
     else
@@ -617,7 +633,7 @@ static int OpenDecoder(vlc_object_t *p_this, pf_MediaCodecApi_init pf_init)
          && !p_sys->u.audio.i_channels)
         {
             msg_Warn(p_dec, "waiting for valid channel count");
-            return VLC_SUCCESS;
+            b_late_opening = true;
         }
     }
     if ((p_sys->i_quirks & OMXCODEC_QUIRKS_NEED_CSD)
@@ -630,13 +646,31 @@ static int OpenDecoder(vlc_object_t *p_this, pf_MediaCodecApi_init pf_init)
             msg_Warn(p_dec, "late opening with MPEG4 not handled"); /* TODO */
             goto bailout;
         }
-        return VLC_SUCCESS;
+        b_late_opening = true;
     }
 
-    if (StartMediaCodec(p_dec) == VLC_SUCCESS)
-        return VLC_SUCCESS;
-    else
+    vlc_mutex_lock(&p_sys->lock);
+
+    if (!b_late_opening && StartMediaCodec(p_dec) != VLC_SUCCESS)
+    {
         msg_Err(p_dec, "StartMediaCodec failed");
+        vlc_mutex_unlock(&p_sys->lock);
+        goto bailout;
+    }
+
+    p_sys->b_out_thread_running = true;
+    if (vlc_clone(&p_sys->out_thread, OutThread, p_dec,
+                  VLC_THREAD_PRIORITY_LOW))
+    {
+        msg_Err(p_dec, "vlc_clone failed");
+        p_sys->b_out_thread_running = false;
+        vlc_mutex_unlock(&p_sys->lock);
+        goto bailout;
+    }
+    vlc_mutex_unlock(&p_sys->lock);
+
+    return VLC_SUCCESS;
+
 bailout:
     CloseDecoder(p_this);
     return VLC_EGENERIC;
@@ -662,6 +696,21 @@ static void CloseDecoder(vlc_object_t *p_this)
 
     if (!p_sys)
         return;
+    vlc_mutex_lock(&p_sys->lock);
+    if (p_sys->b_out_thread_running)
+    {
+        p_sys->b_out_thread_running = false;
+        DecodeFlush(p_dec);
+        vlc_cond_broadcast(&p_sys->cond);
+        vlc_mutex_unlock(&p_sys->lock);
+        vlc_join(p_sys->out_thread, NULL);
+    }
+    else
+        vlc_mutex_unlock(&p_sys->lock);
+
+    vlc_mutex_destroy(&p_sys->lock);
+    vlc_cond_destroy(&p_sys->cond);
+    vlc_cond_destroy(&p_sys->dec_cond);
 
     StopMediaCodec(p_dec);
 
@@ -731,8 +780,8 @@ static int Video_ProcessOutput(decoder_t *p_dec, mc_api_out *p_out,
                                picture_t **pp_out_pic, block_t **pp_out_block)
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-
-    assert(pp_out_pic && !pp_out_block);
+    (void) pp_out_block;
+    assert(pp_out_pic);
 
     if (p_out->type == MC_OUT_TYPE_BUF)
     {
@@ -880,8 +929,8 @@ static int Audio_ProcessOutput(decoder_t *p_dec, mc_api_out *p_out,
                                picture_t **pp_out_pic, block_t **pp_out_block)
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-
-    assert(!pp_out_pic && pp_out_block);
+    (void) pp_out_pic;
+    assert(pp_out_block);
 
     if (p_out->type == MC_OUT_TYPE_BUF)
     {
@@ -1011,227 +1060,316 @@ static void HEVCProcessBlock(decoder_t *p_dec, block_t *p_block,
 static int DecodeFlush(decoder_t *p_dec)
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
+    bool b_was_running = p_sys->b_mc_running;
 
-    if (p_sys->decoded || p_sys->i_csd_send > 0)
-    {
-        p_sys->pf_on_flush(p_dec);
+    p_sys->b_mc_running = false;
+    p_sys->b_flush_out = true;
+    p_sys->i_preroll_end = 0;
+    p_sys->b_output_ready = false;
+    /* Resend CODEC_CONFIG buffer after a flush */
+    p_sys->i_csd_send = 0;
+
+    p_sys->pf_on_flush(p_dec);
+
+    if (b_was_running && p_sys->api->flush(p_sys->api) != VLC_SUCCESS)
+        return VLC_EGENERIC;
+
+    vlc_cond_broadcast(&p_sys->cond);
+
+    while (!p_sys->b_error && p_sys->b_flush_out)
+        vlc_cond_wait(&p_sys->dec_cond, &p_sys->lock);
+
+    if (p_sys->b_error)
+        return VLC_EGENERIC;
 
-        p_sys->i_preroll_end = 0;
-        if (p_sys->api->flush(p_sys->api) != VLC_SUCCESS)
-            return VLC_EGENERIC;
-        /* resend CODEC_CONFIG buffer after a flush */
-        p_sys->i_csd_send = 0;
-    }
-    p_sys->decoded = false;
     return VLC_SUCCESS;
 }
 
-static int GetAndProcessOutput(decoder_t *p_dec, picture_t **pp_out_pic,
-                               block_t **pp_out_block, mtime_t i_timeout)
+static void *OutThread(void *data)
 {
+    decoder_t *p_dec = data;
     decoder_sys_t *p_sys = p_dec->p_sys;
-    struct mc_api_out out;
-    int i_index, i_ret;
-
-    i_index = p_sys->api->dequeue_out(p_sys->api, i_timeout);
-    if (i_index >= 0 || i_index == MC_API_INFO_OUTPUT_FORMAT_CHANGED
-     || i_index == MC_API_INFO_OUTPUT_BUFFERS_CHANGED)
-        i_ret = p_sys->api->get_out(p_sys->api, i_index, &out);
-    else if (i_index == MC_API_INFO_TRYAGAIN)
-        i_ret = 0;
-    else
-        i_ret = -1;
 
-    if (i_ret != 1)
-        return i_ret;
+    for (;;)
+    {
+        int i_index;
+
+        vlc_mutex_lock(&p_sys->lock);
+
+        /* Wait for output ready */
+        while (!p_sys->b_error && p_sys->b_out_thread_running
+            && !p_sys->b_flush_out && !p_sys->b_output_ready)
+            vlc_cond_wait(&p_sys->cond, &p_sys->lock);
+
+        if (p_sys->b_flush_out)
+        {
+            /* Acknowledge flushed state */
+            p_sys->b_flush_out = false;
+            vlc_cond_broadcast(&p_sys->dec_cond);
+            goto next;
+        }
+
+        /* Check if thread is not stopped */
+        if (!p_sys->b_out_thread_running || p_sys->b_error)
+            goto end;
+
+        vlc_mutex_unlock(&p_sys->lock);
+        /* Wait for an output buffer. This function returns when a new output
+         * is available or if output is flushed. */
+        i_index = p_sys->api->dequeue_out(p_sys->api, -1);
+        vlc_mutex_lock(&p_sys->lock);
+
+        /* Ignore dequeue_out errors caused by flush */
+        if (p_sys->b_flush_out)
+        {
+            /* If i_index >= 0, Release it. There is no way to know if i_index
+             * is owned by us, so don't check the error. */
+            if (i_index >= 0)
+                p_sys->api->release_out(p_sys->api, i_index, false);
+
+            /* Parse output format/buffers even when we are flushing */
+            if (i_index != MC_API_INFO_OUTPUT_FORMAT_CHANGED
+             && i_index != MC_API_INFO_OUTPUT_BUFFERS_CHANGED)
+                goto next;
+        }
+
+        if (i_index >= 0 || i_index == MC_API_INFO_OUTPUT_FORMAT_CHANGED
+         || i_index == MC_API_INFO_OUTPUT_BUFFERS_CHANGED)
+        {
+            struct mc_api_out out;
+            int i_ret = p_sys->api->get_out(p_sys->api, i_index, &out);
+
+            if (i_ret == 1)
+            {
+                picture_t *p_pic = NULL;
+                block_t *p_block = NULL;
+
+                if (p_sys->pf_process_output(p_dec, &out, &p_pic,
+                                             &p_block) == -1)
+                {
+                    msg_Err(p_dec, "pf_process_output failed");
+                    goto end;
+                }
+                if (p_pic)
+                    decoder_QueueVideo(p_dec, p_pic);
+                else if (p_block)
+                    decoder_QueueAudio(p_dec, p_block);
+            } else if (i_ret != 0)
+            {
+                msg_Err(p_dec, "get_out failed");
+                goto end;
+            }
+        }
+        else
+        {
+            msg_Err(p_dec, "dequeue_out failed");
+            goto end;
+        }
+next:
+        vlc_mutex_unlock(&p_sys->lock);
+        continue;
+end:
+        msg_Warn(p_dec, "OutThread stopped");
+        p_sys->b_error = true;
+        vlc_cond_signal(&p_sys->dec_cond);
+        vlc_mutex_unlock(&p_sys->lock);
+        break;
+    }
+
+    return NULL;
+}
 
-    return p_sys->pf_process_output(p_dec, &out, pp_out_pic,
-                                    pp_out_block);
+static block_t *GetNextBlock(decoder_sys_t *p_sys, block_t *p_block)
+{
+    if (p_sys->i_csd_send < p_sys->i_csd_count)
+        return p_sys->pp_csd[p_sys->i_csd_send++];
+    else
+        return p_block;
 }
 
 /**
  * DecodeCommon called from DecodeVideo or DecodeAudio.
- * It returns -1 in case of error, 0 otherwise. The output buffer is returned
- * in pp_out_pic for Video, and pp_out_block for Audio.
+ * It returns -1 in case of error, 0 otherwise.
  */
-static int DecodeCommon(decoder_t *p_dec, block_t **pp_block,
-                        picture_t **pp_out_pic, block_t **pp_out_block)
+static int DecodeCommon(decoder_t *p_dec, block_t **pp_block)
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    block_t *p_block = pp_block ? *pp_block : NULL;
-    unsigned int i_attempts = 0;
-    jlong timeout = 0;
-    int i_output_ret = 0;
-    int i_input_ret = 0;
-    bool b_abort = false;
-    bool b_error = false;
-    bool b_new_block = p_block ? p_sys->b_new_block : false;
-
-    if (p_sys->error_state)
-        goto endclean;
-
-    if (b_new_block)
-    {
-        int i_ret, i_flags = 0;
+    int i_flags = 0;
+    int i_ret;
+    bool b_dequeue_timeout = false;
+    block_t *p_block;
 
-        p_sys->b_new_block = false;
+    if (!pp_block || !*pp_block)
+        return 0;
 
-        if (p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED))
-        {
-            if (DecodeFlush(p_dec) != VLC_SUCCESS)
-                b_error = true;
-            goto endclean;
-        }
+    vlc_mutex_lock(&p_sys->lock);
+
+    if (p_sys->b_error)
+        goto end;
 
-        i_ret = p_sys->pf_on_new_block(p_dec, p_block, &i_flags);
-        if (i_ret != 1)
+    p_block = *pp_block;
+
+    /* Flush */
+    if (p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|
+                            BLOCK_FLAG_CORRUPTED))
+    {
+        if (DecodeFlush(p_dec) != VLC_SUCCESS)
         {
-            if (i_ret == -1)
-                b_error = true;
-            goto endclean;
+            msg_Err(p_dec, "DecodeFlush failed");
+            p_sys->b_error = true;
         }
-        if (i_flags & NEWBLOCK_FLAG_FLUSH)
+        goto end;
+    }
+
+    /* Parse input block */
+    if ((i_ret = p_sys->pf_on_new_block(p_dec, p_block, &i_flags)) == 1)
+    {
+        if (i_flags & (NEWBLOCK_FLAG_FLUSH|NEWBLOCK_FLAG_RESTART))
         {
+            msg_Warn(p_dec, "Flushing from DecodeCommon");
+
+            /* Flush before restart to unblock OutThread */
             if (DecodeFlush(p_dec) != VLC_SUCCESS)
             {
-                b_error = true;
-                goto endclean;
+                p_sys->b_error = true;
+                goto end;
             }
-        }
 
-        if (i_flags & NEWBLOCK_FLAG_RESTART)
-        {
-            StopMediaCodec(p_dec);
-            if (StartMediaCodec(p_dec) != VLC_SUCCESS)
+            if (i_flags & NEWBLOCK_FLAG_RESTART)
             {
-                b_error = true;
-                goto endclean;
+                msg_Warn(p_dec, "Restarting from DecodeCommon");
+                StopMediaCodec(p_dec);
+                if (StartMediaCodec(p_dec) != VLC_SUCCESS)
+                {
+                    msg_Err(p_dec, "StartMediaCodec failed");
+                    p_sys->b_error = true;
+                    goto end;
+                }
             }
         }
     }
+    else
+    {
+        if (i_ret != 0)
+        {
+            p_sys->b_error = true;
+            msg_Err(p_dec, "pf_on_new_block failed");
+        }
+        goto end;
+    }
+
+    /* Abort if MediaCodec is not yet started */
     if (!p_sys->api->b_started)
-        goto endclean;
+        goto end;
 
-    do
+    /* Queue CSD blocks and input blocks */
+    while ((p_block = GetNextBlock(p_sys, *pp_block)))
     {
-        if ((p_sys->i_csd_send < p_sys->i_csd_count || p_block)
-         && i_input_ret == 0)
+        int i_index;
+
+        vlc_mutex_unlock(&p_sys->lock);
+        /* Wait for an input buffer. This function returns when a new input
+         * buffer is available or after 1sec of timeout. */
+        i_index = p_sys->api->dequeue_in(p_sys->api,
+                                         p_sys->api->b_direct_rendering ?
+                                         INT64_C(1000000) : -1);
+        vlc_mutex_lock(&p_sys->lock);
+
+        if (p_sys->b_error)
+            goto end;
+
+        if (i_index >= 0)
         {
-            int i_index = p_sys->api->dequeue_in(p_sys->api, timeout);
+            bool b_config = p_block && (p_block->i_flags & BLOCK_FLAG_CSD);
+            mtime_t i_ts = 0;
+            p_sys->b_mc_running = true;
 
-            if (i_index >= 0)
+            if (!b_config)
             {
-                block_t *p_in_block;
-                mtime_t i_ts;
+                i_ts = p_block->i_pts;
+                if (!i_ts && p_block->i_dts)
+                    i_ts = p_block->i_dts;
+            }
 
-                if (p_sys->i_csd_send < p_sys->i_csd_count)
-                {
-                    p_in_block = p_sys->pp_csd[p_sys->i_csd_send];
-                    i_ts = 0;
-                }
-                else
-                {
-                    p_in_block = p_block;
-                    i_ts = p_block->i_pts;
-                    if (!i_ts && p_block->i_dts)
-                        i_ts = p_block->i_dts;
-                }
-                i_input_ret = p_sys->api->queue_in(p_sys->api, i_index,
-                                                   p_in_block->p_buffer,
-                                                   p_in_block->i_buffer, i_ts,
-                                                   p_in_block->i_flags & BLOCK_FLAG_CSD) == 0 ? 1 : -1;
-                if (i_input_ret == 1)
+            if (p_sys->api->queue_in(p_sys->api, i_index,
+                                     p_block->p_buffer, p_block->i_buffer, i_ts,
+                                     b_config) == 0)
+            {
+                if (!b_config)
                 {
-                    if (p_sys->i_csd_send < p_sys->i_csd_count)
-                    {
-                        p_sys->i_csd_send++;
-                        i_input_ret = 0;
-                    }
-                    else
-                    {
-                        p_sys->decoded = true;
-                        if (p_block->i_flags & BLOCK_FLAG_PREROLL )
-                            p_sys->i_preroll_end = i_ts;
-                    }
+                    if (p_block->i_flags & BLOCK_FLAG_PREROLL )
+                        p_sys->i_preroll_end = i_ts;
+
+                    /* One input buffer is queued, unblock OutThread that will
+                     * fetch output buffers */
+                    p_sys->b_output_ready = true;
+                    vlc_cond_broadcast(&p_sys->cond);
+
+                    assert(p_block == *pp_block),
+                    block_Release(p_block);
+                    *pp_block = NULL;
                 }
+                b_dequeue_timeout = false;
+            } else
+            {
+                msg_Err(p_dec, "queue_in failed");
+                p_sys->b_error = true;
+                goto end;
             }
-            else if (i_index == MC_API_INFO_TRYAGAIN)
-                i_input_ret = 0;
-            else
-                i_input_ret = -1;
-
-            /* No need to try output if no input buffer is decoded */
-            if (!p_sys->decoded)
-                continue;
         }
-
-        if (i_input_ret != -1 && p_sys->decoded && i_output_ret == 0)
+        else if (i_index == MC_API_INFO_TRYAGAIN)
         {
-            i_output_ret = GetAndProcessOutput(p_dec, pp_out_pic, pp_out_block,
-                                               timeout);
-
-            if (i_output_ret == 0 && i_input_ret == 0)
+            /* HACK: When direct rendering is enabled, there is a possible
+             * deadlock between the Decoder and the Vout. It happens when the
+             * Vout is paused and when the Decoder is flushing. In that case,
+             * the Vout won't release any output buffers, therefore MediaCodec
+             * won't dequeue any input buffers. To work around this issue,
+             * release all output buffers if DecodeCommon is waiting more than
+             * 1sec for a new input buffer. */
+            if (!b_dequeue_timeout)
             {
-                if (++i_attempts == 20)
-                {
-                    /* HACK: When direct rendering is enabled, there is a
-                     * possible deadlock between the Decoder and the Vout. It
-                     * happens when the Vout is paused and when the Decoder is
-                     * flushing. In that case, the Vout won't release any
-                     * output buffers, therefore MediaCodec won't dequeue any
-                     * input buffers. To work around this issue, release all
-                     * output buffers if DecodeCommon is waiting more than 400
-                     * msec for a new input buffer. */ 
-                    msg_Warn(p_dec, "Decoder stuck: invalidate all buffers");
-                    InvalidateAllPictures(p_dec);
-                }
-                if (!p_sys->b_has_format && ++i_attempts > 100)
-                {
-                    /* No output and no format, thereforce mediacodec didn't
-                     * produce any output or events yet. Don't wait
-                     * indefinitely and abort after 2seconds (100 * 2 * 10ms)
-                     * without any data.  Indeed, MediaCodec can fail without
-                     * throwing any exception or error returns... */
-                    msg_Err(p_dec, "No output/input for %lld us, abort",
-                                    i_attempts * timeout);
-                    b_error = true;
-                    break;
-                }
+                msg_Warn(p_dec, "Decoder stuck: invalidate all buffers");
+                InvalidateAllPictures(p_dec);
+                b_dequeue_timeout = true;
+                continue;
+            }
+            else
+            {
+                msg_Err(p_dec, "dequeue_in timeout: no input available for 2secs");
+                p_sys->b_error = true;
+                goto end;
             }
         }
-        timeout = 10 * 1000; // 10 ms
-        /* loop until either the input or the output are processed (i_input_ret
-         * or i_output_ret == 1 ) or caused an error (i_input_ret or
-         * i_output_ret == -1 )*/
-    } while (p_block && i_input_ret == 0 && i_output_ret == 0 && !b_abort);
-
-    if (i_input_ret == -1 || i_output_ret == -1)
-    {
-        msg_Err(p_dec, "%s failed",
-                i_input_ret == -1 ? "PutInput" : "GetOutput");
-        b_error = true;
+        else
+        {
+            msg_Err(p_dec, "dequeue_in failed");
+            p_sys->b_error = true;
+            goto end;
+        }
     }
 
-endclean:
-
-    /* If pf_decode returns NULL, we'll get a new p_block from the next
-     * pf_decode call. Therefore we need to release the current one even if we
-     * couldn't process it (it happens in case or error or if MediaCodec is
-     * still not opened). We also must release the current p_block if we were
-     * able to process it. */
-    if (p_block && (i_output_ret != 1 || i_input_ret != 0))
+end:
+    if (pp_block && *pp_block)
     {
-        block_Release(p_block);
+        block_Release(*pp_block);
         *pp_block = NULL;
-        p_sys->b_new_block = true;
     }
-    if (b_error && !p_sys->error_state) {
-        /* Signal the error to the Java. */
-        jni_EventHardwareAccelerationError();
-        p_sys->error_state = true;
+    if (p_sys->b_error)
+    {
+        if (!p_sys->b_error_signaled) {
+            /* Signal the error to the Java. */
+            jni_EventHardwareAccelerationError();
+            p_sys->b_error_signaled = true;
+            vlc_cond_broadcast(&p_sys->cond);
+        }
+        vlc_mutex_unlock(&p_sys->lock);
+        return -1;
+    }
+    else
+    {
+        vlc_mutex_unlock(&p_sys->lock);
+        return 0;
     }
-
-    return b_error ? -1 : 0;
 }
 
 static int Video_OnNewBlock(decoder_t *p_dec, block_t *p_block, int *p_flags)
@@ -1298,11 +1436,8 @@ static void Video_OnFlush(decoder_t *p_dec)
 
 static picture_t *DecodeVideo(decoder_t *p_dec, block_t **pp_block)
 {
-    picture_t *p_out = NULL;
-
-    if (DecodeCommon(p_dec, pp_block, &p_out, NULL))
-        return NULL;
-    return p_out;
+    DecodeCommon(p_dec, pp_block);
+    return NULL;
 }
 
 static int Audio_OnNewBlock(decoder_t *p_dec, block_t *p_block, int *p_flags)
@@ -1346,9 +1481,6 @@ static void Audio_OnFlush(decoder_t *p_dec)
 
 static block_t *DecodeAudio(decoder_t *p_dec, block_t **pp_block)
 {
-    block_t *p_out = NULL;
-
-    if (DecodeCommon(p_dec, pp_block, NULL, &p_out))
-        return NULL;
-    return p_out;
+    DecodeCommon(p_dec, pp_block);
+    return NULL;
 }
-- 
2.1.4



More information about the vlc-devel mailing list