00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "ffmpeg.h"
00029
00030 namespace pangolin
00031 {
00032
00033 PixelFormat FfmpegFmtFromString(const std::string fmt)
00034 {
00035 std::string lfmt = boost::algorithm::to_lower_copy(fmt);
00036 if(!lfmt.compare("gray8") || !lfmt.compare("grey8") || !lfmt.compare("grey"))
00037 {
00038 return PIX_FMT_GRAY8;
00039 }
00040 return av_get_pix_fmt(lfmt.c_str());
00041 }
00042
00043 #define TEST_PIX_FMT_RETURN(fmt) case PIX_FMT_##fmt: return #fmt;
00044
00045 std::string FfmpegFmtToString(const PixelFormat fmt)
00046 {
00047 switch( fmt )
00048 {
00049 TEST_PIX_FMT_RETURN(YUV420P);
00050 TEST_PIX_FMT_RETURN(YUYV422);
00051 TEST_PIX_FMT_RETURN(RGB24);
00052 TEST_PIX_FMT_RETURN(BGR24);
00053 TEST_PIX_FMT_RETURN(YUV422P);
00054 TEST_PIX_FMT_RETURN(YUV444P);
00055 TEST_PIX_FMT_RETURN(YUV410P);
00056 TEST_PIX_FMT_RETURN(YUV411P);
00057 TEST_PIX_FMT_RETURN(GRAY8);
00058 TEST_PIX_FMT_RETURN(MONOWHITE);
00059 TEST_PIX_FMT_RETURN(MONOBLACK);
00060 TEST_PIX_FMT_RETURN(PAL8);
00061 TEST_PIX_FMT_RETURN(YUVJ420P);
00062 TEST_PIX_FMT_RETURN(YUVJ422P);
00063 TEST_PIX_FMT_RETURN(YUVJ444P);
00064 TEST_PIX_FMT_RETURN(XVMC_MPEG2_MC);
00065 TEST_PIX_FMT_RETURN(XVMC_MPEG2_IDCT);
00066 TEST_PIX_FMT_RETURN(UYVY422);
00067 TEST_PIX_FMT_RETURN(UYYVYY411);
00068 TEST_PIX_FMT_RETURN(BGR8);
00069 TEST_PIX_FMT_RETURN(BGR4);
00070 TEST_PIX_FMT_RETURN(BGR4_BYTE);
00071 TEST_PIX_FMT_RETURN(RGB8);
00072 TEST_PIX_FMT_RETURN(RGB4);
00073 TEST_PIX_FMT_RETURN(RGB4_BYTE);
00074 TEST_PIX_FMT_RETURN(NV12);
00075 TEST_PIX_FMT_RETURN(NV21);
00076 TEST_PIX_FMT_RETURN(ARGB);
00077 TEST_PIX_FMT_RETURN(RGBA);
00078 TEST_PIX_FMT_RETURN(ABGR);
00079 TEST_PIX_FMT_RETURN(BGRA);
00080 TEST_PIX_FMT_RETURN(GRAY16BE);
00081 TEST_PIX_FMT_RETURN(GRAY16LE);
00082 TEST_PIX_FMT_RETURN(YUV440P);
00083 TEST_PIX_FMT_RETURN(YUVJ440P);
00084 TEST_PIX_FMT_RETURN(YUVA420P);
00085 TEST_PIX_FMT_RETURN(VDPAU_H264);
00086 TEST_PIX_FMT_RETURN(VDPAU_MPEG1);
00087 TEST_PIX_FMT_RETURN(VDPAU_MPEG2);
00088 TEST_PIX_FMT_RETURN(VDPAU_WMV3);
00089 TEST_PIX_FMT_RETURN(VDPAU_VC1);
00090 TEST_PIX_FMT_RETURN(RGB48BE );
00091 TEST_PIX_FMT_RETURN(RGB48LE );
00092 TEST_PIX_FMT_RETURN(RGB565BE);
00093 TEST_PIX_FMT_RETURN(RGB565LE);
00094 TEST_PIX_FMT_RETURN(RGB555BE);
00095 TEST_PIX_FMT_RETURN(RGB555LE);
00096 TEST_PIX_FMT_RETURN(BGR565BE);
00097 TEST_PIX_FMT_RETURN(BGR565LE);
00098 TEST_PIX_FMT_RETURN(BGR555BE);
00099 TEST_PIX_FMT_RETURN(BGR555LE);
00100 TEST_PIX_FMT_RETURN(VAAPI_MOCO);
00101 TEST_PIX_FMT_RETURN(VAAPI_IDCT);
00102 TEST_PIX_FMT_RETURN(VAAPI_VLD);
00103 TEST_PIX_FMT_RETURN(YUV420P16LE);
00104 TEST_PIX_FMT_RETURN(YUV420P16BE);
00105 TEST_PIX_FMT_RETURN(YUV422P16LE);
00106 TEST_PIX_FMT_RETURN(YUV422P16BE);
00107 TEST_PIX_FMT_RETURN(YUV444P16LE);
00108 TEST_PIX_FMT_RETURN(YUV444P16BE);
00109 TEST_PIX_FMT_RETURN(VDPAU_MPEG4);
00110 TEST_PIX_FMT_RETURN(DXVA2_VLD);
00111 TEST_PIX_FMT_RETURN(RGB444BE);
00112 TEST_PIX_FMT_RETURN(RGB444LE);
00113 TEST_PIX_FMT_RETURN(BGR444BE);
00114 TEST_PIX_FMT_RETURN(BGR444LE);
00115 TEST_PIX_FMT_RETURN(Y400A );
00116 TEST_PIX_FMT_RETURN(NB );
00117 default:
00118 return "";
00119 }
00120 }
00121
00122 #undef TEST_PIX_FMT_RETURN
00123
00124 FfmpegVideo::FfmpegVideo(const std::string filename, const std::string strfmtout, const std::string codec_hint, bool dump_info, int user_video_stream)
00125 :pFormatCtx(0)
00126 {
00127 InitUrl(filename, strfmtout, codec_hint, dump_info, user_video_stream);
00128 }
00129
00130 void FfmpegVideo::InitUrl(const std::string url, const std::string strfmtout, const std::string codec_hint, bool dump_info, int user_video_stream)
00131 {
00132 if( url.find('*') != url.npos )
00133 throw VideoException("Wildcards not supported. Please use ffmpegs printf style formatting for image sequences. e.g. img-000000%04d.ppm");
00134
00135
00136 av_register_all();
00137
00138 AVInputFormat* fmt = NULL;
00139
00140 if( !codec_hint.empty() )
00141 {
00142 fmt = av_find_input_format(codec_hint.c_str());
00143 }
00144
00145 #ifdef CODEC_TYPE_VIDEO
00146
00147 if( av_open_input_file(&pFormatCtx, url.c_str(), fmt, 0, NULL) )
00148 #else
00149 if( avformat_open_input(&pFormatCtx, url.c_str(), fmt, NULL) )
00150 #endif
00151 throw VideoException("Couldn't open stream");
00152
00153 if( !boost::algorithm::to_lower_copy(codec_hint).compare("mjpeg") )
00154 pFormatCtx->max_analyze_duration = AV_TIME_BASE * 0.0;
00155
00156
00157 #if (LIBAVFORMAT_VERSION_MAJOR >= 54)
00158 if(avformat_find_stream_info(pFormatCtx, 0)<0)
00159 #else
00160
00161 if(av_find_stream_info(pFormatCtx)<0)
00162 #endif
00163 throw VideoException("Couldn't find stream information");
00164
00165 if(dump_info)
00166 {
00167
00168 #ifdef CODEC_TYPE_VIDEO
00169
00170 dump_format(pFormatCtx, 0, url.c_str(), false);
00171 #else
00172 av_dump_format(pFormatCtx, 0, url.c_str(), false);
00173 #endif
00174 }
00175
00176
00177 videoStream=-1;
00178 audioStream=-1;
00179
00180 std::vector<int> videoStreams;
00181 std::vector<int> audioStreams;
00182
00183 for(unsigned i=0; i<pFormatCtx->nb_streams; i++)
00184 {
00185 if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
00186 {
00187 videoStreams.push_back(i);
00188 }
00189 else if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO)
00190 {
00191 audioStreams.push_back(i);
00192 }
00193 }
00194
00195 if(videoStreams.size()==0)
00196 throw VideoException("Couldn't find a video stream");
00197
00198 if(0 <= user_video_stream && user_video_stream < (int)videoStreams.size() )
00199 {
00200 videoStream = videoStreams[user_video_stream];
00201 }
00202 else
00203 {
00204 videoStream = videoStreams[0];
00205 }
00206
00207
00208 pVidCodecCtx = pFormatCtx->streams[videoStream]->codec;
00209
00210
00211 pVidCodec=avcodec_find_decoder(pVidCodecCtx->codec_id);
00212 if(pVidCodec==0)
00213 throw VideoException("Codec not found");
00214
00215
00216 #if LIBAVCODEC_VERSION_MAJOR > 52
00217 if(avcodec_open2(pVidCodecCtx, pVidCodec,0)<0)
00218 #else
00219 if(avcodec_open(pVidCodecCtx, pVidCodec)<0)
00220 #endif
00221 throw VideoException("Could not open codec");
00222
00223
00224 if(pVidCodecCtx->time_base.num>1000 && pVidCodecCtx->time_base.den==1)
00225 pVidCodecCtx->time_base.den=1000;
00226
00227
00228 pFrame=avcodec_alloc_frame();
00229
00230
00231 pFrameOut=avcodec_alloc_frame();
00232 if(pFrameOut==0)
00233 throw VideoException("Couldn't allocate frame");
00234
00235 fmtout = FfmpegFmtFromString(strfmtout);
00236 if(fmtout == PIX_FMT_NONE )
00237 throw VideoException("Output format not recognised",strfmtout);
00238
00239
00240 const int w = pVidCodecCtx->width;
00241 const int h = pVidCodecCtx->height;
00242
00243
00244 numBytesOut=avpicture_get_size(fmtout, w, h);
00245
00246 buffer= new uint8_t[numBytesOut];
00247
00248
00249 avpicture_fill((AVPicture *)pFrameOut, buffer, fmtout, w, h);
00250
00251
00252 img_convert_ctx = sws_getContext(w, h,
00253 pVidCodecCtx->pix_fmt,
00254 w, h, fmtout, FFMPEG_POINT,
00255 NULL, NULL, NULL);
00256 if(img_convert_ctx == NULL)
00257 {
00258 throw VideoException("Cannot initialize the conversion context");
00259 }
00260 }
00261
00262 FfmpegVideo::~FfmpegVideo()
00263 {
00264
00265 delete[] buffer;
00266 av_free(pFrameOut);
00267
00268
00269 av_free(pFrame);
00270
00271
00272 avcodec_close(pVidCodecCtx);
00273
00274
00275 #if (LIBAVFORMAT_VERSION_MAJOR >= 54)
00276 avformat_close_input(&pFormatCtx);
00277 #else
00278
00279 av_close_input_file(pFormatCtx);
00280 #endif
00281
00282
00283 sws_freeContext(img_convert_ctx);
00284 }
00285
00286
00287 unsigned FfmpegVideo::Width() const
00288 {
00289 return pVidCodecCtx->width;
00290 }
00291
00292 unsigned FfmpegVideo::Height() const
00293 {
00294 return pVidCodecCtx->height;
00295 }
00296
00297 size_t FfmpegVideo::SizeBytes() const
00298 {
00299 return numBytesOut;
00300 }
00301
00302 std::string FfmpegVideo::PixFormat() const
00303 {
00304 return FfmpegFmtToString(fmtout);
00305 }
00306
00307 void FfmpegVideo::Start()
00308 {
00309 }
00310
00311 void FfmpegVideo::Stop()
00312 {
00313 }
00314
00315 bool FfmpegVideo::GrabNext(unsigned char* image, bool )
00316 {
00317 int gotFrame = 0;
00318
00319 while(!gotFrame && av_read_frame(pFormatCtx, &packet)>=0)
00320 {
00321
00322 if(packet.stream_index==videoStream)
00323 {
00324
00325 avcodec_decode_video2(pVidCodecCtx, pFrame, &gotFrame, &packet);
00326 }
00327
00328
00329 if(gotFrame)
00330 {
00331 sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pVidCodecCtx->height, pFrameOut->data, pFrameOut->linesize);
00332 memcpy(image,pFrameOut->data[0],numBytesOut);
00333 }
00334
00335
00336 av_free_packet(&packet);
00337 }
00338
00339 return gotFrame;
00340 }
00341
00342 bool FfmpegVideo::GrabNewest(unsigned char *image, bool wait)
00343 {
00344 return GrabNext(image,wait);
00345 }
00346
00347 FfmpegConverter::FfmpegConverter(VideoInterface* videoin, const std::string pixelfmtout, FfmpegMethod method )
00348 :videoin(videoin)
00349 {
00350 if( !videoin )
00351 throw VideoException("Source video interface not specified");
00352
00353 w = videoin->Width();
00354 h = videoin->Height();
00355 fmtsrc = FfmpegFmtFromString(videoin->PixFormat());
00356 fmtdst = FfmpegFmtFromString(pixelfmtout);
00357
00358 img_convert_ctx = sws_getContext(
00359 w, h, fmtsrc,
00360 w, h, fmtdst,
00361 method, NULL, NULL, NULL
00362 );
00363 if(!img_convert_ctx)
00364 throw VideoException("Could not create SwScale context for pixel conversion");
00365
00366 numbytessrc=avpicture_get_size(fmtsrc, w, h);
00367 numbytesdst=avpicture_get_size(fmtdst, w, h);
00368 bufsrc = new uint8_t[numbytessrc];
00369 bufdst = new uint8_t[numbytesdst];
00370 avsrc = avcodec_alloc_frame();
00371 avdst = avcodec_alloc_frame();
00372 avpicture_fill((AVPicture*)avsrc,bufsrc,fmtsrc,w,h);
00373 avpicture_fill((AVPicture*)avdst,bufdst,fmtdst,w,h);
00374 }
00375
00376 FfmpegConverter::~FfmpegConverter()
00377 {
00378 sws_freeContext(img_convert_ctx);
00379 delete[] bufsrc;
00380 av_free(avsrc);
00381 delete[] bufdst;
00382 av_free(avdst);
00383 }
00384
00385 void FfmpegConverter::Start()
00386 {
00387
00388 }
00389
00390 void FfmpegConverter::Stop()
00391 {
00392
00393 }
00394
00395 unsigned FfmpegConverter::Width() const
00396 {
00397 return w;
00398 }
00399
00400 unsigned FfmpegConverter::Height() const
00401 {
00402 return h;
00403 }
00404
00405 size_t FfmpegConverter::SizeBytes() const
00406 {
00407 return numbytesdst;
00408 }
00409
00410 std::string FfmpegConverter::PixFormat() const
00411 {
00412 return FfmpegFmtToString(fmtdst);
00413 }
00414
00415 bool FfmpegConverter::GrabNext( unsigned char* image, bool wait )
00416 {
00417 if( videoin->GrabNext(avsrc->data[0],wait) )
00418 {
00419 sws_scale(
00420 img_convert_ctx,
00421 avsrc->data, avsrc->linesize, 0, h,
00422 avdst->data, avdst->linesize
00423 );
00424 memcpy(image,avdst->data[0],numbytesdst);
00425 return true;
00426 }
00427 return false;
00428 }
00429
00430 bool FfmpegConverter::GrabNewest( unsigned char* image, bool wait )
00431 {
00432 if( videoin->GrabNewest(avsrc->data[0],wait) )
00433 {
00434 sws_scale(
00435 img_convert_ctx,
00436 avsrc->data, avsrc->linesize, 0, h,
00437 avdst->data, avdst->linesize
00438 );
00439 memcpy(image,avdst->data[0],numbytesdst);
00440 return true;
00441 }
00442 return false;
00443 }
00444
00445 }
00446