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

StrategyIgnoringNativeIndex.h

Go to the documentation of this file.
00001 #ifndef Impala_Core_Stream_Lavc_StrategyIgnoringNativeIndex_h
00002 #define Impala_Core_Stream_Lavc_StrategyIgnoringNativeIndex_h
00003 
00004 #include "Core/Stream/Lavc/VideoAccessStrategy.h"
00005 #include "Core/Stream/Lavc/VideoIndex.h"
00006 
00007 namespace Impala
00008 {
00009 namespace Core
00010 {
00011 namespace Stream
00012 {
00013 namespace Lavc
00014 {
00015 
00016 class StrategyIgnoringNativeIndex : public VideoAccessStrategy
00017 {
00018 
00019 public:
00020 
00021     StrategyIgnoringNativeIndex(const Lavc::VideoAccessObject* const vao) 
00022         : VideoAccessStrategy(vao)
00023     {
00024         ILOG_DEBUG("Applying video access strategy based on " <<
00025             "frame positions expressed in bytes");
00026     }
00027 
00028     virtual bool
00029     FrameCanBeRead(int frameNr) const
00030     {
00031         // all frames' data can be read
00032         return true;
00033     }
00034 
00035 
00036 protected:
00037 
00038     virtual int
00039     GetJumpFlags() const
00040     {
00041         //return AVSEEK_FLAG_BYTE | AVSEEK_FLAG_ANY;
00042         return AVSEEK_FLAG_BYTE;
00043     }
00044 
00045     virtual bool
00046     ScanProtected()
00047     {
00048         ILOG_INFO("First scan pass, collecting...");
00049         bool debug = false;
00050         if (!debug)
00051             ScanPackets(false);
00052         //else
00053         //    ReadScanData("scandata");
00054         //if (!debug)
00055         //    WriteScanData("scandata");
00056         mScanDataPresent = true;
00057         mVao->Reset();
00058         ILOG_INFO("Second scan pass, validating...");
00059         if (!debug)
00060             ScanPackets(true);
00061         //else
00062         //    ReadScanData("scandata");
00063         //if (!debug)
00064         //    WriteScanData("scandata");
00065 
00066         const int frameCnt = mFrames->Size();
00067         if (frameCnt <= 0)
00068         {
00069             ILOG_ERROR("No frames found");
00070             return false;
00071         }
00072 
00073         ILOG_INFO("Detected " << mLeadingBadFrameCount << 
00074             " leading bad frame(s) and " << mBadFrameCount << 
00075             " bad frame(s) in total");
00076         if (mLeadingBadFrameCount >= frameCnt)
00077         {
00078             ILOG_ERROR("No valid frames found");
00079             return false;
00080         }
00081 
00082         const int firstValidFrameNr = mLeadingBadFrameCount;
00083         if (!FrameIsKey(firstValidFrameNr))
00084         {
00085             ILOG_ERROR("Unexpected: first valid frame (" << firstValidFrameNr <<
00086                 ") is not a key frame (type: " << mVao->FrameType() << ")");
00087             return false;
00088         }
00089 
00090         // validate reproduction of first valid key frame's hash
00091         mVao->Reset();
00092         bool lookForKeyFrame = true;
00093         PacketTrace trace(10);
00094         bool foundFirstKeyFrame = 
00095             DecodeNextValidFrame(lookForKeyFrame, &trace);
00096         if (!foundFirstKeyFrame)
00097         {
00098             ILOG_ERROR("Could not locate first valid key frame");
00099             return false;
00100         }
00101 
00102         mVao->CurrentFrameToRgb();
00103         if (!CurrentFrameMatchesFrame(firstValidFrameNr, &trace))
00104         {
00105             ILOG_ERROR("Could not reproduce first valid key frame " << 
00106                 firstValidFrameNr);
00107             return false;
00108         }
00109 
00110         return true;
00111     }
00112 
00118     virtual VideoIndex*
00119     ConstructIndexProtected() const
00120     {
00121         VideoIndex* videoIndex = new VideoIndex();
00122         UInt64 seekPos;
00123         int packetToStartSearchAt = -1; 
00124         const int frameCount = NrOfFrames();
00125         for (int f = 0; f < frameCount; f++)
00126         {
00127             if (FrameIsValid(f) && FrameIsKey(f) && FrameIsStable(f))
00128             {
00129                 const bool frameIsSeekable = FindSeekPosition(f, 
00130                     &seekPos, &packetToStartSearchAt);
00131                 if (frameIsSeekable)
00132                 {
00133                     videoIndex->AddFrame(f, true, seekPos);
00134                     ILOG_DEBUG("Indexed frame: " << f << " " << f << 
00135                         " true " << seekPos);
00136                 }
00137                 else if (videoIndex->NrOfEntries() == 0)
00138                 {
00139                     ILOG_ERROR("Failed to find a seek position for " <<
00140                         "frame " << f);
00141                     delete videoIndex;
00142                     return 0;
00143                 }
00144             }
00145         }
00146         return videoIndex;
00147     }
00148 
00149     virtual bool
00150     NextFrameMatchesFrame(int frameNr, const VideoIndex& videoIndex) const
00151     {
00152         if (!DecodeNextValidFrame(false))
00153         {
00154             ILOG_DEBUG("Failed on sequential read for frame " << frameNr);
00155             return false;
00156         }
00157 
00158         if (FrameIsStable(frameNr))
00159         {
00160             mVao->CurrentFrameToRgb();
00161             if (!CurrentHashMatchesFrame(frameNr))
00162             {
00163                 ILOG_DEBUG("Index error for frame " << frameNr << 
00164                     " ; hash found = " << mVao->CurrentHash());
00165                 return false;
00166             }
00167         }
00168 
00169         return true;
00170     }
00171 
00172 
00173 private:
00174 
00175     void
00176     ScanPackets(bool validating)
00177     {
00178         int packetCount = 0;
00179         int frameCount = 0;
00180         mBadFrameCount = 0;
00181         mLeadingBadFrameCount = 0;
00182 
00183         // ***************************
00184         // SK: for debugging
00185         bool _limitWork4Debugging = false;
00186         int _myMax = -1;
00187         if (_limitWork4Debugging)
00188         {
00189             _myMax = 30;
00190             _myMax *= 1;
00191         }
00192         else
00193         {
00194             _myMax *= 1;
00195         }
00196 
00197         bool noMorePackets = false;
00198         while (!noMorePackets && !(_limitWork4Debugging && frameCount > _myMax))
00199         // ***************************
00200             noMorePackets = ScanOnePacket(&packetCount, &frameCount, validating);
00201 
00202         ILOG_DEBUG("Scanned " << packetCount << " packets, and found " <<
00203             frameCount << " frames");
00204     }
00205 
00206     // Returns 'true' if no packet could be read; 'false' otherwise.
00207     bool
00208     ScanOnePacket(int* packetCount, int* frameCount, bool validating)
00209     {
00210         const int MAX_POST_EOF_FAILURES = Max(15, 2 * mVao->GopSize());
00211         int nrOfConsecutivePostEofFailures = 0;
00212 
00213         while (true)
00214         {
00215             const bool atEofBeforeRead = mVao->AtEof();
00216             const int readPacketResult = mVao->ReadPacket();
00217             if (mVao->AtEof() && !atEofBeforeRead)
00218                 ILOG_DEBUG("Reached end of file");
00219 
00220             const bool readPacketFailed = (readPacketResult < 0);
00221             if (!readPacketFailed)
00222             {
00223                 if (atEofBeforeRead)
00224                 {
00225                     ILOG_DEBUG("A packet was successfully read after " <<
00226                         "reading arrived at end of file");
00227                 }
00228                 const int packetNr = (*packetCount)++;
00229                 ProcessPacket(packetNr, frameCount, validating);
00230                 return false;
00231             }
00232 
00233             ILOG_DEBUG("ReadPacket() failed and returned: " << 
00234                 readPacketResult);
00235 
00236             if (atEofBeforeRead)
00237             {
00238                 if (readPacketFailed)
00239                 {
00240                     nrOfConsecutivePostEofFailures++;
00241                     if (nrOfConsecutivePostEofFailures > MAX_POST_EOF_FAILURES)
00242                     {
00243                         ILOG_DEBUG("Max. nr of consecutive post-EOF " <<
00244                             "read failures reached (" <<
00245                             MAX_POST_EOF_FAILURES << ")");
00246                         return true;
00247                     }
00248                 }
00249                 else 
00250                     nrOfConsecutivePostEofFailures = 0;
00251             }
00252         }
00253     }
00254 
00255     // Evaluates the currently read packet, which must be the result of a 
00256     // successful read operation; otherwise this call might incorrectly 'see'
00257     // a valid packet and frame!
00258     void
00259     ProcessPacket(int packetNr, int* frameCount, bool validating)
00260     {
00261         const int size = mVao->CurrentPacketSize();
00262         const int flags = mVao->CurrentPacketFlags();
00263         const UInt64 posAfterRead = mVao->CurrentFilePosition();
00264 
00265         if (validating)
00266         {
00267             if (mPackets->Get2(packetNr) != size || 
00268                 mPackets->Get3(packetNr) != flags ||
00269                 mPackets->Get4(packetNr) != posAfterRead)
00270             {
00271                 ILOG_ERROR("Packet " << packetNr << " not reproducable");
00272                 return;
00273             }
00274         }
00275         else
00276             mPackets->Add(packetNr, size, flags, posAfterRead);
00277 
00278         if (mVao->CurrentPacketIsVideo()) 
00279         {
00280             int frameDecoded = 0;
00281             const int len = mVao->DecodeFrame(&frameDecoded);
00282 
00283             // libavcodec's packet flags usage is not clear,  
00284             // but this appeared to work out fine: 
00285             const bool ignorePacket = (frameDecoded <= 0) && (flags != 0);
00286 
00287             if (!ignorePacket)
00288             {
00289                 const bool frameValid = (len >= 0 && frameDecoded > 0);
00290                 bool frameIsKey = false;
00291                 if (frameValid)
00292                 {
00293                     frameIsKey = (mVao->FrameType() == 'I' && mVao->FrameIsKey());
00294                 }
00295                 else
00296                 {
00297                     ILOG_DEBUG("DecodeFrame() failed (" << frameDecoded << 
00298                         ") and returned: " << len );
00299                     mBadFrameCount++;
00300                     if (mBadFrameCount >= *frameCount)
00301                         mLeadingBadFrameCount++;
00302                 }
00303 
00304                 const int frameNr = (*frameCount)++;
00305                 ProcessFrame(frameValid, frameIsKey, frameNr, validating);
00306             }
00307         }
00308     }
00309 
00310     // Returns 'true' if a position was found that allows 
00311     // random (seek) access to the specified frame; 'false' otherwise.
00312     // The frame specified must be valid and be a key frame, must not yet occur 
00313     // in the index, and must be greater than all frame nrs already occurring 
00314     // in the index. 
00315     // Furthermore the packet table is assumed to be in ascending 
00316     // order with regard to post-read file positions.
00317     bool
00318     FindSeekPosition(int frameNr, UInt64* seekPos, int* refPacket) const
00319     {
00320         // find: the first next file position suitable for seeking the frame
00321         bool foundCandSeekPos = FindCandidateSeekPosition(seekPos, refPacket);
00322         if (!foundCandSeekPos || !IsValidSeekTarget(frameNr, *seekPos))
00323         {
00324             ILOG_DEBUG("No valid seek position found for frame " << frameNr);
00325             return false;
00326         }
00327 
00328         // optimize: check whether the next candidate position is also valid
00329         UInt64 nextSeekTarget;
00330         int tempRefPacket = *refPacket;
00331         while (true)
00332         {
00333             foundCandSeekPos = 
00334                 FindCandidateSeekPosition(&nextSeekTarget, &tempRefPacket);
00335             if (!foundCandSeekPos || !IsValidSeekTarget(frameNr, nextSeekTarget))
00336                 break;
00337             *seekPos = nextSeekTarget;
00338             *refPacket = tempRefPacket;
00339         }
00340         return true;
00341     }
00342 
00343     // Determines the smallest post-read file position occurring in the packet 
00344     // table from the specified reference packet on, updates the reference 
00345     // packet with the first next packet nr with a post-read position greater than 
00346     // the value found, and returns 'true'. If a negative value is passed in 
00347     // for the ref packet, the first data position from the video 
00348     // stream will be used. If no valid file position could be found, 'false' 
00349     // is returned.
00350     bool FindCandidateSeekPosition(UInt64* seekPos, int* refPacket) const
00351     {
00352         const int packetTableSize = mPackets->Size();
00353         if (*refPacket >= packetTableSize)
00354             return false;
00355 
00356         int nextRefPacket;
00357         if (*refPacket < 0)
00358         {
00359             *seekPos = mVao->FirstPacketPosition();
00360             nextRefPacket = 0;
00361         }
00362         else
00363         {
00364             *seekPos = mPackets->Get4(*refPacket);
00365             nextRefPacket = *refPacket + 1;
00366         }
00367 
00368         while (nextRefPacket < packetTableSize)
00369         {
00370             if (mPackets->Get4(nextRefPacket) > *seekPos) // post-read file pos
00371             {
00372                 *refPacket = nextRefPacket;
00373                 return true;
00374             }
00375             nextRefPacket++;
00376         }
00377 
00378         return false;
00379     }
00380 
00381     // Returns 'true' if seeking to the specified position in the video and 
00382     // reading frames until a key frame is found, will result in the specified
00383     // key frame;
00384     // assumes the specified frame is a valid and stable key frame!
00385     bool
00386     IsValidSeekTarget(int frameNr, const UInt64& seekPos) const
00387     {
00388         PacketTrace trace(10);
00389         static const bool MUST_BE_KEY = true;
00390         if (!Jump(seekPos, AVSEEK_FLAG_BYTE, MUST_BE_KEY, 2, &trace))
00391             return false;
00392 
00393         CurrentFrameToRgb();
00394         if (!CurrentFrameMatchesFrame(frameNr, &trace))
00395             return false;
00396 
00397         UInt64 postReadPos = mPackets->Get4(mFrames->Get2(frameNr));
00398         UInt64 lastPostReadPosOfTrace = trace.Get3(trace.Size() - 1);
00399         if (lastPostReadPosOfTrace <= postReadPos)
00400             return true;
00401 
00402         for (int f = frameNr + 1; f < mFrames->Size(); f++)
00403         {
00404             if (!DecodeNextValidFrame(false, &trace))
00405             {
00406                 ILOG_ERROR("Unexpected: could not find/decode frame " << f);
00407                 return false;
00408             }
00409 
00410             CurrentFrameToRgb();
00411             if (!CurrentFrameMatchesFrame(f, &trace))
00412             {
00413                 ILOG_DEBUG(seekPos << " is not a valid seek target for " <<
00414                     "frame " << frameNr << ", following from a mismatch for " <<
00415                     "frame " << f);
00416                 return false;
00417             }
00418 
00419             postReadPos = mPackets->Get4(mFrames->Get2(f));
00420             lastPostReadPosOfTrace = trace.Get3(trace.Size() - 1);
00421             if (lastPostReadPosOfTrace <= postReadPos)
00422                 break;
00423         }
00424         return true;
00425     }
00426 
00427 
00428     ILOG_VAR_DECL;
00429 
00430 }; //class
00431 
00432 ILOG_VAR_INIT(StrategyIgnoringNativeIndex, Impala.Core.Stream.Lavc);
00433 
00434 }}}} // namespace Impala::Core::Stream::Lavc
00435 
00436 #endif

Generated on Thu Jan 13 09:04:35 2011 for ImpalaSrc by  doxygen 1.5.1