00001
00002 #ifndef vidl2_ffmpeg_istream_v2_txx_
00003 #define vidl2_ffmpeg_istream_v2_txx_
00004 #include "vidl2_ffmpeg_istream.h"
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "vidl2_ffmpeg_init.h"
00016 #include "vidl2_frame.h"
00017 #include "vidl2_ffmpeg_convert.h"
00018
00019 #include <vcl_string.h>
00020 #include <vcl_iostream.h>
00021
00022 extern "C" {
00023 #if FFMPEG_IN_SEVERAL_DIRECTORIES
00024 #include <libavcodec/avcodec.h>
00025 #include <libavformat/avformat.h>
00026 #include <libswscale/swscale.h>
00027 #else
00028 #include <ffmpeg/avcodec.h>
00029 #include <ffmpeg/avformat.h>
00030 #include <ffmpeg/swscale.h>
00031 #endif
00032 }
00033
00034
00035
00036 struct vidl2_ffmpeg_istream::pimpl
00037 {
00038 pimpl()
00039 : fmt_cxt_( NULL ),
00040 vid_index_( -1 ),
00041 vid_str_( NULL ),
00042 last_dts( 0 ),
00043 frame_( NULL ),
00044 num_frames_( 0 ),
00045 sws_context_( NULL ),
00046 cur_frame_( NULL ),
00047 deinterlace_( false ),
00048 frame_number_offset_( 0 )
00049 {
00050 }
00051
00052 AVFormatContext* fmt_cxt_;
00053 int vid_index_;
00054 AVStream* vid_str_;
00055
00056
00057 int64_t last_dts;
00058
00059
00060 int64_t start_time;
00061
00062
00063
00064
00065
00066
00067 AVFrame* frame_;
00068
00069
00070 int num_frames_;
00071
00072
00073
00074
00075
00076
00077
00078 SwsContext* sws_context_;
00079
00080
00081 vil_memory_chunk_sptr contig_memory_;
00082
00083
00084 mutable vidl2_frame_sptr cur_frame_;
00085
00086
00087 bool deinterlace_;
00088
00089
00090
00091 unsigned frame_number_offset_;
00092 };
00093
00094
00095
00096
00097
00098 vidl2_ffmpeg_istream::
00099 vidl2_ffmpeg_istream()
00100 : is_( new vidl2_ffmpeg_istream::pimpl )
00101 {
00102 vidl2_ffmpeg_init();
00103 }
00104
00105
00106
00107 vidl2_ffmpeg_istream::
00108 vidl2_ffmpeg_istream(const vcl_string& filename)
00109 : is_( new vidl2_ffmpeg_istream::pimpl )
00110 {
00111 vidl2_ffmpeg_init();
00112 open(filename);
00113 }
00114
00115
00116
00117 vidl2_ffmpeg_istream::
00118 ~vidl2_ffmpeg_istream()
00119 {
00120 close();
00121 delete is_;
00122 }
00123
00124
00125 bool
00126 vidl2_ffmpeg_istream::
00127 open(const vcl_string& filename)
00128 {
00129
00130 close();
00131
00132
00133 int err;
00134 if ( ( err = av_open_input_file( &is_->fmt_cxt_, filename.c_str(), NULL, 0, NULL ) ) != 0 ) {
00135 return false;
00136 }
00137
00138
00139 if ( av_find_stream_info( is_->fmt_cxt_ ) < 0 ) {
00140 return false;
00141 }
00142
00143
00144 is_->vid_index_ = -1;
00145 for ( unsigned i = 0; i < is_->fmt_cxt_->nb_streams; ++i ) {
00146 AVCodecContext *enc = is_->fmt_cxt_->streams[i]->codec;
00147 if ( enc->codec_type == CODEC_TYPE_VIDEO ) {
00148 is_->vid_index_ = i;
00149 break;
00150 }
00151 }
00152 if ( is_->vid_index_ == -1 ) {
00153 return false;
00154 }
00155
00156 dump_format( is_->fmt_cxt_, 0, filename.c_str(), 0 );
00157 AVCodecContext *enc = is_->fmt_cxt_->streams[is_->vid_index_]->codec;
00158
00159
00160 AVCodec* codec = avcodec_find_decoder(enc->codec_id);
00161 if ( !codec || avcodec_open( enc, codec ) < 0 ) {
00162 return false;
00163 }
00164
00165 is_->vid_str_ = is_->fmt_cxt_->streams[ is_->vid_index_ ];
00166 is_->frame_ = avcodec_alloc_frame();
00167
00168 if ( is_->vid_str_->start_time == int64_t(1)<<63 ) {
00169 is_->start_time = 0;
00170 } else {
00171 is_->start_time = is_->vid_str_->start_time;
00172 }
00173
00174
00175
00176
00177
00178 if ( is_->vid_str_->codec->codec_id == CODEC_ID_MPEG2VIDEO &&
00179 vcl_string("avi") == is_->fmt_cxt_->iformat->name ) {
00180 is_->frame_number_offset_ = 1;
00181 }
00182
00183 is_->num_frames_ = 0;
00184 while(advance())
00185 ++is_->num_frames_;
00186
00187 av_seek_frame( is_->fmt_cxt_, is_->vid_index_, 0, AVSEEK_FLAG_BACKWARD );
00188
00189 return true;
00190 }
00191
00192
00193
00194 void
00195 vidl2_ffmpeg_istream::
00196 close()
00197 {
00198 if ( is_->frame_ ) {
00199 av_freep( &is_->frame_ );
00200 }
00201
00202 is_->num_frames_ = 0;
00203 is_->contig_memory_ = 0;
00204 is_->vid_index_ = -1;
00205 if ( is_->vid_str_ ) {
00206 avcodec_close( is_->vid_str_->codec );
00207 is_->vid_str_ = 0;
00208 }
00209 if ( is_->fmt_cxt_ ) {
00210 av_close_input_file( is_->fmt_cxt_ );
00211 is_->fmt_cxt_ = 0;
00212 }
00213 }
00214
00215
00216
00217 bool
00218 vidl2_ffmpeg_istream::
00219 is_open() const
00220 {
00221 return is_->frame_;
00222 }
00223
00224
00225
00226 bool
00227 vidl2_ffmpeg_istream::
00228 is_valid() const
00229 {
00230 return is_open() && is_->frame_->data[0] != 0;
00231 }
00232
00233
00234
00235 bool
00236 vidl2_ffmpeg_istream::
00237 is_seekable() const
00238 {
00239 return true;
00240 }
00241
00242
00243
00244
00245 int
00246 vidl2_ffmpeg_istream::num_frames() const
00247 {
00248 return is_->num_frames_;
00249 }
00250
00251
00252
00253 unsigned int
00254 vidl2_ffmpeg_istream::
00255 frame_number() const
00256 {
00257
00258 if ( !is_valid() ) {
00259 return static_cast<unsigned int>(-1);
00260 }
00261
00262 return ((is_->last_dts - is_->start_time)
00263 * is_->vid_str_->r_frame_rate.num / is_->vid_str_->r_frame_rate.den
00264 * is_->vid_str_->time_base.num + is_->vid_str_->time_base.den/2)
00265 / is_->vid_str_->time_base.den
00266 - is_->frame_number_offset_;
00267 }
00268
00269
00270
00271 unsigned int
00272 vidl2_ffmpeg_istream
00273 ::width() const
00274 {
00275
00276 if ( !is_open() ) {
00277 return 0;
00278 }
00279
00280 return is_->fmt_cxt_->streams[is_->vid_index_]->codec->width;
00281 }
00282
00283
00284
00285 unsigned int
00286 vidl2_ffmpeg_istream
00287 ::height() const
00288 {
00289
00290 if ( !is_open() ) {
00291 return 0;
00292 }
00293
00294 return is_->fmt_cxt_->streams[is_->vid_index_]->codec->height;
00295 }
00296
00297
00298
00299 vidl2_pixel_format
00300 vidl2_ffmpeg_istream
00301 ::format() const
00302 {
00303
00304 if ( !is_open() ) {
00305 return VIDL2_PIXEL_FORMAT_UNKNOWN;
00306 }
00307
00308 AVCodecContext* enc = is_->fmt_cxt_->streams[is_->vid_index_]->codec;
00309 vidl2_pixel_format fmt = vidl2_pixel_format_from_ffmpeg(enc->pix_fmt);
00310 if (fmt == VIDL2_PIXEL_FORMAT_UNKNOWN)
00311 return VIDL2_PIXEL_FORMAT_RGB_24;
00312 return fmt;
00313 }
00314
00315
00316
00317 double
00318 vidl2_ffmpeg_istream
00319 ::frame_rate() const
00320 {
00321
00322 if ( !is_open() ) {
00323 return 0.0;
00324 }
00325
00326 return static_cast<double>(is_->vid_str_->time_base.num)/is_->vid_str_->time_base.den
00327 * static_cast<double>(is_->vid_str_->r_frame_rate.num) / is_->vid_str_->r_frame_rate.den;
00328 }
00329
00330
00331
00332 bool
00333 vidl2_ffmpeg_istream::
00334 advance()
00335 {
00336
00337 if ( !is_open() ) {
00338 return false;
00339 }
00340
00341 AVCodecContext* codec = is_->fmt_cxt_->streams[is_->vid_index_]->codec;
00342
00343 AVPacket pkt;
00344 int got_picture = 0;
00345
00346 while ( got_picture == 0 ) {
00347 if ( av_read_frame( is_->fmt_cxt_, &pkt ) < 0 ) {
00348 break;
00349 }
00350 is_->last_dts = pkt.dts;
00351
00352
00353 if (pkt.stream_index==is_->vid_index_)
00354 {
00355 if ( avcodec_decode_video( codec,
00356 is_->frame_, &got_picture,
00357 pkt.data, pkt.size ) < 0 ) {
00358 vcl_cerr << "vidl2_ffmpeg_istream: Error decoding packet!\n";
00359 return false;
00360 }
00361 }
00362 av_free_packet( &pkt );
00363 }
00364
00365
00366
00367
00368 if ( !got_picture ) {
00369 if ( avcodec_decode_video( codec,
00370 is_->frame_, &got_picture,
00371 NULL, 0 ) >= 0 ) {
00372 is_->last_dts += int64_t(is_->vid_str_->time_base.den) * is_->vid_str_->r_frame_rate.den
00373 / is_->vid_str_->time_base.num / is_->vid_str_->r_frame_rate.num;
00374 }
00375 }
00376
00377
00378
00379 if (is_->cur_frame_)
00380 is_->cur_frame_->invalidate();
00381 is_->cur_frame_ = 0;
00382
00383 if ( ! got_picture ) {
00384 is_->frame_->data[0] = NULL;
00385 }
00386
00387 return got_picture != 0;
00388 }
00389
00390
00391
00392 vidl2_frame_sptr
00393 vidl2_ffmpeg_istream::read_frame()
00394 {
00395 if (advance())
00396 return current_frame();
00397 return NULL;
00398 }
00399
00400
00401
00402 vidl2_frame_sptr
00403 vidl2_ffmpeg_istream::current_frame()
00404 {
00405
00406 if ( !is_valid() ) {
00407 return NULL;
00408 }
00409 AVCodecContext* enc = is_->fmt_cxt_->streams[is_->vid_index_]->codec;
00410
00411 if ( !is_->cur_frame_ && is_->frame_->data[0] != 0 )
00412 {
00413 int width = enc->width;
00414 int height = enc->height;
00415
00416
00417 if ( is_->deinterlace_ ) {
00418 avpicture_deinterlace( (AVPicture*)is_->frame_, (AVPicture*)is_->frame_,
00419 enc->pix_fmt, width, height );
00420 }
00421
00422
00423 vidl2_pixel_format fmt = vidl2_pixel_format_from_ffmpeg(enc->pix_fmt);
00424 if (fmt == VIDL2_PIXEL_FORMAT_UNKNOWN)
00425 {
00426 int size = width*height*3;
00427 if (!is_->contig_memory_)
00428 is_->contig_memory_ = new vil_memory_chunk(size, VIL_PIXEL_FORMAT_BYTE);
00429 else
00430 is_->contig_memory_->set_size(size, VIL_PIXEL_FORMAT_BYTE);
00431
00432
00433 is_->sws_context_ = sws_getCachedContext(
00434 is_->sws_context_,
00435 width, height, enc->pix_fmt,
00436 width, height, PIX_FMT_RGB24,
00437 SWS_BILINEAR,
00438 NULL, NULL, NULL );
00439
00440 if ( is_->sws_context_ == NULL ) {
00441 vcl_cerr << "vidl2_ffmpeg_istream: couldn't create conversion context\n";
00442 return vidl2_frame_sptr();
00443 }
00444
00445 AVPicture rgb_frame;
00446 avpicture_fill(&rgb_frame, (uint8_t*)is_->contig_memory_->data(), PIX_FMT_RGB24, width, height);
00447
00448 sws_scale( is_->sws_context_,
00449 is_->frame_->data, is_->frame_->linesize,
00450 0, height,
00451 rgb_frame.data, rgb_frame.linesize );
00452
00453 is_->cur_frame_ = new vidl2_shared_frame(is_->contig_memory_->data(),width,height,
00454 VIDL2_PIXEL_FORMAT_RGB_24);
00455 }
00456 else
00457 {
00458
00459
00460
00461 AVPicture test_frame;
00462 avpicture_fill(&test_frame, is_->frame_->data[0], enc->pix_fmt, width, height);
00463 if (test_frame.data[1] == is_->frame_->data[1] &&
00464 test_frame.data[2] == is_->frame_->data[2] &&
00465 test_frame.linesize[0] == is_->frame_->linesize[0] &&
00466 test_frame.linesize[1] == is_->frame_->linesize[1] &&
00467 test_frame.linesize[2] == is_->frame_->linesize[2] )
00468 {
00469 is_->cur_frame_ = new vidl2_shared_frame(is_->frame_->data[0], width, height, fmt);
00470 }
00471
00472 else
00473 {
00474 if (!is_->contig_memory_){
00475 int size = avpicture_get_size( enc->pix_fmt, width, height );
00476 is_->contig_memory_ = new vil_memory_chunk(size, VIL_PIXEL_FORMAT_BYTE);
00477 }
00478 avpicture_fill(&test_frame, (uint8_t*)is_->contig_memory_->data(), enc->pix_fmt, width, height);
00479 av_picture_copy(&test_frame, (AVPicture*)is_->frame_, enc->pix_fmt, width, height);
00480
00481 is_->cur_frame_ = new vidl2_shared_frame(is_->contig_memory_->data(),width,height,fmt);
00482 }
00483 }
00484 }
00485
00486 return is_->cur_frame_;
00487 }
00488
00489
00490
00491
00492 bool
00493 vidl2_ffmpeg_istream::
00494 seek_frame(unsigned int frame)
00495 {
00496
00497 if ( !is_open() ) {
00498 return false;
00499 }
00500
00501
00502 int64_t req_timestamp =
00503 int64_t(frame + is_->frame_number_offset_)
00504 * is_->vid_str_->time_base.den
00505 * is_->vid_str_->r_frame_rate.den
00506 / is_->vid_str_->time_base.num
00507 / is_->vid_str_->r_frame_rate.num
00508 + is_->start_time;
00509
00510
00511 int seek = av_seek_frame( is_->fmt_cxt_, is_->vid_index_, req_timestamp, AVSEEK_FLAG_BACKWARD );
00512
00513 if ( seek < 0 )
00514 return false;
00515
00516 avcodec_flush_buffers( is_->vid_str_->codec );
00517
00518
00519 while ( true )
00520 {
00521 if ( ! advance() ) {
00522 return false;
00523 }
00524 if ( is_->last_dts >= req_timestamp ) {
00525 if ( is_->last_dts > req_timestamp ) {
00526 vcl_cerr << "Warning: seek went into the future!\n";
00527 return false;
00528 }
00529 return true;
00530 }
00531 }
00532 }
00533
00534 #endif // vidl2_ffmpeg_istream_v2_txx_