Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

vidl2_ffmpeg_istream.cxx

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

Generated on Thu Jan 10 14:51:31 2008 for contrib/brl/bbas/vidl2 by  doxygen 1.4.4