00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <qapplication.h>
00012 #include <qimage.h>
00013
00014 #include <iostream>
00015 #include <cstdlib>
00016 using namespace std;
00017
00018 #ifndef WIN32
00019 #include <linux/videodev.h>
00020 #include "config.h"
00021 #endif
00022
00023 #include "h263.h"
00024
00025
00026 H263Container::H263Container()
00027 {
00028 lastCompressedSize = 0;
00029 PostEncodeFrame = 0;
00030 h263Encoder = 0;
00031 h263EncContext = 0;
00032
00033 h263Decoder = 0;
00034 h263DecContext = 0;
00035 pictureIn = 0;
00036
00037 avcodec_init();
00038 avcodec_register_all();
00039 }
00040
00041 H263Container::~H263Container()
00042 {
00043 }
00044
00045 bool H263Container::H263StartEncoder(int w, int h, int fps)
00046 {
00047 h263Encoder = avcodec_find_encoder(CODEC_ID_H263);
00048 if (!h263Encoder)
00049 {
00050 cerr << "Could not find H.263 Encoder\n";
00051 return false;
00052 }
00053
00054 h263EncContext = avcodec_alloc_context();
00055
00056 h263EncContext->pix_fmt = PIX_FMT_YUV420P;
00057
00058 h263EncContext->bit_rate = 2000000;
00059
00060 h263EncContext->width = w;
00061 h263EncContext->height = h;
00062
00063 #ifdef WIN32 // Windows version uses older avcodec library
00064 h263EncContext->frame_rate = fps;
00065 h263EncContext->frame_rate_base = 1;
00066 #else
00067 h263EncContext->time_base.den = fps;
00068 h263EncContext->time_base.num = 1;
00069 #endif
00070 h263EncContext->gop_size = 600;
00071 h263EncContext->max_b_frames=0;
00072
00073
00074 if (avcodec_open(h263EncContext, h263Encoder) < 0)
00075 {
00076 cerr << "Could not open H.263 Encoder\n";
00077 return false;
00078 }
00079
00080
00081 MaxPostEncodeSize = 100000;
00082 PostEncodeFrame = (uchar *)malloc(MaxPostEncodeSize);
00083
00084
00085 avcodec_get_frame_defaults(&pictureOut);
00086
00087 pictureOut.linesize[0] = h263EncContext->width;
00088 pictureOut.linesize[1] = h263EncContext->width / 2;
00089 pictureOut.linesize[2] = h263EncContext->width / 2;
00090
00091 return true;
00092 }
00093
00094 bool H263Container::H263StartDecoder(int w, int h)
00095 {
00096 h263Decoder = avcodec_find_decoder(CODEC_ID_H263);
00097 if (!h263Decoder)
00098 {
00099 cerr << "Could not find H.263 decoder\n";
00100 return false;
00101 }
00102
00103 h263DecContext = avcodec_alloc_context();
00104 pictureIn = avcodec_alloc_frame();
00105
00106 h263DecContext->codec_id = CODEC_ID_H263;
00107 h263DecContext->width = w;
00108 h263DecContext->height = h;
00109
00110
00111 if (avcodec_open(h263DecContext, h263Decoder) < 0)
00112 {
00113 cerr << "Could not open H.263 Decoder\n";
00114 return false;
00115 }
00116
00117 return true;
00118 }
00119
00120 uchar *H263Container::H263EncodeFrame(const uchar *yuvFrame, int *len)
00121 {
00122 int size = h263EncContext->width * h263EncContext->height;
00123 pictureOut.data[0] = (uchar *)yuvFrame;
00124 pictureOut.data[1] = pictureOut.data[0] + size;
00125 pictureOut.data[2] = pictureOut.data[1] + size / 4;
00126
00127 *len = lastCompressedSize = avcodec_encode_video(h263EncContext, PostEncodeFrame, MaxPostEncodeSize, &pictureOut);
00128
00129 return PostEncodeFrame;
00130 }
00131
00132 uchar *H263Container::H263DecodeFrame(const uchar *h263Frame, int h263FrameLen, uchar *rgbBuffer, int rgbBufferSize)
00133 {
00134 int got_picture;
00135
00136 int len = avcodec_decode_video(h263DecContext, pictureIn, &got_picture, (uchar *) h263Frame, h263FrameLen);
00137 if (len != h263FrameLen)
00138 {
00139 cerr << "Error decoding frame; " << len << endl;
00140 return 0;
00141 }
00142
00143 if (got_picture)
00144 {
00145 YUV420PtoRGB32(pictureIn->data[0], pictureIn->data[1], pictureIn->data[2], h263DecContext->width, h263DecContext->height, pictureIn->linesize[0], rgbBuffer, rgbBufferSize);
00146 return rgbBuffer;
00147 }
00148 return 0;
00149 }
00150
00151 void H263Container::H263ForceIFrame()
00152 {
00153
00154 while (lastCompressedSize != 0)
00155 lastCompressedSize = avcodec_encode_video(h263EncContext, PostEncodeFrame, MaxPostEncodeSize, NULL);
00156 avcodec_close(h263EncContext);
00157 avcodec_open(h263EncContext, h263Encoder);
00158 }
00159
00160 void H263Container::H263StopEncoder()
00161 {
00162 while (lastCompressedSize != 0)
00163 {
00164 lastCompressedSize = avcodec_encode_video(h263EncContext, PostEncodeFrame, MaxPostEncodeSize, NULL);
00165 }
00166
00167 if (PostEncodeFrame)
00168 {
00169 free(PostEncodeFrame);
00170 PostEncodeFrame = 0;
00171 }
00172
00173 if (h263EncContext)
00174 {
00175 avcodec_close(h263EncContext);
00176 av_free(h263EncContext);
00177 h263EncContext = 0;
00178 }
00179 }
00180
00181 void H263Container::H263StopDecoder()
00182 {
00183 int got_picture;
00184
00185
00186 avcodec_decode_video(h263DecContext, pictureIn, &got_picture, NULL, 0);
00187
00188 if (h263DecContext)
00189 {
00190 avcodec_close(h263DecContext);
00191 av_free(h263DecContext);
00192 h263DecContext = 0;
00193 }
00194
00195 if (pictureIn)
00196 av_free(pictureIn);
00197 pictureIn = 0;
00198 }
00199
00200
00202
00203
00205
00206
00207 void RGB24toRGB32(const unsigned char *rgb24, unsigned char *rgb32, int len)
00208 {
00209 for (int i=0; i<len; i++)
00210 {
00211 QRgb *rgb = (QRgb *)rgb32;
00212 *rgb = qRgb(*(rgb24+2), *(rgb24+1), *(rgb24));
00213 rgb24 += 3;
00214 rgb32 += 4;
00215 }
00216 }
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235 void YUV420PtoRGB32(int width, int height, int stride, const unsigned char *src, unsigned char *dst, int dstSize)
00236 {
00237 int h, w;
00238 const unsigned char *py, *pu, *pv;
00239 py = src;
00240 pu = py + (stride * height);
00241 pv = pu + (stride * height) / 4;
00242 int yStrideDelta = stride-width;
00243 int uvStride = stride>>1;
00244
00245 if (dstSize < (width*height*4))
00246 {
00247 cout << "YUVtoRGB buffer (" << dstSize << ") too small for " << width << "x" << height << " pixels" << endl;
00248 return;
00249 }
00250
00251 for (h=0; h<height; h++)
00252 {
00253 for (w=0; w<width; w++)
00254 {
00255 signed int _r,_g,_b;
00256 signed int r, g, b;
00257 signed int y, u, v;
00258
00259 y = *py++ - 16;
00260 u = pu[w>>1] - 128;
00261 v = pv[w>>1] - 128;
00262
00263 _r = _R(y,u,v);
00264 _g = _G(y,u,v);
00265 _b = _B(y,u,v);
00266
00267 r = _S(_r);
00268 g = _S(_g);
00269 b = _S(_b);
00270
00271 *dst++ = r;
00272 *dst++ = g;
00273 *dst++ = b;
00274 *dst++ = 0;
00275 }
00276
00277 py += yStrideDelta;
00278 if (h%2) {
00279 pu += uvStride;
00280 pv += uvStride;
00281 }
00282 }
00283 }
00284
00285
00286 void YUV420PtoRGB32(const uchar *py, const uchar *pu, const uchar *pv, int width, int height, int stride, unsigned char *dst, int dstSize)
00287 {
00288 int h, w;
00289 int yStrideDelta = stride-width;
00290 int uvStride = stride>>1;
00291
00292 if (dstSize < (width*height*4))
00293 {
00294 cout << "YUVtoRGB buffer (" << dstSize << ") too small for " << width << "x" << height << " pixels" << endl;
00295 return;
00296 }
00297
00298 for (h=0; h<height; h++)
00299 {
00300 for (w=0; w<width; w++)
00301 {
00302 signed int _r,_g,_b;
00303 signed int r, g, b;
00304 signed int y, u, v;
00305
00306 y = *py++ - 16;
00307 u = pu[w>>1] - 128;
00308 v = pv[w>>1] - 128;
00309
00310 _r = _R(y,u,v);
00311 _g = _G(y,u,v);
00312 _b = _B(y,u,v);
00313
00314 r = _S(_r);
00315 g = _S(_g);
00316 b = _S(_b);
00317
00318 *dst++ = r;
00319 *dst++ = g;
00320 *dst++ = b;
00321 *dst++ = 0;
00322 }
00323
00324 py += yStrideDelta;
00325 if (h%2) {
00326 pu += uvStride;
00327 pv += uvStride;
00328 }
00329 }
00330 }
00331
00332 void YUV422PtoRGB32(int width, int height, const unsigned char *src, unsigned char *dst, int dstSize)
00333 {
00334 int h, w;
00335 const unsigned char *py, *pu, *pv;
00336 py = src;
00337 pu = py + (width * height);
00338 pv = pu + (width * height) / 4;
00339
00340 if (dstSize < (width*height*4))
00341 {
00342 cout << "YUVtoRGB buffer (" << dstSize << ") too small for " << width << "x" << height << " pixels" << endl;
00343 return;
00344 }
00345
00346 for (h=0; h<height; h++)
00347 {
00348 for (w=0; w<width; w++)
00349 {
00350 signed int _r,_g,_b;
00351 signed int r, g, b;
00352 signed int y, u, v;
00353
00354 y = *py++ - 16;
00355 u = pu[w>>1] - 128;
00356 v = pv[w>>1] - 128;
00357
00358 _r = _R(y,u,v);
00359 _g = _G(y,u,v);
00360 _b = _B(y,u,v);
00361
00362 r = _S(_r);
00363 g = _S(_g);
00364 b = _S(_b);
00365
00366 *dst++ = r;
00367 *dst++ = g;
00368 *dst++ = b;
00369 *dst++ = 0;
00370 }
00371
00372 pu += (width>>1);
00373 pv += (width>>1);
00374 }
00375 }
00376
00377 void YUV422PtoYUV420P(int width, int height, unsigned char *image)
00378 {
00379 uchar *srcU = image + (width*height);
00380 uchar *dstU = image + (width*height);
00381 uchar *srcV = srcU + (width*height/2);
00382 uchar *dstV = srcU + (width*height/4);
00383
00384 for (int h=0; h<height; h+=2)
00385 {
00386 memcpy(dstU, srcU, width/2);
00387 memcpy(dstV, srcV, width/2);
00388
00389 dstU += width/2;
00390 dstV += width/2;
00391 srcU += width;
00392 srcV += width;
00393 }
00394 }
00395
00396
00397 void cropYuvImage(const uchar *yuvBuffer, int ow, int oh, int cx, int cy, int cw, int ch, uchar *dst)
00398 {
00399
00400 if ((cw%2) || (ch%2) || (cx%2) || (cy%2))
00401 {
00402 cout << "YUV crop fn does not handle odd sizes; x,y=" << cx << "," << cy << " w,h=" << cw << "," << ch << endl;
00403 return;
00404 }
00405
00406 int h;
00407 const unsigned char *srcy, *srcu, *srcv;
00408 unsigned char *dsty, *dstu, *dstv;
00409 srcy = yuvBuffer + (ow*cy) + cx;
00410 srcu = yuvBuffer + (ow*oh) + (ow*cy/4) + (cx/2);
00411 srcv = srcu + (ow*oh/4);
00412 dsty = dst;
00413 dstu = dsty + (cw*ch);
00414 dstv = dstu + (cw*ch) / 4;
00415
00416 for (h=0; h<ch; h++)
00417 {
00418 memcpy(dsty, srcy, cw);
00419 dsty += cw;
00420 srcy += ow;
00421 }
00422
00423 for (h=0; h<ch/2; h++)
00424 {
00425 memcpy(dstu, srcu, cw/2);
00426 dstu += (cw/2);
00427 srcu += (ow/2);
00428 memcpy(dstv, srcv, cw/2);
00429 dstv += (cw/2);
00430 srcv += (ow/2);
00431 }
00432 }
00433
00434
00435
00436 void scaleYuvImage(const uchar *yuvBuffer, int ow, int oh, int dw, int dh, uchar *dst)
00437 {
00438 int h;
00439 uchar *dstu = dst + (dw*dh);
00440 uchar *dstv = dstu + (dw*dh/4);
00441 QImage yImage((uchar *)yuvBuffer, ow, oh, 8, (QRgb *)0, 0, QImage::LittleEndian);
00442 QImage uImage((uchar *)yuvBuffer+(ow*oh), ow/2, oh/2, 8, (QRgb *)0, 0, QImage::LittleEndian);
00443 QImage vImage((uchar *)yuvBuffer+(ow*oh*5/4), ow/2, oh/2, 8, (QRgb *)0, 0, QImage::LittleEndian);
00444
00445
00446 QImage ScaledYImage = yImage.scale(dw, dh, QImage::ScaleMax);
00447 QImage ScaledUImage = uImage.scale(dw/2, dh/2, QImage::ScaleMax);
00448 QImage ScaledVImage = vImage.scale(dw/2, dh/2, QImage::ScaleMax);
00449
00450
00451 for (h=0; h<dh; h++)
00452 {
00453 memcpy(dst, ScaledYImage.scanLine(h), dw);
00454 dst += dw;
00455 }
00456 for (h=0; h<dh/2; h++)
00457 {
00458 memcpy(dstu, ScaledUImage.scanLine(h), dw/2);
00459 memcpy(dstv, ScaledVImage.scanLine(h), dw/2);
00460 dstu += (dw/2);
00461 dstv += (dw/2);
00462 }
00463 }
00464
00465
00466 void flipYuv420pImage(const uchar *yuvBuffer, int w, int h, uchar *dst)
00467 {
00468 int h1;
00469
00470
00471 const unsigned char *srcy = yuvBuffer + (w*(h-1));
00472 for (h1=0; h1<h; h1++)
00473 {
00474 memcpy(dst, srcy, w);
00475 dst += w;
00476 srcy -= w;
00477 }
00478
00479
00480 const unsigned char *srcu = yuvBuffer + (w*h) + (w*(h-2)/4);
00481 const unsigned char *srcv = yuvBuffer + (w*h) + (w*h/4) + (w*(h-2)/4);
00482 uchar *dstu = dst;
00483 uchar *dstv = dst+(w*h/4);
00484 w /= 2;
00485 h /= 2;
00486 for (h1=0; h1<h; h1++)
00487 {
00488 memcpy(dstu, srcu, w);
00489 dstu += w;
00490 srcu -= w;
00491 memcpy(dstv, srcv, w);
00492 dstv += w;
00493 srcv -= w;
00494 }
00495 }
00496
00497
00498 void flipYuv422pImage(const uchar *yuvBuffer, int w, int h, uchar *dst)
00499 {
00500 int h1;
00501
00502
00503 const unsigned char *srcy = yuvBuffer + (w*(h-1));
00504 for (h1=0; h1<h; h1++)
00505 {
00506 memcpy(dst, srcy, w);
00507 dst += w;
00508 srcy -= w;
00509 }
00510
00511
00512 const unsigned char *srcu = yuvBuffer + (w*h) + (w*(h-1)/2);
00513 const unsigned char *srcv = yuvBuffer + (w*h) + (w*h/2) + (w*(h-1)/2);
00514 uchar *dstu = dst;
00515 uchar *dstv = dst+(w*h/2);
00516 w /= 2;
00517 for (h1=0; h1<h; h1++)
00518 {
00519 memcpy(dstu, srcu, w);
00520 dstu += w;
00521 srcu -= w;
00522 memcpy(dstv, srcv, w);
00523 dstv += w;
00524 srcv -= w;
00525 }
00526 }
00527
00528
00529 void flipRgb32Image(const uchar *rgbBuffer, int w, int h, uchar *dst)
00530 {
00531 w *= 4;
00532 const unsigned char *src = rgbBuffer + (w*(h-1));
00533 for (int h1=0; h1<h; h1++)
00534 {
00535 memcpy(dst, src, w);
00536 dst += w;
00537 src -= w;
00538 }
00539 }
00540
00541
00542 void flipRgb24Image(const uchar *rgbBuffer, int w, int h, uchar *dst)
00543 {
00544 w *= 3;
00545 const unsigned char *src = rgbBuffer + (w*(h-1));
00546 for (int h1=0; h1<h; h1++)
00547 {
00548 memcpy(dst, src, w);
00549 dst += w;
00550 src -= w;
00551 }
00552 }
00553
00554