Commit 548c7012 authored by Pierre-Eric Pelloux-Prayer's avatar Pierre-Eric Pelloux-Prayer
Browse files

android: add a new video display filter, using OpenGL rendering

To be used, a GLSurfaceView must be setup in app layout
parent e532d550
......@@ -39,7 +39,7 @@ MEDIASTREAMER2_INCLUDES := \
## $(LOCAL_PATH)/../../../externals/openmax-dl/api \
## $(LOCAL_PATH)/../../../externals/openmax-dl/ip/api
## $(LOCAL_PATH)/../../../externals/openmax-dl/ip/api
LOCAL_MODULE := libmediastreamer2
......@@ -76,12 +76,15 @@ LOCAL_SRC_FILES = \
tonedetector.c \
audiostream.c \
qualityindicator.c \
bitratecontrol.c
bitratecontrol.c \
shaders.c \
opengles_display.c \
android-opengl-display.c
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_SRC_FILES += msresample.c.neon
LOCAL_SRC_FILES += msresample.c.neon
else
LOCAL_SRC_FILES += msresample.c
LOCAL_SRC_FILES += msresample.c
endif
......@@ -153,7 +156,7 @@ LOCAL_CFLAGS += \
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_CFLAGS += -DUSE_HARDWARE_RATE=1
LOCAL_CFLAGS += -DUSE_HARDWARE_RATE=1
endif
......@@ -176,6 +179,3 @@ LOCAL_STATIC_LIBRARIES += cpufeatures
include $(BUILD_STATIC_LIBRARY)
$(call import-module,android/cpufeatures)
......@@ -71,7 +71,7 @@ static void android_display_uninit(MSFilter *f){
}
static void android_display_preprocess(MSFilter *f){
}
#define LANDSCAPE 0
......@@ -98,7 +98,7 @@ static void android_display_process(MSFilter *f){
AndroidDisplay *ad=(AndroidDisplay*)f->data;
MSPicture pic;
mblk_t *m;
ms_filter_lock(f);
if (ad->jbitmap!=0 && !ad->orientation_change_pending){
if ((m=ms_queue_peek_last(f->inputs[0]))!=NULL){
......@@ -119,7 +119,7 @@ static void android_display_process(MSFilter *f){
}
/*select_orientation(ad,wsize,vsize);*/
}
ms_layout_compute(wsize,vsize,vsize,-1,0,&vrect, NULL);
if (ad->sws==NULL){
......@@ -129,27 +129,27 @@ static void android_display_process(MSFilter *f){
ms_fatal("Could not obtain sws context !");
}
}
if (sym_AndroidBitmap_lockPixels(jenv,ad->jbitmap,&pixels)==0){
if (pixels!=NULL){
dest.planes[0]=(uint8_t*)pixels+(vrect.y*ad->bmpinfo.stride)+(vrect.x*2);
dest.strides[0]=ad->bmpinfo.stride;
ms_scaler_process(ad->sws,pic.planes,pic.strides,dest.planes,dest.strides);
}else ms_warning("Pixels==NULL in android bitmap !");
sym_AndroidBitmap_unlockPixels(jenv,ad->jbitmap);
}else{
ms_error("AndroidBitmap_lockPixels() failed !");
}
(*jenv)->CallVoidMethod(jenv,ad->android_video_window,ad->update_id);
}
}
}
ms_filter_unlock(f);
ms_queue_flush(f->inputs[0]);
ms_queue_flush(f->inputs[1]);
}
......@@ -160,11 +160,11 @@ static int android_display_set_window(MSFilter *f, void *arg){
int err;
JNIEnv *jenv=ms_get_jni_env();
jobject window=(jobject)id;
ms_filter_lock(f);
if (window!=NULL)
ad->jbitmap=(*jenv)->CallObjectMethod(jenv,window,ad->get_bitmap_id);
else
else
ad->jbitmap=NULL;
ad->android_video_window=window;
if (ad->jbitmap!=NULL){
......@@ -206,15 +206,9 @@ MSFilterDesc ms_android_display_desc={
.methods=methods
};
extern void libmsandroiddisplaybad_init(void);
#define USE_ANDROID_BITMAP 1
void libmsandroiddisplay_init(void){
bool_t libmsandroiddisplay_init(void){
/*See if we can use AndroidBitmap_* symbols (only since android 2.2 normally)*/
#if USE_ANDROID_BITMAP
void *handle=NULL;
handle=dlopen("libjnigraphics.so",RTLD_LAZY);
if (handle!=NULL){
......@@ -228,15 +222,10 @@ void libmsandroiddisplay_init(void){
}else{
ms_filter_register(&ms_android_display_desc);
ms_message("MSAndroidDisplay registered.");
return;
return TRUE;
}
}else{
ms_warning("libjnigraphics.so cannot be loaded.");
libmsandroiddisplaybad_init();
}
#else
libmsandroiddisplaybad_init();
#endif
return FALSE;
}
/*
mediastreamer2 android video display filter
Copyright (C) 2010 Belledonne Communications SARL (simon.morlat@linphone.org)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "mediastreamer2/msfilter.h"
#include "mediastreamer2/msvideo.h"
#include "mediastreamer2/msjava.h"
#include "layouts.h"
#include "opengles_display.h"
#include <android/bitmap.h>
#include <dlfcn.h>
typedef struct AndroidDisplay{
jobject android_video_window;
MSVideoSize vsize;
struct opengles_display* ogl;
jmethodID set_opengles_display_id;
jmethodID request_render_id;
}AndroidDisplay;
static void android_display_init(MSFilter *f){
AndroidDisplay *ad=(AndroidDisplay*)ms_new0(AndroidDisplay,1);
JNIEnv *jenv=NULL;
jclass wc;
jenv=ms_get_jni_env();
wc=(*jenv)->FindClass(jenv,"org/linphone/core/AndroidVideoWindowImpl");
if (wc==0){
ms_fatal("Could not find org.linphone.core.AndroidVideoWindowImpl class !");
}
ad->set_opengles_display_id=(*jenv)->GetMethodID(jenv,wc,"setOpenGLESDisplay","(I)V");
ad->request_render_id=(*jenv)->GetMethodID(jenv,wc,"requestRender","()V");
if (ad->set_opengles_display_id == 0)
ms_error("Could not find 'setOpenGLESDisplay' method\n");
if (ad->request_render_id == 0)
ms_error("Could not find 'requestRender' method\n");
ad->ogl = ogl_display_new();
f->data=ad;
}
static void android_display_uninit(MSFilter *f){
AndroidDisplay *ad=(AndroidDisplay*)f->data;
if (ad->ogl) {
// uninit must be called with gl context set (in SurfaceDestroyed callback)
ogl_display_free(ad->ogl);
}
ms_free(ad);
}
static void android_display_preprocess(MSFilter *f){
}
static void android_display_process(MSFilter *f){
AndroidDisplay *ad=(AndroidDisplay*)f->data;
MSPicture pic;
mblk_t *m;
ms_filter_lock(f);
if (ad->android_video_window){
if ((m=ms_queue_peek_last(f->inputs[0]))!=NULL){
if (ms_yuv_buf_init_from_mblk (&pic,m)==0){
/* schedule display of frame */
ogl_display_set_yuv_to_display(ad->ogl, m);
ms_queue_remove(f->inputs[0], m);
JNIEnv *jenv=ms_get_jni_env();
(*jenv)->CallVoidMethod(jenv,ad->android_video_window,ad->request_render_id);
}
}
}
ms_filter_unlock(f);
ms_queue_flush(f->inputs[0]);
ms_queue_flush(f->inputs[1]);
}
static int android_display_set_window(MSFilter *f, void *arg){
AndroidDisplay *ad=(AndroidDisplay*)f->data;
unsigned long id=*(unsigned long*)arg;
JNIEnv *jenv=ms_get_jni_env();
jobject window=(jobject)id;
ms_filter_lock(f);
ad->android_video_window=window;
if (ad->android_video_window) {
unsigned int ptr = (unsigned int)ad->ogl;
ms_message("Sending opengles_display pointer as long: %p -> %u\n", ad->ogl, ptr);
(*jenv)->CallVoidMethod(jenv,ad->android_video_window,ad->set_opengles_display_id, ptr);
} else {
/* surface if being destroyed, release GL resources */
ogl_display_uninit(ad->ogl);
}
ms_filter_unlock(f);
return 0;
}
static MSFilterMethod methods[]={
{ MS_VIDEO_DISPLAY_SET_NATIVE_WINDOW_ID , android_display_set_window },
{ 0, NULL}
};
MSFilterDesc ms_android_opengl_display_desc={
.id=MS_ANDROID_DISPLAY_ID,
.name="MSAndroidDisplay",
.text="OpenGL-ES2 video display filter for Android.",
.category=MS_FILTER_OTHER,
.ninputs=2, /*number of inputs*/
.noutputs=0, /*number of outputs*/
.init=android_display_init,
.preprocess=android_display_preprocess,
.process=android_display_process,
.uninit=android_display_uninit,
.methods=methods
};
void libmsandroidopengldisplay_init(void){
ms_filter_register(&ms_android_opengl_display_desc);
ms_message("MSAndroidDisplay (OpenGL ES2) registered.");
}
......@@ -29,14 +29,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# endif
#endif
extern void __register_ffmpeg_encoders_if_possible(void);
extern void ms_ffmpeg_check_init();
extern void libmsandroiddisplay_init(void);
#include "mediastreamer2/mscommon.h"
#include "mediastreamer2/msfilter.h"
extern void __register_ffmpeg_encoders_if_possible(void);
extern void ms_ffmpeg_check_init();
extern bool_t libmsandroiddisplay_init(void);
extern void libmsandroiddisplaybad_init(void);
extern void libmsandroidopengldisplay_init(void);
#include "alldescs.h"
#include "mediastreamer2/mssndcard.h"
......@@ -62,7 +62,7 @@ extern void libmsandroiddisplay_init(void);
#if defined(__APPLE__) && !defined(__GNUC__)
#import <Cocoa/Cocoa.h>
#include <Foundation/Foundation.h>
#include <Foundation/Foundation.h>
#endif
#ifdef ANDROID
......@@ -276,10 +276,10 @@ typedef void (*init_func_t)(void);
int ms_load_plugins(const char *dir){
int num=0;
#if defined(WIN32) && !defined(_WIN32_WCE)
WIN32_FIND_DATA FileData;
HANDLE hSearch;
char szDirPath[1024];
char szPluginFile[1024];
WIN32_FIND_DATA FileData;
HANDLE hSearch;
char szDirPath[1024];
char szPluginFile[1024];
BOOL fFinished = FALSE;
const char *tmp=getenv("DEBUG");
BOOL debug=(tmp!=NULL && atoi(tmp)==1);
......@@ -296,13 +296,13 @@ int ms_load_plugins(const char *dir){
}
snprintf(szDirPath, sizeof(szDirPath), "%s", dir);
while (!fFinished)
while (!fFinished)
{
/* load library */
HINSTANCE os_handle;
UINT em;
if (!debug) em = SetErrorMode (SEM_FAILCRITICALERRORS);
snprintf(szPluginFile, sizeof(szPluginFile), "%s\\%s", szDirPath, FileData.cFileName);
os_handle = LoadLibraryEx (szPluginFile, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
if (os_handle==NULL)
......@@ -312,10 +312,10 @@ int ms_load_plugins(const char *dir){
}
if (!debug) SetErrorMode (em);
if (os_handle==NULL)
ms_error("Fail to load plugin %s", szPluginFile);
ms_error("Fail to load plugin %s", szPluginFile);
else{
init_func_t initroutine;
char szPluginName[256];
char szPluginName[256];
char szMethodName[256];
char *minus;
snprintf(szPluginName, 256, "%s", FileData.cFileName);
......@@ -337,16 +337,16 @@ int ms_load_plugins(const char *dir){
}
}
if (!FindNextFile(hSearch, &FileData)) {
if (GetLastError() == ERROR_NO_MORE_FILES){
fFinished = TRUE;
}
else
{
ms_error("couldn't find next plugin dll.");
fFinished = TRUE;
}
if (GetLastError() == ERROR_NO_MORE_FILES){
fFinished = TRUE;
}
else
{
ms_error("couldn't find next plugin dll.");
fFinished = TRUE;
}
}
}
}
/* Close the search handle. */
FindClose(hSearch);
......@@ -354,7 +354,7 @@ int ms_load_plugins(const char *dir){
DIR *ds;
struct dirent *de;
char *fullpath;
ds=opendir(dir);
ds=opendir(dir);
if (ds==NULL){
ms_message("Cannot open directory %s: %s",dir,strerror(errno));
return -1;
......@@ -365,7 +365,7 @@ int ms_load_plugins(const char *dir){
void *handle;
fullpath=ms_strdup_printf("%s/%s",dir,de->d_name);
ms_message("Loading plugin %s...",fullpath);
if ( (handle=dlopen(fullpath,RTLD_NOW))==NULL){
ms_warning("Fail to load plugin %s : %s",fullpath,dlerror());
}else {
......@@ -416,7 +416,7 @@ int ms_load_plugins(const char *dir){
void ms_unload_plugins(){
#if defined(WIN32) && !defined(_WIN32_WCE)
MSList *elem;
for(elem=ms_plugins_loaded_list;elem!=NULL;elem=elem->next)
{
HINSTANCE handle=(HINSTANCE )elem->data;
......@@ -553,7 +553,7 @@ static MSWebCamDesc * ms_web_cam_descs[]={
#if defined(WIN32) && defined(HAVE_VFW)
&ms_vfw_cam_desc,
#endif
#if defined(__MINGW32__) || defined (HAVE_DIRECTSHOW)
#if defined(__MINGW32__) || defined (HAVE_DIRECTSHOW)
&ms_dshow_cam_desc,
#endif
#ifdef __APPLE__
......@@ -636,7 +636,13 @@ void ms_init(){
#endif
#if defined(ANDROID) && defined (VIDEO_ENABLED)
libmsandroiddisplay_init();
if (1) {
libmsandroidopengldisplay_init();
} else {
if (!libmsandroiddisplay_init()) {
libmsandroiddisplaybad_init();
}
}
#endif
ms_message("ms_init() done");
}
......@@ -728,7 +734,7 @@ void ms_get_cur_time(MSTimeSpec *ret){
ret->tv_nsec=tv.tv_usec*1000LL;
#elif defined(__MACH__)
struct timeb time_val;
ftime (&time_val);
ret->tv_sec = time_val.time;
ret->tv_nsec = time_val.millitm * 1000000LL;
......@@ -741,5 +747,3 @@ void ms_get_cur_time(MSTimeSpec *ret){
ret->tv_nsec=ts.tv_nsec;
#endif
}
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