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
00032 return true;
00033 }
00034
00035
00036 protected:
00037
00038 virtual int
00039 GetJumpFlags() const
00040 {
00041
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
00053
00054
00055
00056 mScanDataPresent = true;
00057 mVao->Reset();
00058 ILOG_INFO("Second scan pass, validating...");
00059 if (!debug)
00060 ScanPackets(true);
00061
00062
00063
00064
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
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
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
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
00256
00257
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
00284
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
00311
00312
00313
00314
00315
00316
00317 bool
00318 FindSeekPosition(int frameNr, UInt64* seekPos, int* refPacket) const
00319 {
00320
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
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
00344
00345
00346
00347
00348
00349
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)
00371 {
00372 *refPacket = nextRefPacket;
00373 return true;
00374 }
00375 nextRefPacket++;
00376 }
00377
00378 return false;
00379 }
00380
00381
00382
00383
00384
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 };
00431
00432 ILOG_VAR_INIT(StrategyIgnoringNativeIndex, Impala.Core.Stream.Lavc);
00433
00434 }}}}
00435
00436 #endif