00001
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005
00006
00007
00008
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
00046 int64_t last_dts;
00047
00048
00049
00050
00051
00052
00053 AVFrame* frame_;
00054
00055
00056 vil_memory_chunk_sptr contig_memory_;
00057
00058
00059 mutable vidl2_frame_sptr cur_frame_;
00060
00061
00062 bool deinterlace_;
00063
00064
00065
00066 unsigned frame_number_offset_;
00067 };
00068
00069
00070
00071
00072
00073 vidl2_ffmpeg_istream::
00074 vidl2_ffmpeg_istream()
00075 : is_( new vidl2_ffmpeg_istream::pimpl )
00076 {
00077 vidl2_ffmpeg_init();
00078 }
00079
00080
00081
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
00092 vidl2_ffmpeg_istream::
00093 ~vidl2_ffmpeg_istream()
00094 {
00095 close();
00096 delete is_;
00097 }
00098
00099
00100 bool
00101 vidl2_ffmpeg_istream::
00102 open(const vcl_string& filename)
00103 {
00104
00105 close();
00106
00107
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
00114 if ( av_find_stream_info( is_->fmt_cxt_ ) < 0 ) {
00115 return false;
00116 }
00117
00118
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
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
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
00189 bool
00190 vidl2_ffmpeg_istream::
00191 is_open() const
00192 {
00193 return is_->frame_;
00194 }
00195
00196
00197
00198 bool
00199 vidl2_ffmpeg_istream::
00200 is_valid() const
00201 {
00202 return is_open();
00203 }
00204
00205
00206
00207 bool
00208 vidl2_ffmpeg_istream::
00209 is_seekable() const
00210 {
00211 return true;
00212 }
00213
00214
00215
00216 unsigned int
00217 vidl2_ffmpeg_istream::
00218 frame_number() const
00219 {
00220
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
00239 bool
00240 vidl2_ffmpeg_istream::
00241 advance()
00242 {
00243
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
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
00283
00284
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
00298
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
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
00322 vidl2_frame_sptr
00323 vidl2_ffmpeg_istream::current_frame()
00324 {
00325
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
00335 if ( !is_->cur_frame_ && is_->frame_->data[0] != 0 )
00336 {
00337 int width = enc->width;
00338 int height = enc->height;
00339
00340
00341 if ( is_->deinterlace_ ) {
00342 avpicture_deinterlace( (AVPicture*)is_->frame_, (AVPicture*)is_->frame_,
00343 enc->pix_fmt, width, height );
00344 }
00345
00346
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
00365
00366
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
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
00387 is_->cur_frame_ = new vidl2_shared_frame(is_->contig_memory_->data(),width,height,fmt);
00388 }
00389 }
00390 }
00391
00392
00393
00394
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
00405
00406 bool
00407 vidl2_ffmpeg_istream::
00408 seek_frame(unsigned int frame)
00409 {
00410
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
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
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