Home || Architecture || Video Search || Visual Search || Scripts || Applications || Important Messages || OGL || Src

RgbDataSrcLavc_old.h

Go to the documentation of this file.
00001 #ifndef Impala_Core_Stream_RgbDataSrcLavc_old_h
00002 #define Impala_Core_Stream_RgbDataSrcLavc_old_h
00003 
00004 #include <string>
00005 #include <iostream>
00006 #include <vector>
00007 
00008 //extern "C"{
00009 //#include "ffmpeg/swscale.h"
00010 //}
00011 
00012 #include "Basis/CmdOptions.h"
00013 #include "Util/Database.h"
00014 #include "Util/IOBuffer.h"
00015 
00016 // include our one and only entry point into libavcodec:
00017 #include "Link/Lavc/Lavc.h"
00018 
00019 #include "Link/DiskImage/DiskImageFuncs.h"
00020 #include "Core/Stream/RgbDataSrcInfo.h"
00021 #include "Core/Stream/LavcProtocolDataServer.h"
00022 #include "Core/Table/TableTem.h"
00023 
00024 #ifdef USE_IFILE
00025 #include "Core/Stream/LavcProtocolLocalFile.h"
00026 #endif
00027 
00028 
00029 namespace Impala
00030 {
00031 namespace Core
00032 {
00033 namespace Stream
00034 {
00035 
00036 
00037 class LAVCException : public std::exception
00038 {
00039     String mWhat;
00040     int mType;
00041 
00042 public:
00043 
00044     LAVCException(const String what, int type) : mWhat(what), mType(type) {}
00045     ~LAVCException() throw() {}
00046     virtual const char* what() const throw() { return mWhat.c_str(); }
00047 };
00048 
00049 
00050 class RgbDataSrcLavc_old : public RgbDataSrcInfo
00051 {
00052 
00053     typedef Array::Array2dVec3UInt8 Array2dVec3UInt8;
00054 
00055 public:
00056 
00057     RgbDataSrcLavc_old(int src, CString srcName, Util::Database* db, 
00058         IndexMode mode = READIDX)
00059         : RgbDataSrcInfo(src, srcName, db, 
00060             DetermineInfoName(srcName, mode, db), true)
00061     {
00062         CmdOptions& options = CmdOptions::GetInstance();
00063         mValid = false;
00064         mMode = mode;
00065         mBufferedFrameNr = -1;
00066         mFixCnt = 0;
00067         mLastFixNr = 0;
00068 
00069         mLastFrame = mFrameCnt = LASTFRAME_UNKNOWN;
00070         mSrcName = StringReplaceAll(srcName, "\\", "/", false);
00071         mPacket = 0;
00072 
00073         mFixIndexIfBroken = options.GetBool("fixIdx", true);
00074         if (!mFixIndexIfBroken)
00075         {
00076             ILOG_WARN("Index will NOT be fixed if broken!");
00077         }
00078         SetJumpMethod(options.GetString("jmp", "pos"));        
00079 
00080         Init();
00081     }
00082 
00083     virtual
00084     ~RgbDataSrcLavc_old() 
00085     {
00086         // Free the RGB image data
00087         delete [] mData;
00088 
00089         if (mPacket != 0)
00090             delete mPacket;
00091 
00092         av_free(mFrameRGB);
00093 
00094         // Free the YUV frame
00095         av_free(mFrame);
00096 
00097         // free the image conversion context
00098         sws_freeContext(mSwsContext);
00099 
00100         // Close the codec
00101         avcodec_close(mCodecCtx);
00102 
00103         // Close the video file
00104         av_close_input_file(mFormatCtx);
00105     }
00106     
00107     virtual char
00108     FrameType() const
00109     {
00110         switch (mFrame->pict_type)
00111         {
00112             case FF_I_TYPE : return 'I';
00113             case FF_P_TYPE : return 'P';
00114             case FF_B_TYPE : return 'B';
00115         }
00116         return '?';
00117     }
00118 
00119     virtual bool
00120     CurIsIFrame() const
00121     {
00122         return mFrame->pict_type == FF_I_TYPE;
00123     }
00124 
00125 
00126 //public:
00127 
00128     virtual bool
00129     Valid() const
00130     {
00131         return mValid;
00132     }
00133 
00134     void
00135     JumpToKeyFrame(int key)
00136     {
00137         const int64_t targetPos = GetPos(key);
00138         ILOG_DEBUG("Jumping to Keyframe " << key << " @ " 
00139                 << targetPos << " (" << mJumpMethod << ") " );
00140 
00141         //flush after the jump and sync to keyframe
00142         Jump(targetPos, mJumpFlags, 2, 2);
00143         mCurrentFrameNr = mBufferedFrameNr = key;
00144         CheckMD5Hash(key);
00145     }
00146 
00147     void
00148     Jump(int64_t newPos, int flag, int flush=0, int sync=0)
00149     {
00150         ILOG_DEBUG("Attempting jump to " << newPos << " (method: " << 
00151             mJumpMethod << ")");
00152 
00153         if (mCodecCtx->codec->flush == NULL)
00154             flush = 0; // never flush
00155         else if (flush & 1) // flush before seek (flushing was introduced by Taylan)
00156             mCodecCtx->codec->flush(mCodecCtx);
00157 
00158         //ILOG_DEBUG("[Jump] " << mVideoStream->last_IP_duration << " " << mVideoStream->cur_dts);
00159         int res = av_seek_frame(mFormatCtx, mVideoStreamIndex, newPos, flag);
00160         //ILOG_DEBUG("[Jump] " << mVideoStream->last_IP_duration << " " << mVideoStream->cur_dts);
00161 
00162         if (res >= 0)
00163         {
00164             if (flush & 2) // flush after seek (flushing was introduced by Taylan)
00165                 mCodecCtx->codec->flush(mCodecCtx);
00166         }
00167         else
00168         {
00169             ILOG_ERROR("av_seek_frame returned negative value: " << res << 
00170                 " (" << newPos << " " << flag << " " << flush << " " << sync << ")");
00171             return;
00172         }
00173 
00174         if (sync == 1)
00175             FindNextDecodedFrame(false);
00176         else 
00177             if (sync == 2)
00178                 FindNextDecodedFrame(true);
00179     }
00180     
00181     bool
00182     FindNextDecodedFrame(const bool lookForKeyFrame) 
00183     {
00184         //ILOG_DEBUG("[FindNextDecodedFrame] mCurrentFrameNr=" << mCurrentFrameNr << " mBufferedFrameNr=" << mBufferedFrameNr);
00185         //ILOG_DEBUG("  video stream's curdts=" << mVideoStream->cur_dts << " mPacket->dts=" << mPacket->dts);
00186 
00187         bool isValidFrame;
00188         bool isKeyFrame;
00189         do
00190         {
00191             const bool gotFrame = (DecodeNextFrame(isValidFrame, isKeyFrame) == 0);
00192             if (!gotFrame) // indicates eof or error
00193                 return false; 
00194             if (!isValidFrame)
00195             {
00196                 ILOG_DEBUG("Skipping invalid frame");
00197                 continue;
00198             }
00199             if (lookForKeyFrame && !isKeyFrame)
00200             {
00201                 ILOG_DEBUG("Skipping non-keyframe");
00202                 continue;
00203             }
00204             break;
00205         } while (true);
00206 
00207         ConvertFrameToRgb();
00208         return true;
00209     }
00210     
00211 private:
00212 
00213     void
00214     SetJumpMethod(String jmp)
00215     {
00216         mJumpMethod = jmp;
00217         ILOG_DEBUG("Jump Method is " << mJumpMethod);
00218         if (mJumpMethod == "pos")
00219             mJumpFlags = AVSEEK_FLAG_ANY | AVSEEK_FLAG_BYTE;
00220         else
00221             //mJumpFlags = AVSEEK_FLAG_ANY | AVSEEK_FLAG_BACKWARD;
00222             mJumpFlags = AVSEEK_FLAG_ANY;
00223     }
00224 
00225     void
00226     Init()
00227     {
00228         try
00229         {
00230             InitFFMPEG();
00231             InitFormatCtx();
00232             InitStreams();
00233             InitCodecCtx();
00234             InitFrames();
00235 
00236             if (!PrepareForReading())
00237             {
00238                 mValid = false;
00239                 return;
00240             }
00241 
00242             if (mMode != NOCHECK)
00243             {
00244                 if (mMode == READIDX && !ReadInfo())
00245                 {
00246                     throw LAVCException("Could not read info file for: " + 
00247                         mSrcName, 0);
00248                 }
00249 
00250                 else if (mMode == WITHIDX)
00251                 {
00252                     if (!ReadInfo(true))
00253                         PopulateIndex();
00254                 }
00255 
00256                 else if (mMode == ADHOCIDX)
00257                 {
00258                     // Create but don't store
00259                     PopulateIndex();
00260                 }
00261 
00262                 else if (mMode == WRITEIDX)
00263                 {
00264                     // Create and store
00265                     PopulateIndex();
00266                     WriteInfo();
00267                 }
00268 
00269                 Reset();
00270             }
00271         }
00272         catch (LAVCException& e)
00273         {
00274             mValid = false;
00275             ILOG_ERROR("Initialization failed: " << e.what());
00276             return;
00277         }
00278 
00279         mValid = true;
00280         ILOG_DEBUG("Initialization succeeded");
00281     }
00282     
00283     bool 
00284     InitFFMPEG()
00285     {
00286         ILOG_INFO("libavcodec version  : " << 
00287             (int)(LIBAVCODEC_VERSION_INT>>16) << "." << 
00288             (int)((LIBAVCODEC_VERSION_INT>>8)&0xFF) << "." << 
00289             (int)(LIBAVCODEC_VERSION_INT&0xFF));
00290 
00291         ILOG_INFO("libavformat version : " << 
00292             (int)(LIBAVFORMAT_VERSION_INT>>16) << "." << 
00293             (int)((LIBAVFORMAT_VERSION_INT>>8)&0xFF) << "." << 
00294             (int)(LIBAVFORMAT_VERSION_INT&0xFF));
00295 
00296         ILOG_INFO("libavutil version   : " << 
00297             (int)(LIBAVUTIL_VERSION_INT>>16) << "." << 
00298             (int)((LIBAVUTIL_VERSION_INT>>8)&0xFF) << "." << 
00299             (int)(LIBAVUTIL_VERSION_INT&0xFF));
00300 
00301 
00302         // Set libavcodec's log output level
00303         //av_log_set_level(AV_LOG_DEBUG);
00304         //av_log_set_level(AV_LOG_ERROR);
00305         //av_log_set_level(AV_LOG_FATAL);
00306         av_log_set_level(AV_LOG_QUIET);
00307 
00308 
00309         // Register all formats and codecs 
00310         av_register_all();
00311         avcodec_register_all();
00312 
00313         register_protocol(&LavcProtocolDataServer_protocol);
00314 
00315         if (Link::DiskImage::DiskImageUsed())
00316         {
00317             ILOG_DEBUG("Registering disk image protocol..");
00318             Link::DiskImage::RegisterProtocol();
00319         }
00320 
00321 #ifdef USE_IFILE
00322         ILOG_DEBUG("Registering Impala file protocol..");
00323         register_protocol(&LavcProtocolLocalFile_protocol);
00324 #endif
00325         return true;
00326     }
00327 
00328 
00329     bool 
00330     InitFormatCtx()
00331     {
00332         // Open video file 
00333         CmdOptions& options = CmdOptions::GetInstance();
00334         String dataServer = options.GetString("dataServer");
00335         String srcAddress = mSrcName;
00336         if (!dataServer.empty())
00337             srcAddress = "dataserver:" + mSrcName;
00338 
00339         int result = av_open_input_file(&mFormatCtx, 
00340                                  srcAddress.c_str(), NULL, 0, NULL);
00341 
00342         if (result != 0)
00343         {
00344             ILOG_ERROR("Return value from av_open_input_file(): " << result);
00345             throw (LAVCException("Unable to open: " + mSrcName, 0));
00346             return false;
00347         }
00348 
00349 #if LIBAVFORMAT_VERSION_INT >= ((51<<16)+(14<<8)+0) // from version 51.14.0 on
00350         if (mFormatCtx->iformat->flags & AVFMT_GENERIC_INDEX)
00351         {
00352             // if flag not initially cleared, may result in invalid data;
00353             // mFormatCtx is not available until input file is opened
00354             mFormatCtx->iformat->flags -= AVFMT_GENERIC_INDEX;
00355             ILOG_DEBUG("Flag cleared: mFormatCtx->iformat->flags -= " <<
00356                 "AVFMT_GENERIC_INDEX");
00357 
00358             // re-open the file
00359             result = av_open_input_file(&mFormatCtx, 
00360                                  srcAddress.c_str(), NULL, 0, NULL);
00361         }
00362 #endif
00363 
00364         // Retrieve stream information
00365         if (av_find_stream_info(mFormatCtx) < 0) 
00366             throw LAVCException("Could not find stream info in: " + mSrcName, 0);
00367 
00368         // Dump information about file onto standard error
00369         dump_format(mFormatCtx, 0, mSrcName.c_str(), false);
00370 
00371         mFormatCtx->flags |= AVFMT_FLAG_GENPTS;
00372 
00373         mBitRate     = mFormatCtx->bit_rate;
00374         mFormatName  = mFormatCtx->iformat->name;
00375         mFormatLName = mFormatCtx->iformat->long_name;
00376         ILOG_INFO("Format name is: " << mFormatLName << " (" << mFormatName << ")");
00377         
00378         if ((mFormatName == "avi") ||
00379             (mFormatName == "mov,mp4,m4a,3gp,3g2,mj2"))
00380         {
00381             SetJumpMethod("pts");
00382         }
00383         else
00384         {
00385              //SK, 16-Mar-2009: It appears the following clause should
00386              //  never be used anyway.
00387 //#if LIBAVFORMAT_VERSION_INT >= ((51<<16)+(14<<8)+0) 
00388 //            // SK, 11-Mar-2009: this appeared not to work out well for AVI:
00389 //            int oldFlags = mFormatCtx->iformat->flags;
00390 //            ILOG_DEBUG("Changing mFormatCtx->iformat->flags from " << 
00391 //                oldFlags << " into " << (oldFlags | AVFMT_GENERIC_INDEX));
00392 //            mFormatCtx->iformat->flags |= AVFMT_GENERIC_INDEX;
00393 //#endif
00394         }
00395 
00396         return true;
00397     }
00398 
00399 
00400     bool
00401     InitStreams()
00402     {
00403         mStreamCount = mFormatCtx->nb_streams;
00404         mVideoStreamIndex = -1;
00405         mVideoStream = 0;
00406 
00407         // find the first video stream 
00408         for (int i = 0; i < mStreamCount; i++)
00409         {
00410             if (mFormatCtx->streams[i]->codec->codec_type 
00411                                                     == CODEC_TYPE_VIDEO)
00412             {
00413                 if (mVideoStreamIndex >= 0)
00414                     throw (LAVCException("Multiple video streams found in: " 
00415                                 + mSrcName, 0));
00416 
00417                 mVideoStreamIndex = i;
00418                 mVideoStream = mFormatCtx->streams[i];
00419             }
00420         }
00421         if (mVideoStream == 0) 
00422             throw LAVCException("Could not find video stream in: " 
00423                                 + mSrcName, 0);
00424 
00425         // collect video stream info
00426         mVideoDuration = mVideoStream->duration; // number of (time) fractions
00427         const AVRational videoTimeBase = 
00428             mVideoStream->time_base; // time fraction duration (seconds)
00429         mTimeBaseNum = videoTimeBase.num;
00430         mTimeBaseDen = videoTimeBase.den;
00431         mDuration = ceil(
00432             double(mVideoDuration) * mTimeBaseNum / mTimeBaseDen
00433             ); // rounded up (number of seconds)
00434         mDurationSec = mDuration;
00435         mDurationHour = mDurationSec / 3600;
00436         mDurationSec %= 3600;
00437         mDurationMin = mDurationSec / 60;
00438         mDurationSec %= 60;
00439 
00440         // collect frame info
00441         mFrameRateNum = mVideoStream->r_frame_rate.num;
00442         mFrameRateDen = mVideoStream->r_frame_rate.den;
00443         const double fractionsPerSec = double(mTimeBaseDen) / mTimeBaseNum;
00444         const double secondsPerFrame = double(mFrameRateDen) / mFrameRateNum;
00445         const double fractionsPerFrame = fractionsPerSec * secondsPerFrame;
00446         const double frameCount = mVideoDuration / fractionsPerFrame;
00447         mFrameCountCalculated = ceil(frameCount);
00448         ILOG_DEBUG("Frame count estimate based on video duration: " << 
00449             mFrameCountCalculated);
00450 
00451         return true;
00452     }
00453 
00454 
00455     bool InitCodecCtx()
00456     {
00457         // Get a pointer to the codec context for the video stream
00458         mCodecCtx = mVideoStream->codec;
00459         
00460         // Find the decoder for the video stream
00461         mCodec = avcodec_find_decoder(mCodecCtx->codec_id);
00462         if (mCodec == NULL) 
00463             throw LAVCException("Codec not found for: " + mSrcName, 0);
00464 
00465         // Open codec
00466         if (avcodec_open(mCodecCtx, mCodec) < 0) 
00467             throw LAVCException("Could not open codec (id=" + 
00468                 MakeString(mCodecCtx->codec_id) + ", name=" + 
00469                 mCodecName + ") for: " + mSrcName, 0);
00470 
00471         mFrameWidth = mCodecCtx->width;
00472         mFrameHeight = mCodecCtx->height;
00473 
00474         mAspectRatioNum = mCodecCtx->sample_aspect_ratio.num;
00475         mAspectRatioDen = mCodecCtx->sample_aspect_ratio.den;
00476 
00477         mGopSize = mCodecCtx->gop_size;
00478 
00479         // setup image conversion context
00480         mSwsContext = sws_getContext(
00481             mFrameWidth, mFrameHeight, mCodecCtx->pix_fmt, 
00482             mFrameWidth, mFrameHeight, PIX_FMT_RGB24, 
00483             SWS_BICUBIC, NULL, NULL, NULL);
00484         if (mSwsContext == NULL) 
00485             throw LAVCException(
00486                 "Failed to initialize image conversion context for: " + 
00487                 mSrcName, 0);
00488 
00489 
00490         char buf[5];
00491 #ifdef WIN32
00492         _snprintf(
00493 #else
00494         snprintf(
00495 #endif
00496             buf, sizeof(buf), "%c%c%c%c",
00497             mCodecCtx->codec_tag & 0xff,
00498             (mCodecCtx->codec_tag >> 8) & 0xff,
00499             (mCodecCtx->codec_tag >> 16) & 0xff,
00500             (mCodecCtx->codec_tag >> 24) & 0xff);
00501         mCodecTag = buf;
00502 
00503 
00504         mCodecName = mCodec->name;
00505 
00506         ILOG_INFO("Opened codec (id=" << mCodecCtx->codec_id << 
00507             ", name=" << mCodecName << ") for: " << mSrcName);
00508 
00509         if (mCodecName == "mpeg1video")
00510         {
00511             // "mpeg1video" is troublesome with presentation timestamps,
00512             SetJumpMethod("pos");
00513         }
00514 
00515         return true;
00516     }
00517 
00518     bool InitFrames()
00519     {
00520         mPacket = new AVPacket;
00521 
00522         // Allocate frame for reading
00523         mFrame = avcodec_alloc_frame();
00524 
00525         // Allocate frame for RGB conversion
00526         mFrameRGB = avcodec_alloc_frame();
00527 
00528         if ((mFrameRGB == NULL) || (mFrame == NULL)) 
00529             throw LAVCException("Could not allocate frame memory for: "
00530                                  + mSrcName, 0);
00531 
00532         // allocate buffer to hold frame data converted to RGB
00533         const int numBytes = avpicture_get_size(
00534             PIX_FMT_RGB24, mFrameWidth, mFrameHeight);
00535         mData = new UInt8[numBytes];
00536 
00537         // Assign appropriate parts of buffer to image planes in mFrameRGB
00538         int result = avpicture_fill( (AVPicture*) mFrameRGB, 
00539             mData, PIX_FMT_RGB24, mFrameWidth, mFrameHeight);
00540 
00541         return true;
00542     }
00543 
00544     void 
00545     Reset()
00546     {
00547         ILOG_DEBUG("Rewinding stream");
00548 
00549         Int64 startPos = GetPos(mBlankFrames);
00550         if (startPos < 0)
00551         {
00552             ILOG_WARN("No position found for frame: " << mBlankFrames <<
00553                 ". Trying 0 as position (which is probably fine " <<
00554                 "for getting to the head of the file)");
00555             startPos = 0;
00556         }
00557 
00558         const int flush = 2; // i.e. flush after jump
00559         const int sync = 1;  // i.e. no sync on key frames
00560         Jump(startPos, mJumpFlags, flush, sync);
00561 
00562         mBufferedFrameNr = mBlankFrames; // the currently buffered (valid) frame
00563         mCurrentFrameNr = 0;
00564     }
00565     
00566     bool 
00567     PrepareForReading()
00568     {
00569         ILOG_DEBUG("Preparing for reading video stream...");
00570 
00571 #ifdef FFMPEG_52
00572         ILOG_DEBUG("[PrepareForReading] stream's curdts=" << mVideoStream->cur_dts << " mPacket->dts=" << mPacket->dts << " mPacket->pts=" << mPacket->pts << " mPacket->size=" << mPacket->size << "; pb->pos=" << mFormatCtx->pb->pos);
00573         int result = av_seek_frame(mFormatCtx, mVideoStreamIndex, 0, AVSEEK_FLAG_BYTE | AVSEEK_FLAG_ANY);
00574         ILOG_DEBUG("[PrepareForReading] stream's curdts=" << mVideoStream->cur_dts << " mPacket->dts=" << mPacket->dts << " mPacket->pts=" << mPacket->pts << " mPacket->size=" << mPacket->size << "; pb->pos=" << mFormatCtx->pb->pos << "; result = " << result);
00575         //result = av_seek_frame(mFormatCtx, mVideoStreamIndex, 0, AVSEEK_FLAG_BYTE | AVSEEK_FLAG_ANY);
00576         //ILOG_DEBUG("[PrepareForReading] stream's curdts=" << mVideoStream->cur_dts << " mPacket->dts=" << mPacket->dts << " mPacket->pts=" << mPacket->pts << " mPacket->size=" << mPacket->size << "; pb->pos=" << mFormatCtx->pb->pos << "; result = " << result);
00577 #else
00578         ILOG_DEBUG("[PrepareForReading] stream's curdts=" << mVideoStream->cur_dts << " mPacket->dts=" << mPacket->dts << " mPacket->pts=" << mPacket->pts << " mPacket->size=" << mPacket->size << "; pb.pos=" << mFormatCtx->pb.pos);
00579         const int flags = AVSEEK_FLAG_BYTE | AVSEEK_FLAG_ANY;
00580         int result = av_seek_frame(mFormatCtx, mVideoStreamIndex, 0, flags);
00581         ILOG_DEBUG("[PrepareForReading] stream's curdts=" << mVideoStream->cur_dts << " mPacket->dts=" << mPacket->dts << " mPacket->pts=" << mPacket->pts << " mPacket->size=" << mPacket->size << "; pb.pos=" << mFormatCtx->pb.pos << "; result = " << result);
00582         //result = av_seek_frame(mFormatCtx, mVideoStreamIndex, 0, AVSEEK_FLAG_BYTE | AVSEEK_FLAG_ANY);
00583         //ILOG_DEBUG("[PrepareForReading] stream's curdts=" << mVideoStream->cur_dts << " mPacket->dts=" << mPacket->dts << " mPacket->pts=" << mPacket->pts << " mPacket->size=" << mPacket->size << "; pb.pos=" << mFormatCtx->pb.pos << "; result = " << result);
00584 #endif
00585 
00586         if (result < 0)
00587         {
00588             ILOG_ERROR("[PrepareForReading] av_seek_frame returned " << result);
00589             return false;
00590         }
00591 
00592         if (mCodecCtx->codec->flush != NULL)
00593             mCodecCtx->codec->flush(mCodecCtx);
00594 
00595         mBlankFrames = 0;
00596         int currentFrameNr = -1;
00597         const bool startAtKeyFrame = false; // SK: I think we should start at a keyframe; Taylan did not; what does VirtualDub do? Might a first frame be non-keyframe but readable nevertheless?
00598         bool isValidFrame = false;
00599         bool isKeyFrame = false;
00600         while (!isValidFrame || (startAtKeyFrame && !isKeyFrame))
00601         {
00602             const bool gotFrame = (DecodeNextFrame(isValidFrame, isKeyFrame) == 0);
00603             if (!gotFrame) // indicates eof or error
00604                 return false; 
00605             currentFrameNr++;
00606             if (!isValidFrame)
00607             {
00608                 MarkBadFrame(currentFrameNr);
00609                 mBlankFrames++;
00610             }
00611         }
00612 
00613         ConvertFrameToRgb();
00614 
00615         mCurrentFrameNr = mBufferedFrameNr = currentFrameNr;
00616         ILOG_DEBUG("Prepared for reading video stream; detected " << mBlankFrames << " leading invalid frame(s)");
00617         return true;
00618     }
00619 
00620     bool PopulateIndex()
00621     {
00622         ILOG_DEBUG("Creating the video index!");
00623 
00624         const String formatName(mFormatCtx->iformat->name);
00625         if (("mpeg" == formatName) || ("mpg" == formatName) 
00626             || mCodecName == "mpeg1video")
00627         {
00628             PopulateMpegIndex();
00629         }
00630         else if (("avi" == formatName) || ("mov,mp4,m4a,3gp,3g2,mj2" == formatName))
00631         {
00632             PopulateAviIndex();
00633         }
00634         else
00635         {
00636             ILOG_WARN("Cannot an create external index for format: " << formatName);
00637             mLastFrame = mFrameCountCalculated - 1; // is an estimate
00638             return false;
00639 
00640             //PopulateTrivialIndex();
00641         }
00642         
00643         ILOG_DEBUG("Frame count established from populating the index: " << mLastFrame + 1);
00644         return true;
00645     }
00646 
00647 
00648     void 
00649     PopulateMpegIndex()
00650     {
00651         AVIndexEntry *idx = mVideoStream->index_entries;
00652         if (idx && !(mFormatCtx->flags & AVFMT_FLAG_IGNIDX))
00653         {
00654             const int nrOfIndexEntries = 
00655                 mVideoStream->nb_index_entries;
00656             int countValidSize = 0;
00657             int countKeyFrame = 0;
00658             int indexPos = 0;
00659             while (indexPos < nrOfIndexEntries)
00660             {
00661                 if (idx[indexPos].size > 0)
00662                 {
00663                     countValidSize++;
00664                     if (idx[indexPos].flags & AVINDEX_KEYFRAME)
00665                         countKeyFrame++;
00666                 }
00667                 indexPos++;
00668             }
00669             ILOG_INFO("Stream contains an index which will be ignored; nr of entries is " << 
00670                 nrOfIndexEntries << 
00671                 ", of which " << countValidSize << " have size>0" <<
00672                 ", of which " << countKeyFrame << " are marked as KEYFRAME");
00673         }
00674 
00675         // add blank frames to the index
00676         for (int i = 0; i < mBlankFrames; i++)
00677         {
00678             ILOG_DEBUG("AddIndex(" << i << ", -1, -1, " << DUMMY_FRAME_HASH << ")");
00679             AddIndex(i, -1, -1, DUMMY_FRAME_HASH);
00680         }
00681 
00682         PopulateMpegIndexBase();
00683 
00684         mIndexExists = true;
00685     }
00686 
00687     void 
00688     PopulateMpegIndexBase()
00689     {
00690         AVIndexEntry *idx = mVideoStream->index_entries;
00691 
00692         typedef Column::FixedStringColumn::ColElemType FixedString;
00693 
00694         // frame nr | key frame nr | hash
00695         typedef Table::TableTem< Column::ColumnTem<Int32>,
00696                                  Column::ColumnTem<Int32>,
00697                                  Column::FixedStringColumn > FrameTable;
00698 
00699         // frame nr | seek position | recurrence | hash
00700         typedef Table::TableTem< Column::ColumnTem<Int32>,
00701                                  Column::ColumnTem<Real64>,
00702                                  Column::ColumnTem<Int32>,
00703                                  Column::FixedStringColumn > KeyFrameTable;
00704 
00705         // seek position (unique)
00706         typedef Table::TableTem< Column::ColumnTem<Real64> > SeekPositionTable;
00707 
00708         static const int HASH_SIZE = 32;
00709 
00710         FrameTable frameTable(Column::ColumnTem<Int32>(1000),
00711                               Column::ColumnTem<Int32>(1000),
00712                               Column::FixedStringColumn(HASH_SIZE, 1000));
00713 
00714         KeyFrameTable keyFrameTable(Column::ColumnTem<Int32>(1000),
00715                                     Column::ColumnTem<Real64>(1000),
00716                                     Column::ColumnTem<Int32>(1000),
00717                                     Column::FixedStringColumn(HASH_SIZE, 1000));
00718 
00719         SeekPositionTable seekPosTable(Column::ColumnTem<Real64>(1000));
00720 
00721 
00722         // list frames, key frames and candidate seek positions;
00723         // note that values of mCurrentFrameNr and mBufferedFrameNr follow from the search for leading bad frames ("blank frames")
00724 
00725         int64_t startPosOfBuffer = 0;
00726         int64_t lastEndPosOfBuffer = 0;
00727 
00728         String prevHash = "";
00729         int lastKeyFrameNr = -1;
00730         while (mCurrentFrameNr < mLastFrame)
00731         //while (mCurrentFrameNr < 500)
00732         {
00733 #ifdef FFMPEG_52
00734             const int64_t& actualEndPosOfBuffer = mFormatCtx->pb->pos;
00735 #else
00736             const int64_t& actualEndPosOfBuffer = mFormatCtx->pb.pos;
00737 #endif
00738             if (actualEndPosOfBuffer < lastEndPosOfBuffer)
00739             {
00740                 ILOG_ERROR("Unexpected buffer position change (from " <<
00741                     lastEndPosOfBuffer << " to " << actualEndPosOfBuffer << ")");
00742                 return;
00743             }
00744 
00745             const bool bufferAdvanced = (actualEndPosOfBuffer > lastEndPosOfBuffer);
00746             if (bufferAdvanced)
00747             {
00748                 startPosOfBuffer = lastEndPosOfBuffer;
00749                 lastEndPosOfBuffer = actualEndPosOfBuffer;
00750 
00751                 seekPosTable.Add(startPosOfBuffer);
00752             }
00753 
00754             // did reading a frame result in a valid frame?
00755             if  (mCurrentFrameNr > mBufferedFrameNr)
00756             {
00757                 MarkBadFrame(mCurrentFrameNr);
00758                 ILOG_DEBUG("Found a bad frame where mCurrentFrameNr = " << mCurrentFrameNr << " (and mBufferedFrameNr = " << mBufferedFrameNr << ")");
00759             }
00760             else
00761             {
00762                 const String hash = CalcHash_protected();
00763                 const FixedString hashAsFixedStr(HASH_SIZE, (char*) hash.c_str(), false);
00764 
00765                 if (mFrame->pict_type == FF_I_TYPE) // I-frames only
00766                 {
00767                     int recurrence = 1;
00768                     if (hash == prevHash) // (adjacent) duplicate frames/hashes
00769                     {
00770                         recurrence = 1 + keyFrameTable.Get3(keyFrameTable.Size() - 1);
00771                         //keyFrameTable.Set3(keyFrameTable.Size() - 1, recurrence + 1);
00772                     }
00773                     else
00774                     {
00775                         prevHash = hash;
00776                     }
00777                     const Int64 position = 0;
00778                     keyFrameTable.Add(mCurrentFrameNr, position, recurrence, hashAsFixedStr);
00779                     lastKeyFrameNr = mCurrentFrameNr;
00780                 }
00781                 else if (mFrame->pict_type != FF_P_TYPE &&
00782                     mFrame->pict_type != FF_B_TYPE)
00783                 {
00784                     ILOG_ERROR("Unexpected picture type: " << mFrame->pict_type);
00785                     return;
00786                 }
00787 
00788                 frameTable.Add(mCurrentFrameNr, lastKeyFrameNr, hashAsFixedStr);
00789                 ILOG_DEBUG("Added frame to frame table: " << mCurrentFrameNr << " : " << lastKeyFrameNr << " : " << hashAsFixedStr);
00790             }
00791 
00792             NextFrame();
00793         }
00794 
00795 
00796         keyFrameTable.Dump(0, 25);
00797 
00798 
00799         // match candidate jump positions to key frames:
00800 
00801         int keyFrameTableIndexMin = 0;
00802         int64_t topSafeSeekPos = 0;
00803 
00804         for (int seekPosTableIndex = 0; seekPosTableIndex < seekPosTable.Size(); seekPosTableIndex++)
00805         {
00806             const int64_t seekPos = seekPosTable.Get1(seekPosTableIndex);
00807 
00808             // reset (without using the index)
00809             const int posZero = 0;
00810             const int flush = 2;
00811             const int no_sync = 1;
00812             const int sync = 2;
00813             Jump(posZero, mJumpFlags, flush, (seekPos == posZero) ? sync : no_sync);
00814             ILOG_DEBUG("Jumped to head of file for seekPosTableIndex " << seekPosTableIndex);
00815             if (seekPos != posZero)
00816                 Jump(seekPos, mJumpFlags, flush, sync);
00817             ILOG_DEBUG("Jumped to seekPos " << seekPos);
00818 
00819             Array2dVec3UInt8* arr = 
00820                 new Array2dVec3UInt8(FrameWidth(), FrameHeight(), 0, 0,
00821                 mData, true, false);
00822             const String hashOfKeyFrameJumpedTo = Array::MD5Hash(arr);
00823             delete arr;
00824 
00825             int k = keyFrameTableIndexMin;
00826 
00827             for (; k < keyFrameTable.Size(); k++)
00828             {
00829                 const String hash(keyFrameTable.Get4(k).GetData(), HASH_SIZE);
00830                 if (hash == hashOfKeyFrameJumpedTo)
00831                 {
00832                     ILOG_DEBUG("Key frame " << k << " matches hash of first key frame found");
00833                     break;
00834                 }
00835 
00836                 keyFrameTable.Set2(k, topSafeSeekPos);
00837                 keyFrameTableIndexMin++;
00838             }
00839             if (k >= keyFrameTable.Size())
00840             {
00841                 ILOG_DEBUG("At end of key frame table; no matching key frame for seek pos jumped to");
00842                 break; // ready
00843             }
00844 
00845 
00846 
00847             // A: how many remaining, consecutive key frame entries have this hash as well (and so are identical images)? 
00848 
00849             int recurrence = 0;
00850             k = keyFrameTableIndexMin + 1;
00851             for (; k < keyFrameTable.Size(); k++)
00852             {
00853                 const String hash(keyFrameTable.Get4(k).GetData(), HASH_SIZE);
00854                 if (hash != hashOfKeyFrameJumpedTo)
00855                     break;
00856 
00857                 recurrence++;
00858             }
00859 
00860 
00861             // B: how many key frames can be read with this hash?
00862 
00863             mCurrentFrameNr = mBlankFrames; // mCurrentFrame is used by CalcHash_protected to check if current frame is valid
00864             int distanceToDifferentHash = 1; // in number of keyframes
00865             bool foundNextKeyFrame = false;
00866             while (true)
00867             {
00868                 foundNextKeyFrame = FindNextDecodedFrame(true);
00869                 if (!foundNextKeyFrame)
00870                     break;
00871 
00872                 const String hash = CalcHash_protected();
00873                 if (hash != hashOfKeyFrameJumpedTo) // what if at eof?
00874                     break;
00875 
00876                 //for (int f = keyFrameTableIndexMin; f < keyFrameTable.Size(); f++)
00877                 //    if (keyFrameTable.Get1(f) == // shit; wat 
00878 
00879                 distanceToDifferentHash++;
00880             }
00881 
00882 
00883 
00884             // now resolve using A and B!
00885 
00886             int keyFramesWithOldSafePos = 0;
00887             if (distanceToDifferentHash <= recurrence)
00888             {
00889                 keyFramesWithOldSafePos = (1 + recurrence) - distanceToDifferentHash;
00890                 for (int kk = 0; kk < keyFramesWithOldSafePos; kk++)
00891                 {
00892                     keyFrameTable.Set2(keyFrameTableIndexMin, topSafeSeekPos);
00893                     keyFrameTableIndexMin++;
00894                 }
00895             }
00896 
00897             keyFrameTable.Set2(keyFrameTableIndexMin, seekPos);
00898             topSafeSeekPos = seekPos;
00899 
00900 
00901             if (!foundNextKeyFrame)
00902             {
00903                 break; // assumed this only occurs at eof
00904             }
00905         }
00906 
00907         // frameTable aanpassen zodat alleen gewezen wordt naar key frames met een seek position
00908         int64_t lastProperSeekPos = -1;
00909         int frameIndex = 0;
00910         int keyFrameIndex = 0;
00911         int nextProperKeyFrameIndex = 0;
00912         while (keyFrameIndex < keyFrameTable.Size())
00913         {
00914             int seekFrameNr = keyFrameTable.Get1(keyFrameIndex);
00915             lastProperSeekPos = keyFrameTable.Get2(keyFrameIndex);
00916             nextProperKeyFrameIndex = keyFrameIndex;
00917             while (nextProperKeyFrameIndex < keyFrameTable.Size() && keyFrameTable.Get2(nextProperKeyFrameIndex) == lastProperSeekPos)
00918                 nextProperKeyFrameIndex++;
00919 
00920             int nextProperSeekFrame = 1000000;
00921             if (nextProperKeyFrameIndex < keyFrameTable.Size())
00922             {
00923                 nextProperSeekFrame = keyFrameTable.Get1(nextProperKeyFrameIndex);
00924             }
00925 
00926             while (frameIndex < frameTable.Size() && frameTable.Get2(frameIndex) < nextProperSeekFrame)
00927             {
00928                 frameTable.Set2(frameIndex, seekFrameNr);
00929                 frameIndex++;
00930             }
00931 
00932             keyFrameIndex = nextProperKeyFrameIndex;
00933         }
00934 
00935 
00936         // Add results to the index
00937         keyFrameIndex = 0;
00938         for (int i = 0; i < frameTable.Size(); i++)
00939         {
00940             const int frameNr = frameTable.Get1(i);
00941             const int keyFrameNr = frameTable.Get2(i);
00942             const String hash(frameTable.Get3(i).GetData(), HASH_SIZE);
00943             while (keyFrameTable.Get1(keyFrameIndex) < keyFrameNr)
00944                 keyFrameIndex++;
00945             const int64_t seekPos = keyFrameTable.Get2(keyFrameIndex);
00946             ILOG_DEBUG("AddIndex(" << frameNr << ", " << keyFrameNr << ", " << seekPos << ", " << hash << ")");
00947             AddIndex(frameNr, keyFrameNr, seekPos, hash);
00948         }
00949     }
00950 
00951     void
00952     PopulateAviIndex()
00953     {
00954         ILOG_INFO("Timestamp Based Indexing for AVI started!");
00955 
00956         if (mBlankFrames > 0)
00957         {
00958             // for AVI lavc is not expected to actually try to read invalid frames 
00959             ILOG_ERROR("Did not expect blank frames to have been registered here");
00960             return;
00961         }
00962 
00963         const AVIndexEntry * const idx = mVideoStream->index_entries;
00964         if (!idx)
00965         {
00966             ILOG_ERROR("Stream contains no index");
00967             mFrameCnt = 0;
00968             mLastFrame = -1;
00969             return;
00970         }
00971 
00972         mFrameCnt = mVideoStream->nb_index_entries;
00973         mLastFrame = mFrameCnt - 1;
00974         ILOG_INFO("FrameCount from Index: " << mFrameCnt);
00975 
00976         for (int e = 0; e <= 20; e++)
00977             ILOG_DEBUG("index entry " << e << ": size=" << idx[e].size << ", flags=" << idx[e].flags << ", timestamp=" << idx[e].timestamp << ", pos=" << idx[e].pos << ", min_distance=" << idx[e].min_distance << ")"); 
00978 
00979         // add dummy index entries for all leading bad frames;
00980         // note that the currently cached frame is the first valid key-frame,
00981         // and that leading bad frames may already have been marked as such;
00982         int indexPos = 0;
00983         while (indexPos < mFrameCnt &&
00984             (idx[indexPos].size <= 0 ||  // assumed to indicate frame validity
00985             idx[indexPos].flags != AVINDEX_KEYFRAME))
00986         {
00987             MarkBadFrame(indexPos);
00988             AddIndex(indexPos, -1, -1, DUMMY_FRAME_HASH);
00989             ILOG_DEBUG(indexPos << " -1 -1 " << DUMMY_FRAME_HASH << " (idx[indexPos].size=" << idx[indexPos].size << ", idx[indexPos].flags=" << idx[indexPos].flags << ", idx[indexPos].timestamp=" << idx[indexPos].timestamp << ")");
00990             indexPos++;
00991         }
00992 
00993         if (indexPos > 0)
00994         {
00995             mBlankFrames = mBufferedFrameNr = mCurrentFrameNr = indexPos;
00996             ILOG_INFO("Stream starts with " << mBlankFrames << " bad frame(s)");
00997         }
00998 
00999         // reset in order to make jumping back to the head of file reproducable also for mpeg4 files;
01000         // (without using the index)
01001         const int posZero = 0;
01002         const int flush = 2;
01003         const int no_sync = 1;
01004         const int sync = 2;
01005         Jump(posZero, mJumpFlags, flush, no_sync);
01006         Jump(mBlankFrames, mJumpFlags, flush, sync);
01007         ILOG_DEBUG("Jumped to head of file");
01008 
01009         int lastKeyPos = -1;
01010         int64_t keyPts = -1;
01011         for (; indexPos < mFrameCnt; indexPos++)
01012         //for (; indexPos < 100; indexPos++)
01013         {
01014             if (idx[indexPos].size <= 0)
01015             {
01016                 ILOG_INFO("Bad frame at index position: " << indexPos << " (idx[indexPos].size=" << idx[indexPos].size << ", idx[indexPos].flags=" << idx[indexPos].flags << ", idx[indexPos].timestamp=" << idx[indexPos].timestamp << ")");
01017                 AddIndex(indexPos, -1, -1, DUMMY_FRAME_HASH);
01018                 ILOG_DEBUG(indexPos << " -1 -1 " << DUMMY_FRAME_HASH);
01019                 MarkBadFrame(indexPos);
01020                 mCurrentFrameNr++;
01021                 mBufferedFrameNr++;
01022                 continue;
01023             }
01024 
01025             if (indexPos > mBlankFrames) // the first valid (key-) frame is currently in the frame cache
01026                 NextFrame();
01027 
01028             String frameHash;
01029             if (FrameValid(mCurrentFrameNr))
01030             {
01031                 if (idx[indexPos].flags == AVINDEX_KEYFRAME )
01032                 {
01033                     lastKeyPos = indexPos;
01034                     keyPts = idx[lastKeyPos].timestamp;
01035                 }
01036                 frameHash = CalcHash_protected();
01037             }
01038             else
01039                 frameHash = DUMMY_FRAME_HASH;
01040 
01041             AddIndex(indexPos, lastKeyPos, keyPts, frameHash);
01042             ILOG_DEBUG(indexPos << " " << lastKeyPos
01043                         << " " << keyPts << " " << frameHash);
01044         }
01045 
01046         mIndexExists = true;
01047     }
01048 
01049     // SK: Don't access the stream before actually using it:
01050     // for asf's we are not able to properly reset the stream once we
01051     // have accessed it. So the number of frames remains an estimate based upon
01052     // the file's meta-data.
01053     //
01054     // No attempt made to identify seek positions
01055     void 
01056     PopulateTrivialIndex()
01057     {
01058         const int firstValidFrameNr = FrameNr();
01059         while (FrameNr() < mLastFrame)
01060         //while (FrameNr() < 10)
01061         {
01062             const int frameNr = FrameNr();
01063             // did reading a frame result in a valid frame?
01064             if  (frameNr > mBufferedFrameNr)
01065             {
01066                 MarkBadFrame(frameNr);
01067                 ILOG_DEBUG("Found a bad frame where mCurrentFrameNr = " << 
01068                     frameNr << " (and mBufferedFrameNr = " << 
01069                     mBufferedFrameNr << ")");
01070                 //AddIndex(frameNr, -1, -1, DUMMY_FRAME_HASH);
01071                 //ILOG_DEBUG(frameNr<< " -1 -1 " << DUMMY_FRAME_HASH);
01072             }
01073             else
01074             {
01075                 // hashes calculated appear not to be reproducable and are
01076                 //   therefore useless.
01077                 //const String frameHash = CalcHash_protected();
01078                 //const String frameHash = "0123456789abcdef0123456789abcdef";
01079                 //const FixedString hashAsFixedStr(HASH_SIZE, (char*) hash.c_str(), false);
01080                 //AddIndex(frameNr, firstValidFrameNr, 0, frameHash);
01081                 //ILOG_DEBUG(frameNr << " 0 0 " << frameHash);
01082             }
01083 
01084             NextFrame();
01085         }
01086 
01087         //mIndexExists = true;
01088     }
01089 
01090     bool
01091     ReadFrameData()
01092     {
01093         if (mTargetFrameNr == mCurrentFrameNr)
01094             return true;
01095 
01096         if (!FrameValid(mTargetFrameNr) ||
01097             mTargetFrameNr == mBufferedFrameNr)
01098         {
01099             mCurrentFrameNr = mTargetFrameNr;
01100             return true;
01101         }
01102 
01103 //SK
01104 try
01105 {
01106         if (mTargetFrameNr < mBufferedFrameNr)
01107         {
01108             //Jump(GetPos(0), AVSEEK_FLAG_BYTE, 2, 1);
01109             //mBufferedFrameNr = mBlankFrames;
01110 
01111             Reset(); 
01112         }
01113 
01114         if ((mIndexExists) && (mTargetFrameNr - mBufferedFrameNr > mGopSize))
01115         {
01116             int key = GetSeekableFrame(mTargetFrameNr);
01117             ILOG_DEBUG("Jumping to Keyframe " << key << " for " << mTargetFrameNr);
01118             JumpToKeyFrame(key);
01119         }
01120 
01121         //ILOG_DEBUG("[DoReadFrameData] Going from mBufferedFrameNr=" << mBufferedFrameNr << " to mTargetFrameNr=" << mTargetFrameNr);
01122         const int target = mTargetFrameNr;
01123         while (mCurrentFrameNr < target)
01124         {
01125             //bool isValidFrame = mIndexExists ? (mIndex->Get2(mBufferedFrameNr + 1) >= 0) : true;
01126             const int nextFrameNr = mCurrentFrameNr + 1;
01127             bool isValidFrame = FrameValid(nextFrameNr);
01128             if (nextFrameNr != mBufferedFrameNr && isValidFrame)
01129             {
01130                 bool isKeyFrame; // not used
01131                 const bool gotFrame = (DecodeNextFrame(isValidFrame, isKeyFrame) == 0);
01132                 if (gotFrame)
01133                 {
01134                     if (!isValidFrame)
01135                     {
01136                         ILOG_DEBUG("[DoReadFrameData] Frame read is invalid: " << 
01137                             nextFrameNr);
01138                         MarkBadFrame(nextFrameNr);
01139                     }
01140                     else
01141                         mBufferedFrameNr = nextFrameNr;
01142                 }
01143                 else 
01144                 {
01145                     // SK: following code needs a new home! Use return code instead of void?
01146                     if (mLastFrame == LASTFRAME_UNKNOWN)
01147                     {
01148                         mLastFrame = mCurrentFrameNr;
01149                         ILOG_INFO("Adjusted last frame nr to: " << mLastFrame);
01150                     }
01151                     else
01152                     {
01153                         // for avi/pts
01154                         MarkBadFrame(nextFrameNr); 
01155                         mCurrentFrameNr = nextFrameNr;
01156                     }
01157                     return true; 
01158                 }
01159             }
01160             mCurrentFrameNr = nextFrameNr;
01161         }
01162 
01163         if (mBufferedFrameNr == mCurrentFrameNr)
01164         {
01165             ConvertFrameToRgb();
01166             if (mFormatName != "asf") // SK: dirty debug fix
01167                 CheckMD5Hash(mBufferedFrameNr);
01168         }
01169 }
01170 catch (LAVCException e)
01171 {
01172     ILOG_ERROR("Failure when going to frame: " << mTargetFrameNr << "; " << e.what());
01173     return false;
01174 }
01175 //SK
01176 
01177         return true;
01178     }
01179 
01180     void
01181     CheckMD5Hash(int frameNr)
01182     {
01183         if (!mIndexExists)
01184             return;
01185 
01186         String refHash = GetHash(frameNr);
01187         //if (refHash == "") //If it's an avi file there is no hash check
01188         //{
01189         //    mIsFrameAccurate = true;
01190         //    return;
01191         //}
01192 
01193         //Array2dVec3UInt8* arr = new Array2dVec3UInt8(FrameWidth(),
01194         //                                             FrameHeight(), 0, 0,
01195         //                                             DataPtr(),true,false);
01196         //String hash = Array::MD5Hash(arr);
01197         //delete arr;
01198         String hash = CalcHash_protected();
01199 
01200         ILOG_DEBUG("[CheckMD5Hash] frameNr=" << frameNr << " hash_calculated=" << hash << " hash_found=" << refHash);
01201 
01202         mIsFrameAccurate = (hash==refHash);
01203         if (!mFixIndexIfBroken)
01204         {
01205             if (!mIsFrameAccurate)
01206             {
01207                 ILOG_ERROR("Jumping to Frame("<<frameNr<<") ends in Frame("
01208                             <<GetFrameFromHash(hash)<<")");
01209                 
01210             }
01211             return;
01212         }
01213    
01214         //if it's not frame accurate, we have to relocate our position
01215         if (!mIsFrameAccurate)
01216         {
01217             if (true)
01218             {
01219                 ILOG_ERROR("SK: Index is not correct for video: " << mSrcName);
01220                 throw LAVCException("Index is not correct", 0);
01221             }
01222 
01223 
01224             if (frameNr==mLastFixNr)
01225             {
01226                 mFixCnt++;
01227                 if (mFixCnt>10)
01228                 {
01229                     String msg = "Cannot Fix video: " + mSrcName;
01230                     ILOG_ERROR(msg << "; try with src=LAVC_NOIDX");
01231                     throw LAVCException(msg, 0);
01232                 }
01233             }
01234             else{
01235                 mFixCnt=0;
01236                 mLastFixNr=frameNr;
01237             }
01238 
01239             ILOG_WARN("Fixing Frame Accuracy for frame "<<frameNr
01240                     <<" (ended in "<<GetFrameFromHash(hash)<<")");
01241 
01242             //Find the broken key frame that we couldn't jump to 
01243             //and discard it from the index
01244             int BrokenKey = GetSeekableFrame(frameNr);
01245             
01246             int fNr = frameNr;
01247             int cNr = mBufferedFrameNr;
01248             
01249             while (--fNr)
01250             {
01251                 ILOG_DEBUG("Checking for previous Non-Broken @ "<< fNr);
01252 
01253                 if (fNr < 0)
01254                 {
01255                     ILOG_ERROR("fNr is negative (" << fNr << ") and cannot be used as a column index");
01256                     return;
01257                 }
01258 
01259                 if ( (UInt32) fNr < mBlankFrames)
01260                 {
01261                     ILOG_DEBUG("fNr (" << fNr << ") is less than mBlankFrames (" << mBlankFrames << ")");
01262                     return;
01263                 }
01264                 if (fNr==mBlankFrames)
01265                     break;
01266 
01267                 if (GetSeekableFrame(fNr) != BrokenKey)
01268                     break;
01269             }
01270 
01271             ILOG_DEBUG("Found Previous Non-Broken frame " << fNr);
01272             
01273             int     PrevKey    = GetSeekableFrame(fNr);
01274             if (PrevKey < 0)
01275             {
01276                 ILOG_ERROR("PrevKey has negative value: " << PrevKey);
01277                 return;
01278             }
01279             int64_t PrevKeyPos = GetPos(fNr);
01280             ILOG_DEBUG("Previous Non-Broken for Keyframe " << PrevKey);
01281         
01282             fNr++;
01283             while (GetSeekableFrame(fNr)==BrokenKey)
01284             {
01285                 ILOG_DEBUG("Resetting keyframe Information for  "<<fNr);
01286                 SetKey(fNr,PrevKey);
01287                 SetPos(fNr,PrevKeyPos);                
01288                 fNr++;
01289             }
01290             ILOG_DEBUG("Retrying...");
01291             
01292             //Jump(GetPos(0), AVSEEK_FLAG_BYTE, 2, 2);
01293             //mBufferedFrameNr = mBlankFrames;
01294             Reset();
01295             ReadFrameData();
01296         }
01297         else
01298         {
01299             ILOG_DEBUG("Frame Accuracy OK for frame "<<frameNr);
01300         }
01301     }
01302 
01303 
01304     String DetermineInfoName(CString srcName, IndexMode mode, Util::Database* db)
01305     {
01306         String infoName = "";
01307         if (Link::DiskImage::DiskImageUsed())
01308         {
01309             String subPath = FileNamePath(srcName);
01310             if (subPath.substr(0, 10) == "diskimage:")
01311             {
01312                 int posAfterDiskImageFileName = subPath.find("://", 10);
01313                 // SK: assume disk image file name is unique, 
01314                 // not needing an additional (sub-)path specification
01315                 const String uptoDiskImageToken = 
01316                     subPath.substr(0, posAfterDiskImageFileName);
01317                 int diskImageFileNamePos = 
01318                     FileNameLastPathSepPos(uptoDiskImageToken) + 1;
01319                 if (diskImageFileNamePos == String::npos)
01320                     ILOG_ERROR("Disk image file was expected to be prefixed "
01321                     << "with a path: " << uptoDiskImageToken);
01322 
01323                 String subSubPath = 
01324                         subPath.substr(posAfterDiskImageFileName + 1);
01325                 subSubPath = StringReplaceAll(subSubPath,
01326                                                      "0x", "0x30x", false);
01327                 subSubPath = StringReplaceAll(subSubPath, 
01328                                                      "//", "/0x2F", false);
01329                 subSubPath = subSubPath.substr(0, subSubPath.size() - 1);
01330                 subPath = subPath.substr(diskImageFileNamePos, 
01331                     posAfterDiskImageFileName-diskImageFileNamePos)+subSubPath;
01332 
01333                 String dir = "FramePosIndex/" + subPath;
01334 
01335                 bool toWrite = (mode == WRITEIDX);
01336                 bool silent = (mode != READIDX);
01337 
01338                 if (toWrite)
01339                     db->MakeDir(dir);
01340 
01341                 String fname = FileNameTail(srcName) + ".info";
01342                 infoName = db->GetFilePath(dir, fname, toWrite, silent);
01343             }
01344             else
01345                 infoName = srcName + ".info";
01346         }
01347         return infoName;
01348     }
01349 
01350     // Returns zero if successful, a negative value otherwise.
01351     int
01352     DecodeNextFrame(bool& isValidFrame, bool& isKeyFrame)
01353     {
01354         //avcodec_get_frame_defaults(mFrame);
01355 
01356         const int MAX_READ_FAILURES = Impala::Max(15, 5 * mGopSize);
01357         int nrOfReadFailures = 0;
01358 
01359         int atEndOfFile = 
01360 #ifdef FFMPEG_52
01361         url_feof(mFormatCtx->pb);
01362 #else
01363         url_feof(&mFormatCtx->pb);
01364 #endif
01365         //if (atEndOfFile != 0)
01366         //    return -1;
01367 
01368         bool readFrameFailed = false;
01369 
01370         isValidFrame = false;
01371         isKeyFrame = false;
01372         int rc = 0;
01373         while (true)
01374         {
01375             int readFrameResult = av_read_frame(mFormatCtx, mPacket);
01376             readFrameFailed = (readFrameResult < 0);
01377             if (readFrameFailed)
01378             {
01379                 // upon a negative value, there may still be 
01380                 // valid frames left to decode
01381                 ILOG_DEBUG("av_read_frame failed and returned: " << readFrameResult);
01382             }
01383 
01384             //ILOG_DEBUG("  video stream's curdts=" << mVideoStream->cur_dts << " mPacket->dts=" << mPacket->dts);
01385             //ILOG_DEBUG("  [DecodeNextFrame] mPacket->size=" << mPacket->size << "; mPacket->flags=" << mPacket->flags << "; bp.pos=" << mFormatCtx->pb.pos);
01386 
01387             if (mPacket->stream_index == mVideoStreamIndex) 
01388             {
01389                 int frameDecoded = -1;
01390 
01391                 //int len = avcodec_decode_video(mCodecCtx, mFrame, &frameDecoded,
01392                 //                           mPacket->data, mPacket->size);
01393 
01394                 // provide buffer padding cf. definition of avcodec_decode_video;
01395                 // unsure if required here, but rather safe than sorry...
01396                 const int bufSize = mPacket->size;
01397                 uint8_t *buf = new uint8_t[bufSize + FF_INPUT_BUFFER_PADDING_SIZE];
01398                 for (int i = 0; i < bufSize; i++)
01399                     buf[i] = (mPacket->data)[i];
01400                 for (int i = 0; i < FF_INPUT_BUFFER_PADDING_SIZE; i++)
01401                     buf[bufSize + i] = 0;
01402                 int len = avcodec_decode_video(mCodecCtx, mFrame, &frameDecoded,
01403                                            buf, bufSize);
01404                 delete [] buf;
01405 
01406                 ILOG_DEBUG("mPacket->pts =  " << mPacket->pts << " ; mPacket->dts =  " << mPacket->dts);
01407                 if (len < 0)
01408                     ILOG_DEBUG("  avcodec_decode_video returned: " << len); // implies: frameDecoded==false
01409 
01410                 if (frameDecoded)
01411                 {
01412                     isValidFrame = true;
01413                     isKeyFrame = (mFrame->pict_type==FF_I_TYPE && mFrame->key_frame==1);
01414                     break;
01415                 }
01416                 else
01417                 {
01418 #ifdef FFMPEG_52
01419                     ILOG_DEBUG(
01420                         "  [DecodeNextFrame] Frame not valid; mPacket->size=" << 
01421                         mPacket->size << "; mPacket->flags=" << 
01422                         mPacket->flags << "; bp->pos=" << mFormatCtx->pb->pos);
01423 #else
01424                     ILOG_DEBUG(
01425                         "  [DecodeNextFrame] Frame not valid; mPacket->size=" << 
01426                         mPacket->size << "; mPacket->flags=" << 
01427                         mPacket->flags << "; bp.pos=" << mFormatCtx->pb.pos);
01428 #endif
01429 
01430                     // don't continue if reading reached eof
01431                     if (atEndOfFile)
01432                     {
01433                         rc = -3;
01434                         break;
01435                     }
01436 
01437                     // mPacket->flags unequal zero seems to indicate incomplete
01438                     // frames other than P or B frames missing I or P frame data
01439                     if (mPacket->flags == 0)
01440                         break;
01441                 }
01442             }
01443 
01444             av_free_packet(mPacket);
01445  
01446             // while the read buffer already reached the eof, there may
01447             // still be some valid frames left to decode!
01448             nrOfReadFailures++;
01449             if ((atEndOfFile || readFrameFailed) && (nrOfReadFailures > MAX_READ_FAILURES))
01450             {
01451                 ILOG_WARN("Max. nr of frame read failures reached (" <<
01452                     MAX_READ_FAILURES << "); probably at end of file");
01453                 rc = -1;
01454                 break;
01455             }
01456         }
01457 
01458         av_free_packet(mPacket);
01459         return rc;
01460     }
01461 
01462     // Convert the image from its native format to RGB
01463     void
01464     ConvertFrameToRgb()
01465     {
01466         const int result = sws_scale(mSwsContext, 
01467             mFrame->data, mFrame->linesize, 
01468             0, mFrameHeight, 
01469             mFrameRGB->data, mFrameRGB->linesize);
01470     }
01471 
01472 
01473     int              mVideoStreamIndex;
01474     AVStream*        mVideoStream;
01475     AVFormatContext* mFormatCtx;
01476     AVCodecContext*  mCodecCtx;
01477     struct SwsContext* mSwsContext;
01478     AVCodec*         mCodec;
01479     AVFrame*         mFrame;
01480     AVFrame*         mFrameRGB;
01481     AVPacket*        mPacket;
01482     
01483     int              mBufferedFrameNr;
01484     bool             mValid;
01485     uint32_t         mFrameCnt;
01486     uint32_t         mFrameCountCalculated; // based on mDuration
01487     IndexMode        mMode;
01488     bool             mFixIndexIfBroken;
01489     String           mJumpMethod;
01490     int              mJumpFlags;
01491     int              mLastFixNr;
01492     int              mFixCnt;
01493 
01494     ILOG_VAR_DECL;
01495 
01496 }; //class
01497 
01498 ILOG_VAR_INIT(RgbDataSrcLavc_old, Impala.Core.Stream);
01499 
01500 }}} // namespace Impala::Core::Stream
01501 
01502 #endif

Generated on Fri Mar 19 09:31:19 2010 for ImpalaSrc by  doxygen 1.5.1