📄 videoout.c
字号:
/*mediastreamer2 library - modular sound and video processing and streamingCopyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org)This program is free software; you can redistribute it and/ormodify it under the terms of the GNU General Public Licenseas published by the Free Software Foundation; either version 2of the License, or (at your option) any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/#ifdef HAVE_CONFIG_H#include "mediastreamer-config.h"#endif#include "mediastreamer2/msfilter.h"#include "mediastreamer2/msvideo.h"#include "mediastreamer2/msvideoout.h"#include "ffmpeg-priv.h"static int video_out_handle_resize(MSFilter *f, void *arg);bool_t ms_display_poll_event(MSDisplay *d, MSDisplayEvent *ev){ if (d->desc->pollevent) return d->desc->pollevent(d,ev); else return FALSE;}#ifndef WIN32#include <SDL/SDL.h>#include <SDL/SDL_video.h>static bool_t sdl_initialized=FALSE;static ms_mutex_t sdl_mutex;static SDL_Surface *sdl_screen=0;#ifdef HAVE_X11_XLIB_H#include <SDL/SDL_syswm.h>static void sdl_show_window(bool_t show){ SDL_SysWMinfo info; SDL_VERSION(&info.version); if ( SDL_GetWMInfo(&info) ) { if ( info.subsystem == SDL_SYSWM_X11 ) { Display *display; Window window; info.info.x11.lock_func(); display = info.info.x11.display; window = info.info.x11.wmwindow; if (show) XMapWindow(display,window); else XUnmapWindow(display,window); info.info.x11.unlock_func(); } }}#elsestatic void sdl_show_window(bool_t show){ ms_warning("SDL window show/hide not implemented");}#endifstatic SDL_Overlay * sdl_create_window(int w, int h){ SDL_Overlay *lay; sdl_screen = SDL_SetVideoMode(w,h, 0,SDL_SWSURFACE|SDL_RESIZABLE); if (sdl_screen == NULL ) { ms_warning("Couldn't set video mode: %s\n", SDL_GetError()); return NULL; } if (sdl_screen->flags & SDL_HWSURFACE) ms_message("SDL surface created in hardware"); SDL_WM_SetCaption("Linphone Video", NULL); ms_message("Using yuv overlay."); lay=SDL_CreateYUVOverlay(w,h,SDL_YV12_OVERLAY,sdl_screen); if (lay==NULL){ ms_warning("Couldn't create yuv overlay: %s\n", SDL_GetError()); return NULL; }else{ if (lay->hw_overlay) ms_message("YUV overlay using hardware acceleration."); } return lay;}static bool_t sdl_display_init(MSDisplay *obj, MSPicture *fbuf){ SDL_Overlay *lay; if (!sdl_initialized){ /* Initialize the SDL library */ if( SDL_Init(SDL_INIT_VIDEO) < 0 ) { ms_error("Couldn't initialize SDL: %s", SDL_GetError()); return FALSE; } /* Clean up on exit */ atexit(SDL_Quit); sdl_initialized=TRUE; ms_mutex_init(&sdl_mutex,NULL); } if (obj->data!=NULL) SDL_FreeYUVOverlay((SDL_Overlay*)obj->data); lay=sdl_create_window(fbuf->w, fbuf->h); if (lay){ fbuf->planes[0]=lay->pixels[0]; fbuf->planes[1]=lay->pixels[2]; fbuf->planes[2]=lay->pixels[1]; fbuf->strides[0]=lay->pitches[0]; fbuf->strides[1]=lay->pitches[2]; fbuf->strides[2]=lay->pitches[1]; obj->data=lay; sdl_show_window(TRUE); return TRUE; } return FALSE;}static void sdl_display_lock(MSDisplay *obj){ ms_mutex_lock(&sdl_mutex); SDL_LockYUVOverlay((SDL_Overlay*)obj->data); ms_mutex_unlock(&sdl_mutex);}static void sdl_display_unlock(MSDisplay *obj){ SDL_Overlay *lay=(SDL_Overlay*)obj->data; ms_mutex_lock(&sdl_mutex); SDL_UnlockYUVOverlay(lay); ms_mutex_unlock(&sdl_mutex);}static void sdl_display_update(MSDisplay *obj){ SDL_Rect rect; SDL_Overlay *lay=(SDL_Overlay*)obj->data; rect.x=0; rect.y=0; rect.w=lay->w; rect.h=lay->h; ms_mutex_lock(&sdl_mutex); SDL_DisplayYUVOverlay(lay,&rect); ms_mutex_unlock(&sdl_mutex);}static bool_t sdl_poll_event(MSDisplay *obj, MSDisplayEvent *ev){ SDL_Event event; static MSDisplayEvent last_ev; static struct timeval tv; static bool_t got_rs_ev=FALSE; struct timeval cur; int elapsed; bool_t ret=FALSE; ms_mutex_lock(&sdl_mutex); if (SDL_PollEvent(&event)){ ms_mutex_unlock(&sdl_mutex); switch(event.type){ case SDL_VIDEORESIZE: last_ev.evtype=MS_DISPLAY_RESIZE_EVENT; last_ev.w=event.resize.w; last_ev.h=event.resize.h; got_rs_ev=TRUE; gettimeofday(&tv,NULL); break; default: break; } }else ms_mutex_unlock(&sdl_mutex); if (got_rs_ev){ gettimeofday(&cur,NULL); elapsed=((cur.tv_sec-tv.tv_sec)*1000) + ((cur.tv_usec-tv.tv_usec)/1000); if (elapsed>1000){ got_rs_ev=FALSE; *ev=last_ev; ret=TRUE; } } return ret;}static void sdl_display_uninit(MSDisplay *obj){ SDL_Overlay *lay=(SDL_Overlay*)obj->data; if (lay==NULL) return; if (lay!=NULL) SDL_FreeYUVOverlay(lay); if (sdl_screen!=NULL){ SDL_FreeSurface(sdl_screen); sdl_screen=NULL; } sdl_show_window(FALSE);}MSDisplayDesc ms_sdl_display_desc={ .init=sdl_display_init, .lock=sdl_display_lock, .unlock=sdl_display_unlock, .update=sdl_display_update, .uninit=sdl_display_uninit, .pollevent=sdl_poll_event};#else#include <Vfw.h>typedef struct _WinDisplay{ HWND window; HDRAWDIB ddh; MSPicture fb; MSDisplayEvent last_rsz; uint8_t *rgb; int rgb_len; bool_t new_ev;}WinDisplay;static LRESULT CALLBACK window_proc( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam) // second message parameter{ switch(uMsg){ case WM_DESTROY: break; case WM_SIZE: if (wParam==SIZE_RESTORED){ int h=(lParam>>16) & 0xffff; int w=lParam & 0xffff; MSDisplay *obj; WinDisplay *wd; ms_message("Resized to %i,%i",w,h); obj=(MSDisplay*)GetWindowLongPtr(hwnd,GWLP_USERDATA); if (obj!=NULL){ wd=(WinDisplay*)obj->data; wd->last_rsz.evtype=MS_DISPLAY_RESIZE_EVENT; wd->last_rsz.w=w; wd->last_rsz.h=h; wd->new_ev=TRUE; }else{ ms_error("Could not retrieve MSDisplay from window !"); } } break; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } return 0;}static HWND create_window(int w, int h){ WNDCLASS wc; HINSTANCE hInstance = GetModuleHandle(NULL); HWND hwnd; RECT rect; wc.style = 0 ; wc.lpfnWndProc = window_proc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = NULL; wc.hIcon = NULL; wc.hCursor = LoadCursor(hInstance, IDC_ARROW); wc.hbrBackground = NULL; wc.lpszMenuName = NULL; wc.lpszClassName = "Video Window"; if(!RegisterClass(&wc)) { /* already registred! */ } rect.left=100; rect.top=100; rect.right=rect.left+w; rect.bottom=rect.top+h; if (!AdjustWindowRect(&rect,WS_OVERLAPPEDWINDOW|WS_VISIBLE /*WS_CAPTION WS_TILED|WS_BORDER*/,FALSE)){ ms_error("AdjustWindowRect failed."); } ms_message("AdjustWindowRect: %li,%li %li,%li",rect.left,rect.top,rect.right,rect.bottom); hwnd=CreateWindow("Video Window", "Video window", WS_OVERLAPPEDWINDOW|WS_VISIBLE , CW_USEDEFAULT, CW_USEDEFAULT, rect.right-rect.left,rect.bottom-rect.top, NULL, NULL, hInstance, NULL); if (hwnd==NULL){ ms_error("Fail to create video window"); } return hwnd;}static bool_t win_display_init(MSDisplay *obj, MSPicture *fbuf){ WinDisplay *wd=(WinDisplay*)obj->data; int ysize,usize; if (wd!=NULL) { if (wd->ddh) DrawDibClose(wd->ddh); wd->ddh=NULL; if (wd->fb.planes[0]) ms_free(wd->fb.planes[0]); wd->fb.planes[0]=NULL; wd->fb.planes[1]=NULL; wd->fb.planes[2]=NULL; if (wd->rgb) ms_free(wd->rgb); wd->rgb=NULL; wd->rgb_len=0; } else wd=(WinDisplay*)ms_new0(WinDisplay,1); obj->data=wd; wd->fb.w=fbuf->w; wd->fb.h=fbuf->h; if (wd->window==NULL){ if (obj->window_id!=0){ void *p; wd->window=(HWND)obj->window_id; p=(void*)GetWindowLongPtr(wd->window,GWLP_USERDATA); if (p!=NULL){ ms_error("Gulp: this externally supplied windows seems to " "already have a userdata ! resizing will crash !"); }else SetWindowLongPtr(wd->window,GWLP_USERDATA,(LONG_PTR)obj); }else{ wd->window=create_window(wd->fb.w,wd->fb.h); if (wd->window!=NULL) SetWindowLongPtr(wd->window,GWLP_USERDATA,(LONG_PTR)obj); else return FALSE; } } if (wd->ddh==NULL) wd->ddh=DrawDibOpen(); if (wd->ddh==NULL){ ms_error("DrawDibOpen() failed."); return FALSE; } /*allocate yuv and rgb buffers*/ if (wd->fb.planes[0]) ms_free(wd->fb.planes[0]); if (wd->rgb) ms_free(wd->rgb); ysize=wd->fb.w*wd->fb.h; usize=ysize/4; fbuf->planes[0]=wd->fb.planes[0]=(uint8_t*)ms_malloc0(ysize+2*usize); fbuf->planes[1]=wd->fb.planes[1]=wd->fb.planes[0]+ysize; fbuf->planes[2]=wd->fb.planes[2]=wd->fb.planes[1]+usize; fbuf->strides[0]=wd->fb.strides[0]=wd->fb.w; fbuf->strides[1]=wd->fb.strides[1]=wd->fb.w/2; fbuf->strides[2]=wd->fb.strides[2]=wd->fb.w/2; wd->rgb_len=ysize*3; wd->rgb=(uint8_t*)ms_malloc0(wd->rgb_len); return TRUE;}typedef struct rgb{ uint8_t r,g,b;} rgb_t;typedef struct yuv{ uint8_t y,u,v;} yuv_t;static void yuv420p_to_rgb(MSPicture *src, uint8_t *rgb){ struct SwsContext *sws; int rgb_stride=-src->w*3; uint8_t *p; p=rgb+(src->w*3*(src->h-1)); sws=sws_getContext(src->w,src->h,PIX_FMT_YUV420P, src->w,src->h,PIX_FMT_RGB24, 0, NULL, NULL, NULL); if (sws_scale(sws,src->planes,src->strides, 0, 0, &p, &rgb_stride)<0){ ms_error("Error in 420->rgb sws_scale()."); } sws_freeContext(sws); /*revert colors*/ { int i,j,stride; rgb_t pix; stride=src->w*3; p=rgb; for(i=0;i<src->h;++i){ for(j=0;j<stride;j+=3){ pix.r=p[j]; pix.g=p[j+1]; pix.b=p[j+2]; p[j]=pix.b; p[j+2]=pix.r; } p+=stride; } }}static void win_display_update(MSDisplay *obj){ WinDisplay *wd=(WinDisplay*)obj->data; HDC hdc; BITMAPINFOHEADER bi; RECT rect; bool_t ret; if (wd->window==NULL) return; hdc=GetDC(wd->window); if (hdc==NULL) { ms_error("Could not get window dc"); return; } yuv420p_to_rgb(&wd->fb, wd->rgb); memset(&bi,0,sizeof(bi));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -