| 1 /*************************************************************************** |
|
| 2 * mssdlout.c |
|
| 3 * |
|
| 4 * Mon Jul 11 16:17:59 2005 |
|
| 5 * Copyright 2005 Simon Morlat |
|
| 6 * Email simon dot morlat at linphone dot org |
|
| 7 ****************************************************************************/ |
|
| 8 |
|
| 9 /* |
|
| 10 The mediastreamer library aims at providing modular media processing and I/O |
|
| 11 for linphone, but also for any telephony application. |
|
| 12 Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org |
|
| 13 |
|
| 14 This library is free software; you can redistribute it and/or |
|
| 15 modify it under the terms of the GNU Lesser General Public |
|
| 16 License as published by the Free Software Foundation; either |
|
| 17 version 2.1 of the License, or (at your option) any later version. |
|
| 18 |
|
| 19 This library is distributed in the hope that it will be useful, |
|
| 20 but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
| 22 Lesser General Public License for more details. |
|
| 23 |
|
| 24 You should have received a copy of the GNU Lesser General Public |
|
| 25 License along with this library; if not, write to the Free Software |
|
| 26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
| 27 */ |
|
| 28 |
|
| 29 #include "mssdlout.h" |
|
| 30 |
|
| 31 MSSdlOutClass *ms_sdl_out_class=NULL; |
|
| 32 |
|
| 33 void ms_sdl_out_init(MSSdlOut *obj){ |
|
| 34 ms_filter_init(MS_FILTER(obj)); |
|
| 35 obj->width=VIDEO_SIZE_CIF_W; |
|
| 36 obj->height=VIDEO_SIZE_CIF_H; |
|
| 37 obj->format="RGB24"; |
|
| 38 obj->use_yuv=FALSE; |
|
| 39 obj->oldinm1=NULL; |
|
| 40 MS_FILTER(obj)->inqueues=obj->input; |
|
| 41 } |
|
| 42 |
|
| 43 void ms_sdl_out_set_format(MSSdlOut *obj, const char *fmt){ |
|
| 44 obj->format=fmt; |
|
| 45 if (strcmp(fmt,"YUV420P")==0) obj->use_yuv=TRUE; |
|
| 46 else obj->use_yuv=FALSE; |
|
| 47 } |
|
| 48 |
|
| 49 void ms_sdl_uninit_sdl(MSSdlOut *obj){ |
|
| 50 if (obj->overlay!=NULL){ |
|
| 51 SDL_FreeYUVOverlay(obj->overlay); |
|
| 52 obj->overlay=NULL; |
|
| 53 } |
|
| 54 if (obj->screen!=NULL){ |
|
| 55 SDL_FreeSurface(obj->screen); |
|
| 56 obj->screen=NULL; |
|
| 57 } |
|
| 58 |
|
| 59 } |
|
| 60 |
|
| 61 void ms_sdl_out_uninit(MSSdlOut *obj){ |
|
| 62 ms_sdl_uninit_sdl(obj); |
|
| 63 } |
|
| 64 |
|
| 65 void ms_sdl_out_destroy(MSSdlOut *obj){ |
|
| 66 ms_sdl_out_uninit(obj); |
|
| 67 if (obj->oldinm1!=NULL) ms_message_destroy(obj->oldinm1); |
|
| 68 g_free(obj); |
|
| 69 } |
|
| 70 |
|
| 71 void ms_sdl_init_sdl(MSSdlOut *obj){ |
|
| 72 if (strcmp(obj->format,"RGB24")==0){ |
|
| 73 }else{ |
|
| 74 obj->use_yuv=TRUE; |
|
| 75 } |
|
| 76 obj->screen = SDL_SetVideoMode(obj->width, obj->height, 0,SDL_HWSURFACE|SDL_ANYFORMAT); |
|
| 77 if ( obj->screen == NULL ) { |
|
| 78 g_warning("Couldn't set video mode: %s\n", |
|
| 79 SDL_GetError()); |
|
| 80 return ; |
|
| 81 } |
|
| 82 if (obj->screen->flags & SDL_HWSURFACE) g_message("SDL surface created in hardware"); |
|
| 83 SDL_WM_SetCaption("Linphone Video", NULL); |
|
| 84 |
|
| 85 if (obj->use_yuv){ |
|
| 86 g_message("Using yuv overlay."); |
|
| 87 obj->overlay=SDL_CreateYUVOverlay(obj->width,obj->height,SDL_IYUV_OVERLAY,obj->screen); |
|
| 88 if (obj->overlay==NULL){ |
|
| 89 g_warning("Couldn't create yuv overlay: %s\n", |
|
| 90 SDL_GetError()); |
|
| 91 }else{ |
|
| 92 if (obj->overlay->hw_overlay) g_message("YUV overlay using hardware acceleration."); |
|
| 93 } |
|
| 94 } |
|
| 95 |
|
| 96 } |
|
| 97 |
|
| 98 static void resize_yuv_small(char *pict, int w, int h, int scale){ |
|
| 99 int i,j,id,jd; |
|
| 100 int nh,nw; |
|
| 101 char *smallpict; |
|
| 102 int ysize,usize,ydsize,udsize; |
|
| 103 int smallpict_sz; |
|
| 104 char *dptr,*sptr; |
|
| 105 nw=w/scale; |
|
| 106 nh=h/scale; |
|
| 107 ysize=w*h; |
|
| 108 usize=ysize/4; |
|
| 109 ydsize=nw*nh; |
|
| 110 udsize=ydsize/4; |
|
| 111 smallpict_sz=(ydsize*3)/2; |
|
| 112 smallpict=(char*)alloca(smallpict_sz); |
|
| 113 memset(smallpict,0,smallpict_sz); |
|
| 114 |
|
| 115 |
|
| 116 dptr=smallpict; |
|
| 117 sptr=pict; |
|
| 118 for (j=0,jd=0;j<nh;j++,jd+=scale){ |
|
| 119 for (i=0,id=0;i<nw;i++,id+=scale){ |
|
| 120 dptr[(j*nw) + i]=sptr[(jd*w)+id]; |
|
| 121 } |
|
| 122 } |
|
| 123 |
|
| 124 nh=nh/2; |
|
| 125 nw=nw/2; |
|
| 126 w=w/2; |
|
| 127 h=h/2; |
|
| 128 dptr+=ydsize; |
|
| 129 sptr+=ysize; |
|
| 130 for (j=0,jd=0;j<nh;j++,jd+=scale){ |
|
| 131 for (i=0,id=0;i<nw;i++,id+=scale){ |
|
| 132 dptr[(j*nw) + i]=sptr[(jd*w)+id]; |
|
| 133 } |
|
| 134 } |
|
| 135 dptr+=udsize; |
|
| 136 sptr+=usize; |
|
| 137 for (j=0,jd=0;j<nh;j++,jd+=scale){ |
|
| 138 for (i=0,id=0;i<nw;i++,id+=scale){ |
|
| 139 dptr[(j*nw) + i]=sptr[(jd*w)+id]; |
|
| 140 } |
|
| 141 } |
|
| 142 |
|
| 143 memcpy(pict,smallpict,smallpict_sz); |
|
| 144 } |
|
| 145 |
|
| 146 static void fill_overlay_at_pos(SDL_Overlay *lay, MSMessage *m, int x, int y, int w, int h){ |
|
| 147 char *data=(char*)m->data; |
|
| 148 int i,j; |
|
| 149 int jlim,ilim; |
|
| 150 int off; |
|
| 151 char *dptr; |
|
| 152 |
|
| 153 ilim=MIN(x+w,lay->w); |
|
| 154 jlim=MIN(y+h,lay->h); |
|
| 155 SDL_LockYUVOverlay(lay); |
|
| 156 /* set Y */ |
|
| 157 dptr=lay->pixels[0]; |
|
| 158 for (j=y;j<jlim;j++){ |
|
| 159 off=j*lay->w; |
|
| 160 for (i=x;i<ilim;i++){ |
|
| 161 dptr[off + i]=*data; |
|
| 162 data++; |
|
| 163 } |
|
| 164 } |
|
| 165 /*set U and V*/ |
|
| 166 ilim=ilim/2; |
|
| 167 jlim=jlim/2; |
|
| 168 dptr=lay->pixels[1]; |
|
| 169 for (j=y/2;j<jlim;j++){ |
|
| 170 off=j*(lay->w/2); |
|
| 171 for (i=x/2;i<ilim;i++){ |
|
| 172 dptr[off + i]=*data; |
|
| 173 data++; |
|
| 174 } |
|
| 175 } |
|
| 176 dptr=lay->pixels[2]; |
|
| 177 for (j=y/2;j<jlim;j++){ |
|
| 178 off=j*(lay->w/2); |
|
| 179 for (i=x/2;i<ilim;i++){ |
|
| 180 dptr[off + i]=*data; |
|
| 181 data++; |
|
| 182 } |
|
| 183 } |
|
| 184 SDL_UnlockYUVOverlay(lay); |
|
| 185 } |
|
| 186 |
|
| 187 static void fill_overlay(SDL_Overlay *lay, MSMessage *m){ |
|
| 188 |
|
| 189 int w2,h2; |
|
| 190 char *data=(char*)m->data; |
|
| 191 int ysize=lay->w*lay->h; |
|
| 192 int usize; |
|
| 193 w2=lay->w/2; |
|
| 194 h2=lay->h/2; |
|
| 195 usize=w2*h2; |
|
| 196 SDL_LockYUVOverlay(lay); |
|
| 197 memcpy(lay->pixels[0],data,ysize); |
|
| 198 memcpy(lay->pixels[1],data+ysize,usize); |
|
| 199 memcpy(lay->pixels[2],data+ysize+usize,usize); |
|
| 200 SDL_UnlockYUVOverlay(lay); |
|
| 201 } |
|
| 202 |
|
| 203 #define SCALE_FACTOR 6 |
|
| 204 |
|
| 205 void ms_sdl_out_process(MSSdlOut *obj){ |
|
| 206 MSQueue *q0=obj->input[0]; |
|
| 207 MSQueue *q1=obj->input[1]; |
|
| 208 MSMessage *inm0=NULL; |
|
| 209 MSMessage *inm1=NULL; |
|
| 210 int err; |
|
| 211 SDL_Rect smallrect; |
|
| 212 SDL_Rect rect; |
|
| 213 rect.w=obj->width; |
|
| 214 rect.h=obj->height; |
|
| 215 rect.x=0; |
|
| 216 rect.y=0; |
|
| 217 smallrect.w=obj->width/SCALE_FACTOR; |
|
| 218 smallrect.h=obj->height/SCALE_FACTOR; |
|
| 219 smallrect.x=obj->width - smallrect.w ; |
|
| 220 smallrect.y=obj->height -smallrect.h; |
|
| 221 |
|
| 222 if (obj->screen==NULL){ |
|
| 223 ms_sdl_init_sdl(obj); |
|
| 224 } |
|
| 225 |
|
| 226 if (q0!=NULL) |
|
| 227 inm0=ms_queue_get(q0); |
|
| 228 if (q1!=NULL) |
|
| 229 inm1=ms_queue_get(q1); |
|
| 230 |
|
| 231 if (inm0!=NULL){ |
|
| 232 SDL_Surface *surf; |
|
| 233 if (obj->use_yuv){ |
|
| 234 |
|
| 235 fill_overlay(obj->overlay,inm0); |
|
| 236 |
|
| 237 }else { |
|
| 238 surf=SDL_CreateRGBSurfaceFrom(inm0->data,obj->width,obj->height,24,obj->width*3,0,0,0,0); |
|
| 239 |
|
| 240 err=SDL_BlitSurface(surf,NULL,obj->screen,NULL); |
|
| 241 if (err<0) g_warning("Fail to blit surface: %s",SDL_GetError()); |
|
| 242 SDL_FreeSurface(surf); |
|
| 243 } |
|
| 244 ms_message_destroy(inm0); |
|
| 245 } |
|
| 246 if (inm1!=NULL){ |
|
| 247 /* this message is blitted on the right,bottom corner of the screen */ |
|
| 248 SDL_Surface *surf; |
|
| 249 |
|
| 250 if (obj->use_yuv){ |
|
| 251 resize_yuv_small(inm1->data,rect.w,rect.h,SCALE_FACTOR); |
|
| 252 fill_overlay_at_pos(obj->overlay,inm1,smallrect.x, smallrect.y, smallrect.w, smallrect.h); |
|
| 253 }else { |
|
| 254 surf=SDL_CreateRGBSurfaceFrom(inm1->data,obj->width,obj->height,24,obj->width*3,0,0,0,0); |
|
| 255 |
|
| 256 err=SDL_BlitSurface(surf,NULL,obj->screen,&smallrect); |
|
| 257 if (err<0) g_warning("Fail to blit surface: %s",SDL_GetError()); |
|
| 258 SDL_FreeSurface(surf); |
|
| 259 } |
|
| 260 if (obj->oldinm1!=NULL) { |
|
| 261 ms_message_destroy(obj->oldinm1); |
|
| 262 } |
|
| 263 obj->oldinm1=inm1; |
|
| 264 |
|
| 265 }else{ |
|
| 266 /* this is the case were we have only inm0, we have to redisplay inm1 */ |
|
| 267 if (obj->use_yuv){ |
|
| 268 if (obj->oldinm1!=NULL){ |
|
| 269 fill_overlay_at_pos(obj->overlay,obj->oldinm1,smallrect.x, smallrect.y, smallrect.w, smallrect.h); |
|
| 270 } |
|
| 271 } |
|
| 272 } |
|
| 273 |
|
| 274 if (obj->use_yuv) SDL_DisplayYUVOverlay(obj->overlay,&rect); |
|
| 275 SDL_UpdateRect(obj->screen,0,0,obj->width,obj->height); |
|
| 276 |
|
| 277 } |
|
| 278 |
|
| 279 void ms_sdl_out_class_init(MSSdlOutClass *klass){ |
|
| 280 MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_sdl_out_process; |
|
| 281 MS_FILTER_CLASS(klass)->max_qinputs=2; |
|
| 282 MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_sdl_out_destroy; |
|
| 283 MS_FILTER_CLASS(klass)->name="MSSdlOut"; |
|
| 284 /* Initialize the SDL library */ |
|
| 285 if( SDL_Init(SDL_INIT_VIDEO) < 0 ) { |
|
| 286 fprintf(stderr, |
|
| 287 "Couldn't initialize SDL: %s\n", SDL_GetError()); |
|
| 288 return; |
|
| 289 } |
|
| 290 /* Clean up on exit */ |
|
| 291 atexit(SDL_Quit); |
|
| 292 } |
|
| 293 |
|
| 294 MSFilter * ms_sdl_out_new(void){ |
|
| 295 MSSdlOut *obj=g_new0(MSSdlOut,1); |
|
| 296 if (ms_sdl_out_class==NULL){ |
|
| 297 ms_sdl_out_class=g_new0(MSSdlOutClass,1); |
|
| 298 ms_sdl_out_class_init(ms_sdl_out_class); |
|
| 299 } |
|
| 300 MS_FILTER(obj)->klass=MS_FILTER_CLASS(ms_sdl_out_class); |
|
| 301 ms_sdl_out_init(obj); |
|
| 302 return MS_FILTER(obj); |
|
| 303 } |
|