ffmpeg.cpp
Go to the documentation of this file.
00001 /* This file is part of the Pangolin Project.
00002  * http://github.com/stevenlovegrove/Pangolin
00003  *
00004  * Copyright (c) 2011 Steven Lovegrove
00005  *
00006  * Permission is hereby granted, free of charge, to any person
00007  * obtaining a copy of this software and associated documentation
00008  * files (the "Software"), to deal in the Software without
00009  * restriction, including without limitation the rights to use,
00010  * copy, modify, merge, publish, distribute, sublicense, and/or sell
00011  * copies of the Software, and to permit persons to whom the
00012  * Software is furnished to do so, subject to the following
00013  * conditions:
00014  *
00015  * The above copyright notice and this permission notice shall be
00016  * included in all copies or substantial portions of the Software.
00017  *
00018  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00019  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
00020  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00021  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
00022  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
00023  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00024  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00025  * OTHER DEALINGS IN THE SOFTWARE.
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     // Register all formats and codecs
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     // Old (deprecated) interface - can't use with mjpeg
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     // Retrieve stream information
00157 #if (LIBAVFORMAT_VERSION_MAJOR >= 54)
00158     if(avformat_find_stream_info(pFormatCtx, 0)<0)
00159 #else
00160     // Deprecated
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         // Dump information about file onto standard error
00168 #ifdef CODEC_TYPE_VIDEO
00169         // Old (deprecated) interface
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     // Find the first video stream
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     // Get a pointer to the codec context for the video stream
00208     pVidCodecCtx = pFormatCtx->streams[videoStream]->codec;
00209 
00210     // Find the decoder for the video stream
00211     pVidCodec=avcodec_find_decoder(pVidCodecCtx->codec_id);
00212     if(pVidCodec==0)
00213         throw VideoException("Codec not found");
00214 
00215     // Open video codec
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     // Hack to correct wrong frame rates that seem to be generated by some codecs
00224     if(pVidCodecCtx->time_base.num>1000 && pVidCodecCtx->time_base.den==1)
00225         pVidCodecCtx->time_base.den=1000;
00226 
00227     // Allocate video frame
00228     pFrame=avcodec_alloc_frame();
00229 
00230     // Allocate an AVFrame structure
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     // Image dimensions
00240     const int w = pVidCodecCtx->width;
00241     const int h = pVidCodecCtx->height;
00242 
00243     // Determine required buffer size and allocate buffer
00244     numBytesOut=avpicture_get_size(fmtout, w, h);
00245 
00246     buffer= new uint8_t[numBytesOut];
00247 
00248     // Assign appropriate parts of buffer to image planes in pFrameRGB
00249     avpicture_fill((AVPicture *)pFrameOut, buffer, fmtout, w, h);
00250 
00251     // Allocate SWS for converting pixel formats
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     // Free the RGB image
00265     delete[] buffer;
00266     av_free(pFrameOut);
00267 
00268     // Free the YUV frame
00269     av_free(pFrame);
00270 
00271     // Close the codec
00272     avcodec_close(pVidCodecCtx);
00273 
00274     // Close the video file
00275 #if (LIBAVFORMAT_VERSION_MAJOR >= 54)
00276     avformat_close_input(&pFormatCtx);
00277 #else
00278     // Deprecated
00279     av_close_input_file(pFormatCtx);
00280 #endif
00281 
00282     // Free pixel conversion context
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 /*wait*/)
00316 {
00317     int gotFrame = 0;
00318 
00319     while(!gotFrame && av_read_frame(pFormatCtx, &packet)>=0)
00320     {
00321         // Is this a packet from the video stream?
00322         if(packet.stream_index==videoStream)
00323         {
00324             // Decode video frame
00325             avcodec_decode_video2(pVidCodecCtx, pFrame, &gotFrame, &packet);
00326         }
00327 
00328         // Did we get a video frame?
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         // Free the packet that was allocated by av_read_frame
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     // No-Op
00388 }
00389 
00390 void FfmpegConverter::Stop()
00391 {
00392     // No-Op
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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines


pangolin_wrapper
Author(s): Todor Stoyanov
autogenerated on Wed Feb 13 2013 14:03:25