Commit 11a2eced authored by jehan's avatar jehan

Merge branch 'master' of git://git.linphone.org/mediastreamer2

parents 91c60d1a ceb98cab
mediastreamer-2.7.0:
* add android video capture filter
* add android video display filters: one for 2.1 and one for 2.2+
* tune video encoder parameters for android
* new scaler/colorspace conversion abstraction, with native ARM-optimized implementation
* new X11+XvXshm display filter, deprecating SDL display filter.
mediastreamer-2.6.0: July 1st, 2010
* android sound capture optimisations
* optional "threaded" v4l2 capture
......
......@@ -124,7 +124,7 @@ AC_DEFUN([MS_CHECK_VIDEO],[
yes) enable_sdl=true ;;
no) enable_sdl=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --disable-sdl) ;;
esac],[enable_sdl=true])
esac],[enable_sdl=false])
sdl_found=no
if test "$enable_sdl" = "true"; then
......
......@@ -33,7 +33,11 @@ if test -d /opt/local/share/aclocal ; then
ACLOCAL_ARGS="-I /opt/local/share/aclocal"
fi
if test -d /usr/local/share/aclocal ; then
ACLOCAL_ARGS="-I /usr/local/share/aclocal"
ACLOCAL_ARGS="$ACLOCAL_ARGS -I /usr/local/share/aclocal"
fi
if test -d /share/aclocal ; then
ACLOCAL_ARGS="$ACLOCAL_ARGS -I /share/aclocal"
fi
echo "Generating build scripts in mediastreamer..."
......
......@@ -22,6 +22,24 @@
LOCAL_PATH:= $(call my-dir)/../../src
include $(CLEAR_VARS)
LOCAL_ARM_MODE := arm
MEDIASTREAMER2_INCLUDES := \
$(LOCAL_PATH)/../build/android \
$(LOCAL_PATH)/../include \
$(LOCAL_PATH)/../../oRTP \
$(LOCAL_PATH)/../../oRTP/include \
$(LOCAL_PATH)/../../../externals/speex/include \
$(LOCAL_PATH)/../../../externals/build/speex \
$(LOCAL_PATH)/../../../externals/gsm/inc \
$(LOCAL_PATH)/../../../externals/ffmpeg \
$(LOCAL_PATH)/../../../externals/ \
$(LOCAL_PATH)/../../../externals/build/ffmpeg
## $(LOCAL_PATH)/../../../externals/openmax-dl/api \
## $(LOCAL_PATH)/../../../externals/openmax-dl/ip/api
LOCAL_MODULE := libmediastreamer2
......@@ -53,7 +71,8 @@ LOCAL_SRC_FILES = \
kiss_fftr.c \
void.c \
msandroid.cpp \
eventqueue.c
eventqueue.c \
msjava.c
LOCAL_SRC_FILES += audiostream.c
......@@ -95,7 +114,13 @@ LOCAL_SRC_FILES += \
h264dec.c \
rfc3984.c \
mire.c \
videostream.c
videostream.c \
layouts.c \
android-display.c \
android-display-bad.cpp \
msandroidvideo.cpp \
scaler.c.neon \
scaler_arm.S
endif
......@@ -115,27 +140,19 @@ LOCAL_SRC_FILES += gsm.c
LOCAL_CFLAGS += \
-UHAVE_CONFIG_H \
-include $(LOCAL_PATH)/../build/android/libmediastreamer2_AndroidConfig.h \
-D_POSIX_SOURCE
-D_POSIX_SOURCE -Wall
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_CFLAGS += -DUSE_HARDWARE_RATE=1
LOCAL_ARM_NEON := true
endif
#LOCAL_CFLAGS += -DDEBUG
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/../build/android \
$(LOCAL_PATH)/../include \
$(LOCAL_PATH)/../../oRTP \
$(LOCAL_PATH)/../../oRTP/include \
$(LOCAL_PATH)/../../../externals/speex/include \
$(LOCAL_PATH)/../../../externals/build/speex \
$(LOCAL_PATH)/../../../externals/gsm/inc \
$(LOCAL_PATH)/../../../externals/ffmpeg \
$(LOCAL_PATH)/../../../externals/ \
$(LOCAL_PATH)/../../../externals/build/ffmpeg
$(MEDIASTREAMER2_INCLUDES)
LOCAL_STATIC_LIBRARIES := \
libortp \
......@@ -147,6 +164,8 @@ LOCAL_SHARED_LIBRARIES += libasound
endif
include $(BUILD_STATIC_LIBRARY)
......@@ -32,6 +32,7 @@ extern MSFilterDesc ms_h263_dec_desc;
extern MSFilterDesc ms_h264_dec_desc;
extern MSFilterDesc ms_pix_conv_desc;
extern MSFilterDesc ms_size_conv_desc;
MSFilterDesc * ms_filter_descs[]={
&ms_alaw_dec_desc,
......
......@@ -29,7 +29,8 @@ mediastreamer2_include_HEADERS= ice.h \
msaudiomixer.h \
msitc.h \
msextdisplay.h \
msjpegwriter.h
msjpegwriter.h \
msjava.h
EXTRA_DIST=$(mediastreamer2_include_HEADERS)
......@@ -103,7 +103,10 @@ typedef enum MSFilterId{
MS_ANDROID_SOUND_READ_ID,
MS_ANDROID_SOUND_WRITE_ID,
MS_JPEG_WRITER_ID,
MS_X11VIDEO_ID
MS_X11VIDEO_ID,
MS_ANDROID_DISPLAY_ID,
MS_ANDROID_VIDEO_READ_ID,
MS_ANDROID_VIDEO_WRITE_ID
} MSFilterId;
......
......@@ -198,6 +198,7 @@ struct _VideoStream
unsigned long window_id;
unsigned long preview_window_id;
VideoStreamDir dir;
MSWebCam *cam;
bool_t use_preview_window;
bool_t adapt_bitrate;
};
......@@ -218,6 +219,9 @@ int video_stream_start(VideoStream * stream, RtpProfile *profile, const char *re
void video_stream_set_relay_session_id(VideoStream *stream, const char *relay_session_id);
void video_stream_set_rtcp_information(VideoStream *st, const char *cname, const char *tool);
void video_stream_change_camera(VideoStream *stream, MSWebCam *cam);
/* Calling video_stream_set_sent_video_size() or changing the bitrate value in the used PayloadType during a stream is running does nothing.
The following function allows to take into account new parameters by redrawing the sending graph*/
void video_stream_update_video_params(VideoStream *stream);
/*function to call periodically to handle various events */
void video_stream_iterate(VideoStream *stream);
void video_stream_send_vfu(VideoStream *stream);
......@@ -238,6 +242,11 @@ int video_stream_send_only_start(VideoStream *videostream,
void video_stream_recv_only_stop(VideoStream *vs);
void video_stream_send_only_stop(VideoStream *vs);
/**
* Small API to display a local preview window.
**/
typedef VideoStream VideoPreview;
VideoPreview * video_preview_new();
......
......@@ -88,7 +88,7 @@ static inline void ms_debug(const char *fmt,...)
#define ms_thread_t ortp_thread_t
#define ms_thread_create ortp_thread_create
#define ms_thread_join ortp_thread_join
#define ms_thread_exit ortp_thread_exit
struct _MSList {
struct _MSList *next;
......@@ -102,10 +102,13 @@ typedef struct _MSList MSList;
#define ms_list_next(elem) ((elem)->next)
typedef int (*MSCompareFunc)(const void *a, const void *b);
#ifdef __cplusplus
extern "C"{
#endif
void ms_thread_exit(void* ret_val);
MSList * ms_list_append(MSList *elem, void * data);
MSList * ms_list_prepend(MSList *elem, void * data);
MSList * ms_list_free(MSList *elem);
......@@ -116,11 +119,11 @@ void ms_list_for_each(const MSList *list, void (*func)(void *));
void ms_list_for_each2(const MSList *list, void (*func)(void *, void *), void *user_data);
MSList *ms_list_remove_link(MSList *list, MSList *elem);
MSList *ms_list_find(MSList *list, void *data);
MSList *ms_list_find_custom(MSList *list, int (*compare_func)(const void *, const void*), void *user_data);
MSList *ms_list_find_custom(MSList *list, MSCompareFunc compare_func, const void *user_data);
void * ms_list_nth_data(const MSList *list, int index);
int ms_list_position(const MSList *list, MSList *elem);
int ms_list_index(const MSList *list, void *data);
MSList *ms_list_insert_sorted(MSList *list, void *data, int (*compare_func)(const void *, const void*));
MSList *ms_list_insert_sorted(MSList *list, void *data, MSCompareFunc compare_func);
MSList *ms_list_insert(MSList *list, MSList *before, void *data);
MSList *ms_list_copy(const MSList *list);
......@@ -210,4 +213,8 @@ void ms_set_mtu(int mtu);
}
#endif
#ifdef ANDROID
#include "mediastreamer2/msjava.h"
#endif
#endif
......@@ -95,6 +95,15 @@ enum _MSFilterFlags{
typedef enum _MSFilterFlags MSFilterFlags;
struct _MSFilterStats{
const char *name; /*<filter name*/
uint64_t elapsed; /*<cumulative number of nanoseconds elapsed */
unsigned int count; /*<number of time the filter is called for processing*/
};
typedef struct _MSFilterStats MSFilterStats;
struct _MSFilterDesc{
MSFilterId id; /* the id declared in allfilters.h */
const char *name; /* filter name */
......@@ -130,6 +139,7 @@ struct _MSFilter{
struct _MSTicker *ticker;
/*private attributes */
uint32_t last_tick;
MSFilterStats *stats;
bool_t seen;
bool_t synchronous_notifies;
};
......@@ -433,6 +443,33 @@ int ms_connection_helper_link(MSConnectionHelper *h, MSFilter *f, int inpin, int
**/
int ms_connection_helper_unlink(MSConnectionHelper *h, MSFilter *f, int inpin, int outpin);
/**
* \brief Enable processing time measurements statistics for filters.
*
**/
void ms_filter_enable_statistics(bool_t enabled);
/**
* \brief Reset processing time statistics for filters.
*
**/
void ms_filter_reset_statistics(void);
/**
* \brief Retrieves statistics for running filters.
* Returns a list of MSFilterStats
**/
const MSList * ms_filter_get_statistics(void);
/**
* \brief Logs runtime statistics for running filters.
*
**/
void ms_filter_log_statistics(void);
/* I define the id taking the lower bits of the address of the MSFilterDesc object,
the method index (_cnt_) and the argument size */
/* I hope using this to avoid type mismatch (calling a method on the wrong filter)*/
......
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2010 Belledonne Communications SARL
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.
*/
#ifndef msjava_h
#define msjava_h
/* Helper routines for filters that use a jvm with upcalls to perform some processing */
#include <jni.h>
#ifdef __cplusplus
extern "C"{
#endif
void ms_set_jvm(JavaVM *vm);
JavaVM *ms_get_jvm(void);
JNIEnv *ms_get_jni_env(void);
#ifdef __cplusplus
}
#endif
#endif
......@@ -171,6 +171,7 @@ typedef enum{
MS_UYVY,
MS_YUY2, /* -> same as MS_YUYV */
MS_RGBA32,
MS_RGB565,
MS_PIX_FMT_UNKNOWN
}MSPixFmt;
......@@ -191,7 +192,8 @@ MSPixFmt ffmpeg_pix_fmt_to_ms(int fmt);
MSPixFmt ms_fourcc_to_pix_fmt(uint32_t fourcc);
void ms_ffmpeg_check_init(void);
int ms_yuv_buf_init_from_mblk(MSPicture *buf, mblk_t *m);
void ms_yuv_buf_init_from_mblk_with_size(MSPicture *buf, mblk_t *m, int w, int h);
int ms_yuv_buf_init_from_mblk_with_size(MSPicture *buf, mblk_t *m, int w, int h);
int ms_picture_init_from_mblk_with_size(MSPicture *buf, mblk_t *m, MSPixFmt fmt, int w, int h);
mblk_t * ms_yuv_buf_alloc(MSPicture *buf, int w, int h);
void ms_yuv_buf_copy(uint8_t *src_planes[], const int src_strides[],
uint8_t *dst_planes[], const int dst_strides[3], MSVideoSize roi);
......@@ -207,6 +209,10 @@ static inline bool_t ms_video_size_greater_than(MSVideoSize vs1, MSVideoSize vs2
return (vs1.width>=vs2.width) && (vs1.height>=vs2.height);
}
static inline bool_t ms_video_size_area_greater_than(MSVideoSize vs1, MSVideoSize vs2){
return (vs1.width*vs1.height >= vs2.width*vs2.height);
}
static inline MSVideoSize ms_video_size_max(MSVideoSize vs1, MSVideoSize vs2){
return ms_video_size_greater_than(vs1,vs2) ? vs1 : vs2;
}
......@@ -215,43 +221,57 @@ static inline MSVideoSize ms_video_size_min(MSVideoSize vs1, MSVideoSize vs2){
return ms_video_size_greater_than(vs1,vs2) ? vs2 : vs1;
}
static inline MSVideoSize ms_video_size_area_max(MSVideoSize vs1, MSVideoSize vs2){
return ms_video_size_area_greater_than(vs1,vs2) ? vs1 : vs2;
}
static inline MSVideoSize ms_video_size_area_min(MSVideoSize vs1, MSVideoSize vs2){
return ms_video_size_area_greater_than(vs1,vs2) ? vs2 : vs1;
}
static inline bool_t ms_video_size_equal(MSVideoSize vs1, MSVideoSize vs2){
return vs1.width==vs2.width && vs1.height==vs2.height;
}
MSVideoSize ms_video_size_get_just_lower_than(MSVideoSize vs);
struct ms_SwsContext;
struct _SwsFilter;
struct ms_SwsContext *ms_sws_getContext(int srcW, int srcH, int srcFormat,
int dstW, int dstH, int dstFormat,
int flags, struct _SwsFilter *srcFilter,
struct _SwsFilter *dstFilter, double *param);
void ms_sws_freeContext(struct ms_SwsContext *swsContext);
int ms_sws_scale(struct ms_SwsContext *context, uint8_t* srcSlice[], int srcStride[],
int srcSliceY, int srcSliceH, uint8_t* dst[], int dstStride[]);
typedef struct ms_SwsContext *(*sws_getContextFunc)(int srcW, int srcH, int srcFormat,
int dstW, int dstH, int dstFormat,
int flags, struct _SwsFilter *srcFilter,
struct _SwsFilter *dstFilter, double *param);
typedef void (*sws_freeContextFunc)(struct ms_SwsContext *swsContext);
typedef int (*sws_scaleFunc)(struct ms_SwsContext *context, uint8_t* srcSlice[], int srcStride[],
int srcSliceY, int srcSliceH, uint8_t* dst[], int dstStride[]);
typedef void (*yuv_buf_mirrorFunc)(MSPicture *buf);
typedef void (*yuv_buf_copyFunc)(uint8_t *src_planes[], const int src_strides[],
uint8_t *dst_planes[], const int dst_strides[3], MSVideoSize roi);
static inline MSVideoOrientation ms_video_size_get_orientation(MSVideoSize vs){
return vs.width>=vs.height ? MS_VIDEO_LANDSCAPE : MS_VIDEO_PORTRAIT;
}
struct ms_swscaleDesc {
sws_getContextFunc sws_getContext;
sws_freeContextFunc sws_freeContext;
sws_scaleFunc sws_scale;
yuv_buf_mirrorFunc yuv_buf_mirror;
yuv_buf_copyFunc yuv_buf_copy;
static inline MSVideoSize ms_video_size_change_orientation(MSVideoSize vs, MSVideoOrientation o){
MSVideoSize ret;
if (o!=ms_video_size_get_orientation(vs)){
ret.width=vs.height;
ret.height=vs.width;
}else ret=vs;
return ret;
}
/* abstraction for image scaling and color space conversion routines*/
typedef struct _MSScalerContext MSScalerContext;
#define MS_SCALER_METHOD_NEIGHBOUR 1
#define MS_SCALER_METHOD_BILINEAR (1<<1)
struct _MSScalerDesc {
MSScalerContext * (*create_context)(int src_w, int src_h, MSPixFmt src_fmt,
int dst_w, int dst_h, MSPixFmt dst_fmt, int flags);
int (*context_process)(MSScalerContext *ctx, uint8_t *src[], int src_strides[], uint8_t *dst[], int dst_strides[]);
void (*context_free)(MSScalerContext *ctx);
};
void ms_video_set_video_func(struct ms_swscaleDesc *_ms_swscale_desc);
typedef struct _MSScalerDesc MSScalerDesc;
MSScalerContext *ms_scaler_create_context(int src_w, int src_h, MSPixFmt src_fmt,
int dst_w, int dst_h, MSPixFmt dst_fmt, int flags);
int ms_scaler_process(MSScalerContext *ctx, uint8_t *src[], int src_strides[], uint8_t *dst[], int dst_strides[]);
void ms_scaler_context_free(MSScalerContext *ctx);
void ms_video_set_scaler_impl(MSScalerDesc *desc);
#ifdef __cplusplus
}
......
......@@ -67,6 +67,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define MS_VOLUME_REMOVE_DC MS_FILTER_METHOD(MS_VOLUME_ID,16,int)
#define MS_VOLUME_SET_EA_TRANSMIT_THRESHOLD MS_FILTER_METHOD(MS_VOLUME_ID,17,float)
extern MSFilterDesc ms_volume_desc;
#endif
ANDROID_SRC_FILES= \
msandroid.cpp \
android-display.c \
android-display-bad.cpp \
msandroidvideo.cpp
EXTRA_DIST= winsnd2.c winsnd.c winvideo.c \
winvideods.c wincevideods.c dxfilter.h dxfilter.cpp \
msfileplayer_win.c msfilerec_win.c winsndds.cpp nowebcamCIF.jpg winsnd3.c vfw-missing.h \
winvideo2.c
winvideo2.c msjava.c $(ANDROID_SRC_FILES)
BUILT_SOURCES=alldescs.h
......@@ -168,10 +174,11 @@ libmediastreamer_la_LIBADD= $(ORTP_LIBS) \
$(GSM_LIBS) \
$(LIBV4L1_LIBS) \
$(LIBV4L2_LIBS)
libmediastreamer_la_LDFLAGS= -no-undefined -version-info $(LIBMEDIASTREAMER_SO_VERSION)
if !BUILD_WIN32
libmediastreamer_la_LDFLAGS=-rdynamic
else
libmediastreamer_la_LDFLAGS=-no-undefined
libmediastreamer_la_LDFLAGS+=-rdynamic
endif
if BUILD_VIDEO
......
......@@ -264,7 +264,7 @@ static snd_pcm_t * alsa_open_w(const char *pcmdev,int bits,int stereo,int rate)
{
snd_pcm_t *pcm_handle;
ms_message("alsa_open_r: opening %s at %iHz, bits=%i, stereo=%i",pcmdev,rate,bits,stereo);
ms_message("alsa_open_w: opening %s at %iHz, bits=%i, stereo=%i",pcmdev,rate,bits,stereo);
if (snd_pcm_open(&pcm_handle, pcmdev,SND_PCM_STREAM_PLAYBACK,SND_PCM_NONBLOCK) < 0) {
ms_warning("alsa_open_w: Error opening PCM device %s",pcmdev );
......
/*
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 <android/bitmap.h>
#include <dlfcn.h>
static int android_version=0;
typedef unsigned int PixelFormat;
struct SurfaceInfo15{
uint32_t w;
uint32_t h;
uint32_t bpr;
PixelFormat format;
void* bits;
void* base;
uint32_t reserved[2];
};
struct SurfaceInfo21 {
uint32_t w;
uint32_t h;
uint32_t s;
uint32_t usage;
PixelFormat format;
void* bits;
uint32_t reserved[2];
};
union SurfaceInfo{
SurfaceInfo15 info15;
SurfaceInfo21 info21;
};
class SurfaceInfoAccess{
public:
SurfaceInfoAccess(SurfaceInfo *i){
info=i;
}
int getWidth(){
return info->info21.w;
}
int getHeight(){
return info->info21.h;
}
int getStride(){
return android_version<21 ? info->info15.bpr : (info->info21.s*2);
}
void *getBits(){
return android_version<21 ? (info->info15.bits) : info->info21.bits;
}
private:
SurfaceInfo *info;
};
class RefBase{
};
class Surface : public RefBase{
};
typedef int (*Android_Surface_lock)(Surface *surf, SurfaceInfo *info,bool blocking);
typedef int (*Android_Surface_unlockAndPost)(Surface *surf);
typedef int (*Android_RefBase_incStrong)(RefBase *obj, const void *);
typedef int (*Android_RefBase_decStrong)(RefBase *obj, const void *);
static Android_Surface_lock sym_Android_Surface_lock=NULL;
static Android_Surface_unlockAndPost sym_Android_Surface_unlockAndPost=NULL;
static Android_RefBase_incStrong sym_Android_RefBase_incStrong=NULL;
static Android_RefBase_decStrong sym_Android_RefBase_decStrong=NULL;
typedef struct AndroidDisplay{
Surface *surf;
jfieldID surface_id; /* private mSurface field of android.view.Surface */
jmethodID get_surface_id; /* AndroidVideoWindowImpl.getSurface() method */
MSScalerContext *sws;
MSVideoSize vsize;
MSVideoSize wsize;
}AndroidDisplay;
static void android_display_init(MSFilter *f){
AndroidDisplay *ad=(AndroidDisplay*)ms_new0(AndroidDisplay,1);
JNIEnv *jenv=ms_get_jni_env();
jclass wc;
wc=jenv->FindClass("org/linphone/core/AndroidVideoWindowImpl");
if (wc==0){
ms_fatal("Could not find org.linphone.core.AndroidVideoWindowImpl class !");
}
ad->get_surface_id=jenv->GetMethodID(wc,"getSurface", "()Landroid/view/Surface;");
if (ad->get_surface_id==NULL){
ms_fatal("Could not find getSurface() method of AndroidVideoWindowImpl");
return;
}
wc=jenv->FindClass("android/view/Surface");
if (wc==0){
ms_fatal("Could not find android/view/Surface class !");
}
ad->surface_id=jenv->GetFieldID(wc,"mSurface","I");
if (ad->surface_id==NULL){
ms_fatal("Could not find mSurface field of android.view.Surface");
return;
}
MS_VIDEO_SIZE_ASSIGN(ad->vsize,CIF);
MS_VIDEO_SIZE_ASSIGN(ad->wsize,CIF);
f->data=ad;
}
static void android_display_uninit(MSFilter *f){
AndroidDisplay *ad=(AndroidDisplay*)f->data;
if (ad->sws){
ms_scaler_context_free (ad->sws);
ad->sws=NULL;
}
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->surf!=NULL){
if ((m=ms_queue_peek_last(f->inputs[0]))!=NULL){
if (ms_yuv_buf_init_from_mblk (&pic,m)==0){
SurfaceInfo info;
if (sym_Android_Surface_lock(ad->surf,&info,true)==0){
SurfaceInfoAccess infoAccess(&info);
MSVideoSize wsize={infoAccess.getWidth(),infoAccess.getHeight()};
MSVideoSize vsize={pic.w, pic.h};
MSRect vrect;
MSPicture dest={0};
//ms_message("Got surface with w=%i, h=%i, s=%i",info.w, info.h, info.s);
if (!ms_video_size_equal(vsize,ad->vsize)
|| !ms_video_size_equal(wsize,ad->wsize) ){
ad->vsize=vsize;
ad->wsize=wsize;
if (ad->sws){
ms_scaler_context_free(ad->sws);
ad->sws=NULL;
}
}
ms_layout_compute(wsize,vsize,vsize,-1,0,&vrect, NULL);
if (ad->sws==NULL){
ad->sws=ms_scaler_create_context(vsize.width,vsize.height,MS_YUV420P,
vrect.w,vrect.h,MS_RGB565,MS_SCALER_METHOD_BILINEAR);
if (ad->sws==NULL){
ms_fatal("Could not obtain sws context !");
}
}
dest.planes[0]=(uint8_t*)infoAccess.getBits()+(vrect.y*infoAccess.getStride())+(vrect.x*2);
dest.strides[0]=infoAccess.getStride();
ms_scaler_process(ad->sws,pic.planes,pic.strides,dest.planes,dest.strides);
sym_Android_Surface_unlockAndPost(ad->surf);
}else{
ms_error("AndroidBitmap_lockPixels() failed !");
}
}
}
}
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 jsurface=NULL;
jobject android_window=(jobject)id;
Surface *oldsurf;
if (android_window!=NULL)
jsurface=jenv->CallObjectMethod(android_window,ad->get_surface_id);
ms_filter_lock(f);
oldsurf=ad->surf;
if (jsurface!=NULL) ad->surf=(Surface*)jenv->GetIntField(jsurface,ad->surface_id);
else ad->surf=NULL;
if (ad->surf)
sym_Android_RefBase_incStrong(ad->surf,NULL);
if (oldsurf)
sym_Android_RefBase_decStrong(oldsurf,NULL);
ms_filter_unlock(f);
ms_message("Got new surface to draw (%p)",ad->surf);
return 0;
}