linphone-iphone/linphone/mediastreamer/mssdlout.c
aymeric 2b8200409c Initial import
git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@1 3f6dc0c8-ddfe-455d-9043-3cd528dc4637
2008-09-04 15:47:34 +00:00

303 lines
7.5 KiB
C

/***************************************************************************
* mssdlout.c
*
* Mon Jul 11 16:17:59 2005
* Copyright 2005 Simon Morlat
* Email simon dot morlat at linphone dot org
****************************************************************************/
/*
The mediastreamer library aims at providing modular media processing and I/O
for linphone, but also for any telephony application.
Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "mssdlout.h"
MSSdlOutClass *ms_sdl_out_class=NULL;
void ms_sdl_out_init(MSSdlOut *obj){
ms_filter_init(MS_FILTER(obj));
obj->width=VIDEO_SIZE_CIF_W;
obj->height=VIDEO_SIZE_CIF_H;
obj->format="RGB24";
obj->use_yuv=FALSE;
obj->oldinm1=NULL;
MS_FILTER(obj)->inqueues=obj->input;
}
void ms_sdl_out_set_format(MSSdlOut *obj, const char *fmt){
obj->format=fmt;
if (strcmp(fmt,"YUV420P")==0) obj->use_yuv=TRUE;
else obj->use_yuv=FALSE;
}
void ms_sdl_uninit_sdl(MSSdlOut *obj){
if (obj->overlay!=NULL){
SDL_FreeYUVOverlay(obj->overlay);
obj->overlay=NULL;
}
if (obj->screen!=NULL){
SDL_FreeSurface(obj->screen);
obj->screen=NULL;
}
}
void ms_sdl_out_uninit(MSSdlOut *obj){
ms_sdl_uninit_sdl(obj);
}
void ms_sdl_out_destroy(MSSdlOut *obj){
ms_sdl_out_uninit(obj);
if (obj->oldinm1!=NULL) ms_message_destroy(obj->oldinm1);
g_free(obj);
}
void ms_sdl_init_sdl(MSSdlOut *obj){
if (strcmp(obj->format,"RGB24")==0){
}else{
obj->use_yuv=TRUE;
}
obj->screen = SDL_SetVideoMode(obj->width, obj->height, 0,SDL_HWSURFACE|SDL_ANYFORMAT);
if ( obj->screen == NULL ) {
g_warning("Couldn't set video mode: %s\n",
SDL_GetError());
return ;
}
if (obj->screen->flags & SDL_HWSURFACE) g_message("SDL surface created in hardware");
SDL_WM_SetCaption("Linphone Video", NULL);
if (obj->use_yuv){
g_message("Using yuv overlay.");
obj->overlay=SDL_CreateYUVOverlay(obj->width,obj->height,SDL_IYUV_OVERLAY,obj->screen);
if (obj->overlay==NULL){
g_warning("Couldn't create yuv overlay: %s\n",
SDL_GetError());
}else{
if (obj->overlay->hw_overlay) g_message("YUV overlay using hardware acceleration.");
}
}
}
static void resize_yuv_small(char *pict, int w, int h, int scale){
int i,j,id,jd;
int nh,nw;
char *smallpict;
int ysize,usize,ydsize,udsize;
int smallpict_sz;
char *dptr,*sptr;
nw=w/scale;
nh=h/scale;
ysize=w*h;
usize=ysize/4;
ydsize=nw*nh;
udsize=ydsize/4;
smallpict_sz=(ydsize*3)/2;
smallpict=(char*)alloca(smallpict_sz);
memset(smallpict,0,smallpict_sz);
dptr=smallpict;
sptr=pict;
for (j=0,jd=0;j<nh;j++,jd+=scale){
for (i=0,id=0;i<nw;i++,id+=scale){
dptr[(j*nw) + i]=sptr[(jd*w)+id];
}
}
nh=nh/2;
nw=nw/2;
w=w/2;
h=h/2;
dptr+=ydsize;
sptr+=ysize;
for (j=0,jd=0;j<nh;j++,jd+=scale){
for (i=0,id=0;i<nw;i++,id+=scale){
dptr[(j*nw) + i]=sptr[(jd*w)+id];
}
}
dptr+=udsize;
sptr+=usize;
for (j=0,jd=0;j<nh;j++,jd+=scale){
for (i=0,id=0;i<nw;i++,id+=scale){
dptr[(j*nw) + i]=sptr[(jd*w)+id];
}
}
memcpy(pict,smallpict,smallpict_sz);
}
static void fill_overlay_at_pos(SDL_Overlay *lay, MSMessage *m, int x, int y, int w, int h){
char *data=(char*)m->data;
int i,j;
int jlim,ilim;
int off;
char *dptr;
ilim=MIN(x+w,lay->w);
jlim=MIN(y+h,lay->h);
SDL_LockYUVOverlay(lay);
/* set Y */
dptr=lay->pixels[0];
for (j=y;j<jlim;j++){
off=j*lay->w;
for (i=x;i<ilim;i++){
dptr[off + i]=*data;
data++;
}
}
/*set U and V*/
ilim=ilim/2;
jlim=jlim/2;
dptr=lay->pixels[1];
for (j=y/2;j<jlim;j++){
off=j*(lay->w/2);
for (i=x/2;i<ilim;i++){
dptr[off + i]=*data;
data++;
}
}
dptr=lay->pixels[2];
for (j=y/2;j<jlim;j++){
off=j*(lay->w/2);
for (i=x/2;i<ilim;i++){
dptr[off + i]=*data;
data++;
}
}
SDL_UnlockYUVOverlay(lay);
}
static void fill_overlay(SDL_Overlay *lay, MSMessage *m){
int w2,h2;
char *data=(char*)m->data;
int ysize=lay->w*lay->h;
int usize;
w2=lay->w/2;
h2=lay->h/2;
usize=w2*h2;
SDL_LockYUVOverlay(lay);
memcpy(lay->pixels[0],data,ysize);
memcpy(lay->pixels[1],data+ysize,usize);
memcpy(lay->pixels[2],data+ysize+usize,usize);
SDL_UnlockYUVOverlay(lay);
}
#define SCALE_FACTOR 6
void ms_sdl_out_process(MSSdlOut *obj){
MSQueue *q0=obj->input[0];
MSQueue *q1=obj->input[1];
MSMessage *inm0=NULL;
MSMessage *inm1=NULL;
int err;
SDL_Rect smallrect;
SDL_Rect rect;
rect.w=obj->width;
rect.h=obj->height;
rect.x=0;
rect.y=0;
smallrect.w=obj->width/SCALE_FACTOR;
smallrect.h=obj->height/SCALE_FACTOR;
smallrect.x=obj->width - smallrect.w ;
smallrect.y=obj->height -smallrect.h;
if (obj->screen==NULL){
ms_sdl_init_sdl(obj);
}
if (q0!=NULL)
inm0=ms_queue_get(q0);
if (q1!=NULL)
inm1=ms_queue_get(q1);
if (inm0!=NULL){
SDL_Surface *surf;
if (obj->use_yuv){
fill_overlay(obj->overlay,inm0);
}else {
surf=SDL_CreateRGBSurfaceFrom(inm0->data,obj->width,obj->height,24,obj->width*3,0,0,0,0);
err=SDL_BlitSurface(surf,NULL,obj->screen,NULL);
if (err<0) g_warning("Fail to blit surface: %s",SDL_GetError());
SDL_FreeSurface(surf);
}
ms_message_destroy(inm0);
}
if (inm1!=NULL){
/* this message is blitted on the right,bottom corner of the screen */
SDL_Surface *surf;
if (obj->use_yuv){
resize_yuv_small(inm1->data,rect.w,rect.h,SCALE_FACTOR);
fill_overlay_at_pos(obj->overlay,inm1,smallrect.x, smallrect.y, smallrect.w, smallrect.h);
}else {
surf=SDL_CreateRGBSurfaceFrom(inm1->data,obj->width,obj->height,24,obj->width*3,0,0,0,0);
err=SDL_BlitSurface(surf,NULL,obj->screen,&smallrect);
if (err<0) g_warning("Fail to blit surface: %s",SDL_GetError());
SDL_FreeSurface(surf);
}
if (obj->oldinm1!=NULL) {
ms_message_destroy(obj->oldinm1);
}
obj->oldinm1=inm1;
}else{
/* this is the case were we have only inm0, we have to redisplay inm1 */
if (obj->use_yuv){
if (obj->oldinm1!=NULL){
fill_overlay_at_pos(obj->overlay,obj->oldinm1,smallrect.x, smallrect.y, smallrect.w, smallrect.h);
}
}
}
if (obj->use_yuv) SDL_DisplayYUVOverlay(obj->overlay,&rect);
SDL_UpdateRect(obj->screen,0,0,obj->width,obj->height);
}
void ms_sdl_out_class_init(MSSdlOutClass *klass){
MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_sdl_out_process;
MS_FILTER_CLASS(klass)->max_qinputs=2;
MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_sdl_out_destroy;
MS_FILTER_CLASS(klass)->name="MSSdlOut";
/* Initialize the SDL library */
if( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
fprintf(stderr,
"Couldn't initialize SDL: %s\n", SDL_GetError());
return;
}
/* Clean up on exit */
atexit(SDL_Quit);
}
MSFilter * ms_sdl_out_new(void){
MSSdlOut *obj=g_new0(MSSdlOut,1);
if (ms_sdl_out_class==NULL){
ms_sdl_out_class=g_new0(MSSdlOutClass,1);
ms_sdl_out_class_init(ms_sdl_out_class);
}
MS_FILTER(obj)->klass=MS_FILTER_CLASS(ms_sdl_out_class);
ms_sdl_out_init(obj);
return MS_FILTER(obj);
}