[vlc-devel] [PATCH 3/3] mediacodec: implementation of MediaCodec direct rendering based on the work by Martin Storsjö.

Martin Storsjö martin at martin.st
Fri Dec 13 22:39:24 CET 2013


On Mon, 18 Nov 2013, Felix Abecassis wrote:

> Somehow the new files were not added to the patch after rebasing.
> Resending.
>
> The decoder stores opaque buffers in the p_sys member of the picture
> and the vout uses a callback from the decoder to render these
> buffers. When the decoder flushes or closes, all the currently in
> flight pictures (filled by the decoder but not displayed yet) need to
> be invalidated. A mutex is required in order to prevent the vout from using
> destroyed MediaCodec buffers.
> ---
> modules/codec/Makefile.am                |   2 +-
> modules/codec/omxil/android_mediacodec.c | 222 +++++++++++++++++++++++++++----
> modules/codec/omxil/android_opaque.c     |  30 +++++
> modules/codec/omxil/android_opaque.h     |  44 ++++++
> modules/video_output/Modules.am          |   1 +
> modules/video_output/android/opaque.c    | 204 ++++++++++++++++++++++++++++
> modules/video_output/android/surface.c   |   3 +
> 7 files changed, 477 insertions(+), 29 deletions(-)
> create mode 100644 modules/codec/omxil/android_opaque.c
> create mode 100644 modules/codec/omxil/android_opaque.h
> create mode 100644 modules/video_output/android/opaque.c
>

> @@ -392,9 +440,79 @@ static void CloseDecoder(vlc_object_t *p_this)
>
>     free(p_sys->name);
>     ArchitectureSpecificCopyHooksDestroy(p_sys->pixel_format, &p_sys->architecture_specific_data);
> +    free(p_sys->inflight_picture);
>     free(p_sys);
> }
>
> +/*****************************************************************************
> + * 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;
> +
> +    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;
> +    }
> +
> +    uint32_t i_index = p_picsys->i_index;
> +    p_sys->inflight_picture[i_index] = NULL;
> +
> +    /* Release the MediaCodec buffer. */
> +    JNIEnv *env = NULL;
> +    (*myVm)->AttachCurrentThread(myVm, &env, NULL);
> +    (*env)->CallVoidMethod(env, p_sys->codec, p_sys->release_output_buffer, i_index, b_render);
> +    jthrowable exception = (*env)->ExceptionOccurred(env);
> +    if (exception != NULL) {
> +        jclass illegalStateException = (*env)->FindClass(env, "java/lang/IllegalStateException");
> +        if ((*env)->IsInstanceOf(env, exception, illegalStateException)) {
> +            msg_Err(p_dec, "Codec error (IllegalStateException) in MediaCodec.releaseOutputBuffer (ReleaseOutputBuffer)");
> +            (*env)->ExceptionClear(env);
> +            (*env)->DeleteLocalRef(env, illegalStateException);
> +        }

Why do you need to explicitly check for this particular exception class? 
This is the most likely exception to be thrown (most of the MediaCodec 
methods throw this when something unexpected happens). This is the only 
place where we handle exceptions where we actually check what class it is. 
If we don't do ExceptionClear, the JNI env will abort on the next JNI 
call. Not sure if that's better or worse than just ignoring the exception 
and hoping that it will sort itself out (at least exiting cleanly). The 
code would at least be shorter and simpler without the explicit check.



>             return;
>         } else if (index == INFO_OUTPUT_BUFFERS_CHANGED) {
>             msg_Dbg(p_dec, "output buffers changed");
>             (*env)->DeleteGlobalRef(env, p_sys->output_buffers);
> +
>             p_sys->output_buffers = (*env)->CallObjectMethod(env, p_sys->codec,
>                                                              p_sys->get_output_buffers);
>             p_sys->output_buffers = (*env)->NewGlobalRef(env, p_sys->output_buffers);
> +
> +            vlc_mutex_lock(get_android_opaque_mutex());
> +            free(p_sys->inflight_picture);
> +            p_sys->i_output_buffers = (*env)->GetArrayLength(env, p_sys->output_buffers);
> +            p_sys->inflight_picture = calloc(1, sizeof(picture_t*) * p_sys->i_output_buffers);
> +            vlc_mutex_unlock(get_android_opaque_mutex());
> +
>         } else if (index == INFO_OUTPUT_FORMAT_CHANGED) {
>
>             jobject format = (*env)->CallObjectMethod(env, p_sys->codec, p_sys->get_output_format);
> @@ -468,7 +623,13 @@ static void GetOutput(decoder_t *p_dec, JNIEnv *env, picture_t **pp_pic)
>             int crop_bottom     = GET_INTEGER(format, "crop-bottom");
>
>             const char *name = "unknown";
> -            GetVlcChromaFormat(p_sys->pixel_format, &p_dec->fmt_out.i_codec, &name);
> +            if (p_sys->direct_rendering)
> +            {
> +                jni_SetAndroidSurfaceSizeEnv(env, width, height, width, height, 1, 1);
> +            }
> +            else
> +                GetVlcChromaFormat(p_sys->pixel_format, &p_dec->fmt_out.i_codec, &name);
> +

nit: While VLC generally has favoured this indentation style, it's not the 
general norm all over the place. Most of this file places the braces on 
the same line as the if/else, so it would be more consistent with the rest 
of the file in that form.

> diff --git a/modules/codec/omxil/android_opaque.c b/modules/codec/omxil/android_opaque.c
> new file mode 100644
> index 0000000..7a06842
> --- /dev/null
> +++ b/modules/codec/omxil/android_opaque.c
> @@ -0,0 +1,30 @@
> +
> +#include "android_opaque.h"
> +
> +vlc_mutex_t* get_android_opaque_mutex()
> +{
> +    static vlc_mutex_t s_mutex = VLC_STATIC_MUTEX;
> +    return &s_mutex;
> +}

This is a little bit hackish - having one plugin define a public symbol 
that other plugins directly link against. Yes, it works on android right 
now when all the plugins are statically linked into one big blob, but it 
violates general VLC plugin designs. (No, I don't have other suggestions 
either.)


In general the patch looks ok once these details have been 
fixed/discussed/agreed upon, but the deadlock on shutdown that I saw would 
have to be fixed.

// Martin



More information about the vlc-devel mailing list