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 return AVSEEK_FLAG_BYTE;
00042 }
00043
00044 virtual bool
00045 ScanProtected()
00046 {
00047 ILOG_INFO("First scan pass, collecting...");
00048 bool debug = false;
00049 if (!debug)
00050 ScanPackets(false);
00051
00052
00053
00054
00055 mScanDataPresent = true;
00056 mVao->Reset();
00057 ILOG_INFO("Second scan pass, validating...");
00058 if (!debug)
00059 ScanPackets(true);
00060
00061
00062
00063
00064
00065 const int frameCnt = mFrames->Size();
00066 if (frameCnt <= 0)
00067 {
00068 ILOG_ERROR("No frames found");
00069 return false;
00070 }
00071
00072 ILOG_INFO("Detected " << mLeadingBadFrameCount <<
00073 " leading bad frame(s) and " << mBadFrameCount <<
00074 " bad frame(s) in total");
00075 if (mLeadingBadFrameCount >= frameCnt)
00076 {
00077 ILOG_ERROR("No valid frames found");
00078 return false;
00079 }
00080
00081 const int firstValidFrameNr = mLeadingBadFrameCount;
00082 if (!FrameIsKey(firstValidFrameNr))
00083 {
00084 ILOG_ERROR("Unexpected: first valid frame (" << firstValidFrameNr <<
00085 ") is not a key frame (type: " << mVao->FrameType() << ")");
00086 return false;
00087 }
00088
00089
00090 mVao->Reset();
00091 bool lookForKeyFrame = true;
00092 PacketTrace trace(10);
00093 bool foundFirstKeyFrame =
00094 DecodeNextValidFrame(lookForKeyFrame, &trace);
00095 if (!foundFirstKeyFrame)
00096 {
00097 ILOG_ERROR("Could not locate first valid key frame");
00098 return false;
00099 }
00100
00101 mVao->CurrentFrameToRgb();
00102 if (!CurrentFrameMatchesFrame(firstValidFrameNr, &trace))
00103 {
00104 ILOG_ERROR("Could not reproduce first valid key frame " <<
00105 firstValidFrameNr);
00106 return false;
00107 }
00108
00109 return true;
00110 }
00111
00117 virtual VideoIndex*
00118 ConstructIndexProtected() const
00119 {
00120 VideoIndex* videoIndex = new VideoIndex();
00121 UInt64 seekPos;
00122 int packetToStartSearchAt = -1;
00123 const int frameCount = NrOfFrames();
00124 for (int f = 0; f < frameCount; f++)
00125 {
00126 if (FrameIsValid(f) && FrameIsKey(f) && FrameIsStable(f))
00127 {
00128 const bool frameIsSeekable = FindSeekPosition(f,
00129 &seekPos, &packetToStartSearchAt);
00130 if (frameIsSeekable)
00131 {
00132 videoIndex->AddFrame(f, true, seekPos);
00133 ILOG_DEBUG("Indexed frame: " << f << " " << f <<
00134 " true " << seekPos);
00135 }
00136 else if (videoIndex->NrOfEntries() == 0)
00137 {
00138 ILOG_ERROR("Failed to find a seek position for " <<
00139 "frame " << f);
00140 delete videoIndex;
00141 return 0;
00142 }
00143 }
00144 }
00145 return videoIndex;
00146 }
00147
00148 virtual bool
00149 NextFrameMatchesFrame(int frameNr, const VideoIndex& videoIndex) const
00150 {
00151 if (!DecodeNextValidFrame(false))
00152 {
00153 ILOG_DEBUG("Failed on sequential read for frame " << frameNr);
00154 return false;
00155 }
00156
00157 if (FrameIsStable(frameNr))
00158 {
00159 mVao->CurrentFrameToRgb();
00160 if (!CurrentHashMatchesFrame(frameNr))
00161 {
00162 ILOG_DEBUG("Index error for frame " << frameNr <<
00163 " ; hash found = " << mVao->CurrentHash());
00164 return false;
00165 }
00166 }
00167
00168 return true;
00169 }
00170
00171
00172 private:
00173
00174 void
00175 ScanPackets(bool validating)
00176 {
00177 int packetCount = 0;
00178 int frameCount = 0;
00179 mBadFrameCount = 0;
00180 mLeadingBadFrameCount = 0;
00181
00182
00183
00184 bool _limitWork4Debugging = false;
00185 int _myMax = -1;
00186 if (_limitWork4Debugging)
00187 {
00188 _myMax = 30;
00189 _myMax *= 1;
00190 }
00191 else
00192 {
00193 _myMax *= 1;
00194 }
00195
00196 bool noMorePackets = false;
00197 while (!noMorePackets && !(_limitWork4Debugging && frameCount > _myMax))
00198
00199 noMorePackets = ScanOnePacket(&packetCount, &frameCount, validating);
00200
00201 ILOG_DEBUG("Scanned " << packetCount << " packets, and found " <<
00202 frameCount << " frames");
00203 }
00204
00205
00206 bool
00207 ScanOnePacket(int* packetCount, int* frameCount, bool validating)
00208 {
00209 const int MAX_POST_EOF_FAILURES = Max(15, 2 * mVao->GopSize());
00210 int nrOfConsecutivePostEofFailures = 0;
00211
00212 while (true)
00213 {
00214 const bool atEofBeforeRead = mVao->AtEof();
00215 const int readPacketResult = mVao->ReadPacket();
00216 if (mVao->AtEof() && !atEofBeforeRead)
00217 ILOG_DEBUG("Reached end of file");
00218
00219 const bool readPacketFailed = (readPacketResult < 0);
00220 if (!readPacketFailed)
00221 {
00222 if (atEofBeforeRead)
00223 {
00224 ILOG_DEBUG("A packet was successfully read after " <<
00225 "reading arrived at end of file");
00226 }
00227 const int packetNr = (*packetCount)++;
00228 ProcessPacket(packetNr, frameCount, validating);
00229 return false;
00230 }
00231
00232 ILOG_DEBUG("ReadPacket() failed and returned: " <<
00233 readPacketResult);
00234
00235 if (atEofBeforeRead)
00236 {
00237 if (readPacketFailed)
00238 {
00239 nrOfConsecutivePostEofFailures++;
00240 if (nrOfConsecutivePostEofFailures > MAX_POST_EOF_FAILURES)
00241 {
00242 ILOG_DEBUG("Max. nr of consecutive post-EOF " <<
00243 "read failures reached (" <<
00244 MAX_POST_EOF_FAILURES << ")");
00245 return true;
00246 }
00247 }
00248 else
00249 nrOfConsecutivePostEofFailures = 0;
00250 }
00251 }
00252 }
00253
00254
00255
00256
00257 void
00258 ProcessPacket(int packetNr, int* frameCount, bool validating)
00259 {
00260 const int size = mVao->CurrentPacketSize();
00261 const int flags = mVao->CurrentPacketFlags();
00262 const UInt64 posAfterRead = mVao->CurrentFilePosition();
00263
00264 if (validating)
00265 {
00266 if (mPackets->Get2(packetNr) != size ||
00267 mPackets->Get3(packetNr) != flags ||
00268 mPackets->Get4(packetNr) != posAfterRead)
00269 {
00270 ILOG_ERROR("Packet " << packetNr << " not reproducable");
00271 return;
00272 }
00273 }
00274 else
00275 mPackets->Add(packetNr, size, flags, posAfterRead);
00276
00277 if (mVao->CurrentPacketIsVideo())
00278 {
00279 int frameDecoded = 0;
00280 const int len = mVao->DecodeFrame(&frameDecoded);
00281
00282
00283
00284 const bool ignorePacket = (frameDecoded <= 0) && (flags != 0);
00285
00286 if (!ignorePacket)
00287 {
00288 const bool frameValid = (len >= 0 && frameDecoded > 0);
00289 bool frameIsKey = false;
00290 if (frameValid)
00291 {
00292 frameIsKey = (mVao->FrameType() == 'I' && mVao->FrameIsKey());
00293 }
00294 else
00295 {
00296 ILOG_DEBUG("DecodeFrame() failed (" << frameDecoded <<
00297 ") and returned: " << len );
00298 mBadFrameCount++;
00299 if (mBadFrameCount >= *frameCount)
00300 mLeadingBadFrameCount++;
00301 }
00302
00303 const int frameNr = (*frameCount)++;
00304 ProcessFrame(frameValid, frameIsKey, frameNr, validating);
00305 }
00306 }
00307 }
00308
00309
00310
00311
00312
00313
00314
00315
00316 bool
00317 FindSeekPosition(int frameNr, UInt64* seekPos, int* refPacket) const
00318 {
00319
00320 bool foundCandSeekPos = FindCandidateSeekPosition(seekPos, refPacket);
00321 if (!foundCandSeekPos || !IsValidSeekTarget(frameNr, *seekPos))
00322 {
00323 ILOG_DEBUG("No valid seek position found for frame " << frameNr);
00324 return false;
00325 }
00326
00327
00328 UInt64 nextSeekTarget;
00329 int tempRefPacket = *refPacket;
00330 while (true)
00331 {
00332 foundCandSeekPos =
00333 FindCandidateSeekPosition(&nextSeekTarget, &tempRefPacket);
00334 if (!foundCandSeekPos || !IsValidSeekTarget(frameNr, nextSeekTarget))
00335 break;
00336 *seekPos = nextSeekTarget;
00337 *refPacket = tempRefPacket;
00338 }
00339 return true;
00340 }
00341
00342
00343
00344
00345
00346
00347
00348
00349 bool FindCandidateSeekPosition(UInt64* seekPos, int* refPacket) const
00350 {
00351 const int packetTableSize = mPackets->Size();
00352 if (*refPacket >= packetTableSize)
00353 return false;
00354
00355 int nextRefPacket;
00356 if (*refPacket < 0)
00357 {
00358 *seekPos = mVao->FirstPacketPosition();
00359 nextRefPacket = 0;
00360 }
00361 else
00362 {
00363 *seekPos = mPackets->Get4(*refPacket);
00364 nextRefPacket = *refPacket + 1;
00365 }
00366
00367 while (nextRefPacket < packetTableSize)
00368 {
00369 if (mPackets->Get4(nextRefPacket) > *seekPos)
00370 {
00371 *refPacket = nextRefPacket;
00372 return true;
00373 }
00374 nextRefPacket++;
00375 }
00376
00377 return false;
00378 }
00379
00380
00381
00382
00383
00384 bool
00385 IsValidSeekTarget(int frameNr, const UInt64& seekPos) const
00386 {
00387 PacketTrace trace(10);
00388 static const bool MUST_BE_KEY = true;
00389 if (!Jump(seekPos, AVSEEK_FLAG_BYTE, MUST_BE_KEY, 2, &trace))
00390 return false;
00391
00392 CurrentFrameToRgb();
00393 if (!CurrentFrameMatchesFrame(frameNr, &trace))
00394 return false;
00395
00396 UInt64 postReadPos = mPackets->Get4(mFrames->Get2(frameNr));
00397 UInt64 lastPostReadPosOfTrace = trace.Get3(trace.Size() - 1);
00398 if (lastPostReadPosOfTrace <= postReadPos)
00399 return true;
00400
00401 for (int f = frameNr + 1; f < mFrames->Size(); f++)
00402 {
00403 if (!DecodeNextValidFrame(false, &trace))
00404 {
00405 ILOG_ERROR("Unexpected: could not find/decode frame " << f);
00406 return false;
00407 }
00408
00409 CurrentFrameToRgb();
00410 if (!CurrentFrameMatchesFrame(f, &trace))
00411 {
00412 ILOG_DEBUG(seekPos << " is not a valid seek target for " <<
00413 "frame " << frameNr << ", following from a mismatch for " <<
00414 "frame " << f);
00415 return false;
00416 }
00417
00418 postReadPos = mPackets->Get4(mFrames->Get2(f));
00419 lastPostReadPosOfTrace = trace.Get3(trace.Size() - 1);
00420 if (lastPostReadPosOfTrace <= postReadPos)
00421 break;
00422 }
00423 return true;
00424 }
00425
00426
00427 ILOG_VAR_DECL;
00428
00429 };
00430
00431 ILOG_VAR_INIT(StrategyIgnoringNativeIndex, Impala.Core.Stream.Lavc);
00432
00433 }}}}
00434
00435 #endif