Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members
VideoRenderer.cpp
00001 /*********************************************************************** 00002 * * 00003 * ViTooKi * 00004 * * 00005 * title: VideoRenderer.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: VideoRenderer.cpp,v 1.19 2006/02/23 15:42:29 tkuglits Exp $ 00041 * * 00042 ***********************************************************************/ 00043 00044 #include "global.hpp" 00045 #include "IO.hpp" 00046 #include "Frame.hpp" 00047 #include "VideoRenderer.hpp" 00048 00049 VideoRenderer::VideoRenderer(const VideoESInfo *_es, UncompressedVideoFrame::ColorSpace colorSpace, 00050 int width, int height, 00051 bool isLabelResizable, bool fixAspectRatio, 00052 bool allowUpscaleX) 00053 : IO() { 00054 strcpy(this->url,"VideoRenderer"); 00055 this->es = _es; 00056 this->colorSpace = colorSpace; 00057 this->outputDepth = 24; //default value assumes modern display 00058 this->directBitBlt = false; 00059 frameBuffer = NULL; 00060 00061 dprintf_full("VideoRenderer Construct (colorSpace %s, depth %i bit, resolution %ix%i, allowUpscaleX: %s)\n", 00062 colorSpace==UncompressedVideoFrame::ColorSpaceGRAY8?"RGB8gray": 00063 colorSpace==UncompressedVideoFrame::ColorSpaceRGB24?"RGB24": 00064 colorSpace==UncompressedVideoFrame::ColorSpaceRGB32?"RGB32": 00065 colorSpace==UncompressedVideoFrame::ColorSpaceRGB565?"RGB565": 00066 colorSpace==UncompressedVideoFrame::ColorSpaceI420?"I420": 00067 colorSpace==UncompressedVideoFrame::ColorSpaceYV12?"YV12": 00068 "UNKNOWN", 00069 UncompressedVideoFrame::mapColorSpaceToBitDepth(colorSpace), 00070 width, height, allowUpscaleX?"yes":"no"); 00071 frame_info.width = 0; 00072 frame_info.height = 0; 00073 frame_info.size = 0; 00074 frame_info.scaleX = INT2FIXED(1); 00075 frame_info.scaleY = INT2FIXED(1); 00076 frame_info.fixAspectRatio = fixAspectRatio; 00077 frame_info.allowUpscaleX = allowUpscaleX; 00078 out_label_info.isLabelResizable = isLabelResizable; 00079 out_label_info.left=0; 00080 out_label_info.top=0; 00081 00082 if (isLabelResizable) { 00083 //get first hint from ES, aspectRatio may be calc'd later 00084 out_label_info.width=es->getWidth(); 00085 out_label_info.height=es->getHeight(); 00086 } else { 00087 out_label_info.width=width; 00088 out_label_info.height=height; 00089 } 00090 state = CLOSED; 00091 } 00092 00093 00094 VideoRenderer::~VideoRenderer() { 00095 } 00096 00097 00098 void VideoRenderer::setOutputDepth(int depth) { 00099 assert (depth == 16 || depth == 24 /* || depth == 8 */); 00100 dprintf_full("VideoRenderer::setOutputDepth to %i\n",depth); 00101 outputDepth = depth; 00102 } 00103 00104 00105 void VideoRenderer::setVideoFrameBuffer( VideoFrameBuffer *vfb ) { 00106 assert(frameBuffer == NULL); 00107 frameBuffer = vfb; 00108 } 00109 00110 00111 bool VideoRenderer::updateDisplayRegion() { 00112 int width, height; 00113 double scalex, scaley; 00114 double aspect; 00115 00116 if (!es || !es->isVisualStream()) { 00117 dprintf_err("VideoRenderer::updateDisplayRegion(): invalid member: es = %p\n", es); 00118 return false; 00119 } 00120 /* update frame_info */ 00121 frame_info.width = (int) es->getWidth(); 00122 frame_info.height = (int) es->getHeight(); 00123 /* compute frame display region with correct aspect ratio */ 00124 display_region.top = 0; 00125 display_region.left = 0; 00126 display_region.width = frame_info.width; 00127 display_region.height = frame_info.height; 00128 00129 aspect = (double) frame_info.width / (double) frame_info.height; 00130 if (es->getAspectRatio() > 0.0 && es->getAspectRatio() < 10.0) 00131 aspect = es->getAspectRatio(); 00132 width=display_region.width; 00133 height = (int) ((double) display_region.width / aspect); 00134 if (height < display_region.height) { //always scale up, not down! 00135 height= display_region.height; 00136 width = (int) ((double) display_region.height * aspect); 00137 } 00138 00139 // adjust to even value 00140 height += height % 2; 00141 if (height == 242 || height == 642) //quick hack, but works 00142 height -= 2; 00143 display_region.height = height; 00144 display_region.width = width; 00145 dprintf_full("VideoRenderer::updateDisplayRegion() aspect-correct frame size (%d x %d)\n" 00146 " aspect ratio = %5.3f (using: %5.3f)\n", 00147 display_region.width, display_region.height, 00148 es->getAspectRatio(), aspect); 00149 00150 /* if label/widget is resizeable, adjust out_label_info to display_region */ 00151 if (out_label_info.isLabelResizable) { 00152 out_label_info.width = display_region.width; 00153 out_label_info.height = display_region.height; 00154 scalex = scaley = 1.0; 00155 } else { 00156 /* otherwise, fit display_region into label */ 00157 width = out_label_info.width; 00158 height = out_label_info.height; 00159 if (display_region.width < width && !frame_info.allowUpscaleX) { 00160 width = display_region.width; 00161 } 00162 scalex = (double) width / (double) display_region.width; 00163 scaley = (double) height / (double) display_region.height; 00164 if ((scalex >= scaley && scaley >= 1.0) 00165 || (scaley <= scalex && scaley < 1.0)) { 00166 /* scale to height */ 00167 if (height == display_region.height) 00168 width = display_region.width; 00169 else 00170 width = (int) (display_region.width * scaley); 00171 } else if ((scaley >= scalex && scalex >= 1.0) 00172 || (scalex <= scaley && scalex < 1.0)) { 00173 /* scale to width */ 00174 if (width == display_region.width) 00175 height = display_region.height; 00176 else 00177 height = (int) (display_region.height * scalex); 00178 } 00179 // adjust width and height to even values 00180 width += width % 2; 00181 height += height % 2; 00182 display_region.width = width; 00183 display_region.height = height; 00184 } 00185 00186 dprintf_full("VideoRenderer::updateDisplayRegion() set display_region to (%d x %d)\n" 00187 " scalex = %5.3f, scaley = %5.3f, label/widget (%d x %d)\n", 00188 display_region.width, display_region.height, 00189 scalex, scaley, out_label_info.width, out_label_info.height); 00190 00191 if (display_region.width > out_label_info.width 00192 || display_region.height > out_label_info.height 00193 || display_region.width <= 0 00194 || display_region.height <= 0) { 00195 dprintf_err("VideoRenderer::updateDisplayRegion(): invalid size:\n" 00196 " video (%d x %d), qlabel (%d x %d)\n", 00197 display_region.width, display_region.height, 00198 out_label_info.width, out_label_info.height); 00199 return false; 00200 } 00201 /* center displayed region within label/widget */ 00202 display_region.left += (out_label_info.width - display_region.width) / 2; 00203 display_region.top += (out_label_info.height - display_region.height) / 2; 00204 /* update frame_info.scale{X,Y} */ 00205 frame_info.scaleX = DIV_FIXED(frame_info.width, display_region.width); 00206 frame_info.scaleY = DIV_FIXED(frame_info.height, display_region.height); 00207 00208 display_region.right = display_region.left + display_region.width; 00209 display_region.bottom = display_region.top + display_region.height; 00210 return true; 00211 } 00212 00213 00214 bool VideoRenderer::open() { 00215 /* implement in subclass! */ 00216 return true; 00217 } 00218 00219 00220 int VideoRenderer::writeFrame(Frame * frm, ESInfo *out_es) { 00221 struct AU *au; 00222 register int x, x0, y, y0; 00223 register u8 *pix, *pixline; 00224 register u32 yframe; 00225 register u32 one = INT2FIXED(1); 00226 00227 if (!frm || !frm->getAU()) { 00228 dprintf_err("VideoRenderer::writeFrame(): invalid parameter: frm = %p, au = %p\n", 00229 frm, frm ? (void *) frm->getAU() : NULL); 00230 state = STREAMERR; 00231 return 0; 00232 } 00233 if (state != OPEN) 00234 return 1; 00235 framesSeen++; 00236 /* we don't set currentFrameNumber, as we have no way to determine it! */ 00237 00238 au = frm->getAU(); 00239 if (au->size != (u32) frame_info.size) { 00240 dprintf_err("VideoRenderer::writeFrame(): frame size mismatch: expected %d bytes, " 00241 "got %u bytes\n", frame_info.size, au->size); 00242 state = STREAMERR; 00243 return 0; 00244 } 00245 00246 /* convert frame to frameBuffer, 00247 * scaling the frame according to frame_info.scaleX and frame_info.scaleY 00248 */ 00249 frameBuffer->lock(); 00250 switch (colorSpace) { 00251 case UncompressedVideoFrame::ColorSpaceGRAY8: 00252 CHOOSE_SCALE_FRAME(1, *pix) 00253 break; 00254 case UncompressedVideoFrame::ColorSpaceRGB24: 00255 if (outputDepth >= 24) { 00256 //note: it is BGR! 00257 CHOOSE_SCALE_FRAME(3, (pix[0] << 16) | (pix[1] << 8) | pix[2]) 00258 } else { 00259 CHOOSE_SCALE_FRAME(3, ((pix[0] >> 3) << 11) + ((pix[1] >> 2) << 5) + (pix[2] >> 3)) 00260 // CHOOSE_SCALE_FRAME(3, ((pix[2] >> 11) << 11) + ((pix[1] >> 10) << 5) + (pix[0] >> 11)) 00261 } 00262 break; 00263 case UncompressedVideoFrame::ColorSpaceRGB32: 00264 /* Qt expected input format: BGRA */ 00265 // CHOOSE_SCALE_FRAME(4, qRgba(pix[2], pix[1], pix[0], pix[3])) 00266 /* SDL expected input format: ARGB */ 00267 // CHOOSE_SCALE_FRAME(4, (pix[3] << 24) | (pix[2] << 16) | (pix[1] << 8) | pix[0]) 00268 /* X11 expected input format: ARGB */ 00269 00270 00271 //note: it is RGB! 00272 if (outputDepth >= 24) 00273 CHOOSE_SCALE_FRAME(4, (pix[3] << 24) | (pix[2] << 16) | (pix[1] << 8) | pix[0]) 00274 else 00275 CHOOSE_SCALE_FRAME(4, ((pix[2] >> 3) << 11) + ((pix[1] >> 2) << 5) + (pix[0] >> 3)) 00276 00277 break; 00278 case UncompressedVideoFrame::ColorSpaceRGB565: 00279 /* How Do I Convert RGB5XX into a 16-bit number? 00280 * #define RGB565(r, g, b) ((r >> 3) << 11)| ((g >> 2) << 5)| ((b >> 3) << 0) 00281 * #define RGB555(r, g, b) ((r >> 3) << 10)| ((g >> 3) << 5)| ((b >> 3) << 0) 00282 */ 00283 00284 if (outputDepth >= 24) { 00285 //FIXME: the RGB green-part is fucked up, and I don't find the problem :( 00286 00287 //scale up from 16 to 24 bit 00288 // CHOOSE_SCALE_FRAME(2, ((pix[0] << 3) <<0) | (pix[0] >>5 | pix[1] >>5 <<3)<<8 | ((pix[1] << 3)>>3)<<16 ) 00289 CHOOSE_SCALE_FRAME(2, ((pix[0] << 3)) /*blue*/ | ((pix[1] << 3)>>3<<16) /*red*/ 00290 | pix[0] >>5<<10 | pix[1] >>5 <<13 /*green*/ ) 00291 00292 } else { 00293 CHOOSE_SCALE_FRAME(2, (pix[1]<<8) | pix[0]) 00294 } 00295 break; 00296 default: 00297 /* make compiler happy */ 00298 break; 00299 } 00300 frameBuffer->unlock(); 00301 dprintf_full("VideoRenderer::writeFrame() posting paint event to frame buffer\n"); 00302 frameBuffer->postPaintEvent(); 00303 00304 00305 00306 #ifdef _POSIX_PRIORITY_SCHEDULING 00307 sched_yield(); //this is necessary to give parallel getFrames a chance 00308 #endif 00309 00310 return 1; 00311 } 00312