SDLRenderer Class Reference

This I/O class renders a gray-scale or RGB24/32 or YUV I420/YV12 stream the used SDL surface is created within this function, incl. CTRL-C/ESC signal/event catchers. More...

#include <SDLRenderer.hpp>

Inheritance diagram for SDLRenderer:

VideoRenderer IO VThread List of all members.

Public Member Functions

 SDLRenderer (const VideoESInfo *es, UncompressedVideoFrame::ColorSpace colorSpace=UncompressedVideoFrame::ColorSpaceI420, int width=0, int height=0, bool fullScreen=false, bool pollEvents=true, bool isLabelResizable=true, bool fixAspectRatio=true, bool allowUpscaleX=false, bool rotateXDisplay=false)
 Constructor.
virtual ~SDLRenderer ()
 Destructor.
virtual int writeFrame (Frame *frm, ESInfo *out_es=NULL)
 Renders a frame to the destination YUV_Overlay/RGB_Surface.
virtual bool open ()
 Creates internal frame buffers and checks whether the stream to be rendered matches the widget dimensions.
void setESInfo (ESInfo *es)
 Not implemented.

Protected Member Functions

bool updateDisplayRegion ()
 Update frame_info (except size) and display_region.
void doRotateXDisplay (int orientation)
 rotate the X11 display using the XRandr extension

Detailed Description

This I/O class renders a gray-scale or RGB24/32 or YUV I420/YV12 stream the used SDL surface is created within this function, incl. CTRL-C/ESC signal/event catchers.

It is intended to be used as a DataSink connected to a DataChannel.

Video frames will be (down or up) scaled to fit into the given size by preserving the aspect ratio given in VideoESInfo.

The expected format of the gray-scale stream is: 1 byte per pixel.

The expected format of the RGB24 stream is: 3 bytes per pixel, in the order RGB (red, green, blue).

The expected format of the RGB32 stream is: 4 bytes per pixel, in the order BGRA (blue, green, red, alpha). This conforms to the PIX_FMT_RGBA32 format defined in ffmpeg/libavcodec/avcodec.h on little endian architectures.

Author:
Michael Kropfberger
Version:
Id
SDLRenderer.hpp,v 1.11 2006/01/20 15:37:18 mkropfbe Exp

Definition at line 80 of file SDLRenderer.hpp.


Constructor & Destructor Documentation

SDLRenderer::SDLRenderer const VideoESInfo *  es,
UncompressedVideoFrame::ColorSpace  colorSpace = UncompressedVideoFrame::ColorSpaceI420,
int  width = 0,
int  height = 0,
bool  fullScreen = false,
bool  pollEvents = true,
bool  isLabelResizable = true,
bool  fixAspectRatio = true,
bool  allowUpscaleX = false,
bool  rotateXDisplay = false
 

Constructor.

If the parameters are invalid, the open() method will fail.

Parameters:
es elementary stream information about the video stream to be rendered.
colorSpace the color space of the video stream to be rendered; must be one of: VideoFrame::::ColorSpaceGRAY8, UncompressedVideoFrame::ColorSpaceRGB24, UncompressedVideoFrame::ColorSpaceRGB32, UncompressedVideoFrame::ColorSpaceRGB565, UncompressedVideoFrame::ColorSpaceI420, UncompressedVideoFrame::ColorSpaceYV12
width the width of the SDL window
height the height of the SDL window
fullScreen opens the SDL window in FullScreen Mode
pollEvents if true, the SDL event handler is checked for keypresses like CTRL-C or ESC, and a "SDL window close" is detected if such an event occurs, the state of the stream is set to STREAMERR beware, that this polling might grab away ALL events, so implement on on your own, if you want to support eg. joysticks or more keycodes!
isLabelResizable if true, the given width/height is assumed to be flexible, so it will be tried to keep the original video size (plus adhering #fixAspectRatio) setting this to true, width&height may be zero, only the video is used to determine the resolution
fixAspectRatio if true, video frames may be resized according to their ESInfo aspectRatio, which means upscaling in the y-dimension
allowUpscaleX if true, video frames may be upscaled in x-dimension to fit the label, which may result in significant quality loss, since a very simple upscaling algorithm is used (assumes isLabelResizable==false).
rotateXDisplay uses XRandr X11 extension to rotate the screen, play SDL video, then rotate back
Definition at line 68 of file SDLRenderer.cpp.

References UncompressedVideoFrame::ColorSpace.

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 }


Member Function Documentation

void SDLRenderer::doRotateXDisplay int  orientation  )  [protected]
 

rotate the X11 display using the XRandr extension

Parameters:
orientation 0 for normal, 1 for 90 degrees
Definition at line 120 of file SDLRenderer.cpp.

Referenced by open(), and ~SDLRenderer().

00120 { 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 }

bool SDLRenderer::open  )  [virtual]
 

Creates internal frame buffers and checks whether the stream to be rendered matches the widget dimensions.

Returns:
true on success, false on error.
See also:
IO::open()

Reimplemented from VideoRenderer.

Definition at line 149 of file SDLRenderer.cpp.

References doRotateXDisplay(), UncompressedVideoFrame::mapColorSpaceToBitDepth(), and updateDisplayRegion().

00149 { 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 }

bool SDLRenderer::updateDisplayRegion  )  [protected]
 

Update frame_info (except size) and display_region.

This function is not thread-safe, and is internally called by the open() method.

Reimplemented from VideoRenderer.

Definition at line 108 of file SDLRenderer.cpp.

References VideoRenderer::updateDisplayRegion().

Referenced by open().

00108 { 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 }

int SDLRenderer::writeFrame Frame frm,
ESInfo out_es = NULL
[virtual]
 

Renders a frame to the destination YUV_Overlay/RGB_Surface.

Returns:
1 on success, 0 on error.

Reimplemented from VideoRenderer.

Definition at line 315 of file SDLRenderer.cpp.

References Frame::getAU(), and VideoRenderer::writeFrame().

00315 { 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 }


The documentation for this class was generated from the following files: