📄 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"/*required for dllexport of win_display_desc */#define INVIDEOUT_C 1#include "mediastreamer2/msvideoout.h"#include "ffmpeg-priv.h"static int video_out_set_vsize(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;}#ifdef HAVE_SDL#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 long sdl_get_native_window_id(){ SDL_SysWMinfo info; SDL_VERSION(&info.version); if ( SDL_GetWMInfo(&info) ) { if ( info.subsystem == SDL_SYSWM_X11 ) { return (long) info.info.x11.wmwindow; } } return 0;}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");}static long sdl_get_native_window_id(){ ms_warning("sdl_get_native_window_id not implemented"); return 0;}#endifstatic void sdl_display_uninit(MSDisplay *obj);static 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("Video window", 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{ ms_message("%i x %i YUV overlay created: hw_accel=%i, pitches=%i,%i,%i",lay->w,lay->h,lay->hw_overlay, lay->pitches[0],lay->pitches[1],lay->pitches[2]); ms_message("planes= %p %p %p %i %i",lay->pixels[0],lay->pixels[1],lay->pixels[2], lay->pixels[1]-lay->pixels[0],lay->pixels[2]-lay->pixels[1]); } 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]; fbuf->w=lay->w; fbuf->h=lay->h; obj->data=lay; sdl_show_window(TRUE); obj->window_id=sdl_get_native_window_id(); 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; bool_t ret=FALSE; if (sdl_screen==NULL) return FALSE; ms_mutex_lock(&sdl_mutex); if (SDL_PollEvent(&event)){ ms_mutex_unlock(&sdl_mutex); switch(event.type){ case SDL_VIDEORESIZE: ev->evtype=MS_DISPLAY_RESIZE_EVENT; ev->w=event.resize.w; ev->h=event.resize.h; return TRUE; break; default: break; } }else ms_mutex_unlock(&sdl_mutex); 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,};#elif defined(WIN32)#include <Vfw.h>typedef struct _WinDisplay{ HWND window; HDRAWDIB ddh; MSPicture fb; MSDisplayEvent last_rsz; uint8_t *rgb; int rgb_len; struct SwsContext *sws; 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_THICKFRAME|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; sws_freeContext(wd->sws); wd->sws=NULL; } 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->use_external_window && 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); obj->window_id=(long)wd->window; if (wd->window!=NULL) SetWindowLongPtr(wd->window,GWLP_USERDATA,(LONG_PTR)obj); else return FALSE; } }else if (!obj->use_external_window){ /* the window might need to be resized*/ RECT cur; GetWindowRect(wd->window,&cur); MoveWindow(wd->window,cur.left, cur.top, wd->fb.w, wd->fb.h,TRUE); } 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(WinDisplay *wd, MSPicture *src, uint8_t *rgb){ int rgb_stride=-src->w*3; uint8_t *p; p=rgb+(src->w*3*(src->h-1)); if (wd->sws==NULL){ wd->sws=sws_getContext(src->w,src->h,PIX_FMT_YUV420P, src->w,src->h,PIX_FMT_BGR24, 0, NULL, NULL, NULL); } if (sws_scale(wd->sws,src->planes,src->strides, 0, src->h, &p, &rgb_stride)<0){ ms_error("Error in 420->rgb sws_scale()."); }}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, &wd->fb, wd->rgb); memset(&bi,0,sizeof(bi)); bi.biSize=sizeof(bi); GetClientRect(wd->window,&rect); /* bi.biWidth=wd->fb.w; bi.biHeight=wd->fb.h; bi.biPlanes=3; bi.biBitCount=12; bi.biCompression=MAKEFOURCC('I','4','2','0'); bi.biSizeImage=(wd->fb.w*wd->fb.h*3)/2; */ bi.biWidth=wd->fb.w; bi.biHeight=wd->fb.h; bi.biPlanes=1; bi.biBitCount=24; bi.biCompression=BI_RGB; bi.biSizeImage=wd->rgb_len; //if (bi.biHeight>rect.bottom) // bi.biHeight=rect.bottom; //bi.biSizeImage=(bi.biWidth*bi.biHeight)*3; ret=DrawDibDraw(wd->ddh,hdc,0,0, //bi.biWidth,bi.biHeight, rect.right,rect.bottom, &bi,wd->rgb, //0,0,rect.right,rect.bottom,0); 0,0,bi.biWidth,bi.biHeight,0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -