contrib/brl/bbas/vidl2/vidl2_ffmpeg_istream_v1.txx

Go to the documentation of this file.
00001 // This is brl/bbas/vidl2/vidl2_ffmpeg_istream_v1.txx
00002 #ifndef vidl2_ffmpeg_istream_v1_txx_
00003 #define vidl2_ffmpeg_istream_v1_txx_
00004 #include "vidl2_ffmpeg_istream.h"
00005 //:
00006 // \file
00007 // \author Matt Leotta
00008 // \date   21 Dec 2005
00009 //
00010 //-----------------------------------------------------------------------------
00011 
00012 #include "vidl2_ffmpeg_init.h"
00013 #include "vidl2_frame.h"
00014 #include "vidl2_ffmpeg_convert.h"
00015 
00016 #include <vcl_string.h>
00017 #include <vcl_iostream.h>
00018 
00019 extern "C" {
00020 #if FFMPEG_IN_SEVERAL_DIRECTORIES
00021 #include <libavcodec/avcodec.h>
00022 #include <libavformat/avformat.h>
00023 #else
00024 #include <ffmpeg/avcodec.h>
00025 #include <ffmpeg/avformat.h>
00026 #endif
00027 }
00028 
00029 //--------------------------------------------------------------------------------
00030 
00031 struct vidl2_ffmpeg_istream::pimpl
00032 {
00033   pimpl()
00034   : fmt_cxt_( NULL ),
00035   vid_index_( -1 ),
00036   vid_str_( NULL ),
00037   last_dts( 0 ),
00038   frame_( NULL ),
00039   num_frames_( 0 ),
00040   cur_frame_( NULL ),
00041   deinterlace_( false ),
00042   frame_number_offset_( 0 )
00043   {
00044   }
00045 
00046   AVFormatContext* fmt_cxt_;
00047   int vid_index_;
00048   AVStream* vid_str_;
00049 
00050   //: Decode time of last frame.
00051   int64_t last_dts;
00052 
00053   //: The last successfully read frame.
00054   //
00055   // If frame_->data[0] is not NULL, then the frame corresponds to
00056   // the codec state, so that codec.width and so on apply to the
00057   // frame data.
00058   AVFrame* frame_;
00059 
00060   //: number of counted frames
00061   int num_frames_;
00062 
00063   //: A contiguous memory buffer to store the current image data
00064   vil_memory_chunk_sptr contig_memory_;
00065 
00066   //: The last successfully decoded frame.
00067   mutable vidl2_frame_sptr cur_frame_;
00068 
00069   //: Apply deinterlacing on the frames?
00070   bool deinterlace_;
00071 
00072   //: Some codec/file format combinations need a frame number offset.
00073   // These codecs have a delay between reading packets and generating frames.
00074   unsigned frame_number_offset_;
00075 };
00076 
00077 
00078 //--------------------------------------------------------------------------------
00079 
00080 //: Constructor
00081 vidl2_ffmpeg_istream::
00082 vidl2_ffmpeg_istream()
00083   : is_( new vidl2_ffmpeg_istream::pimpl )
00084 {
00085   vidl2_ffmpeg_init();
00086 }
00087 
00088 
00089 //: Constructor - from a filename
00090 vidl2_ffmpeg_istream::
00091 vidl2_ffmpeg_istream(const vcl_string& filename)
00092   : is_( new vidl2_ffmpeg_istream::pimpl )
00093 {
00094   vidl2_ffmpeg_init();
00095   open(filename);
00096 }
00097 
00098 
00099 //: Destructor
00100 vidl2_ffmpeg_istream::
00101 ~vidl2_ffmpeg_istream()
00102 {
00103   close();
00104   delete is_;
00105 }
00106 
00107 //: Open a new stream using a filename
00108 bool
00109 vidl2_ffmpeg_istream::
00110 open(const vcl_string& filename)
00111 {
00112   // Close any currently opened file
00113   close();
00114 
00115   // Open the file
00116   int err;
00117   if ( ( err = av_open_input_file( &is_->fmt_cxt_, filename.c_str(), NULL, 0, NULL ) ) != 0 ) {
00118     return false;
00119   }
00120 
00121   // Get the stream information by reading a bit of the file
00122   if ( av_find_stream_info( is_->fmt_cxt_ ) < 0 ) {
00123     return false;
00124   }
00125 
00126   // Find a video stream. Use the first one we find.
00127   is_->vid_index_ = -1;
00128   for ( unsigned int i = 0; i < is_->fmt_cxt_->nb_streams; ++i ) {
00129 #if LIBAVFORMAT_BUILD <= 4628
00130     AVCodecContext *enc = &is_->fmt_cxt_->streams[i]->codec;
00131 #else
00132     AVCodecContext *enc = is_->fmt_cxt_->streams[i]->codec;
00133 #endif
00134     if ( enc->codec_type == CODEC_TYPE_VIDEO ) {
00135   is_->vid_index_ = i;
00136   break;
00137     }
00138   }
00139   if ( is_->vid_index_ == -1 ) {
00140     return false;
00141   }
00142 
00143   dump_format( is_->fmt_cxt_, 0, filename.c_str(), 0 );
00144 #if LIBAVFORMAT_BUILD <= 4628
00145   AVCodecContext *enc = &is_->fmt_cxt_->streams[is_->vid_index_]->codec;
00146 #else
00147   AVCodecContext *enc = is_->fmt_cxt_->streams[is_->vid_index_]->codec;
00148 #endif
00149   // Open the stream
00150   AVCodec* codec = avcodec_find_decoder(enc->codec_id);
00151   if ( !codec || avcodec_open( enc, codec ) < 0 ) {
00152     return false;
00153   }
00154 
00155 #if LIBAVFORMAT_BUILD <= 4623
00156   if (enc->frame_rate>1000 && enc->frame_rate_base==1)
00157     enc->frame_rate_base=1000;
00158 #endif
00159 
00160   is_->vid_str_ = is_->fmt_cxt_->streams[ is_->vid_index_ ];
00161   is_->frame_ = avcodec_alloc_frame();
00162 
00163   is_->num_frames_ = 0;
00164   while (advance())
00165     ++is_->num_frames_;
00166 
00167   // newer releases of ffmpeg may require a 4th argument to av_seek_frame
00168 #if LIBAVFORMAT_BUILD <= 4616
00169   av_seek_frame( is_->fmt_cxt_, is_->vid_index_, 0 );
00170 #else
00171   av_seek_frame( is_->fmt_cxt_, is_->vid_index_, 0, AVSEEK_FLAG_BACKWARD );
00172 #endif
00173 
00174   return true;
00175 }
00176 
00177 
00178 //: Close the stream
00179 void
00180 vidl2_ffmpeg_istream::
00181 close()
00182 {
00183   if ( is_->frame_ ) {
00184     av_free( is_->frame_ );
00185     is_->frame_ = 0;
00186   }
00187 
00188   is_->num_frames_ = 0;
00189   is_->contig_memory_ = 0;
00190   is_->vid_index_ = -1;
00191   if ( is_->vid_str_ ) {
00192 #if LIBAVFORMAT_BUILD <= 4628
00193     avcodec_close( &is_->vid_str_->codec );
00194 #else
00195     avcodec_close( is_->vid_str_->codec );
00196 #endif
00197     is_->vid_str_ = 0;
00198   }
00199   if ( is_->fmt_cxt_ ) {
00200     av_close_input_file( is_->fmt_cxt_ );
00201     is_->fmt_cxt_ = 0;
00202   }
00203 }
00204 
00205 
00206 //: Return true if the stream is open for reading
00207 bool
00208 vidl2_ffmpeg_istream::
00209 is_open() const
00210 {
00211   return is_->frame_;
00212 }
00213 
00214 
00215 //: Return true if the stream is in a valid state
00216 bool
00217 vidl2_ffmpeg_istream::
00218 is_valid() const
00219 {
00220   return is_open() && is_->frame_->data[0] != 0;
00221 }
00222 
00223 
00224 //: Return true if the stream support seeking
00225 bool
00226 vidl2_ffmpeg_istream::
00227 is_seekable() const
00228 {
00229   return true;
00230 }
00231 
00232 
00233 //: Return the number of frames if known
00234 //  returns -1 for non-seekable streams
00235 int
00236 vidl2_ffmpeg_istream::num_frames() const
00237 {
00238   return is_->num_frames_;
00239 }
00240 
00241 
00242 //: Return the current frame number
00243 unsigned int
00244 vidl2_ffmpeg_istream::
00245 frame_number() const
00246 {
00247   // Quick return if the stream isn't open.
00248   if ( !is_valid() ) {
00249     return static_cast<unsigned int>(-1);
00250   }
00251 
00252   return ((is_->last_dts - is_->vid_str_->start_time)
00253 #if LIBAVFORMAT_BUILD <= 4623
00254           * is_->vid_str_->r_frame_rate / is_->vid_str_->r_frame_rate_base
00255           + AV_TIME_BASE/2) / AV_TIME_BASE
00256 #else
00257           * is_->vid_str_->r_frame_rate.num / is_->vid_str_->r_frame_rate.den
00258           * is_->vid_str_->time_base.num + is_->vid_str_->time_base.den/2)
00259          / is_->vid_str_->time_base.den
00260 #endif
00261       - is_->frame_number_offset_;
00262 }
00263 
00264 
00265 //: Return the width of each frame
00266 unsigned int
00267 vidl2_ffmpeg_istream
00268 ::width() const
00269 {
00270   // Quick return if the stream isn't open.
00271   if ( !is_open() ) {
00272     return 0;
00273   }
00274 #if LIBAVFORMAT_BUILD <= 4628
00275   AVCodecContext* enc = &is_->fmt_cxt_->streams[is_->vid_index_]->codec;
00276 #else
00277   AVCodecContext* enc = is_->fmt_cxt_->streams[is_->vid_index_]->codec;
00278 #endif
00279   return enc->width;
00280 }
00281 
00282 
00283 //: Return the height of each frame
00284 unsigned int
00285 vidl2_ffmpeg_istream
00286 ::height() const
00287 {
00288   // Quick return if the stream isn't open.
00289   if ( !is_open() ) {
00290     return 0;
00291   }
00292 #if LIBAVFORMAT_BUILD <= 4628
00293   AVCodecContext* enc = &is_->fmt_cxt_->streams[is_->vid_index_]->codec;
00294 #else
00295   AVCodecContext* enc = is_->fmt_cxt_->streams[is_->vid_index_]->codec;
00296 #endif
00297   return enc->height;
00298 }
00299 
00300 
00301 //: Return the pixel format
00302 vidl2_pixel_format
00303 vidl2_ffmpeg_istream
00304 ::format() const
00305 {
00306   // Quick return if the stream isn't open.
00307   if ( !is_open() ) {
00308     return VIDL2_PIXEL_FORMAT_UNKNOWN;
00309   }
00310 #if LIBAVFORMAT_BUILD <= 4628
00311   AVCodecContext* enc = &is_->fmt_cxt_->streams[is_->vid_index_]->codec;
00312 #else
00313   AVCodecContext* enc = is_->fmt_cxt_->streams[is_->vid_index_]->codec;
00314 #endif
00315   vidl2_pixel_format fmt = vidl2_pixel_format_from_ffmpeg(enc->pix_fmt);
00316   if (fmt == VIDL2_PIXEL_FORMAT_UNKNOWN)
00317     return VIDL2_PIXEL_FORMAT_RGB_24;
00318   return fmt;
00319 }
00320 
00321 
00322 //: Return the frame rate (0.0 if unspecified)
00323 double
00324 vidl2_ffmpeg_istream
00325 ::frame_rate() const
00326 {
00327   // Quick return if the stream isn't open.
00328   if ( !is_open() ) {
00329     return 0.0;
00330   }
00331 #if LIBAVFORMAT_BUILD <= 4623
00332   return static_cast<double>(is_->vid_str_->r_frame_rate)
00333          / is_->vid_str_->r_frame_rate_base
00334          / AV_TIME_BASE;
00335 #else
00336   return static_cast<double>(is_->vid_str_->time_base.num)/is_->vid_str_->time_base.den
00337          * static_cast<double>(is_->vid_str_->r_frame_rate.num) / is_->vid_str_->r_frame_rate.den;
00338 #endif
00339 }
00340 
00341 
00342 //: Advance to the next frame (but don't acquire an image)
00343 bool
00344 vidl2_ffmpeg_istream::
00345 advance()
00346 {
00347   // Quick return if the file isn't open.
00348   if ( !is_open() ) {
00349     return false;
00350   }
00351 
00352 #if LIBAVFORMAT_BUILD <= 4628
00353   AVCodecContext* codec = &is_->fmt_cxt_->streams[is_->vid_index_]->codec;
00354 #else
00355   AVCodecContext* codec = is_->fmt_cxt_->streams[is_->vid_index_]->codec;
00356 #endif
00357 
00358   AVPacket pkt;
00359   int got_picture = 0;
00360 
00361   while ( got_picture == 0 )
00362   {
00363     if ( av_read_frame( is_->fmt_cxt_, &pkt ) < 0 ) {
00364       break;
00365     }
00366     is_->last_dts = pkt.dts;
00367 
00368     // Make sure that the packet is from the actual video stream.
00369     if (pkt.stream_index==is_->vid_index_)
00370     {
00371       if ( codec->codec_id == CODEC_ID_RAWVIDEO ) {
00372         avpicture_fill( (AVPicture*)is_->frame_, pkt.data,
00373                         codec->pix_fmt,
00374                         codec->width,
00375                         codec->height );
00376         is_->frame_->pict_type = FF_I_TYPE;
00377         got_picture = 1;
00378       } else {
00379         avcodec_decode_video( codec,
00380                               is_->frame_, &got_picture,
00381                               pkt.data, pkt.size );
00382       }
00383     }
00384     av_free_packet( &pkt );
00385   }
00386 
00387   // From ffmpeg apiexample.c: some codecs, such as MPEG, transmit the
00388   // I and P frame with a latency of one frame. You must do the
00389   // following to have a chance to get the last frame of the video.
00390   if ( !got_picture ) {
00391     avcodec_decode_video( codec,
00392                           is_->frame_, &got_picture,
00393                           NULL, 0 );
00394 #if LIBAVFORMAT_BUILD <= 4623
00395       is_->last_dts += AV_TIME_BASE * is_->vid_str_->r_frame_rate_base / is_->vid_str_->r_frame_rate;
00396 #else
00397       is_->last_dts += int64_t(is_->vid_str_->time_base.den) * is_->vid_str_->r_frame_rate.den
00398                   / is_->vid_str_->time_base.num / is_->vid_str_->r_frame_rate.num;
00399 #endif
00400   }
00401 
00402   // The cached frame is out of date, whether we managed to get a new
00403   // frame or not.
00404   if (is_->cur_frame_)
00405     is_->cur_frame_->invalidate();
00406   is_->cur_frame_ = 0;
00407 
00408   if ( ! got_picture ) {
00409     is_->frame_->data[0] = NULL;
00410   }
00411 
00412   return got_picture != 0;
00413 }
00414 
00415 
00416 //: Read the next frame from the stream
00417 vidl2_frame_sptr
00418 vidl2_ffmpeg_istream::read_frame()
00419 {
00420   if (advance())
00421     return current_frame();
00422   return NULL;
00423 }
00424 
00425 
00426 //: Return the current frame in the stream
00427 vidl2_frame_sptr
00428 vidl2_ffmpeg_istream::current_frame()
00429 {
00430   // Quick return if the stream isn't valid
00431   if ( !is_valid() ) {
00432     return NULL;
00433   }
00434 #if LIBAVFORMAT_BUILD <= 4628
00435   AVCodecContext* enc = &is_->fmt_cxt_->streams[is_->vid_index_]->codec;
00436 #else
00437   AVCodecContext* enc = is_->fmt_cxt_->streams[is_->vid_index_]->codec;
00438 #endif
00439   // If we have not already converted this frame, try to convert it
00440   if ( !is_->cur_frame_ && is_->frame_->data[0] != 0 )
00441   {
00442     int width = enc->width;
00443     int height = enc->height;
00444 
00445     // Deinterlace if requested
00446     if ( is_->deinterlace_ ) {
00447       avpicture_deinterlace( (AVPicture*)is_->frame_, (AVPicture*)is_->frame_,
00448                              enc->pix_fmt, width, height );
00449     }
00450 
00451     // If the pixel format is not recognized by vidl2 then convert the data into RGB_24
00452     vidl2_pixel_format fmt = vidl2_pixel_format_from_ffmpeg(enc->pix_fmt);
00453     if (fmt == VIDL2_PIXEL_FORMAT_UNKNOWN)
00454     {
00455       int size = width*height*3;
00456       if (!is_->contig_memory_)
00457         is_->contig_memory_ = new vil_memory_chunk(size, VIL_PIXEL_FORMAT_BYTE);
00458       else
00459         is_->contig_memory_->set_size(size, VIL_PIXEL_FORMAT_BYTE);
00460 
00461       AVPicture rgb_frame;
00462       avpicture_fill(&rgb_frame, (uint8_t*)is_->contig_memory_->data(), PIX_FMT_RGB24, width, height);
00463       img_convert(&rgb_frame, PIX_FMT_RGB24, (AVPicture*)is_->frame_, enc->pix_fmt, width, height);
00464       is_->cur_frame_ = new vidl2_shared_frame(is_->contig_memory_->data(),width,height,
00465                                                VIDL2_PIXEL_FORMAT_RGB_24);
00466     }
00467     else
00468     {
00469       // Test for contiguous memory.  Sometimes FFMPEG uses scanline buffers larger
00470       // than the image width.  The extra memory is used in optimized decoding routines.
00471       // This leads to a segmented image buffer, not supported by vidl2.
00472       AVPicture test_frame;
00473       avpicture_fill(&test_frame, is_->frame_->data[0], enc->pix_fmt, width, height);
00474       if (test_frame.data[1] == is_->frame_->data[1] &&
00475           test_frame.data[2] == is_->frame_->data[2] &&
00476           test_frame.linesize[0] == is_->frame_->linesize[0] &&
00477           test_frame.linesize[1] == is_->frame_->linesize[1] &&
00478           test_frame.linesize[2] == is_->frame_->linesize[2] )
00479       {
00480         is_->cur_frame_ = new vidl2_shared_frame(is_->frame_->data[0], width, height, fmt);
00481       }
00482       // Copy the image into contiguous memory.
00483       else
00484       {
00485         if (!is_->contig_memory_){
00486           int size = avpicture_get_size( enc->pix_fmt, width, height );
00487           is_->contig_memory_ = new vil_memory_chunk(size, VIL_PIXEL_FORMAT_BYTE);
00488         }
00489         avpicture_fill(&test_frame, (uint8_t*)is_->contig_memory_->data(), enc->pix_fmt, width, height);
00490         img_copy(&test_frame, (AVPicture*)is_->frame_, enc->pix_fmt, width, height);
00491         // use a shared frame because the vil_memory_chunk is reused for each frame
00492         is_->cur_frame_ = new vidl2_shared_frame(is_->contig_memory_->data(),width,height,fmt);
00493       }
00494     }
00495   }
00496 
00497   // The MPEG 2 codec has a latency of 1 frame, so the dts of the last
00498   // packet (stored in last_dts) is actually the next frame's
00499   // dts.
00500   if ( enc->codec_id == CODEC_ID_MPEG2VIDEO &&
00501        vcl_string("avi") == is_->fmt_cxt_->iformat->name ) {
00502     is_->frame_number_offset_ = 1;
00503   }
00504 
00505   return is_->cur_frame_;
00506 }
00507 
00508 
00509 //: Seek to the given frame number
00510 // \returns true if successful
00511 bool
00512 vidl2_ffmpeg_istream::
00513 seek_frame(unsigned int frame)
00514 {
00515   // Quick return if the stream isn't open.
00516   if ( !is_open() ) {
00517     return false;
00518   }
00519 
00520 #if LIBAVFORMAT_BUILD <= 4623
00521   int64_t frame_size = int64_t(AV_TIME_BASE) * is_->vid_str_->r_frame_rate_base
00522                        / is_->vid_str_->r_frame_rate;
00523   int64_t req_timestamp = int64_t(AV_TIME_BASE) * frame * is_->vid_str_->r_frame_rate_base
00524                        / is_->vid_str_->r_frame_rate + is_->vid_str_->start_time;
00525 #else
00526   int64_t frame_size = int64_t(is_->vid_str_->time_base.den) * is_->vid_str_->r_frame_rate.den
00527                        / is_->vid_str_->time_base.num / is_->vid_str_->r_frame_rate.num;
00528   int64_t req_timestamp = int64_t(is_->vid_str_->time_base.den) * frame * is_->vid_str_->r_frame_rate.den
00529                        / is_->vid_str_->time_base.num / is_->vid_str_->r_frame_rate.num + is_->vid_str_->start_time;
00530 #endif
00531 
00532   if ( req_timestamp > frame_size/2 )
00533     req_timestamp -= frame_size/2;
00534   else
00535     req_timestamp = 0;
00536 
00537   // newer releases of ffmpeg may require a 4th argument to av_seek_frame
00538 #if LIBAVFORMAT_BUILD <= 4616
00539   int seek = av_seek_frame( is_->fmt_cxt_, is_->vid_index_, req_timestamp );
00540 #else
00541   int seek = av_seek_frame( is_->fmt_cxt_, is_->vid_index_, req_timestamp, AVSEEK_FLAG_BACKWARD );
00542 #endif
00543 
00544   if ( seek < 0 )
00545     return false;
00546   // We got to a key frame. Forward until we get to the frame we want.
00547   while ( true )
00548   {
00549     if ( ! advance() ) {
00550       return false;
00551     }
00552     if ( is_->last_dts >= req_timestamp ) {
00553       if ( is_->last_dts >= req_timestamp + frame_size ) {
00554         vcl_cerr << "Warning: seek went into the future!\n";
00555         return false;
00556       }
00557       return true;
00558     }
00559   }
00560 }
00561 
00562 #endif // vidl2_ffmpeg_istream_v1_txx_

Generated on Wed Dec 3 05:21:03 2008 for contrib/brl/bbas/vidl2 by  doxygen 1.5.1