| 1 | /* |
|---|
| 2 | mediastreamer2 android video display filter |
|---|
| 3 | Copyright (C) 2010 Belledonne Communications SARL (simon.morlat@linphone.org) |
|---|
| 4 | |
|---|
| 5 | This program is free software; you can redistribute it and/or |
|---|
| 6 | modify it under the terms of the GNU General Public License |
|---|
| 7 | as published by the Free Software Foundation; either version 2 |
|---|
| 8 | of the License, or (at your option) any later version. |
|---|
| 9 | |
|---|
| 10 | This program is distributed in the hope that it will be useful, |
|---|
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 13 | GNU General Public License for more details. |
|---|
| 14 | |
|---|
| 15 | You should have received a copy of the GNU General Public License |
|---|
| 16 | along with this program; if not, write to the Free Software |
|---|
| 17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|---|
| 18 | */ |
|---|
| 19 | |
|---|
| 20 | #include "ffmpeg-priv.h" |
|---|
| 21 | |
|---|
| 22 | #include "mediastreamer2/msfilter.h" |
|---|
| 23 | #include "mediastreamer2/msvideo.h" |
|---|
| 24 | #include "layouts.h" |
|---|
| 25 | #include <android/bitmap.h> |
|---|
| 26 | #include <jni.h> |
|---|
| 27 | #include <dlfcn.h> |
|---|
| 28 | |
|---|
| 29 | /*defined in msandroid.cpp*/ |
|---|
| 30 | extern JavaVM *ms_andsnd_jvm; |
|---|
| 31 | |
|---|
| 32 | typedef struct AndroidDisplay{ |
|---|
| 33 | JavaVM *jvm; |
|---|
| 34 | JNIEnv *jenv; |
|---|
| 35 | jobject android_video_window; |
|---|
| 36 | jobject jbitmap; |
|---|
| 37 | jmethodID get_bitmap_id; |
|---|
| 38 | jmethodID update_id; |
|---|
| 39 | AndroidBitmapInfo bmpinfo; |
|---|
| 40 | struct ms_SwsContext *sws; |
|---|
| 41 | MSVideoSize vsize; |
|---|
| 42 | }AndroidDisplay; |
|---|
| 43 | |
|---|
| 44 | |
|---|
| 45 | static int (*sym_AndroidBitmap_getInfo)(JNIEnv *env,jobject bitmap, AndroidBitmapInfo *bmpinfo)=NULL; |
|---|
| 46 | static int (*sym_AndroidBitmap_lockPixels)(JNIEnv *env, jobject bitmap, void **pixels)=NULL; |
|---|
| 47 | static int (*sym_AndroidBitmap_unlockPixels)(JNIEnv *env, jobject bitmap)=NULL; |
|---|
| 48 | |
|---|
| 49 | static void android_display_init(MSFilter *f){ |
|---|
| 50 | AndroidDisplay *ad=(AndroidDisplay*)ms_new0(AndroidDisplay,1); |
|---|
| 51 | JNIEnv *jenv=NULL; |
|---|
| 52 | jclass wc; |
|---|
| 53 | |
|---|
| 54 | ad->jvm=ms_andsnd_jvm; |
|---|
| 55 | |
|---|
| 56 | if ((*(ad->jvm))->AttachCurrentThread(ad->jvm,&jenv,NULL)!=0){ |
|---|
| 57 | ms_error("Could not get JNIEnv"); |
|---|
| 58 | return ; |
|---|
| 59 | } |
|---|
| 60 | wc=(*jenv)->FindClass(jenv,"org/linphone/core/AndroidVideoWindowImpl"); |
|---|
| 61 | if (wc==0){ |
|---|
| 62 | ms_fatal("Could not find org.linphone.core.AndroidVideoWindowImpl class !"); |
|---|
| 63 | } |
|---|
| 64 | ad->get_bitmap_id=(*jenv)->GetMethodID(jenv,wc,"getBitmap", "()Landroid/graphics/Bitmap;"); |
|---|
| 65 | ad->update_id=(*jenv)->GetMethodID(jenv,wc,"update","()V"); |
|---|
| 66 | |
|---|
| 67 | MS_VIDEO_SIZE_ASSIGN(ad->vsize,CIF); |
|---|
| 68 | f->data=ad; |
|---|
| 69 | } |
|---|
| 70 | |
|---|
| 71 | static void android_display_uninit(MSFilter *f){ |
|---|
| 72 | AndroidDisplay *ad=(AndroidDisplay*)f->data; |
|---|
| 73 | if (ad->sws){ |
|---|
| 74 | ms_sws_freeContext (ad->sws); |
|---|
| 75 | ad->sws=NULL; |
|---|
| 76 | } |
|---|
| 77 | ms_free(ad); |
|---|
| 78 | } |
|---|
| 79 | |
|---|
| 80 | static void android_display_preprocess(MSFilter *f){ |
|---|
| 81 | |
|---|
| 82 | } |
|---|
| 83 | |
|---|
| 84 | static void android_display_process(MSFilter *f){ |
|---|
| 85 | AndroidDisplay *ad=(AndroidDisplay*)f->data; |
|---|
| 86 | MSPicture pic; |
|---|
| 87 | mblk_t *m; |
|---|
| 88 | |
|---|
| 89 | if (ad->jenv==NULL){ |
|---|
| 90 | jint result = (*(ad->jvm))->AttachCurrentThread(ad->jvm,&ad->jenv,NULL); |
|---|
| 91 | if (result != 0) { |
|---|
| 92 | ms_error("android_display_process(): cannot attach VM"); |
|---|
| 93 | goto end; |
|---|
| 94 | } |
|---|
| 95 | } |
|---|
| 96 | |
|---|
| 97 | ms_filter_lock(f); |
|---|
| 98 | if (ad->jbitmap!=0){ |
|---|
| 99 | if ((m=ms_queue_peek_last(f->inputs[0]))!=NULL){ |
|---|
| 100 | if (ms_yuv_buf_init_from_mblk (&pic,m)==0){ |
|---|
| 101 | MSVideoSize wsize={ad->bmpinfo.width,ad->bmpinfo.height}; |
|---|
| 102 | MSVideoSize vsize={pic.w, pic.h}; |
|---|
| 103 | MSRect vrect; |
|---|
| 104 | MSPicture dest={0}; |
|---|
| 105 | void *pixels=NULL; |
|---|
| 106 | |
|---|
| 107 | if (!ms_video_size_equal(vsize,ad->vsize)){ |
|---|
| 108 | ad->vsize=vsize; |
|---|
| 109 | if (ad->sws){ |
|---|
| 110 | ms_sws_freeContext (ad->sws); |
|---|
| 111 | ad->sws=NULL; |
|---|
| 112 | } |
|---|
| 113 | } |
|---|
| 114 | |
|---|
| 115 | ms_layout_compute(wsize,vsize,vsize,-1,0,&vrect, NULL); |
|---|
| 116 | |
|---|
| 117 | if (ad->sws==NULL){ |
|---|
| 118 | ad->sws=ms_sws_getContext (vsize.width,vsize.height,PIX_FMT_YUV420P, |
|---|
| 119 | vrect.w,vrect.h,PIX_FMT_RGB565,SWS_BILINEAR,NULL,NULL,NULL); |
|---|
| 120 | if (ad->sws==NULL){ |
|---|
| 121 | ms_fatal("Could not obtain sws context !"); |
|---|
| 122 | } |
|---|
| 123 | } |
|---|
| 124 | if (sym_AndroidBitmap_lockPixels(ad->jenv,ad->jbitmap,&pixels)==0){ |
|---|
| 125 | dest.planes[0]=(uint8_t*)pixels+(vrect.y*ad->bmpinfo.stride)+(vrect.x*2); |
|---|
| 126 | dest.strides[0]=ad->bmpinfo.stride; |
|---|
| 127 | ms_sws_scale (ad->sws,pic.planes,pic.strides,0,pic.h,dest.planes,dest.strides); |
|---|
| 128 | sym_AndroidBitmap_unlockPixels(ad->jenv,ad->jbitmap); |
|---|
| 129 | }else{ |
|---|
| 130 | ms_error("AndroidBitmap_lockPixels() failed !"); |
|---|
| 131 | } |
|---|
| 132 | ms_message("Ask draw of bitmap"); |
|---|
| 133 | (*ad->jenv)->CallVoidMethod(ad->jenv,ad->android_video_window,ad->update_id); |
|---|
| 134 | } |
|---|
| 135 | } |
|---|
| 136 | } |
|---|
| 137 | ms_filter_unlock(f); |
|---|
| 138 | |
|---|
| 139 | end: |
|---|
| 140 | ms_queue_flush(f->inputs[0]); |
|---|
| 141 | ms_queue_flush(f->inputs[1]); |
|---|
| 142 | } |
|---|
| 143 | |
|---|
| 144 | static int android_display_set_window(MSFilter *f, void *arg){ |
|---|
| 145 | AndroidDisplay *ad=(AndroidDisplay*)f->data; |
|---|
| 146 | unsigned long id=*(unsigned long*)arg; |
|---|
| 147 | int err; |
|---|
| 148 | JNIEnv *jenv=NULL; |
|---|
| 149 | jobject window=(jobject)id; |
|---|
| 150 | |
|---|
| 151 | if ((*(ad->jvm))->AttachCurrentThread(ad->jvm,&jenv,NULL)!=0){ |
|---|
| 152 | ms_error("Could not get JNIEnv"); |
|---|
| 153 | return -1; |
|---|
| 154 | } |
|---|
| 155 | |
|---|
| 156 | ms_filter_lock(f); |
|---|
| 157 | ad->jbitmap=(*jenv)->CallObjectMethod(jenv,window,ad->get_bitmap_id); |
|---|
| 158 | ad->android_video_window=window; |
|---|
| 159 | err=sym_AndroidBitmap_getInfo(jenv,ad->jbitmap,&ad->bmpinfo); |
|---|
| 160 | if (err!=0){ |
|---|
| 161 | ms_error("AndroidBitmap_getInfo() failed."); |
|---|
| 162 | ad->jbitmap=0; |
|---|
| 163 | ms_filter_unlock(f); |
|---|
| 164 | return -1; |
|---|
| 165 | } |
|---|
| 166 | ms_filter_unlock(f); |
|---|
| 167 | ms_message("New java bitmap given with w=%i,h=%i,stride=%i,format=%i", |
|---|
| 168 | ad->bmpinfo.width,ad->bmpinfo.height,ad->bmpinfo.stride,ad->bmpinfo.format); |
|---|
| 169 | } |
|---|
| 170 | |
|---|
| 171 | static MSFilterMethod methods[]={ |
|---|
| 172 | { MS_VIDEO_DISPLAY_SET_NATIVE_WINDOW_ID , android_display_set_window }, |
|---|
| 173 | { 0, NULL} |
|---|
| 174 | }; |
|---|
| 175 | |
|---|
| 176 | MSFilterDesc ms_android_display_desc={ |
|---|
| 177 | .id=MS_ANDROID_DISPLAY_ID, |
|---|
| 178 | .name="MSAndroidDisplay", |
|---|
| 179 | .text="Video display filter for Android.", |
|---|
| 180 | .category=MS_FILTER_OTHER, |
|---|
| 181 | .ninputs=2, /*number of inputs*/ |
|---|
| 182 | .noutputs=0, /*number of outputs*/ |
|---|
| 183 | .init=android_display_init, |
|---|
| 184 | .preprocess=android_display_preprocess, |
|---|
| 185 | .process=android_display_process, |
|---|
| 186 | .uninit=android_display_uninit |
|---|
| 187 | }; |
|---|
| 188 | |
|---|
| 189 | void libmsandroiddisplay_init(void){ |
|---|
| 190 | /*See if we can use AndroidBitmap_* symbols (only since android 2.2 normally)*/ |
|---|
| 191 | void *handle=dlopen("libjnigraphics.so",RTLD_LAZY); |
|---|
| 192 | if (handle!=NULL){ |
|---|
| 193 | sym_AndroidBitmap_getInfo=dlsym(handle,"AndroidBitmap_getInfo"); |
|---|
| 194 | sym_AndroidBitmap_lockPixels=dlsym(handle,"AndroidBitmap_lockPixels"); |
|---|
| 195 | sym_AndroidBitmap_unlockPixels=dlsym(handle,"AndroidBitmap_unlockPixels"); |
|---|
| 196 | |
|---|
| 197 | if (sym_AndroidBitmap_getInfo==NULL || sym_AndroidBitmap_lockPixels==NULL |
|---|
| 198 | || sym_AndroidBitmap_unlockPixels==NULL){ |
|---|
| 199 | ms_warning("AndroidBitmap not available."); |
|---|
| 200 | }else{ |
|---|
| 201 | ms_filter_register(&ms_android_display_desc); |
|---|
| 202 | ms_message("MSAndroidDisplay registered."); |
|---|
| 203 | } |
|---|
| 204 | }else ms_warning("libjnigraphics.so cannot be loaded."); |
|---|
| 205 | } |
|---|
| 206 | |
|---|
| 207 | |
|---|