source: mediastreamer2/linphone/mediastreamer2/src/videoout.c @ 152:994ae61ef42c

Last change on this file since 152:994ae61ef42c was 152:994ae61ef42c, checked in by smorlat <smorlat@…>, 5 years ago

fiw bug when using libswscale, and optimize.

git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@155 3f6dc0c8-ddfe-455d-9043-3cd528dc4637

File size: 20.2 KB
Line 
1/*
2mediastreamer2 library - modular sound and video processing and streaming
3Copyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)
4
5This program is free software; you can redistribute it and/or
6modify it under the terms of the GNU General Public License
7as published by the Free Software Foundation; either version 2
8of the License, or (at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18*/
19
20#ifdef HAVE_CONFIG_H
21#include "mediastreamer-config.h"
22#endif
23
24#include "mediastreamer2/msfilter.h"
25#include "mediastreamer2/msvideo.h"
26#include "mediastreamer2/msvideoout.h"
27
28#include "ffmpeg-priv.h"
29
30static int video_out_set_vsize(MSFilter *f,void *arg);
31
32bool_t ms_display_poll_event(MSDisplay *d, MSDisplayEvent *ev){
33        if (d->desc->pollevent)
34                return d->desc->pollevent(d,ev);
35        else return FALSE;
36}
37
38#ifdef HAVE_SDL
39
40#include <SDL/SDL.h>
41#include <SDL/SDL_video.h>
42
43static bool_t sdl_initialized=FALSE;
44
45static ms_mutex_t sdl_mutex;
46
47static SDL_Surface *sdl_screen=0;
48
49#ifdef HAVE_X11_XLIB_H
50
51#include <SDL/SDL_syswm.h>
52
53static void sdl_show_window(bool_t show){
54        SDL_SysWMinfo info;
55        SDL_VERSION(&info.version);
56        if ( SDL_GetWMInfo(&info) ) {
57                if ( info.subsystem == SDL_SYSWM_X11 ) {
58                        Display *display;
59                        Window window;
60               
61                        info.info.x11.lock_func();
62                        display = info.info.x11.display;
63                        window = info.info.x11.wmwindow;
64                        if (show)
65                                XMapWindow(display,window);
66                        else
67                                XUnmapWindow(display,window);
68                        info.info.x11.unlock_func();
69                }
70        }
71}
72
73#else
74
75static void sdl_show_window(bool_t show){
76        ms_warning("SDL window show/hide not implemented");
77}
78
79#endif
80
81static void sdl_display_uninit(MSDisplay *obj);
82
83static SDL_Overlay * sdl_create_window(int w, int h){
84        SDL_Overlay *lay;
85        sdl_screen = SDL_SetVideoMode(w,h, 0,SDL_SWSURFACE|SDL_RESIZABLE);
86        if (sdl_screen == NULL ) {
87                ms_warning("Couldn't set video mode: %s\n",
88                                                SDL_GetError());
89                return NULL;
90        }
91        if (sdl_screen->flags & SDL_HWSURFACE) ms_message("SDL surface created in hardware");
92        SDL_WM_SetCaption("Linphone Video", NULL);
93        ms_message("Using yuv overlay.");
94        lay=SDL_CreateYUVOverlay(w , h ,SDL_YV12_OVERLAY,sdl_screen);
95        if (lay==NULL){
96                ms_warning("Couldn't create yuv overlay: %s\n",
97                                                SDL_GetError());
98                return NULL;
99        }else{
100                ms_message("%i x %i YUV overlay created: hw_accel=%i, pitches=%i,%i,%i",lay->w,lay->h,lay->hw_overlay,
101                        lay->pitches[0],lay->pitches[1],lay->pitches[2]);
102                ms_message("planes= %p %p %p  %i %i",lay->pixels[0],lay->pixels[1],lay->pixels[2],
103                        lay->pixels[1]-lay->pixels[0],lay->pixels[2]-lay->pixels[1]);
104        }
105        return lay;
106}
107
108static bool_t sdl_display_init(MSDisplay *obj, MSPicture *fbuf){
109        SDL_Overlay *lay;
110        if (!sdl_initialized){
111                /* Initialize the SDL library */
112                if( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
113                        ms_error("Couldn't initialize SDL: %s", SDL_GetError());
114                        return FALSE;
115                }
116                /* Clean up on exit */
117                atexit(SDL_Quit);
118                sdl_initialized=TRUE;
119                ms_mutex_init(&sdl_mutex,NULL);
120        }
121        if (obj->data!=NULL){
122                SDL_FreeYUVOverlay((SDL_Overlay*)obj->data);
123        }
124       
125        lay=sdl_create_window(fbuf->w, fbuf->h);
126        if (lay){
127                fbuf->planes[0]=lay->pixels[0];
128                fbuf->planes[1]=lay->pixels[2];
129                fbuf->planes[2]=lay->pixels[1];
130                fbuf->strides[0]=lay->pitches[0];
131                fbuf->strides[1]=lay->pitches[2];
132                fbuf->strides[2]=lay->pitches[1];
133                fbuf->w=lay->w;
134                fbuf->h=lay->h;
135                obj->data=lay;
136                sdl_show_window(TRUE);
137                return TRUE;
138        }
139        return FALSE;
140}
141
142static void sdl_display_lock(MSDisplay *obj){
143        ms_mutex_lock(&sdl_mutex);
144        SDL_LockYUVOverlay((SDL_Overlay*)obj->data);
145        ms_mutex_unlock(&sdl_mutex);
146}
147
148static void sdl_display_unlock(MSDisplay *obj){
149        SDL_Overlay *lay=(SDL_Overlay*)obj->data;
150        ms_mutex_lock(&sdl_mutex);
151        SDL_UnlockYUVOverlay(lay);
152        ms_mutex_unlock(&sdl_mutex);
153}
154
155static void sdl_display_update(MSDisplay *obj){
156        SDL_Rect rect;
157        SDL_Overlay *lay=(SDL_Overlay*)obj->data;
158        rect.x=0;
159        rect.y=0;
160        rect.w=lay->w;
161        rect.h=lay->h;
162        ms_mutex_lock(&sdl_mutex);
163        SDL_DisplayYUVOverlay(lay,&rect);
164        ms_mutex_unlock(&sdl_mutex);
165}
166
167static bool_t sdl_poll_event(MSDisplay *obj, MSDisplayEvent *ev){
168        SDL_Event event;
169        bool_t ret=FALSE;
170        if (sdl_screen==NULL) return FALSE;
171        ms_mutex_lock(&sdl_mutex);
172        if (SDL_PollEvent(&event)){
173                ms_mutex_unlock(&sdl_mutex);
174                switch(event.type){
175                        case SDL_VIDEORESIZE:
176                                ev->evtype=MS_DISPLAY_RESIZE_EVENT;
177                                ev->w=event.resize.w;
178                                ev->h=event.resize.h;
179                                return TRUE;
180                        break;
181                        default:
182                        break;
183                }
184        }else ms_mutex_unlock(&sdl_mutex);
185        return ret;
186}
187
188static void sdl_display_uninit(MSDisplay *obj){
189        SDL_Overlay *lay=(SDL_Overlay*)obj->data;
190        if (lay==NULL)
191                return;
192        if (lay!=NULL)
193                SDL_FreeYUVOverlay(lay);
194        if (sdl_screen!=NULL){
195                SDL_FreeSurface(sdl_screen);
196                sdl_screen=NULL;
197        }
198        sdl_show_window(FALSE);
199}
200
201MSDisplayDesc ms_sdl_display_desc={
202        .init=sdl_display_init,
203        .lock=sdl_display_lock,
204        .unlock=sdl_display_unlock,
205        .update=sdl_display_update,
206        .uninit=sdl_display_uninit,
207        .pollevent=sdl_poll_event
208};
209
210#elif defined(WIN32)
211
212#include <Vfw.h>
213
214
215typedef struct _WinDisplay{
216        HWND window;
217        HDRAWDIB ddh;
218        MSPicture fb;
219        MSDisplayEvent last_rsz;
220        uint8_t *rgb;
221        int rgb_len;
222        struct SwsContext *sws;
223        bool_t new_ev;
224}WinDisplay;
225
226static LRESULT CALLBACK window_proc(
227    HWND hwnd,        // handle to window
228    UINT uMsg,        // message identifier
229    WPARAM wParam,    // first message parameter
230    LPARAM lParam)    // second message parameter
231{
232        switch(uMsg){
233                case WM_DESTROY:
234                break;
235                case WM_SIZE:
236                        if (wParam==SIZE_RESTORED){
237                                int h=(lParam>>16) & 0xffff;
238                                int w=lParam & 0xffff;
239                                MSDisplay *obj;
240                                WinDisplay *wd;
241                                ms_message("Resized to %i,%i",w,h);
242                                obj=(MSDisplay*)GetWindowLongPtr(hwnd,GWLP_USERDATA);
243                                if (obj!=NULL){
244                                        wd=(WinDisplay*)obj->data;
245                                        wd->last_rsz.evtype=MS_DISPLAY_RESIZE_EVENT;
246                                        wd->last_rsz.w=w;
247                                        wd->last_rsz.h=h;
248                                        wd->new_ev=TRUE;
249                                }else{
250                                        ms_error("Could not retrieve MSDisplay from window !");
251                                }
252                        }
253                break;
254                default:
255                        return DefWindowProc(hwnd, uMsg, wParam, lParam);
256        }
257        return 0;
258}
259
260static HWND create_window(int w, int h)
261{
262        WNDCLASS wc;
263        HINSTANCE hInstance = GetModuleHandle(NULL);
264        HWND hwnd;
265        RECT rect;
266        wc.style = 0 ;
267        wc.lpfnWndProc = window_proc;
268        wc.cbClsExtra = 0;
269        wc.cbWndExtra = 0;
270        wc.hInstance = NULL;
271        wc.hIcon = NULL;
272        wc.hCursor = LoadCursor(hInstance, IDC_ARROW);
273        wc.hbrBackground = NULL;
274        wc.lpszMenuName =  NULL;
275        wc.lpszClassName = "Video Window";
276       
277        if(!RegisterClass(&wc))
278        {
279                /* already registred! */
280        }
281        rect.left=100;
282        rect.top=100;
283        rect.right=rect.left+w;
284        rect.bottom=rect.top+h;
285        if (!AdjustWindowRect(&rect,WS_OVERLAPPEDWINDOW|WS_VISIBLE /*WS_CAPTION WS_TILED|WS_BORDER*/,FALSE)){
286                ms_error("AdjustWindowRect failed.");
287        }
288        ms_message("AdjustWindowRect: %li,%li %li,%li",rect.left,rect.top,rect.right,rect.bottom);
289        hwnd=CreateWindow("Video Window", "Video window", WS_OVERLAPPEDWINDOW|WS_VISIBLE ,
290                                                CW_USEDEFAULT, CW_USEDEFAULT, rect.right-rect.left,rect.bottom-rect.top,
291                                                                                                        NULL, NULL, hInstance, NULL);
292        if (hwnd==NULL){
293                ms_error("Fail to create video window");
294        }
295        return hwnd;
296}
297
298static bool_t win_display_init(MSDisplay *obj, MSPicture *fbuf){
299        WinDisplay *wd=(WinDisplay*)obj->data;
300        int ysize,usize;
301
302        if (wd!=NULL)
303        {
304                if (wd->ddh) DrawDibClose(wd->ddh);
305                wd->ddh=NULL;
306                if (wd->fb.planes[0]) ms_free(wd->fb.planes[0]);
307                wd->fb.planes[0]=NULL;
308                wd->fb.planes[1]=NULL;
309                wd->fb.planes[2]=NULL;
310                if (wd->rgb) ms_free(wd->rgb);
311                wd->rgb=NULL;
312                wd->rgb_len=0;
313                sws_freeContext(wd->sws);
314                wd->sws=NULL;
315        }
316        else
317                wd=(WinDisplay*)ms_new0(WinDisplay,1);
318       
319        obj->data=wd;
320       
321        wd->fb.w=fbuf->w;
322        wd->fb.h=fbuf->h;
323       
324        if (wd->window==NULL){
325                if (obj->window_id!=0){
326                        void *p;
327                        wd->window=(HWND)obj->window_id;
328                        p=(void*)GetWindowLongPtr(wd->window,GWLP_USERDATA);
329                        if (p!=NULL){
330                                ms_error("Gulp: this externally supplied windows seems to "
331                                        "already have a userdata ! resizing will crash !");
332                        }else SetWindowLongPtr(wd->window,GWLP_USERDATA,(LONG_PTR)obj);
333                }else{
334                        wd->window=create_window(wd->fb.w,wd->fb.h);
335                        if (wd->window!=NULL) SetWindowLongPtr(wd->window,GWLP_USERDATA,(LONG_PTR)obj);
336                        else return FALSE;
337                }
338        }
339       
340        if (wd->ddh==NULL) wd->ddh=DrawDibOpen();
341        if (wd->ddh==NULL){
342                ms_error("DrawDibOpen() failed.");
343                return FALSE;
344        }
345        /*allocate yuv and rgb buffers*/
346        if (wd->fb.planes[0]) ms_free(wd->fb.planes[0]);
347        if (wd->rgb) ms_free(wd->rgb);
348        ysize=wd->fb.w*wd->fb.h;
349        usize=ysize/4;
350        fbuf->planes[0]=wd->fb.planes[0]=(uint8_t*)ms_malloc0(ysize+2*usize);
351        fbuf->planes[1]=wd->fb.planes[1]=wd->fb.planes[0]+ysize;
352        fbuf->planes[2]=wd->fb.planes[2]=wd->fb.planes[1]+usize;
353        fbuf->strides[0]=wd->fb.strides[0]=wd->fb.w;
354        fbuf->strides[1]=wd->fb.strides[1]=wd->fb.w/2;
355        fbuf->strides[2]=wd->fb.strides[2]=wd->fb.w/2;
356
357        wd->rgb_len=ysize*3;
358        wd->rgb=(uint8_t*)ms_malloc0(wd->rgb_len);
359        return TRUE;
360}
361
362typedef struct rgb{
363        uint8_t r,g,b;
364} rgb_t;
365
366typedef struct yuv{
367        uint8_t y,u,v;
368} yuv_t;
369
370
371
372static void yuv420p_to_rgb(WinDisplay *wd, MSPicture *src, uint8_t *rgb){
373        int rgb_stride=-src->w*3;
374        uint8_t *p;
375
376        p=rgb+(src->w*3*(src->h-1));
377        if (wd->sws==NULL){
378                wd->sws=sws_getContext(src->w,src->h,PIX_FMT_YUV420P,
379                        src->w,src->h,PIX_FMT_BGR24,
380                        0, NULL, NULL, NULL);
381        }
382        if (sws_scale(wd->sws,src->planes,src->strides, 0,
383                                src->h, &p, &rgb_stride)<0){
384                ms_error("Error in 420->rgb sws_scale().");
385        }
386}
387
388static void win_display_update(MSDisplay *obj){
389        WinDisplay *wd=(WinDisplay*)obj->data;
390        HDC hdc;
391        BITMAPINFOHEADER bi;
392        RECT rect;
393        MSG msg;
394        bool_t ret;
395        if (wd->window==NULL) return;
396        hdc=GetDC(wd->window);
397        if (hdc==NULL) {
398                ms_error("Could not get window dc");
399                return;
400        }
401        yuv420p_to_rgb(&wd->fb, wd->rgb);
402        memset(&bi,0,sizeof(bi));
403        bi.biSize=sizeof(bi);
404        GetClientRect(wd->window,&rect);
405        /*
406        bi.biWidth=wd->fb.w;
407        bi.biHeight=wd->fb.h;
408        bi.biPlanes=3;
409        bi.biBitCount=12;
410        bi.biCompression=MAKEFOURCC('I','4','2','0');
411        bi.biSizeImage=(wd->fb.w*wd->fb.h*3)/2;
412        */
413        bi.biWidth=wd->fb.w;
414        bi.biHeight=wd->fb.h;
415        bi.biPlanes=1;
416        bi.biBitCount=24;
417        bi.biCompression=BI_RGB;
418        bi.biSizeImage=wd->rgb_len;
419
420        //if (bi.biHeight>rect.bottom)
421        //      bi.biHeight=rect.bottom;
422        //bi.biSizeImage=(bi.biWidth*bi.biHeight)*3;
423
424        ret=DrawDibDraw(wd->ddh,hdc,0,0,
425                //bi.biWidth,bi.biHeight,
426                rect.right,rect.bottom,
427                &bi,wd->rgb,
428                //0,0,rect.right,rect.bottom,0);
429                0,0,bi.biWidth,bi.biHeight,0);
430       
431        if (!ret) ms_error("DrawDibDraw failed.");
432        ReleaseDC(NULL,hdc);
433        while (PeekMessage(&msg, wd->window, 0, 0, PM_REMOVE) != 0)
434        {
435                  TranslateMessage(&msg);
436                  DispatchMessage(&msg);
437        }
438}
439
440static void win_display_uninit(MSDisplay *obj){
441        WinDisplay *wd=(WinDisplay*)obj->data;
442        if (wd==NULL)
443                return;
444        if (wd->window && !obj->window_id) DestroyWindow(wd->window);
445        if (wd->ddh) DrawDibClose(wd->ddh);
446        if (wd->fb.planes[0]) ms_free(wd->fb.planes[0]);
447        if (wd->rgb) ms_free(wd->rgb);
448        if (wd->sws) sws_freeContext(wd->sws);
449        ms_free(wd);
450}
451
452bool_t win_display_pollevent(MSDisplay *d, MSDisplayEvent *ev){
453        return FALSE;
454}
455
456#ifdef _MSC_VER
457
458extern MSDisplayDesc ms_win_display_desc={
459        win_display_init,
460        NULL,
461        NULL,
462        win_display_update,
463        win_display_uninit,
464        win_display_pollevent
465};
466
467#else
468
469MSDisplayDesc ms_win_display_desc={
470        .init=win_display_init,
471        .update=win_display_update,
472        .uninit=win_display_uninit,
473        .pollevent=win_display_pollevent
474};
475
476#endif
477
478#endif
479
480MSDisplay *ms_display_new(MSDisplayDesc *desc){
481        MSDisplay *obj=(MSDisplay *)ms_new0(MSDisplay,1);
482        obj->desc=desc;
483        obj->data=NULL;
484        return obj;
485}
486
487void ms_display_set_window_id(MSDisplay *d, long id){
488        d->window_id=id;
489}
490
491void ms_display_destroy(MSDisplay *obj){
492        obj->desc->uninit(obj);
493        ms_free(obj);
494}
495
496#ifdef HAVE_SDL
497static MSDisplayDesc *default_display_desc=&ms_sdl_display_desc;
498#elif defined(WIN32)
499static MSDisplayDesc *default_display_desc=&ms_win_display_desc;
500#else
501static MSDisplayDesc *default_display_desc=NULL;
502#endif
503
504void ms_display_desc_set_default(MSDisplayDesc *desc){
505        default_display_desc=desc;
506}
507
508MSDisplayDesc * ms_display_desc_get_default(void){
509        return default_display_desc;
510}
511
512void ms_display_desc_set_default_window_id(MSDisplayDesc *desc, long id){
513        desc->default_window_id=id;
514}
515
516typedef struct VideoOut
517{
518        AVRational ratio;
519        MSPicture fbuf;
520        MSPicture local_pic;
521        MSRect local_rect;
522        mblk_t *local_msg;
523        int corner;
524        struct SwsContext *sws1;
525        struct SwsContext *sws2;
526        MSDisplay *display;
527        bool_t own_display;
528        bool_t ready;
529        bool_t autofit;
530} VideoOut;
531
532
533#define SCALE_FACTOR 6
534
535static void set_corner(VideoOut *s, int corner)
536{
537        s->corner=corner;
538        s->local_pic.w=(s->fbuf.w/SCALE_FACTOR) & ~0x1;
539        s->local_pic.h=(s->fbuf.h/SCALE_FACTOR) & ~0x1;
540        if (corner==1)
541        {
542        /* top left corner */
543        s->local_rect.x=0;
544        s->local_rect.y=0;
545        s->local_rect.w=s->local_pic.w;
546        s->local_rect.h=s->local_pic.h;
547        }
548        else if (corner==2)
549        {
550        /* top right corner */
551        s->local_rect.x=s->fbuf.w-s->local_pic.w;
552        s->local_rect.y=0;
553        s->local_rect.w=s->local_pic.w;
554        s->local_rect.h=s->local_pic.h;
555        }
556        else if (corner==3)
557        {
558        /* bottom left corner */
559        s->local_rect.x=0;
560        s->local_rect.y=s->fbuf.h-s->local_pic.h;
561        s->local_rect.w=s->local_pic.w;
562        s->local_rect.h=s->local_pic.h;
563        }
564        else
565        {
566        /* default: bottom right corner */
567        /* corner can be set to -1: to disable the self view... */
568        s->local_rect.x=s->fbuf.w-s->local_pic.w;
569        s->local_rect.y=s->fbuf.h-s->local_pic.h;
570        s->local_rect.w=s->local_pic.w;
571        s->local_rect.h=s->local_pic.h;
572        }
573}
574
575static void set_vsize(VideoOut *s, MSVideoSize *sz){
576        s->fbuf.w=sz->width & ~0x1;
577        s->fbuf.h=sz->height & ~0x1;
578        set_corner(s,s->corner);
579        ms_message("Video size set to %ix%i",s->fbuf.w,s->fbuf.h);
580}
581
582static void video_out_init(MSFilter  *f){
583        VideoOut *obj=(VideoOut*)ms_new(VideoOut,1);
584        MSVideoSize def_size;
585        obj->ratio.num=11;
586        obj->ratio.den=9;
587        def_size.width=MS_VIDEO_SIZE_CIF_W;
588        def_size.height=MS_VIDEO_SIZE_CIF_H;
589        obj->local_msg=NULL;
590        obj->corner=0;
591        obj->sws1=NULL;
592        obj->sws2=NULL;
593        obj->display=NULL;
594        obj->own_display=FALSE;
595        obj->ready=FALSE;
596        obj->autofit=FALSE;
597        set_vsize(obj,&def_size);
598        f->data=obj;
599}
600
601
602static void video_out_uninit(MSFilter *f){
603        VideoOut *obj=(VideoOut*)f->data;
604        if (obj->display!=NULL && obj->own_display)
605                ms_display_destroy(obj->display);
606        if (obj->sws1!=NULL){
607                sws_freeContext(obj->sws1);
608                obj->sws1=NULL;
609        }
610        if (obj->sws2!=NULL){
611                sws_freeContext(obj->sws2);
612                obj->sws2=NULL;
613        }
614        if (obj->local_msg!=NULL) {
615                freemsg(obj->local_msg);
616                obj->local_msg=NULL;
617        }
618        ms_free(obj);
619}
620
621static void video_out_prepare(MSFilter *f){
622        VideoOut *obj=(VideoOut*)f->data;
623        if (obj->display==NULL){
624                obj->display=ms_display_new(default_display_desc);
625                obj->own_display=TRUE;
626        }
627        if (!ms_display_init(obj->display,&obj->fbuf)){
628                if (obj->own_display) ms_display_destroy(obj->display);
629                obj->display=NULL;
630        }
631        if (obj->sws1!=NULL){
632                sws_freeContext(obj->sws1);
633                obj->sws1=NULL;
634        }
635        if (obj->sws2!=NULL){
636                sws_freeContext(obj->sws2);
637                obj->sws2=NULL;
638        }
639        if (obj->local_msg!=NULL) {
640                freemsg(obj->local_msg);
641                obj->local_msg=NULL;
642        }
643        set_corner(obj,obj->corner);
644        obj->ready=TRUE;
645}
646
647static int video_out_handle_resizing(MSFilter *f, void *data){
648        VideoOut *s=(VideoOut*)f->data;
649        MSDisplay *disp=s->display;
650        if (disp!=NULL){
651                MSDisplayEvent ev;
652                if (ms_display_poll_event(disp,&ev)){
653                        if (ev.evtype==MS_DISPLAY_RESIZE_EVENT){
654                                MSVideoSize sz;
655                                sz.width=ev.w;
656                                sz.height=ev.h;
657                                ms_filter_lock(f);
658                                set_vsize(s,&sz);
659                                s->ready=FALSE;
660                                ms_filter_unlock(f);
661                        }
662                }
663        }
664        return 0;
665}
666
667static void video_out_postprocess(MSFilter *f){
668}
669
670
671static void video_out_process(MSFilter *f){
672        VideoOut *obj=(VideoOut*)f->data;
673        mblk_t *inm;
674
675        ms_filter_lock(f);
676        if (!obj->ready) video_out_prepare(f);
677        if (obj->display==NULL){
678                ms_filter_unlock(f);
679                if (f->inputs[0]!=NULL)
680                        ms_queue_flush(f->inputs[0]);
681                if (f->inputs[1]!=NULL)
682                        ms_queue_flush(f->inputs[1]);
683                return;
684        }
685        /*get most recent message and draw it*/
686        if (f->inputs[1]!=NULL && (inm=ms_queue_peek_last(f->inputs[1]))!=0) {
687                if (obj->corner==-1){
688                        if (obj->local_msg!=NULL) {
689                                freemsg(obj->local_msg);
690                                obj->local_msg=NULL;
691                        }
692                }else{
693                        MSPicture src;
694                        if (yuv_buf_init_from_mblk(&src,inm)==0){
695                       
696                                if (obj->sws2==NULL){
697                                        obj->sws2=sws_getContext(src.w,src.h,PIX_FMT_YUV420P,
698                                                                obj->local_pic.w,obj->local_pic.h,PIX_FMT_YUV420P,
699                                                                SWS_FAST_BILINEAR, NULL, NULL, NULL);
700                                }
701                                if (obj->local_msg==NULL){
702                                        obj->local_msg=yuv_buf_alloc(&obj->local_pic,
703                                                obj->local_pic.w,obj->local_pic.h);
704                                }
705                                if (sws_scale(obj->sws2,src.planes,src.strides, 0,
706                                        src.h, obj->local_pic.planes, obj->local_pic.strides)<0){
707                                        ms_error("Error in sws_scale().");
708                                }
709                                if (!mblk_get_precious_flag(inm)) yuv_buf_mirror(&obj->local_pic);
710                        }
711                }
712                ms_queue_flush(f->inputs[1]);
713        }
714       
715        if (f->inputs[0]!=NULL && (inm=ms_queue_peek_last(f->inputs[0]))!=0) {
716                MSPicture src;
717                if (yuv_buf_init_from_mblk(&src,inm)==0){
718                        if (obj->sws1==NULL){
719                                MSVideoSize cur,newsize;
720                                cur.width=obj->fbuf.w;
721                                cur.height=obj->fbuf.h;
722                                newsize.width=src.w;
723                                newsize.height=src.h;
724                                if (obj->autofit && (ms_video_size_greater_than(newsize,cur) && 
725                                        !ms_video_size_equal(newsize,cur) ) ){
726                                        set_vsize(obj,&newsize);
727                                        video_out_prepare(f);
728                                        obj->autofit=FALSE;
729                                }
730                                obj->sws1=sws_getContext(src.w,src.h,PIX_FMT_YUV420P,
731                                obj->fbuf.w,obj->fbuf.h,PIX_FMT_YUV420P,
732                                SWS_FAST_BILINEAR, NULL, NULL, NULL);
733                        }
734                        ms_display_lock(obj->display);
735                        if (sws_scale(obj->sws1,src.planes,src.strides, 0,
736                                src.h, obj->fbuf.planes, obj->fbuf.strides)<0){
737                                ms_error("Error in sws_scale().");
738                        }
739                        ms_display_unlock(obj->display);
740                }
741                ms_queue_flush(f->inputs[0]);
742        }
743        /*copy resized local view into main buffer, at bottom left corner:*/
744        if (obj->local_msg!=NULL){
745                MSPicture corner=obj->fbuf;
746                MSVideoSize roi;
747                roi.width=obj->local_pic.w;
748                roi.height=obj->local_pic.h;
749                corner.w=obj->local_pic.w;
750                corner.h=obj->local_pic.h;
751                corner.planes[0]+=obj->local_rect.x+(obj->local_rect.y*corner.strides[0]);
752                corner.planes[1]+=(obj->local_rect.x/2)+((obj->local_rect.y/2)*corner.strides[1]);
753                corner.planes[2]+=(obj->local_rect.x/2)+((obj->local_rect.y/2)*corner.strides[2]);
754                ms_display_lock(obj->display);
755                yuv_buf_copy(obj->local_pic.planes,obj->local_pic.strides,
756                                corner.planes,corner.strides,roi);
757                ms_display_unlock(obj->display);
758        }
759        ms_display_update(obj->display);
760        ms_filter_unlock(f);
761}
762
763static int video_out_set_vsize(MSFilter *f,void *arg){
764        VideoOut *s=(VideoOut*)f->data;
765        ms_filter_lock(f);
766        set_vsize(s,(MSVideoSize*)arg);
767        ms_filter_unlock(f);
768        return 0;
769}
770
771static int video_out_set_display(MSFilter *f,void *arg){
772        VideoOut *s=(VideoOut*)f->data;
773        s->display=(MSDisplay*)arg;
774        return 0;
775}
776
777static int video_out_auto_fit(MSFilter *f, void *arg){
778        VideoOut *s=(VideoOut*)f->data;
779        s->autofit=*(int*)arg;
780        return 0;
781}
782
783static int video_out_set_corner(MSFilter *f,void *arg){
784        VideoOut *s=(VideoOut*)f->data;
785        ms_filter_lock(f);
786        set_corner(s, *(int*)arg);
787        ms_display_lock(s->display);
788        {
789          int w=s->fbuf.w;
790          int h=s->fbuf.h;
791          int ysize=w*h;
792          int usize=ysize/4;
793         
794          memset(s->fbuf.planes[0], 0, ysize);
795          memset(s->fbuf.planes[1], 0, usize);
796          memset(s->fbuf.planes[2], 0, usize);
797        }
798        ms_display_unlock(s->display);
799        ms_filter_unlock(f);
800        return 0;
801}
802
803static MSFilterMethod methods[]={
804        {       MS_FILTER_SET_VIDEO_SIZE        ,       video_out_set_vsize },
805        {       MS_VIDEO_OUT_SET_DISPLAY        ,       video_out_set_display},
806        {       MS_VIDEO_OUT_SET_CORNER         ,       video_out_set_corner},
807        {       MS_VIDEO_OUT_AUTO_FIT           ,       video_out_auto_fit},
808        {       MS_VIDEO_OUT_HANDLE_RESIZING    ,       video_out_handle_resizing},
809        {       0       ,NULL}
810};
811
812#ifdef _MSC_VER
813
814MSFilterDesc ms_video_out_desc={
815        MS_VIDEO_OUT_ID,
816        "MSVideoOut",
817        "A generic video display",
818        MS_FILTER_OTHER,
819        NULL,
820        2,
821        0,
822        video_out_init,
823        NULL,
824        video_out_process,
825        video_out_postprocess,
826        video_out_uninit,
827        methods,
828        MS_FILTER_IS_PUMP
829};
830
831#else
832
833MSFilterDesc ms_video_out_desc={
834        .id=MS_VIDEO_OUT_ID,
835        .name="MSVideoOut",
836        .text="A generic video display",
837        .category=MS_FILTER_OTHER,
838        .ninputs=2,
839        .noutputs=0,
840        .init=video_out_init,
841        .preprocess=NULL,
842        .process=video_out_process,
843        .postprocess=video_out_postprocess,
844        .uninit=video_out_uninit,
845        .methods=methods,
846        .flags=MS_FILTER_IS_PUMP
847};
848
849#endif
850
851MS_FILTER_DESC_EXPORT(ms_video_out_desc)
Note: See TracBrowser for help on using the repository browser.