SDLRenderer.cpp

00001 /*********************************************************************** 00002 * * 00003 * ViTooKi * 00004 * * 00005 * title: SDLRenderer.cpp * 00006 * * 00007 * * 00008 * * 00009 * ITEC institute of the University of Klagenfurt (Austria) * 00010 * http://www.itec.uni-klu.ac.at * 00011 * * 00012 * * 00013 * For more information visit the ViTooKi homepage: * 00014 * http://ViTooKi.sourceforge.net * 00015 * vitooki-user@lists.sourceforge.net * 00016 * vitooki-devel@lists.sourceforge.net * 00017 * * 00018 * This file is part of ViTooKi, a free video toolkit. * 00019 * ViTooKi is free software; you can redistribute it and/or * 00020 * modify it under the terms of the GNU General Public License * 00021 * as published by the Free Software Foundation; either version 2 * 00022 * of the License, or (at your option) any later version. * 00023 * * 00024 * This program is distributed in the hope that it will be useful, * 00025 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00026 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00027 * GNU General Public License for more details. * 00028 * * 00029 * You should have received a copy of the GNU General Public License * 00030 * along with this program; if not, write to the Free Software * 00031 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * 00032 * MA 02111-1307, USA. * 00033 * * 00034 ***********************************************************************/ 00035 00036 /*********************************************************************** 00037 * * 00038 * REVISION HISTORY: * 00039 * * 00040 * $Id: SDLRenderer.cpp,v 1.36 2006/06/22 10:02:26 mkropfbe Exp $ 00041 * * 00042 ***********************************************************************/ 00043 00044 #ifndef WINCE 00045 #include <sys/types.h> 00046 #include <signal.h> 00047 #endif 00048 #include "global.hpp" 00049 #include "IO.hpp" 00050 #include "Frame.hpp" 00051 #include "SDLRenderer.hpp" 00052 #include "SDLFrameBuffer.hpp" 00053 #include "VideoRenderer.hpp" 00054 00055 00056 #ifdef ENABLE_X11 00057 #include <X11/Xatom.h> 00058 #include <unistd.h> 00059 #include <X11/X.h> 00060 #include <X11/Xlib.h> 00061 #include <X11/Xutil.h> 00062 #include <X11/xpm.h> 00063 #include <X11/extensions/shape.h> 00064 #include <X11/extensions/Xrandr.h> 00065 #endif 00066 00067 00068 SDLRenderer::SDLRenderer(const VideoESInfo *_es, UncompressedVideoFrame::ColorSpace colorSpace, 00069 int width, int height, bool fullScreen, bool pollEvents, 00070 bool isLabelResizable, bool fixAspectRatio, bool allowUpscaleX, 00071 bool rotateXDisplay) 00072 : VideoRenderer(_es, colorSpace, width, height, isLabelResizable, fixAspectRatio, allowUpscaleX) { 00073 dprintf_full("SDLRenderer Construct %s ES %p\n",this->url, this->es); 00074 strcpy(this->url,"SDLRenderer"); 00075 this->fullScreen = fullScreen; 00076 this->pollEvents = pollEvents; 00077 this->rotateXDisplay = rotateXDisplay; 00078 00079 overlay=NULL; 00080 surface=NULL; 00081 video_info=NULL; 00082 } 00083 00084 00085 SDLRenderer::~SDLRenderer() { 00086 00087 if (rotateXDisplay) 00088 doRotateXDisplay(0); 00089 00090 if (overlay) 00091 SDL_FreeYUVOverlay(overlay); 00092 overlay=NULL; 00093 if (surface) 00094 SDL_FreeSurface(surface); 00095 surface=NULL; 00096 00097 //free video_info not needed, is read-only from SDL! 00098 00099 SDL_ShowCursor(SDL_ENABLE); 00100 SDL_Quit(); 00101 } 00102 00103 void SDLRenderer::setESInfo(ESInfo * es) { 00104 this->es = (VideoESInfo*)es; 00105 } 00106 00107 00108 bool SDLRenderer::updateDisplayRegion() { 00109 00110 if (!es || !es->isVisualStream()) { 00111 dprintf_err("SDLRenderer::updateDisplayRegion(): invalid members: es = %p\n",es); 00112 ::exit(1); 00113 return false; 00114 } 00115 00116 return VideoRenderer::updateDisplayRegion(); 00117 } 00118 00119 00120 void SDLRenderer::doRotateXDisplay(int orientation) { 00121 00122 #ifdef BUILD_ARCH_ARM 00123 #ifdef ENABLE_X11 00124 int status; 00125 char *hostname = new char[MAX_STR_LEN]; 00126 char *envhost = getenv("DISPLAY"); 00127 00128 00129 if (!envhost) 00130 strcpy(hostname,"localhost:0"); 00131 else 00132 strcpy(hostname,envhost); 00133 00134 Display *display = XOpenDisplay(hostname); 00135 assert(display); 00136 00137 XRRScreenConfiguration *sc; 00138 sc = XRRGetScreenInfo (display, DefaultRootWindow(display)); 00139 status = XRRSetScreenConfigAndRate(display,sc,DefaultRootWindow (display),0,1 << orientation,0,0); 00140 dprintf_full("SDLRenderer::open rotating X11 screen, status: %i\n",status); 00141 00142 XRRFreeScreenConfigInfo(sc); 00143 delete [] hostname; 00144 #endif 00145 #endif 00146 } 00147 00148 00149 bool SDLRenderer::open() { 00150 if (state == OPEN) { 00151 dprintf_full("SDLRenderer::open state was already OPEN, ignoring opening request.\n"); 00152 return true; 00153 } 00154 if (state != CLOSED) { 00155 dprintf_err("SDLRenderer::open state was not CLOSED but state=%i!\n",state); 00156 return false; 00157 } 00158 00159 if (!updateDisplayRegion()) { 00160 state = STREAMERR; 00161 return false; 00162 } 00163 00164 char *buf = new char[MAX_STR_LEN]; 00165 //on iPAQ, dont forget: export DISPLAY=:0 00166 //if without X11, maybe this helps: export SDL_NOMOUSE=1 00167 if (SDL_Init(SDL_INIT_VIDEO) < 0 || !SDL_VideoDriverName(buf, 1)) { 00168 dprintf_err("Could not init SDL video: %s\r\n", SDL_GetError()); 00169 delete [] buf; 00170 ::exit(-1); 00171 } 00172 atexit(SDL_Quit); 00173 video_info = SDL_GetVideoInfo(); 00174 uint flags = SDL_SWSURFACE; 00175 if (fullScreen) 00176 flags |= SDL_FULLSCREEN; 00177 00178 #ifndef WINCE 00179 surface = SDL_SetVideoMode(out_label_info.width, out_label_info.height, 0, flags); 00180 #else 00181 #ifndef DISABLE_CE_RESIZE 00182 int myWidth = GetSystemMetrics(SM_CXSCREEN); 00183 int myHeight = GetSystemMetrics(SM_CYSCREEN); 00184 #else 00185 int myWidth = out_label_info.width; 00186 int myHeight = out_label_info.height; 00187 #endif 00188 surface = SDL_SetVideoMode(myWidth, myHeight, 0, flags); 00189 #endif 00190 00191 if (surface == NULL) { 00192 dprintf_err("Couldn't initialize window with dimension %ix%i: %s\n", out_label_info.width, out_label_info.height, SDL_GetError()); 00193 delete [] buf; 00194 ::exit(1); 00195 } 00196 00197 if (rotateXDisplay) 00198 doRotateXDisplay(1); 00199 00200 SDL_ShowCursor(SDL_DISABLE); 00201 if ( (surface->format->BitsPerPixel == UncompressedVideoFrame::mapColorSpaceToBitDepth(colorSpace) ) && 00202 (out_label_info.width == frame_info.width) && (out_label_info.height == frame_info.height) && 00203 (display_region.left == 0) && (display_region.top == 0) ) 00204 directBitBlt=true; //optimize via rgbSurface bitBlitting 00205 else 00206 directBitBlt=false; //use slow pixel-per-pixel painting and scaling 00207 00208 00209 dprintf_full("SDLRenderer::open() set SDL video mode to (%dx%d - %dx%d) bpp %i, using %s.\n", 00210 out_label_info.left, out_label_info.width, out_label_info.top, out_label_info.height, 00211 surface->format->BitsPerPixel, directBitBlt?"fastBitBlit":"slow pixel painting"); 00212 00213 //set 8, 16 or both 24/32 to 24 00214 setOutputDepth(surface->format->BitsPerPixel>=24?24:surface->format->BitsPerPixel); 00215 00216 SDL_WM_SetCaption("ViTooKi SDLRenderer", ""); 00217 00218 if (overlay) 00219 SDL_FreeYUVOverlay(overlay); 00220 overlay=NULL; 00221 00222 /* initialize frameBuffer */ 00223 if (frameBuffer) { 00224 delete frameBuffer; 00225 frameBuffer = NULL; 00226 } 00227 bool gray=false; 00228 switch (colorSpace) { 00229 case UncompressedVideoFrame::ColorSpaceGRAY8: 00230 dprintf_full("SDLRenderer::open() ColorSpaceGRAY8\n"); 00231 frame_info.size = frame_info.width * frame_info.height; 00232 gray=true; 00233 break; 00234 case UncompressedVideoFrame::ColorSpaceRGB565: 00235 dprintf_full("SDLRenderer::open() ColorSpaceRGB565 with 16bit depth\n"); 00236 frame_info.size = frame_info.width * frame_info.height * 2; 00237 break; 00238 case UncompressedVideoFrame::ColorSpaceRGB24: 00239 dprintf_full("SDLRenderer::open() ColorSpaceRGB24\n"); 00240 frame_info.size = frame_info.width * frame_info.height * 3; 00241 break; 00242 case UncompressedVideoFrame::ColorSpaceRGB32: 00243 dprintf_full("SDLRenderer::open() ColorSpaceRGB32\n"); 00244 frame_info.size = frame_info.width * frame_info.height * 4; 00245 break; 00246 case UncompressedVideoFrame::ColorSpaceYV12: 00247 dprintf_full("SDLRenderer::open() ColorSpaceYV12\n"); 00248 //overlay is scalable, so frame_info is used, and then up/down-scaled by hardware with SDL_YV12 00249 overlay = SDL_CreateYUVOverlay(frame_info.width, frame_info.height, SDL_YV12_OVERLAY, surface); 00250 frame_info.ySize = frame_info.width * frame_info.height; 00251 frame_info.uvSize = frame_info.width * frame_info.height / 4; 00252 frame_info.size = frame_info.ySize + 2 * frame_info.uvSize; 00253 dstrect.x = out_label_info.left; 00254 dstrect.y = out_label_info.top; 00255 dstrect.w = out_label_info.width; 00256 dstrect.h = out_label_info.height; 00257 break; 00258 case UncompressedVideoFrame::ColorSpaceI420: 00259 dprintf_full("SDLRenderer::open() ColorSpaceI420\n"); 00260 //overlay is scalable, so frame_info is used, and then up/down-scaled by hardware with SDL_IYUV 00261 overlay = SDL_CreateYUVOverlay(frame_info.width, frame_info.height, SDL_IYUV_OVERLAY, surface); 00262 frame_info.ySize = frame_info.width * frame_info.height; 00263 frame_info.uvSize = frame_info.width * frame_info.height / 4; 00264 frame_info.size = frame_info.ySize + 2 * frame_info.uvSize; 00265 dstrect.x = out_label_info.left; 00266 dstrect.y = out_label_info.top; 00267 dstrect.w = out_label_info.width; 00268 dstrect.h = out_label_info.height; 00269 break; 00270 default: 00271 dprintf_err("SDLRenderer::open(): invalid color space: %d\n", colorSpace); 00272 state = STREAMERR; 00273 delete [] buf; 00274 return false; 00275 } 00276 00277 #ifdef WINCE 00278 #ifndef DISABLE_CE_RESIZE 00279 dstrect.w = GetSystemMetrics(SM_CXSCREEN); 00280 dstrect.h = GetSystemMetrics(SM_CYSCREEN); 00281 #else 00282 dstrect.w = out_label_info.width; 00283 dstrect.h = out_label_info.height; 00284 #endif 00285 #endif 00286 00287 if (!overlay) 00288 frameBuffer = new SDLFrameBuffer(surface, UncompressedVideoFrame::mapColorSpaceToBitDepth(colorSpace), 00289 gray, out_label_info.width, out_label_info.height ); 00290 00291 if (!frameBuffer && !overlay) { 00292 dprintf_err("SDLRenderer::open(): SDLFrameBuffer creation FAILED! (w = %d, h = %d)\n", 00293 out_label_info.width, out_label_info.height ); 00294 state = STREAMERR; 00295 delete [] buf; 00296 return false; 00297 } 00298 00299 state = OPEN; 00300 framesSeen = 0; 00301 currentFrameNumber = 0; 00302 dprintf_small("SDLRenderer::open() (state=%i): initialized frame and display regions:\n" 00303 " frame: width = %d, height = %d, size = %d, scaleX = %5.3f, scaleY = %5.3f\n" 00304 " display: x(%d:%d), y(%d:%d), width = %d, height = %d\n", 00305 state, frame_info.width, frame_info.height, frame_info.size, 00306 FIXED2DOUBLE(frame_info.scaleX), FIXED2DOUBLE(frame_info.scaleY), 00307 display_region.left, display_region.right, 00308 display_region.top, display_region.bottom, 00309 display_region.width, display_region.height); 00310 delete [] buf; 00311 return true; 00312 } 00313 00314 00315 int SDLRenderer::writeFrame(Frame * frm, ESInfo *out_es) { 00316 if (pollEvents && SDL_PollEvent( &event )) { 00317 SDL_KeyboardEvent *key = &event.key; 00318 char *buf = SDL_GetKeyName( key->keysym.sym ); 00319 char c; 00320 if (buf[1]=='\0') //only single character (a-zA-Z...) 00321 c = toupper(buf[0]); 00322 switch( event.type ) { 00323 case SDL_KEYUP: 00324 PrintKeyInfo( &event.key ); 00325 if ( ((key->keysym.mod & KMOD_CTRL) && (c == 'C')) || 00326 (strstr(buf, "escape") != NULL)) { 00327 dprintf_err("SDLRenderer::writeFrame STREAMERR because of CTRL-C/ESC!\n"); 00328 state = STREAMERR; 00329 //kill(0,SIGQUIT); //kill the app incl. other eg. audio stream 00330 return 0; 00331 } 00332 break; 00333 00334 case SDL_KEYDOWN: 00335 PrintKeyInfo( &event.key ); 00336 break; 00337 00338 /* SDL_QUIT event (window close) */ 00339 case SDL_MOUSEBUTTONDOWN: 00340 case SDL_QUIT: 00341 dprintf_err("SDLRenderer::writeFrame STREAMERR because of window close!\n"); 00342 state = STREAMERR; 00343 return 0; 00344 break; 00345 00346 default: 00347 break; 00348 } 00349 } 00350 00351 //SDL-YUV will not need a frameBuffer so don't supercall! 00352 if ((colorSpace == UncompressedVideoFrame::ColorSpaceI420) || (colorSpace == UncompressedVideoFrame::ColorSpaceYV12)) { 00353 if (state != OPEN) 00354 return 1; 00355 framesSeen++; 00356 /* we don't set currentFrameNumber, as we have no way to determine it! */ 00357 00358 #ifndef WINCE 00359 if (SDL_MUSTLOCK(surface)) { 00360 if (SDL_LockSurface(surface) < 0) { 00361 ::exit(2); 00362 } 00363 } 00364 00365 if(SDL_LockYUVOverlay(overlay) !=0) { 00366 return -1; 00367 } 00368 #endif 00369 00370 #ifndef WINCE 00371 memcpy(overlay->pixels[0], frm->getAU()->payload, frame_info.ySize); // Y part 00372 00373 if (colorSpace == UncompressedVideoFrame::ColorSpaceI420) { 00374 memcpy(overlay->pixels[1], frm->getAU()->payload + frame_info.ySize, frame_info.uvSize); // U part 00375 memcpy(overlay->pixels[2], frm->getAU()->payload + frame_info.ySize + frame_info.uvSize, frame_info.uvSize); // V Part 00376 } else { // YV12, so exchange U and V 00377 memcpy(overlay->pixels[2], frm->getAU()->payload + frame_info.ySize, frame_info.uvSize); // U part 00378 memcpy(overlay->pixels[1], frm->getAU()->payload + frame_info.ySize + frame_info.uvSize, frame_info.uvSize); // V Part 00379 } 00380 #else 00381 int i,j,k; 00382 int edgedWidth = (frame_info.width + 15) / 16; 00383 int pitch = 16 * edgedWidth + 2 * EDGE_SIZE; 00384 00385 00386 u8 *y = frm->getAU()->y; 00387 u8 *u = frm->getAU()->u; 00388 u8 *v = frm->getAU()->v; 00389 00390 u8 *pixels1 = overlay->pixels[0]; 00391 u8 *pixels2 = overlay->pixels[1]; 00392 u8 *pixels3 = overlay->pixels[2]; 00393 00394 int halfWidth = frame_info.width >> 1; 00395 int halfHeight = frame_info.height >> 1; 00396 int halfPitch = pitch >> 1; 00397 00398 for (i=0; i < frame_info.height; i++) { 00399 memcpy(pixels1, y, frame_info.width); 00400 if ( i < halfHeight) { 00401 memcpy(pixels2, u, halfWidth); 00402 memcpy(pixels3, v, halfWidth); 00403 00404 u += halfPitch; 00405 v += halfPitch; 00406 pixels2 += halfWidth; 00407 pixels3 += halfWidth; 00408 } 00409 y += pitch; 00410 pixels1 += frame_info.width; 00411 00412 } 00413 00414 #endif 00415 00416 00417 SDL_DisplayYUVOverlay(overlay, &dstrect); 00418 dprintf_full("SDLRenderer::writeFrame -> Displaying YUV Frame (%i bytes) to x:%i y:%i -- w:%i h:%i\n", 00419 frm->getAU()->size,dstrect.x,dstrect.y,dstrect.w,dstrect.h); 00420 #ifndef WINCE 00421 SDL_UnlockYUVOverlay(overlay); 00422 00423 if (SDL_MUSTLOCK(surface)) { 00424 SDL_UnlockSurface(surface); 00425 } 00426 #endif 00427 00428 00429 #ifdef _POSIX_PRIORITY_SCHEDULING 00430 sched_yield(); //this is necessary to give parallel getFrames a chance 00431 #endif 00432 00433 return 1; 00434 00435 } else //RGB scale/write+yield is done in superClass 00436 return VideoRenderer::writeFrame(frm); 00437 00438 } 00439 00440 00441 /* Print all information about a key event */ 00442 void SDLRenderer::PrintKeyInfo( SDL_KeyboardEvent *key ) { 00443 /* Is it a release or a press? */ 00444 if( key->type == SDL_KEYUP ) 00445 printf( "SDLRenderer::PrintKeyInfo Release:- " ); 00446 else 00447 printf( "SDLRenderer::PrintKeyInfo Press:- " ); 00448 00449 /* Print the hardware scancode first */ 00450 printf( "Scancode: 0x%02X", key->keysym.scancode ); 00451 /* Print the name of the key */ 00452 printf( ", Name: %s", SDL_GetKeyName( key->keysym.sym ) ); 00453 /* We want to print the unicode info, but we need to make */ 00454 /* sure its a press event first (remember, release events */ 00455 /* don't have unicode info */ 00456 if( key->type == SDL_KEYDOWN ){ 00457 /* If the Unicode value is less than 0x80 then the */ 00458 /* unicode value can be used to get a printable */ 00459 /* representation of the key, using (char)unicode. */ 00460 printf(", Unicode: " ); 00461 if( key->keysym.unicode < 0x80 && key->keysym.unicode > 0 ){ 00462 printf( "%c (0x%04X)", (char)key->keysym.unicode, 00463 key->keysym.unicode ); 00464 } 00465 else{ 00466 printf( "? (0x%04X)", key->keysym.unicode ); 00467 } 00468 } 00469 printf( "\n" ); 00470 /* Print modifier info */ 00471 PrintModifiers( key->keysym.mod ); 00472 } 00473 00474 00475 /* Print modifier info */ 00476 void SDLRenderer::PrintModifiers( SDLMod mod ) { 00477 printf( "Modifers: " ); 00478 00479 /* If there are none then say so and return */ 00480 if( mod == KMOD_NONE ){ 00481 printf( "None\n" ); 00482 return; 00483 } 00484 00485 /* Check for the presence of each SDLMod value */ 00486 /* This looks messy, but there really isn't */ 00487 /* a clearer way. */ 00488 if( mod & KMOD_NUM ) printf( "NUMLOCK " ); 00489 if( mod & KMOD_CAPS ) printf( "CAPSLOCK " ); 00490 if( mod & KMOD_LCTRL ) printf( "LCTRL " ); 00491 if( mod & KMOD_RCTRL ) printf( "RCTRL " ); 00492 if( mod & KMOD_RSHIFT ) printf( "RSHIFT " ); 00493 if( mod & KMOD_LSHIFT ) printf( "LSHIFT " ); 00494 if( mod & KMOD_RALT ) printf( "RALT " ); 00495 if( mod & KMOD_LALT ) printf( "LALT " ); 00496 if( mod & KMOD_CTRL ) printf( "CTRL " ); 00497 if( mod & KMOD_SHIFT ) printf( "SHIFT " ); 00498 if( mod & KMOD_ALT ) printf( "ALT " ); 00499 printf( "\n" ); 00500 }