[vlc-devel] [PATCH] android: implement subtitles rendering for Android MediaCodec opaque direct rendering
Felix Abecassis
felix.abecassis at gmail.com
Wed Jan 22 11:46:17 CET 2014
A blending filter is used on the subtitles surface above the main one by wrapping the corresponding NativeWindow into a picture_t.
---
modules/video_output/android/opaque.c | 114 ++++++++++++++++++++++++++++++++++
1 file changed, 114 insertions(+)
diff --git a/modules/video_output/android/opaque.c b/modules/video_output/android/opaque.c
index 7334e02..371d65f 100644
--- a/modules/video_output/android/opaque.c
+++ b/modules/video_output/android/opaque.c
@@ -29,7 +29,12 @@
#include <vlc_plugin.h>
#include <vlc_vout_display.h>
#include <vlc_picture_pool.h>
+#include <vlc_filter.h>
+
+#include <dlfcn.h>
+
#include "../codec/omxil/android_opaque.h"
+#include "utils.h"
static int Open (vlc_object_t *);
static void Close(vlc_object_t *);
@@ -44,6 +49,16 @@ vlc_module_begin()
set_callbacks(Open, Close)
vlc_module_end()
+extern JavaVM *myVm;
+extern jobject jni_LockAndGetSubtitlesSurface();
+extern void jni_UnlockAndroidSurface();
+
+static const vlc_fourcc_t subpicture_chromas[] =
+{
+ VLC_CODEC_RGBA,
+ 0
+};
+
/*****************************************************************************
* Local prototypes
*****************************************************************************/
@@ -55,8 +70,65 @@ static int Control(vout_display_t *, int, va_list);
struct vout_display_sys_t
{
picture_pool_t *pool;
+
+ void *p_library;
+ native_window_api_t native_window;
+
+ jobject jsurf;
+ ANativeWindow *window;
+
+ video_format_t fmt;
+
+ filter_t *p_spu_blend;
+ picture_t *subtitles_picture;
+
+ bool b_has_subpictures;
};
+static void DisplaySubpicture(vout_display_t *vd, subpicture_t *subpicture)
+{
+ vout_display_sys_t *sys = vd->sys;
+
+ jobject jsurf = jni_LockAndGetSubtitlesSurface();
+ if (sys->window && jsurf != sys->jsurf)
+ {
+ sys->native_window.winRelease(sys->window);
+ sys->window = NULL;
+ }
+ sys->jsurf = jsurf;
+ if (!sys->window)
+ {
+ JNIEnv *p_env;
+ (*myVm)->AttachCurrentThread(myVm, &p_env, NULL);
+ sys->window = sys->native_window.winFromSurface(p_env, jsurf);
+ (*myVm)->DetachCurrentThread(myVm);
+ }
+
+ ANativeWindow_Buffer buf = { 0 };
+ sys->native_window.winLock(sys->window, &buf, NULL);
+
+ if (buf.width >= sys->fmt.i_width && buf.height >= sys->fmt.i_height)
+ {
+ /* Wrap the NativeWindow corresponding to the subtitles surface in a picture_t */
+ picture_t *picture = sys->subtitles_picture;
+ picture->p[0].p_pixels = (uint8_t*)buf.bits;
+ picture->p[0].i_lines = buf.height;
+ picture->p[0].i_pitch = picture->p[0].i_pixel_pitch * buf.stride;
+ /* Clear the subtitles surface. */
+ memset(picture->p[0].p_pixels, 0, picture->p[0].i_pitch * picture->p[0].i_lines);
+ if (subpicture)
+ {
+ /* Allocate a blending filter if needed. */
+ if (unlikely(!sys->p_spu_blend))
+ sys->p_spu_blend = filter_NewBlend(VLC_OBJECT(vd), &picture->format);
+ picture_BlendSubpicture(picture, sys->p_spu_blend, subpicture);
+ }
+ }
+
+ sys->native_window.unlockAndPost(sys->window);
+ jni_UnlockAndroidSurface();
+}
+
static int LockSurface(picture_t *);
static void UnlockSurface(picture_t *);
@@ -79,6 +151,22 @@ static int Open(vlc_object_t *p_this)
if (!sys)
return VLC_ENOMEM;
+ sys->p_library = LoadNativeWindowAPI(&sys->native_window);
+ if (!sys->p_library)
+ {
+ free(sys);
+ msg_Err(vd, "Could not initialize NativeWindow API.");
+ return VLC_EGENERIC;
+ }
+ sys->fmt = fmt;
+ video_format_t subpicture_format = sys->fmt;
+ subpicture_format.i_chroma = VLC_CODEC_RGBA;
+ /* Create a RGBA picture for rendering subtitles. */
+ sys->subtitles_picture = picture_NewFromFormat(&subpicture_format);
+
+ /* Export the subpicture capability of this vout. */
+ vd->info.subpicture_chromas = subpicture_chromas;
+
int i_pictures = POOL_SIZE;
picture_t** pictures = calloc(sizeof(*pictures), i_pictures);
if (!pictures)
@@ -141,6 +229,12 @@ static void Close(vlc_object_t *p_this)
vout_display_sys_t *sys = vd->sys;
picture_pool_Delete(sys->pool);
+ if (sys->window)
+ sys->native_window.winRelease(sys->window);
+ dlclose(sys->p_library);
+ picture_Release(sys->subtitles_picture);
+ if (sys->p_spu_blend)
+ filter_DeleteBlend(sys->p_spu_blend);
free(sys);
}
@@ -172,12 +266,32 @@ static void Display(vout_display_t *vd, picture_t *picture, subpicture_t *subpic
VLC_UNUSED(subpicture);
picture_sys_t *p_picsys = picture->p_sys;
+ vout_display_sys_t *sys = vd->sys;
void (*display_callback)(picture_sys_t*) = p_picsys->pf_display_callback;
if (display_callback)
display_callback(p_picsys);
+ if (subpicture)
+ sys->b_has_subpictures = true;
+ /* As long as no subpicture was received, do not call
+ DisplaySubpicture since JNI calls and clearing the subtitles
+ surface are expensive operations. */
+ if (sys->b_has_subpictures)
+ {
+ DisplaySubpicture(vd, subpicture);
+ if (!subpicture)
+ {
+ /* The surface has been cleared and there is no new
+ subpicture to upload, do not clear again until a new
+ subpicture is received. */
+ sys->b_has_subpictures = false;
+ }
+ }
+
/* refcount lowers to 0, and pool_cfg.unlock is called */
picture_Release(picture);
+ if (subpicture)
+ subpicture_Delete(subpicture);
}
static int Control(vout_display_t *vd, int query, va_list args)
--
1.8.3.2
More information about the vlc-devel
mailing list