[vlc-devel] [PATCH] vout: Overlay for Parrot Asteroid devices

Rémi Denis-Courmont remi at remlab.net
Fri Jun 21 14:25:16 CEST 2013


	Hello,

I do not maintain this plugin but... I think that this exceed the code 
overhead ratio above which a new plugin should be created instead of large 
#ifdef's. Not counting the legal and plugin boilerplate, this patch almost 
doubles the lines count of androidsurface.c.

Also comments inline.

diff --git a/modules/video_output/androidsurface.c 
b/modules/video_output/androidsurface.c
index 6784ab9..a6485b9 100644
--- a/modules/video_output/androidsurface.c
+++ b/modules/video_output/androidsurface.c
@@ -6,6 +6,7 @@
  * Authors: Ming Hu <tewilove at gmail.com>
  *          Ludovic Fauvet <etix at l0cal.com>
  *          Sébastien Toque <xilasz at gmail.com>
+ *          Andrei Mandychev <andron.mobi at 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
@@ -43,6 +44,22 @@
 # define ANDROID_SYM_S_UNLOCK "_ZN7android7Surface13unlockAndPostEv"
 #endif
 
+#ifdef PARROT_MEDIA_OUT
+
+#define SCREEN_PRIMARY_LCD      0
+#define SCREEN_SECONDARY_LCD_   1

Why the trailing underscore?

+#define SCREEN_COMPOSITE_TV     2
+
+#define NUM_BUFFERS_TO_BE_QUEUED_FOR_OPTIMAL_PERFORMANCE 3
+
+#define ANDROID_SYM_OVR_DESTROY "_ZN7android7Overlay7destroyEv"
+#define ANDROID_SYM_OVR_DEQUEUE_BUF "_ZN7android7Overlay13dequeueBufferEPPv"
+#define ANDROID_SYM_OVR_QUEUE_BUF "_ZN7android7Overlay11queueBufferEPv"
+#define ANDROID_SYM_OVR_GET_BUF_ADDR "_ZN7android7Overlay16getBufferAddressEPv"
+#define ANDROID_SYM_OVR_GET_BUF_COUNT "_ZNK7android7Overlay14getBufferCountEv"
+
+#endif /* PARROT_MEDIA_OUT */
+
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
@@ -81,6 +98,45 @@ typedef void (*Surface_lock2)(void *, void *, void *);
 // _ZN7android7Surface13unlockAndPostEv
 typedef void (*Surface_unlockAndPost)(void *);
 
+#ifdef PARROT_MEDIA_OUT
+
+/* possible overlay formats */
+enum {
+    OVERLAY_FORMAT_RGBA_8888    = 1,
+    OVERLAY_FORMAT_RGB_565      = 4,
+    OVERLAY_FORMAT_BGRA_8888    = 5,
+    OVERLAY_FORMAT_YCbCr_422_SP = 0x10, // NV16
+    OVERLAY_FORMAT_YCbYCr_422_I = 0x14,
+    OVERLAY_FORMAT_YCbYCr_420_I = 0x15,
+    OVERLAY_FORMAT_CbYCrY_422_I = 0x16,
+    OVERLAY_FORMAT_CbYCrY_420_I = 0x17,
+    OVERLAY_FORMAT_YCbCr_420_SP = 0x21,
+    OVERLAY_FORMAT_YCbCr_420_SP_SEQ_TB = 0x24, //NV12 Interlaced (Sequential 
Top-Bottom)
+    OVERLAY_FORMAT_DEFAULT      = 99,    // The actual color format is 
determined by the overlay
+};
+
+typedef void ISurface;
+typedef void Overlay;

IMHO, if you want opaque types, you'd better use an incomplete struct. At 
least the compiler will perform basic type safety checks:

typedef struct ISurface ISurface;

