UncompressedVideoFrame.cpp

00001 /*********************************************************************** 00002 * * 00003 * ViTooKi * 00004 * * 00005 * title: UncompressedVideoFrame.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 * * 00041 * * 00042 ***********************************************************************/ 00043 00044 #include "UncompressedVideoFrame.hpp" 00045 #include <math.h> 00046 00047 00052 UncompressedVideoFrame::UncompressedVideoFrame(FrameType t, int w, int h) : VideoFrame(t,w,h) 00053 { 00054 this->psnr = ERR_PSNR; 00055 00056 setType(t); 00057 00058 if (getType() == YUV_VOP) 00059 colorSpace = ColorSpaceYV12; 00060 else 00061 if (getType() == RGB_VOP) 00062 colorSpace = ColorSpaceRGB24; 00063 else 00064 colorSpace = ColorSpaceUNKNOWN; 00065 00066 } 00067 00068 00069 00074 UncompressedVideoFrame::~UncompressedVideoFrame() { 00075 } 00076 00077 00078 /* set to I-frames so that seekToIFrame works on YUVStreams */ 00079 Frame::FrameType UncompressedVideoFrame::detectFrameType() { 00080 00081 #ifndef WINCE 00082 if (!(accessUnit && accessUnit->payload)) { 00083 return ERROR_VOP; 00084 } 00085 #endif 00086 00087 //we detect if it is YUV_VOP or RGB_VOP by comparing the payload size 00088 if (accessUnit->size == width * height * 1.5) 00089 setType( YUV_VOP ); 00090 else 00091 setType( RGB_VOP ); 00092 00093 00094 return getType(); 00095 }; 00096 00097 00098 Frame::FrameType UncompressedVideoFrame::detectFrameType(AU* accessUnit) { 00099 Frame::FrameType type=Frame::ERROR_VOP; 00100 00101 if (!(accessUnit && accessUnit->payload)) { 00102 return type; 00103 } 00104 00105 //problem: there is no way to detect YUV! make it an "important" frame :) 00106 type = Frame::HEADER_VOP; 00107 return type; 00108 } 00109 00110 00111 int UncompressedVideoFrame::mapColorSpaceToBitDepth(ColorSpace colorspace) { 00112 switch (colorspace) { 00113 case ColorSpaceRGB32: 00114 return 32; 00115 break; 00116 case ColorSpaceRGB24: 00117 return 24; 00118 break; 00119 case ColorSpaceRGB565: 00120 return 16; 00121 break; 00122 case ColorSpaceGRAY8: 00123 return 8; 00124 break; 00125 case ColorSpaceYV12: // FIXME: not perfect, but 8 is well-used for adaptors/FrameRotate... 00126 case ColorSpaceI420: 00127 return 8; 00128 break; 00129 default: 00130 dprintf_err("MP4Decoder::mapColorSpaceToBitDepth: Unknown colorspace\n"); 00131 exit(-1); 00132 } 00133 } 00134 00135 00136 /* should transcode a single frame to another colorspace */ 00137 UncompressedVideoFrame* UncompressedVideoFrame::convertToColorSpace(UncompressedVideoFrame::ColorSpace cs) { 00138 if (colorSpace == ColorSpaceYV12) { 00139 00140 long int i, j, uv_i, uv_j, x, r, g, b,y,u,v, cnt; 00141 char* data_y; 00142 char* data_u; 00143 char* data_v; 00144 u8* payload; 00145 int pixel; 00146 int width_uv = width/2; 00147 int height_uv = height/2; 00148 int depth = mapColorSpaceToBitDepth(cs); 00149 UncompressedVideoFrame* frm; 00150 00151 00152 switch (cs) { 00153 case ColorSpaceRGB32: 00154 case ColorSpaceRGB24: 00155 case ColorSpaceRGB565: 00156 frm = new UncompressedVideoFrame( RGB_VOP, width, height); 00157 frm->setAU(new AU(this->getAU())); 00158 00159 payload = (u8*)malloc(width*height*(depth/8)); 00160 00161 00162 #ifdef BUILD_ARCH_ARM 00163 //SUPER HACK.... 00164 // adding cache support for transcoded image... only for one... works for our hourglass splashscreen scenario 00165 #define ARM_HOURGLASS_CACHE "/media/ram/hourglass.rgb565" 00166 FILE* fp = fopen(ARM_HOURGLASS_CACHE ,"r"); 00167 if (fp != NULL) { 00168 fread(payload, width*height*(depth/8), 1, fp); 00169 frm->getAU()->payload = payload; 00170 frm->getAU()->size = width*height*(depth/8); 00171 fclose(fp); 00172 dprintf_err("UncompressedVideoFrame::convertToColorSpace RGB depth %i: reading from cache file!! real code not executed!\n",depth); 00173 return frm; 00174 } 00175 #endif 00176 getYBuffer((u8**)&data_y); 00177 getUBuffer((u8**)&data_u); 00178 getVBuffer((u8**)&data_v); 00179 00180 00181 for(uv_i = 0; uv_i < height_uv; uv_i++) 00182 for(uv_j = 0; uv_j < width_uv; uv_j++) { 00183 00184 u = data_u[uv_i * width_uv + uv_j]; /* U value */ 00185 v = data_v[uv_i * width_uv + uv_j]; /* V value */ 00186 00187 x=0; 00188 while(x < 4) { 00189 if (x == 0) { 00190 /* first pixel */ 00191 i = uv_i * 2; j = uv_j * 2; 00192 } else { 00193 /* second, 3rd, 4th pixel */ 00194 if (x==1) i++; 00195 else if (x==2) j++; 00196 else if (x==3) i--; 00197 } 00198 x++; 00199 y = data_y[i*width+j]; /* Y value */ 00200 00201 r = (long int)round(y + (1.370705 * (v-128))); 00202 g = (long int)round(y - (0.698001 * (v-128)) - (0.337633 * (u-128))); 00203 b = (long int)round(y + (1.732446 * (u-128))); 00204 00205 // Even with proper conversion, some values still need clipping. 00206 if (r > 255) r = 255; if (g > 255) g = 255; 00207 if (b > 255) b = 255; if (r < 0) r = 0; 00208 if (g < 0) g = 0; if (b < 0) b = 0; 00209 00210 if (depth==16) { 00211 ((u16*)(payload))[i*width+j] = ((r >> 3) << 11) + ((g >> 2) << 5) + (b >> 3); 00212 } else 00213 if (depth==32) { 00214 ((u32*)(payload))[i*width+j] = ((r << 16) + (g << 8) + b); 00215 } else 00216 assert("THIS RGB DEPTH IS NOT_SUPPORTED" && (1==0)); 00217 cnt++; 00218 } //yuv 4:2:2 four pixel while 00219 } //scan yuv pic 00220 00221 frm->getAU()->payload = payload; 00222 frm->getAU()->size = width*height*(depth/8); 00223 00224 #ifdef BUILD_ARCH_ARM 00225 //SUPER HACK....write away the rgb565 into a cache 00226 fp = fopen(ARM_HOURGLASS_CACHE ,"w"); 00227 if (fp != NULL) { 00228 fwrite(payload, width*height*(depth/8), 1, fp); 00229 fclose(fp); 00230 } 00231 #endif 00232 dprintf_full("UncompressedVideoFrame::convertToColorSpace RGB depth %i by calculating\n",depth); 00233 return frm; 00234 break; 00235 case ColorSpaceYV12: 00236 //no conversion needed... 00237 return NULL; 00238 break; 00239 case ColorSpaceI420: 00240 case ColorSpaceGRAY8: 00241 default: 00242 dprintf_err("UncompressedVideoFrame::convertToColorSpace does not support this destination colorSpace!\n"); 00243 exit(-1); 00244 } 00245 00246 } else { 00247 dprintf_err("UncompressedVideoFrame::convertToColorSpace does not support RGB->YUV yet!\n"); 00248 return NULL; 00249 } 00250 } 00251 00252 00254 int UncompressedVideoFrame::getYBuffer(u8** buf) { 00255 00256 assert((colorSpace == ColorSpaceI420) || (colorSpace == ColorSpaceYV12)); 00257 00258 if(accessUnit->payload && accessUnit->size > 0) 00259 { 00260 *buf = accessUnit->payload; 00261 return width*height; 00262 } 00263 else 00264 { 00265 *buf = NULL; 00266 return -1; 00267 } 00268 } 00269 00270 00272 int UncompressedVideoFrame::getUBuffer(u8** buf) { 00273 00274 assert((colorSpace == ColorSpaceI420) || (colorSpace == ColorSpaceYV12)); 00275 00276 if(accessUnit->payload && accessUnit->size > 0) 00277 { 00278 *buf = accessUnit->payload + (width*height); 00279 return width*height/4; 00280 } 00281 else 00282 { 00283 *buf = NULL; 00284 return -1; 00285 } 00286 } 00287 00288 00290 int UncompressedVideoFrame::getVBuffer(u8** buf) { 00291 00292 assert((colorSpace == ColorSpaceI420) || (colorSpace == ColorSpaceYV12)); 00293 00294 if(accessUnit->payload && accessUnit->size > 0) 00295 { 00296 *buf = accessUnit->payload + (width*height) + width*height/4; 00297 return width*height/4; 00298 } 00299 else 00300 { 00301 *buf = NULL; 00302 return -1; 00303 } 00304 } 00305 00306 00307 double UncompressedVideoFrame::computePSNRwithOffset(UncompressedVideoFrame *other, long offset) { 00308 double rmse = 0; 00309 double mse = 0; 00310 int k = 0; 00311 int temp = 0; 00312 unsigned char *otherData; 00313 unsigned char *thisData; 00314 00315 int width = this->getWidth(); 00316 int height = this->getHeight(); 00317 00318 00319 assert((colorSpace == ColorSpaceI420) || (colorSpace == ColorSpaceYV12)); 00320 00321 assert (width > 0 && height > 0); 00322 //dprintf_full("UncompressedVideoFrame::computePSNRwithOffset %i (%ix%i)\n",offset,width,height); 00323 00324 if (other->getAU()) 00325 otherData = (unsigned char *) other->getAU()->payload; 00326 else 00327 return ERR_PSNR; 00328 if (this->getAU()) 00329 thisData = (unsigned char *) this->getAU()->payload; 00330 else 00331 return ERR_PSNR; 00332 00333 /* 00334 if (offset == 0) //optimized 00335 for (int i = 0; i < width; i++) { 00336 for (int j = 0; j < height; j++) { 00337 temp = (thisData[k] - otherData[k]); 00338 mse += (double)(temp * temp); 00339 k++; 00340 } 00341 } 00342 else // use offset calculations 00343 */ 00344 for (int i = 0; i < width; i++) { 00345 for (int j = 0; j < height; j++) { 00346 temp = thisData[k + offset] - 00347 otherData[k + offset]; 00348 mse += (double)(temp * temp); 00349 k++; 00350 } 00351 } 00352 00353 if (mse == 0) { 00354 // frames are equal return maxPSNR of stream 00355 // FIXME: ignored now... will return INFINITE 00356 } 00357 00358 mse = (double) mse / ((double) width * (double) height); 00359 rmse = sqrt(mse); 00360 return 20 * log10(255.0 / rmse); 00361 } 00362 00363 00368 double UncompressedVideoFrame::computePSNRy(UncompressedVideoFrame * other) { 00369 00370 return computePSNRwithOffset(other,0); //y component has 0 offset 00371 00372 } 00373 00374 00379 double UncompressedVideoFrame::computePSNRu(UncompressedVideoFrame * other) { 00380 return computePSNRwithOffset(other,width*height); // after Y buf 00381 } 00382 00383 00388 double UncompressedVideoFrame::computePSNRv(UncompressedVideoFrame * other) { 00389 return computePSNRwithOffset(other,width*height +(width*height/4) ); // after Y+U buf 00390 } 00391 00392 00397 double UncompressedVideoFrame::computePSNR(UncompressedVideoFrame * other) { 00398 00399 psnr = this->computePSNRy(other); 00400 return psnr; 00401 } 00402 00403 00404 00405