| 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 | |
|---|
| 28 | /*defined in msandroid.cpp*/ |
|---|
| 29 | extern JavaVM *ms_andsnd_jvm; |
|---|
| 30 | |
|---|
| 31 | typedef struct AndroidDisplay{ |
|---|
| 32 | JavaVM *jvm; |
|---|
| 33 | JNIEnv *jenv; |
|---|
| 34 | jobject android_video_window; |
|---|
| 35 | jobject jbitmap; |
|---|
| 36 | jmethodID get_bitmap_id; |
|---|
| 37 | jmethodID update_id; |
|---|
| 38 | AndroidBitmapInfo bmpinfo; |
|---|
| 39 | struct ms_SwsContext *sws; |
|---|
| 40 | MSVideoSize vsize; |
|---|
| 41 | }AndroidDisplay; |
|---|
| 42 | |
|---|
| 43 | static void android_display_init(MSFilter *f){ |
|---|
| 44 | AndroidDisplay *ad=(AndroidDisplay*)ms_new0(AndroidDisplay,1); |
|---|
| 45 | JNIEnv *jenv=NULL; |
|---|
| 46 | jclass wc; |
|---|
| 47 | |
|---|
| 48 | ad->jvm=ms_andsnd_jvm; |
|---|
| 49 | |
|---|
| 50 | if ((*(ad->jvm))->AttachCurrentThread(ad->jvm,&jenv,NULL)!=0){ |
|---|
| 51 | ms_error("Could not get JNIEnv"); |
|---|
| 52 | return ; |
|---|
| 53 | } |
|---|
| 54 | wc=(*jenv)->FindClass(jenv,"org/linphone/core/AndroidVideoWindowImpl"); |
|---|
| 55 | if (wc==0){ |
|---|
| 56 | ms_fatal("Could not find org.linphone.core.AndroidVideoWindowImpl class !"); |
|---|
| 57 | } |
|---|
| 58 | ad->get_bitmap_id=(*jenv)->GetMethodID(jenv,wc,"getBitmap", "()Landroid/graphics/Bitmap;"); |
|---|
| 59 | ad->update_id=(*jenv)->GetMethodID(jenv,wc,"update","()V"); |
|---|
| 60 | |
|---|
| 61 | MS_VIDEO_SIZE_ASSIGN(ad->vsize,CIF); |
|---|
| 62 | f->data=ad; |
|---|
| 63 | } |
|---|
| 64 | |
|---|
| 65 | static void android_display_uninit(MSFilter *f){ |
|---|
| 66 | AndroidDisplay *ad=(AndroidDisplay*)f->data; |
|---|
| 67 | if (ad->sws){ |
|---|
| 68 | ms_sws_freeContext (ad->sws); |
|---|
| 69 | ad->sws=NULL; |
|---|
| 70 | } |
|---|
| 71 | ms_free(ad); |
|---|
| 72 | } |
|---|
| 73 | |
|---|
| 74 | static void android_display_preprocess(MSFilter *f){ |
|---|
| 75 | |
|---|
| 76 | } |
|---|
| 77 | |
|---|
| 78 | static void android_display_process(MSFilter *f){ |
|---|
| 79 | AndroidDisplay *ad=(AndroidDisplay*)f->data; |
|---|
| 80 | MSPicture pic; |
|---|
| 81 | mblk_t *m; |
|---|
| 82 | |
|---|
| 83 | if (ad->jenv==NULL){ |
|---|
| 84 | jint result = (*(ad->jvm))->AttachCurrentThread(ad->jvm,&ad->jenv,NULL); |
|---|
| 85 | if (result != 0) { |
|---|
| 86 | ms_error("android_display_process(): cannot attach VM"); |
|---|
| 87 | goto end; |
|---|
| 88 | } |
|---|
| 89 | } |
|---|
| 90 | |
|---|
| 91 | ms_filter_lock(f); |
|---|
| 92 | if (ad->jbitmap!=0){ |
|---|
| 93 | if ((m=ms_queue_peek_last(f->inputs[0]))!=NULL){ |
|---|
| 94 | if (ms_yuv_buf_init_from_mblk (&pic,m)==0){ |
|---|
| 95 | MSVideoSize wsize={ad->bmpinfo.width,ad->bmpinfo.height}; |
|---|
| 96 | MSVideoSize vsize={pic.w, pic.h}; |
|---|
| 97 | MSRect vrect; |
|---|
| 98 | MSPicture dest={0}; |
|---|
| 99 | void *pixels=NULL; |
|---|
| 100 | |
|---|
| 101 | if (!ms_video_size_equal(vsize,ad->vsize)){ |
|---|
| 102 | ad->vsize=vsize; |
|---|
| 103 | if (ad->sws){ |
|---|
| 104 | ms_sws_freeContext (ad->sws); |
|---|
| 105 | ad->sws=NULL; |
|---|
| 106 | } |
|---|
| 107 | } |
|---|
| 108 | |
|---|
| 109 | ms_layout_compute(wsize,vsize,vsize,-1,0,&vrect, NULL); |
|---|
| 110 | |
|---|
| 111 | if (ad->sws==NULL){ |
|---|
| 112 | ad->sws=ms_sws_getContext (vsize.width,vsize.height,PIX_FMT_YUV420P, |
|---|
| 113 | vrect.w,vrect.h,PIX_FMT_RGB565,SWS_BILINEAR,NULL,NULL,NULL); |
|---|
| 114 | if (ad->sws==NULL){ |
|---|
| 115 | ms_fatal("Could not obtain sws context !"); |
|---|
| 116 | } |
|---|
| 117 | } |
|---|
| 118 | if (AndroidBitmap_lockPixels(ad->jenv,ad->jbitmap,&pixels)==0){ |
|---|
| 119 | dest.planes[0]=(uint8_t*)pixels+(vrect.y*ad->bmpinfo.stride)+(vrect.x*2); |
|---|
| 120 | dest.strides[0]=ad->bmpinfo.stride; |
|---|
| 121 | ms_sws_scale (ad->sws,pic.planes,pic.strides,0,pic.h,dest.planes,dest.strides); |
|---|
| 122 | AndroidBitmap_unlockPixels(ad->jenv,ad->jbitmap); |
|---|
| 123 | }else{ |
|---|
| 124 | ms_error("AndroidBitmap_lockPixels() failed !"); |
|---|
| 125 | } |
|---|
| 126 | ms_message("Ask draw of bitmap"); |
|---|
| 127 | (*ad->jenv)->CallVoidMethod(ad->jenv,ad->android_video_window,ad->update_id); |
|---|
| 128 | } |
|---|
| 129 | } |
|---|
| 130 | } |
|---|
| 131 | ms_filter_unlock(f); |
|---|
| 132 | |
|---|
| 133 | end: |
|---|
| 134 | ms_queue_flush(f->inputs[0]); |
|---|
| 135 | ms_queue_flush(f->inputs[1]); |
|---|
| 136 | } |
|---|
| 137 | |
|---|
| 138 | static int android_display_set_window(MSFilter *f, void *arg){ |
|---|
| 139 | AndroidDisplay *ad=(AndroidDisplay*)f->data; |
|---|
| 140 | unsigned long id=*(unsigned long*)arg; |
|---|
| 141 | int err; |
|---|
| 142 | JNIEnv *jenv=NULL; |
|---|
| 143 | jobject window=(jobject)id; |
|---|
| 144 | |
|---|
| 145 | if ((*(ad->jvm))->AttachCurrentThread(ad->jvm,&jenv,NULL)!=0){ |
|---|
| 146 | ms_error("Could not get JNIEnv"); |
|---|
| 147 | return -1; |
|---|
| 148 | } |
|---|
| 149 | |
|---|
| 150 | ms_filter_lock(f); |
|---|
| 151 | ad->jbitmap=(*jenv)->CallObjectMethod(jenv,window,ad->get_bitmap_id); |
|---|
| 152 | ad->android_video_window=window; |
|---|
| 153 | err=AndroidBitmap_getInfo(jenv,ad->jbitmap,&ad->bmpinfo); |
|---|
| 154 | if (err!=0){ |
|---|
| 155 | ms_error("AndroidBitmap_getInfo() failed."); |
|---|
| 156 | ad->jbitmap=0; |
|---|
| 157 | ms_filter_unlock(f); |
|---|
| 158 | return -1; |
|---|
| 159 | } |
|---|
| 160 | ms_filter_unlock(f); |
|---|
| 161 | ms_message("New java bitmap given with w=%i,h=%i,stride=%i,format=%i", |
|---|
| 162 | ad->bmpinfo.width,ad->bmpinfo.height,ad->bmpinfo.stride,ad->bmpinfo.format); |
|---|
| 163 | } |
|---|
| 164 | |
|---|
| 165 | static MSFilterMethod methods[]={ |
|---|
| 166 | { MS_VIDEO_DISPLAY_SET_NATIVE_WINDOW_ID , android_display_set_window }, |
|---|
| 167 | { 0, NULL} |
|---|
| 168 | }; |
|---|
| 169 | |
|---|
| 170 | MSFilterDesc ms_android_display_desc={ |
|---|
| 171 | .id=MS_ANDROID_DISPLAY_ID, |
|---|
| 172 | .name="MSAndroidDisplay", |
|---|
| 173 | .text="Video display filter for Android.", |
|---|
| 174 | .category=MS_FILTER_OTHER, |
|---|
| 175 | .ninputs=2, /*number of inputs*/ |
|---|
| 176 | .noutputs=0, /*number of outputs*/ |
|---|
| 177 | .init=android_display_init, |
|---|
| 178 | .preprocess=android_display_preprocess, |
|---|
| 179 | .process=android_display_process, |
|---|
| 180 | .uninit=android_display_uninit |
|---|
| 181 | }; |
|---|
| 182 | |
|---|
| 183 | void libmsandroiddisplay_init(void){ |
|---|
| 184 | ms_filter_register(&ms_android_display_desc); |
|---|
| 185 | } |
|---|
| 186 | |
|---|
| 187 | |
|---|