00001 /*!@file Media/FfmpegPacketDecoder.C */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00005 // by the University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Rob Peters <rjpeters at usc dot edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Media/FfmpegPacketDecoder.C $ 00035 // $Id: FfmpegPacketDecoder.C 12611 2010-01-20 22:49:23Z beobot $ 00036 // 00037 00038 // Some code in this file is based on ffplay from the ffmpeg 00039 // distribution, with this original copyright notice: 00040 00041 /* 00042 * FFplay : Simple Media Player based on the ffmpeg libraries 00043 * Copyright (c) 2003 Fabrice Bellard 00044 * 00045 * This library is free software; you can redistribute it and/or 00046 * modify it under the terms of the GNU Lesser General Public 00047 * License as published by the Free Software Foundation; either 00048 * version 2 of the License, or (at your option) any later version. 00049 * 00050 * This library is distributed in the hope that it will be useful, 00051 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00052 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00053 * Lesser General Public License for more details. 00054 * 00055 * You should have received a copy of the GNU Lesser General Public 00056 * License along with this library; if not, write to the Free Software 00057 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00058 */ 00059 00060 #ifndef MEDIA_FFMPEGPACKETDECODER_C_DEFINED 00061 #define MEDIA_FFMPEGPACKETDECODER_C_DEFINED 00062 00063 #ifdef INVT_HAVE_AVCODEC 00064 00065 #include "Media/FfmpegPacketDecoder.H" 00066 00067 #include "Raster/GenericFrame.H" 00068 #include "Util/Assert.H" 00069 #include "Util/log.H" 00070 #include "Video/FfmpegFrame.H" 00071 00072 #include <cerrno> 00073 00074 // see http://dranger.com/ffmpeg/ffmpegtutorial_all.txt for useful info 00075 00076 namespace 00077 { 00078 // ###################################################################### 00079 static int& eof_reached(AVFormatContext* c) 00080 { 00081 // AVFormatContext's pb member changed from a 'ByteIOContext' to a 00082 // 'ByteIOContext*' with ffmpeg svn rev 11071; see this thread: 00083 // http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/2007-November/037797.html 00084 #if defined (LIBAVFORMAT_BUILD) && (LIBAVFORMAT_BUILD >= ((52<<16)+(0<<8)+0)) 00085 ASSERT(c->pb != 0); 00086 return c->pb->eof_reached; 00087 #else 00088 return c->pb.eof_reached; 00089 #endif 00090 } 00091 00092 // ###################################################################### 00093 const char* get_error_msg(int err) 00094 { 00095 switch(err) 00096 { 00097 case AVERROR_NUMEXPECTED: 00098 return 00099 "Incorrect image filename syntax.\n" 00100 "Use '%%d' to specify the image number:\n" 00101 " for img1.jpg, img2.jpg, ..., use 'img%%d.jpg';\n" 00102 " for img001.jpg, img002.jpg, ..., use 'img%%03d.jpg'."; 00103 00104 case AVERROR_INVALIDDATA: 00105 return "Error while parsing header"; 00106 00107 case AVERROR_NOFMT: 00108 return "Unknown format"; 00109 00110 case AVERROR_IO: 00111 return 00112 "I/O error occured\n" 00113 "Usually that means that input file is truncated and/or corrupted."; 00114 00115 case AVERROR_NOMEM: 00116 return "memory allocation error"; 00117 } 00118 00119 // default: 00120 return "Error while opening file"; 00121 } 00122 00123 bool isNonNegative(int v) { return v >= 0; } 00124 bool isNonNegative(unsigned int v) { return true; } 00125 } 00126 00127 // ###################################################################### 00128 FfmpegPacketDecoder::FfmpegPacketDecoder(const char* fname, 00129 const bool preload) 00130 : 00131 itsFilename(fname), 00132 itsFormatContext(0), 00133 itsCodecContext(0), 00134 itsStreamID(-1), 00135 itsFrameNumber(0), 00136 itsDimsValid(false), 00137 itsNextFramePushback(false), 00138 itsPacketsExhausted(false), 00139 itsPacketQ() 00140 { 00141 // no need to guard these functions for being called multiple times; 00142 // they all have internal guards 00143 av_register_all(); 00144 avcodec_init(); 00145 avcodec_register_all(); 00146 00147 AVFormatParameters params; 00148 memset(¶ms, 0, sizeof(params)); 00149 #if defined (LIBAVFORMAT_BUILD) && (LIBAVFORMAT_BUILD <= ((50<<16)+(6<<8))) 00150 // AVImageFormat* disappeared from ffmpeg mainline on 2006-11-02; 00151 // last version with it was 50.6.0 and first version without it was 00152 // 51.6.0 00153 params.image_format = 0; 00154 #endif 00155 #if defined (LIBAVFORMAT_BUILD) && (LIBAVFORMAT_BUILD >= 4610) 00156 params.initial_pause = 1; /* we force a pause when starting an RTSP 00157 stream */ 00158 #endif 00159 00160 int err = av_open_input_file(&itsFormatContext, itsFilename.c_str(), 00161 0, 0, ¶ms); 00162 if (err < 0) 00163 { 00164 LFATAL("%s: %s %i", itsFilename.c_str(), get_error_msg(err), err); 00165 } 00166 00167 err = av_find_stream_info(itsFormatContext); 00168 if (err < 0) 00169 { 00170 LFATAL("%s: could not find codec parameters\n", 00171 itsFilename.c_str()); 00172 } 00173 eof_reached(itsFormatContext) = 0; //FIXME hack, ffplay maybe shouldnt use url_feof() to test for the end 00174 00175 /* now we can begin to play (RTSP stream only) */ 00176 #if defined (LIBAVFORMAT_BUILD) && (LIBAVFORMAT_BUILD >= 4610) 00177 av_read_play(itsFormatContext); 00178 #endif 00179 00180 LDEBUG("%s: %d streams in file", fname, 00181 itsFormatContext->nb_streams); 00182 00183 // Prior to ffmpeg svn revision 7556, nb_streams was 'int', but then 00184 // changed to 'unsigned int'; to allow either type we will later 00185 // cast it to unsigned int, but first we want to check that it is 00186 // indeed non-negative: 00187 ASSERT(isNonNegative(itsFormatContext->nb_streams)); 00188 00189 for (unsigned int i = 0; i < (unsigned int)(itsFormatContext->nb_streams); ++i) 00190 { 00191 #ifdef INVT_FFMPEG_AVSTREAM_CODEC_IS_POINTER 00192 AVCodecContext *enc = itsFormatContext->streams[i]->codec; 00193 #else 00194 AVCodecContext *enc = itsFormatContext->streams[i]->codec; 00195 #endif 00196 00197 char buf[512]; 00198 avcodec_string(&buf[0], sizeof(buf), enc, /*encode=*/ 0); 00199 buf[sizeof(buf)-1] = '\0'; 00200 00201 LDEBUG("%s: stream %u/%u: codec_string=%s", 00202 fname, i, (unsigned int)(itsFormatContext->nb_streams), 00203 buf); 00204 00205 if (enc->codec_type == CODEC_TYPE_VIDEO) 00206 { 00207 itsStreamID = i; 00208 itsCodecContext = enc; 00209 break; 00210 } 00211 } 00212 00213 if (itsStreamID < 0) 00214 LFATAL("%s: no video stream", itsFilename.c_str()); 00215 00216 ASSERT(itsCodecContext != 0); 00217 AVCodec* codec = avcodec_find_decoder(itsCodecContext->codec_id); 00218 00219 if (codec == 0) 00220 LFATAL("%s: no codec found for codec_id=%d", 00221 fname, int(itsCodecContext->codec_id)); 00222 00223 #if defined(LIBAVCODEC_BUILD) && (LIBAVCODEC_BUILD >= 4697) // rev 2636 00224 itsCodecContext->debug_mv = 0; 00225 #endif 00226 itsCodecContext->debug = 0; 00227 itsCodecContext->workaround_bugs = 1; 00228 #if defined(LIBAVCODEC_BUILD) && (LIBAVCODEC_BUILD >= 4722) // rev 3507 00229 itsCodecContext->lowres = 0; 00230 if (itsCodecContext->lowres) 00231 itsCodecContext->flags |= CODEC_FLAG_EMU_EDGE; 00232 #endif 00233 itsCodecContext->idct_algo= FF_IDCT_AUTO; 00234 #if defined(LIBAVCODEC_BUILD) && (LIBAVCODEC_BUILD > 4721) // rev 3429 00235 if (0) 00236 itsCodecContext->flags2 |= CODEC_FLAG2_FAST; 00237 #endif 00238 #if defined(LIBAVCODEC_BUILD) && (LIBAVCODEC_BUILD >= 4758) // rev 4440 00239 itsCodecContext->skip_frame= AVDISCARD_DEFAULT; 00240 itsCodecContext->skip_idct= AVDISCARD_DEFAULT; 00241 itsCodecContext->skip_loop_filter= AVDISCARD_DEFAULT; 00242 #endif 00243 00244 #if defined(LIBAVCODEC_BUILD) && (LIBAVCODEC_BUILD > 3410431) // rev 5210 00245 // no more error_resilience parameter? 00246 #elif defined(LIBAVCODEC_BUILD) && (LIBAVCODEC_BUILD > 3276800) // rev 4590 00247 itsCodecContext->error_resilience= FF_ER_CAREFUL; 00248 #else 00249 itsCodecContext->error_resilience= FF_ER_CAREFULL; 00250 #endif 00251 itsCodecContext->error_concealment= 3; 00252 if (!codec || avcodec_open(itsCodecContext, codec) < 0) 00253 LFATAL("avcodec_open() failed"); 00254 #if defined(LIBAVCODEC_BUILD) && (LIBAVCODEC_BUILD >= 4702) // rev 2772 00255 itsCodecContext->thread_count= 1; 00256 #endif 00257 00258 #if defined(INVT_FFMPEG_HAS_DEFAULTS_FUNCTIONS) 00259 avcodec_get_frame_defaults(&itsPicture); 00260 #else 00261 { 00262 AVFrame* tmp = avcodec_alloc_frame(); 00263 memcpy(&itsPicture, tmp, sizeof(AVFrame)); 00264 av_free(tmp); 00265 } 00266 #endif 00267 00268 LINFO("libavcodec build %d (%d.%d.%d)", 00269 int(LIBAVCODEC_BUILD), 00270 int((LIBAVCODEC_BUILD & 0xff0000) >> 16), 00271 int((LIBAVCODEC_BUILD & 0xff00) >> 8), 00272 int((LIBAVCODEC_BUILD & 0xff) >> 0)); 00273 00274 LINFO("libavformat build %d (%d.%d.%d)", 00275 int(LIBAVFORMAT_BUILD), 00276 int((LIBAVFORMAT_BUILD & 0xff0000) >> 16), 00277 int((LIBAVFORMAT_BUILD & 0xff00) >> 8), 00278 int((LIBAVFORMAT_BUILD & 0xff) >> 0)); 00279 00280 char buf[512]; 00281 avcodec_string(&buf[0], sizeof(buf), itsCodecContext, /*encode=*/ 0); 00282 buf[sizeof(buf)-1] = '\0'; 00283 LINFO("%s [%s]", fname, &buf[0]); 00284 00285 if (preload) 00286 while (getNextPacket() == true) 00287 { /* empty */ } 00288 } 00289 00290 // ###################################################################### 00291 FfmpegPacketDecoder::~FfmpegPacketDecoder() 00292 { 00293 if (itsCodecContext) 00294 { 00295 avcodec_close(itsCodecContext); 00296 itsCodecContext = 0; 00297 itsStreamID = -1; 00298 } 00299 00300 if (itsFormatContext) 00301 { 00302 av_close_input_file(itsFormatContext); 00303 itsFormatContext = NULL; /* safety */ 00304 } 00305 00306 while (!itsPacketTrashQ.empty()) 00307 { 00308 av_free_packet(&(itsPacketTrashQ.back())); 00309 itsPacketTrashQ.pop_back(); 00310 } 00311 } 00312 00313 // ###################################################################### 00314 int FfmpegPacketDecoder::apparentFrameNumber() const 00315 { 00316 return 00317 itsNextFramePushback 00318 ? itsFrameNumber - 1 00319 : itsFrameNumber; 00320 } 00321 00322 // ###################################################################### 00323 GenericFrameSpec FfmpegPacketDecoder::peekFrameSpec() 00324 { 00325 if (!itsDimsValid) 00326 { 00327 // if we've already peeked at the next frame, then the dims 00328 // should have already be valid: 00329 ASSERT(!itsNextFramePushback); 00330 00331 if (readRawFrame() == 0) 00332 { 00333 if (itsCodecContext->width % 16 != 0) 00334 LFATAL("readRawFrame() failed (this may be because the " 00335 "movie's width is %d, which is not divisible by 16)", 00336 itsCodecContext->width); 00337 else if (itsCodecContext->height % 16 != 0) 00338 LFATAL("readRawFrame() failed (this may be because the " 00339 "movie's height is %d, which is not divisible by 16)", 00340 itsCodecContext->height); 00341 else 00342 LFATAL("readRawFrame() failed"); 00343 } 00344 00345 itsNextFramePushback = true; 00346 } 00347 00348 ASSERT(itsDimsValid); 00349 00350 GenericFrameSpec result; 00351 00352 result.nativeType = GenericFrame::VIDEO; 00353 result.videoFormat = 00354 convertAVPixelFormatToVideoFormat(itsCodecContext->pix_fmt); 00355 result.videoByteSwap = false; 00356 result.dims = Dims(itsCodecContext->width, itsCodecContext->height); 00357 result.floatFlags = 0; 00358 00359 #if defined(LIBAVCODEC_BUILD) && (LIBAVCODEC_BUILD >= 4754) // SVN rev >= 4168 00360 result.frameRate = static_cast<float>(1/av_q2d(itsCodecContext->time_base)) ; 00361 #else // assume FFmpeg libavcodec build 4753 or earlier (i.e., SVN rev <= 4161) 00362 result.frameRate = itsCodecContext->frame_rate ; 00363 #endif 00364 00365 return result; 00366 } 00367 00368 // ###################################################################### 00369 VideoFrame FfmpegPacketDecoder::readVideoFrame() 00370 { 00371 // note that we need to force the peekFrameSpec() call to occur 00372 // before the convertAVFrameToVideoFrame() call, so that 00373 // itsCodecContext->{width,height} are properly initialized 00374 const GenericFrameSpec spec = this->peekFrameSpec(); 00375 00376 return convertAVFrameToVideoFrame(this->readRawFrame(), 00377 itsCodecContext->pix_fmt, 00378 spec.dims); 00379 } 00380 00381 // ###################################################################### 00382 Image<PixRGB<byte> > FfmpegPacketDecoder::readRGB() 00383 { 00384 // note that we need to force the peekFrameSpec() call to occur 00385 // before the convertAVFrameToRGB() call, so that 00386 // itsCodecContext->{width,height} are properly initialized 00387 const GenericFrameSpec spec = this->peekFrameSpec(); 00388 00389 return convertAVFrameToRGB(this->readRawFrame(), 00390 itsCodecContext->pix_fmt, 00391 spec.dims); 00392 } 00393 00394 // ###################################################################### 00395 bool FfmpegPacketDecoder::readAndDiscardFrame() 00396 { 00397 return (readRawFrame() != 0); 00398 } 00399 00400 // ###################################################################### 00401 bool FfmpegPacketDecoder::getNextPacket() 00402 { 00403 #if !(defined(LIBAVFORMAT_BUILD) && (LIBAVFORMAT_BUILD >= 4610)) 00404 LFATAL("you must have <ffmpeg/avformat.h> with " 00405 "LIBAVFORMAT_BUILD >= 4610 to use FfmpegPacketDecoder"); 00406 /* can't happen */ return false; 00407 #else 00408 if (eof_reached(itsFormatContext)) 00409 return false; 00410 00411 while (true) 00412 { 00413 AVPacket pkt; 00414 av_init_packet(&pkt); 00415 const int ret = av_read_frame(itsFormatContext, &pkt); 00416 if (ret < 0) 00417 { 00418 return false; 00419 } 00420 else 00421 { 00422 LDEBUG("eof_reached=%d pkt = {data=%p size=%d " 00423 "stream_index=%d flags=%d duration=%d}", 00424 int(eof_reached(itsFormatContext)), 00425 pkt.data, pkt.size, pkt.stream_index, 00426 pkt.flags, pkt.duration); 00427 00428 if (pkt.stream_index == itsStreamID && 00429 !eof_reached(itsFormatContext)) 00430 { 00431 av_dup_packet(&pkt); 00432 itsPacketQ.push_back(pkt); 00433 return true; 00434 } 00435 else 00436 { 00437 av_free_packet(&pkt); 00438 // no return here; let the loop go around again and try 00439 // to get another packet 00440 } 00441 } 00442 } 00443 #endif 00444 } 00445 00446 // ###################################################################### 00447 AVFrame* FfmpegPacketDecoder::readRawFrame() 00448 { 00449 if (itsNextFramePushback) 00450 { 00451 itsNextFramePushback = false; 00452 return &itsPicture; 00453 } 00454 00455 if (itsPacketsExhausted) 00456 return 0; 00457 00458 while (!itsPacketTrashQ.empty()) 00459 { 00460 av_free_packet(&(itsPacketTrashQ.back())); 00461 itsPacketTrashQ.pop_back(); 00462 } 00463 00464 while (true) 00465 { 00466 this->getNextPacket(); 00467 00468 if (itsPacketQ.size() == 0) 00469 { 00470 // ok, we are out of packets, but try to read one more frame 00471 // (mpeg-1 streams have a latency of one frame) 00472 int got_picture; 00473 const int len = 00474 avcodec_decode_video(itsCodecContext, 00475 &itsPicture, &got_picture, 00476 NULL, 0); 00477 00478 (void) len; 00479 00480 itsPacketsExhausted = true; 00481 00482 if (got_picture) 00483 { 00484 ++itsFrameNumber; 00485 itsDimsValid = true; 00486 return &itsPicture; 00487 } 00488 00489 return 0; 00490 } 00491 00492 // ok, if we got here then our packet queue is non-empty, so 00493 // let's pull out the next packet and handle it: 00494 00495 ASSERT(itsPacketQ.size() > 0); 00496 AVPacket pkt = itsPacketQ.front(); 00497 itsPacketQ.pop_front(); 00498 00499 ASSERT(pkt.stream_index == itsStreamID); 00500 00501 int got_picture; 00502 const int len = 00503 avcodec_decode_video(itsCodecContext, 00504 &itsPicture, &got_picture, 00505 pkt.data, pkt.size); 00506 00507 // we can't call av_free_packet(&pkt) just now because 00508 // itsPicture may refer to pkt.data internally, so if we freed 00509 // the packet we could have dangling pointers in itsPicture; 00510 // instead, we just note that the packet must be freed later and 00511 // then we free it when we start to read the next frame 00512 itsPacketTrashQ.push_back(pkt); 00513 00514 if (len < 0) 00515 LFATAL("avcodec_decode_video() failed"); 00516 00517 if (got_picture) 00518 { 00519 ++itsFrameNumber; 00520 itsDimsValid = true; 00521 return &itsPicture; 00522 } 00523 } 00524 } 00525 00526 #endif // INVT_HAVE_AVCODEC 00527 00528 // ###################################################################### 00529 /* So things look consistent in everyone's emacs... */ 00530 /* Local Variables: */ 00531 /* mode: c++ */ 00532 /* indent-tabs-mode: nil */ 00533 /* End: */ 00534 00535 #endif // MEDIA_FFMPEGPACKETDECODER_C_DEFINED