+typedef int32_t status_t;
+
+typedef ISurface* (*getISurface)(void *);
+typedef Overlay* (*createOverlay)(void *, uint32_t, uint32_t, int32_t, 
int32_t);
+typedef void (*releaseOverlay)();
+typedef void (*setDisplay)(void *, int);
+
+// _ZN7android7Overlay7destroyEv
+typedef void (*Overlay_destroy)(void *);
+// ZN7android7Overlay13dequeueBufferEPPv
+typedef status_t (*Overlay_dequeueBuffer)(void *, int *);
+// ZN7android7Overlay11queueBufferEPv
+typedef status_t (*Overlay_queueBuffer)(void *, int);
+// ZN7android7Overlay16getBufferAddressEPv
+typedef void* (*Overlay_getBufferAddress)(void *, int);
+// ZNK7android7Overlay14getBufferCountEv
+typedef int32_t (*Overlay_getBufferCount)(void *);
+
+#endif /* PARROT_MEDIA_OUT */
+
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
@@ -113,6 +169,32 @@ struct vout_display_sys_t {
     /* density */
     int i_sar_num;
     int i_sar_den;
+
+#ifdef PARROT_MEDIA_OUT
+    // libsurfacehelper.so library and its methods.
+    void *p_libsurfacehelper;
+    getISurface getISurface;
+    createOverlay createOverlay;
+    releaseOverlay releaseOverlay;
+    setDisplay setDisplay;
+
+    // libui.so library and its overlay methods.
+    void *p_libui;
+    Overlay_destroy o_destroy;
+    Overlay_dequeueBuffer o_dequeueBuffer;
+    Overlay_queueBuffer o_queueBuffer;
+    Overlay_getBufferAddress o_getBufferAddress;
+    Overlay_getBufferCount o_getBufferCount;
+
+    // Android framework/base/include/ui/Overlay.h object
+    Overlay* overlay;
+
+    // Overlay's buffer information
+    int buffer_count;
+    int buffer_queued_count;
+    void** buffer_ptrs;
+    int buffer_idx;
+#endif /* PARROT_MEDIA_OUT */
 };
 
 struct picture_sys_t {
@@ -126,6 +208,90 @@ static void AndroidUnlockSurface(picture_t *);
 
 static vlc_mutex_t single_instance = VLC_STATIC_MUTEX;
 
+#ifdef PARROT_MEDIA_OUT
+
+typedef struct {
+    int fd;
+    unsigned int length;
+    uint32_t offset;
+    void *ptr;
+} mapping_data_t;
+
+static inline void *LoadSurfaceHelper(const char *psz_lib, vout_display_sys_t 
*sys) {
+    void *p_library = dlopen(psz_lib, RTLD_NOW);
+    if (!p_library)
+        return NULL;
+
+    sys->getISurface = (getISurface)(dlsym(p_library, "getISurface"));
+    sys->createOverlay = (createOverlay)(dlsym(p_library, "createOverlay"));
+    sys->releaseOverlay = (releaseOverlay)(dlsym(p_library, 
"releaseOverlay"));
+    sys->setDisplay = (setDisplay)(dlsym(p_library, "setDisplay"));
+
+    if (sys->getISurface && sys->createOverlay && sys->setDisplay)
+        return p_library;
+
+    dlclose(p_library);
+    return NULL;
+}
+
+static inline void *LoadOverlay(const char *psz_lib, vout_display_sys_t *sys)
+{
+    void *p_library = dlopen(psz_lib, RTLD_NOW);
+    if (!p_library)
+        return NULL;
+
+    sys->o_destroy = (Overlay_destroy)(dlsym(p_library, 
ANDROID_SYM_OVR_DESTROY));
+    sys->o_dequeueBuffer = (Overlay_dequeueBuffer)(dlsym(p_library, 
ANDROID_SYM_OVR_DEQUEUE_BUF));
+    sys->o_queueBuffer = (Overlay_queueBuffer)(dlsym(p_library, 
ANDROID_SYM_OVR_QUEUE_BUF));
+    sys->o_getBufferAddress = (Overlay_getBufferAddress)(dlsym(p_library, 
ANDROID_SYM_OVR_GET_BUF_ADDR));
+    sys->o_getBufferCount = (Overlay_getBufferCount)(dlsym(p_library, 
ANDROID_SYM_OVR_GET_BUF_COUNT));
+
+    if (sys->o_destroy && sys->o_dequeueBuffer && sys->o_queueBuffer &&
+            sys->o_getBufferAddress && sys->o_getBufferCount)
+        return p_library;
+
+    dlclose(p_library);
+    return NULL;
+}
+
+static int OpenOverlay(vout_display_t *vd, video_format_t *fmt) {
+
+    vout_display_sys_t *sys = vd->sys;
+
+    void* surf = jni_LockAndGetAndroidSurface();
+    if (unlikely(!surf)) {
+        msg_Err(vd, "surface is not set");
+        jni_UnlockAndroidSurface();

Why do you free something you presumably just failed to allocate?

+        return VLC_EGENERIC;
+    }
+    msg_Dbg(vd, "Creating overlay... w=%d, h=%d", fmt->i_width, fmt-
>i_height);
+    sys->overlay = sys->createOverlay(surf, fmt->i_width, fmt->i_height, 
OVERLAY_FORMAT_CbYCrY_422_I, 0);
+    if (!sys->overlay) {
+        msg_Err(vd, "Can't create overlay");
+        jni_UnlockAndroidSurface();
+        return VLC_EGENERIC;
+    }
+    sys->buffer_count = sys->o_getBufferCount(sys->overlay);
+    if (sys->buffer_count <= 0) {
+        msg_Err(vd, "There is no any overlay buffer");
+        jni_UnlockAndroidSurface();

Does this not leak the overlay?

+        return VLC_EGENERIC;
+    }
+    sys->buffer_idx = 0;
+    sys->buffer_queued_count = 0;
+    sys->buffer_ptrs = calloc(sys->buffer_count, sizeof(void*));

No need to memset(), so use malloc().

+    for (int i = 0; i < sys->buffer_count; i++) {
+        mapping_data_t* data = sys->o_getBufferAddress(sys->overlay, i);
+        sys->buffer_ptrs[i] = data->ptr;
+    }
+    sys->setDisplay(surf, SCREEN_PRIMARY_LCD);
+    jni_UnlockAndroidSurface();
+
+    return VLC_SUCCESS;
+}
+
+#endif /* PARROT_MEDIA_OUT */
+
 static inline void *LoadSurface(const char *psz_lib, vout_display_sys_t *sys)
 {
     void *p_library = dlopen(psz_lib, RTLD_NOW);
@@ -186,9 +352,28 @@ static int Open(vlc_object_t *p_this)
         return VLC_EGENERIC;
     }
 
+#ifdef PARROT_MEDIA_OUT
+    // Load libsurfacehelper.so to get ISurface and create/destroy Overlay.
+    sys->p_libsurfacehelper = 
LoadSurfaceHelper("/data/data/org.videolan.vlc/lib/libsurfacehelper.so", sys);
+    if (!sys->p_libsurfacehelper) {
+        msg_Err(vd, "libsurfacehelper.so library is not loaded");
+        return VLC_EGENERIC;
+    }
+
+    // Load libui.so to have an access to overlay methods.
+    sys->p_libui = LoadOverlay("libui.so", sys);
+    if (!sys->p_libui) {
+        msg_Err(vd, "libui.so library is not loaded");
+        return VLC_EGENERIC;
+    }
+#endif /* PARROT_MEDIA_OUT */
+
     /* Setup chroma */
     video_format_t fmt = vd->fmt;
 
+#ifdef PARROT_MEDIA_OUT
+    fmt.i_chroma = VLC_CODEC_UYVY;
+#else
     char *psz_fcc = var_InheritString(vd, CFG_PREFIX "chroma");
     if( psz_fcc ) {
         fmt.i_chroma = vlc_fourcc_GetCodecFromString(VIDEO_ES, psz_fcc);
@@ -220,6 +405,7 @@ static int Open(vlc_object_t *p_this)
             return VLC_EGENERIC;
     }
     video_format_FixRgb(&fmt);
+#endif /* PARROT_MEDIA_OUT */
 
     msg_Dbg(vd, "Pixel format %4.4s", (char*)&fmt.i_chroma);
 
@@ -268,6 +454,20 @@ static int Open(vlc_object_t *p_this)
     sys->i_sar_num = vd->source.i_sar_num;
     sys->i_sar_den = vd->source.i_sar_den;
 
+#ifdef PARROT_MEDIA_OUT
+    if (OpenOverlay(vd, &fmt) != VLC_SUCCESS) {
+        msg_Err(vd, "Could not open overlay");
+        picture_pool_Delete(sys->pool);
+        dlclose(sys->p_libsurfacehelper);
+        dlclose(sys->p_libui);
+        dlclose(sys->p_library);
+        free(sys);
+        vlc_mutex_unlock(&single_instance);
+        return VLC_EGENERIC;
+    }
+    jni_SetAndroidSurfaceSize(fmt.i_width, fmt.i_height, sys->i_sar_num, sys-
>i_sar_den);
+#endif /* PARROT_MEDIA_OUT */
+
     return VLC_SUCCESS;
 
 enomem:
@@ -284,6 +484,13 @@ static void Close(vlc_object_t *p_this)
     vout_display_sys_t *sys = vd->sys;
 
     picture_pool_Delete(sys->pool);
+#ifdef PARROT_MEDIA_OUT
+    sys->o_destroy(sys->overlay);
+    sys->releaseOverlay();
+    free(sys->buffer_ptrs);
+    dlclose(sys->p_libsurfacehelper);
+    dlclose(sys->p_libui);
+#endif /* PARROT_MEDIA_OUT */
     dlclose(sys->p_library);
     free(sys);
     vlc_mutex_unlock(&single_instance);
@@ -326,6 +533,13 @@ static void SetupPictureYV12( SurfaceInfo* p_surfaceInfo, 
picture_t *p_picture )
 
 static int  AndroidLockSurface(picture_t *picture)
 {
+#ifdef PARROT_MEDIA_OUT
+    vout_display_sys_t *sys = picture->p_sys->sys;
+
+    picture->p[0].p_pixels = sys->buffer_ptrs[sys->buffer_idx]; // Set a 
picture buffer
+    picture->p[0].i_lines = picture->p[0].i_visible_lines;
+    picture->p[0].i_pitch = picture->p[0].i_visible_pitch;
+#else
     picture_sys_t *picsys = picture->p_sys;
     vout_display_sys_t *sys = picsys->sys;
     SurfaceInfo *info;
@@ -367,17 +581,23 @@ static int  AndroidLockSurface(picture_t *picture)
     if (info->format == 0x32315659 /*ANDROID_IMAGE_FORMAT_YV12*/)
         SetupPictureYV12(info, picture);
 
+#endif /* PARROT_MEDIA_OUT */
+
     return VLC_SUCCESS;
 }
 
 static void AndroidUnlockSurface(picture_t *picture)
 {
+#ifdef PARROT_MEDIA_OUT
+    picture->p[0].p_pixels = NULL;
+#else
     picture_sys_t *picsys = picture->p_sys;
     vout_display_sys_t *sys = picsys->sys;
 
     if (likely(picsys->surf))
         sys->s_unlockAndPost(picsys->surf);
     jni_UnlockAndroidSurface();
+#endif /* PARROT_MEDIA_OUT */
 }
 
 static void Display(vout_display_t *vd, picture_t *picture, subpicture_t 
*subpicture)
@@ -385,6 +605,39 @@ static void Display(vout_display_t *vd, picture_t 
*picture, subpicture_t *subpic
     VLC_UNUSED(vd);
     VLC_UNUSED(subpicture);
 
+#ifdef PARROT_MEDIA_OUT
+    vout_display_sys_t *sys = vd->sys;
+
+    if (sys->buffer_count > 0 && sys->buffer_queued_count < sys->buffer_count) {
+        int nBuffers_queued_to_dss = vd->sys->o_queueBuffer(sys->overlay, sys-
>buffer_idx);
+        if (nBuffers_queued_to_dss < 0) {
+            msg_Err(vd, "Failed queue buffer#%d to overlay!", sys->buffer_idx);
+        } else {
+            sys->buffer_queued_count++;
+            if (nBuffers_queued_to_dss != sys->buffer_queued_count) {
+                msg_Warn(vd, "Found some buffers discarded by DSS upon STREAM 
OFF!");
+                sys->buffer_queued_count = 1; // discard previously queued 
buffers.
+            }
+            sys->buffer_idx++;
+            if (sys->buffer_idx == sys->buffer_count)
+                sys->buffer_idx = 0;
+        }
+    }
+
+    if (sys->buffer_queued_count >= 
NUM_BUFFERS_TO_BE_QUEUED_FOR_OPTIMAL_PERFORMANCE) {
+        int i;
+        status_t status = vd->sys->o_dequeueBuffer(sys->overlay, &i);
+        if (status == 0) {
+            sys->buffer_queued_count--;
+            //msg_Dbg(vd, "dequeue buffer[%d]", i);
+        } else {
+            msg_Err(vd, "no buffer to dequeue in overlay");
+        }
+    } else {
+        //msg_Dbg(vd, "skip dequeue buffer, there are not enough queued 
buffers");
+    }
+#endif /* PARROT_MEDIA_OUT */
+
     /* refcount lowers to 0, and pool_cfg.unlock is called */
 
     picture_Release(picture);
-- 
1.7.9.5



-- 
Rémi Denis-Courmont
http://www.remlab.net/



More information about the vlc-devel mailing list