Commit d75a07a2 authored by Felix Abecassis's avatar Felix Abecassis Committed by Jean-Baptiste Kempf

mediacodec: implementation of MediaCodec GPU direct rendering

Based on the work by Martin Storsjö.

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.

In order to avoid a deadlock when exiting the decoder, a maximum number of polling
attempts was added in order to avoid blocking the decoder indefinitely if the vout
is not releasing output buffers anymore.
Signed-off-by: default avatarJean-Baptiste Kempf <jb@videolan.org>
parent 31bf4b4d
......@@ -55,6 +55,7 @@ Video Output:
* New CoreGraphics video output module for NPAPI plugins
* New OpenGL ES 2.0 through EGL video output module for Android
* New Android native window provider module
* Direct rendering for MediaCodec Android hardware acceleration
Video Filter:
* New Oldmovie effect filter
......
......@@ -3234,6 +3234,8 @@ if test "${enable_android_surface}" = "yes"; then
if test "${HAVE_ANDROID}" = "1"; then
VLC_ADD_PLUGIN([android_surface])
VLC_ADD_LIBS([android_surface], [-ldl])
VLC_ADD_PLUGIN([android_opaque])
VLC_ADD_LIBS([android_opaque], [-ldl])
fi
fi
......
......@@ -30,6 +30,7 @@ $Id$
* anaglyph: anaglyph 3d video filter
* android_audiotrack: audio output for Android, based on AudioTrack
* android_native_window: Android native window provider module
* android_opaque: Android direct GPU rendering video output
* android_surface: video output for Android, based on Surface
* antiflicker: anti-flicker video filter
* araw: Pseudo audio decoder for raw PCM
......
......@@ -342,7 +342,8 @@ libiomx_plugin_la_CPPFLAGS = $(libomxil_plugin_la_CPPFLAGS) -DUSE_IOMX
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 video_chroma/copy.c
libmediacodec_plugin_la_SOURCES = codec/omxil/android_mediacodec.c codec/omxil/utils.c \
video_chroma/copy.c codec/omxil/android_opaque.c codec/omxil/android_opaque.h
codec_LTLIBRARIES += $(LTLIBomxil) $(LTLIBomxil_vout)
EXTRA_LTLIBRARIES += libomxil_plugin.la libomxil_vout_plugin.la
......
This diff is collapsed.
/*****************************************************************************
* android_opaque.c: shared structures between MediaCodec decoder
* and MediaCodec video output
*****************************************************************************
* Copyright (C) 2013 Felix Abecassis
*
* Authors: Felix Abecassis <felix.abecassis@gmail.com>
*
* 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.
*****************************************************************************/
#include "android_opaque.h"
vlc_mutex_t* get_android_opaque_mutex()
{
static vlc_mutex_t s_mutex = VLC_STATIC_MUTEX;
return &s_mutex;
}
/*****************************************************************************
* android_opaque.h: shared structures between MediaCodec decoder
* and MediaCodec video output
*****************************************************************************
* Copyright (C) 2013 Felix Abecassis
*
* Authors: Felix Abecassis <felix.abecassis@gmail.com>
*
* 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.
*****************************************************************************/
#ifndef ANDROID_OPAQUE_H_
#define ANDROID_OPAQUE_H_
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
struct picture_sys_t
{
void (*pf_display_callback)(picture_sys_t*);
void (*pf_unlock_callback)(picture_sys_t*);
decoder_t *p_dec;
uint32_t i_index;
int b_valid;
};
vlc_mutex_t* get_android_opaque_mutex(void);
#endif
......@@ -13,6 +13,7 @@ SOURCES_vout_macosx = macosx.m opengl.h opengl.c
SOURCES_vout_coregraphicslayer = coregraphicslayer.m
SOURCES_vout_ios2 = ios2.m opengl.h opengl.c
SOURCES_android_surface = android/surface.c android/utils.c
SOURCES_android_opaque = android/opaque.c
if HAVE_DECKLINK
libdecklinkoutput_plugin_la_SOURCES = decklink.cpp
......
/*****************************************************************************
* opaque.c: Android video output module using direct rendering with
* opaque buffers
*****************************************************************************
* Copyright (C) 2013 Felix Abecassis
*
* Authors: Felix Abecassis <felix.abecassis@gmail.com>
*
* 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_plugin.h>
#include <vlc_vout_display.h>
#include <vlc_picture_pool.h>
#include "../codec/omxil/android_opaque.h"
static int Open (vlc_object_t *);
static void Close(vlc_object_t *);
vlc_module_begin()
set_category(CAT_VIDEO)
set_subcategory(SUBCAT_VIDEO_VOUT)
set_shortname("vout_mediacodec")
set_description(N_("Android MediaCodec direct rendering video output"))
set_capability("vout display", 200)
add_shortcut("androidsurface", "android")
set_callbacks(Open, Close)
vlc_module_end()
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static picture_pool_t *Pool (vout_display_t *, unsigned);
static void Display(vout_display_t *, picture_t *, subpicture_t *);
static int Control(vout_display_t *, int, va_list);
struct vout_display_sys_t
{
picture_pool_t *pool;
};
static int LockSurface(picture_t *);
static void UnlockSurface(picture_t *);
/* We need to allocate a picture pool of more than 30 buffers in order
* to be connected directly to the decoder without any intermediate
* buffer pool. */
#define POOL_SIZE 31
static int Open(vlc_object_t *p_this)
{
vout_display_t *vd = (vout_display_t*)p_this;
video_format_t fmt = vd->fmt;
if (fmt.i_chroma != VLC_CODEC_ANDROID_OPAQUE)
return VLC_EGENERIC;
/* Allocate structure */
vout_display_sys_t *sys = (struct vout_display_sys_t*)calloc(1, sizeof(*sys));
if (!sys)
return VLC_ENOMEM;
int i_pictures = POOL_SIZE;
picture_t** pictures = calloc(sizeof(*pictures), i_pictures);
if (!pictures)
goto error;
for (int i = 0; i < i_pictures; i++)
{
picture_sys_t *p_picsys = calloc(1, sizeof(*p_picsys));
if (unlikely(p_picsys == NULL))
goto error;
picture_resource_t resource = { .p_sys = p_picsys };
picture_t *picture = picture_NewFromResource(&fmt, &resource);
if (!picture)
{
free(p_picsys);
goto error;
}
pictures[i] = picture;
}
/* Wrap it into a picture pool */
picture_pool_configuration_t pool_cfg;
memset(&pool_cfg, 0, sizeof(pool_cfg));
pool_cfg.picture_count = i_pictures;
pool_cfg.picture = pictures;
pool_cfg.lock = LockSurface;
pool_cfg.unlock = UnlockSurface;
sys->pool = picture_pool_NewExtended(&pool_cfg);
if (!sys->pool)
{
for (int i = 0; i < i_pictures; i++)
picture_Release(pictures[i]);
goto error;
}
/* Setup vout_display */
vd->sys = sys;
vd->fmt = fmt;
vd->pool = Pool;
vd->display = Display;
vd->control = Control;
vd->prepare = NULL;
vd->manage = NULL;
/* Fix initial state */
vout_display_SendEventFullscreen(vd, false);
return VLC_SUCCESS;
error:
free(pictures);
Close(p_this);
return VLC_ENOMEM;
}
static void Close(vlc_object_t *p_this)
{
vout_display_t *vd = (vout_display_t *)p_this;
vout_display_sys_t *sys = vd->sys;
picture_pool_Delete(sys->pool);
free(sys);
}
static picture_pool_t *Pool(vout_display_t *vd, unsigned count)
{
VLC_UNUSED(count);
return vd->sys->pool;
}
static int LockSurface(picture_t *picture)
{
VLC_UNUSED(picture);
return VLC_SUCCESS;
}
static void UnlockSurface(picture_t *picture)
{
picture_sys_t *p_picsys = picture->p_sys;
void (*unlock_callback)(picture_sys_t*) = p_picsys->pf_unlock_callback;
if (unlock_callback)
unlock_callback(p_picsys);
}
static void Display(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
{
VLC_UNUSED(vd);
VLC_UNUSED(subpicture);
picture_sys_t *p_picsys = picture->p_sys;
void (*display_callback)(picture_sys_t*) = p_picsys->pf_display_callback;
if (display_callback)
display_callback(p_picsys);
/* refcount lowers to 0, and pool_cfg.unlock is called */
picture_Release(picture);
}
static int Control(vout_display_t *vd, int query, va_list args)
{
VLC_UNUSED(args);
switch (query) {
case VOUT_DISPLAY_HIDE_MOUSE:
return VLC_SUCCESS;
default:
msg_Err(vd, "Unknown request in vout mediacodec display");
case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
case VOUT_DISPLAY_CHANGE_FULLSCREEN:
case VOUT_DISPLAY_CHANGE_WINDOW_STATE:
case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED:
case VOUT_DISPLAY_CHANGE_ZOOM:
case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:
case VOUT_DISPLAY_GET_OPENGL:
return VLC_EGENERIC;
}
}
......@@ -202,6 +202,9 @@ static int Open(vlc_object_t *p_this)
/* Setup chroma */
video_format_t fmt = vd->fmt;
if (fmt.i_chroma == VLC_CODEC_ANDROID_OPAQUE)
return VLC_EGENERIC;
char *psz_fcc = var_InheritString(vd, CFG_PREFIX "chroma");
if( psz_fcc ) {
fmt.i_chroma = vlc_fourcc_GetCodecFromString(VIDEO_ES, psz_fcc);
......
......@@ -1136,8 +1136,9 @@ modules/video_filter/vhs.c
modules/video_filter/wave.c
modules/video_filter/yuvp.c
modules/video_output/aa.c
modules/video_output/android/surface.c
modules/video_output/android/nativewindow.c
modules/video_output/android/opaque.c
modules/video_output/android/surface.c
modules/video_output/caca.c
modules/video_output/coregraphicslayer.m
modules/video_output/decklink.cpp
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment