00001 #ifndef Impala_Core_Stream_RgbDataSrcLavc_h
00002 #define Impala_Core_Stream_RgbDataSrcLavc_h
00003
00004 #include "Basis/CmdOptions.h"
00005 #include "Util/Database.h"
00006
00007 #include "Core/Stream/RgbDataSrcInfo.h"
00008
00009 #include "Core/Stream/LavcProtocolDataServer.h"
00010
00011 #include "Core/Stream/Lavc/VideoAccessStrategyFactory.h"
00012 #include "Core/Stream/Lavc/VideoAccessStrategy.h"
00013 #include "Core/Stream/Lavc/VideoIndex.h"
00014
00015 namespace Impala
00016 {
00017 namespace Core
00018 {
00019 namespace Stream
00020 {
00021
00027 class RgbDataSrcLavc : public RgbDataSrcInfo
00028 {
00029
00030 typedef Array::Array2dVec3UInt8 Array2dVec3UInt8;
00031
00032 public:
00033
00034 #ifndef REPOSITORY_USED // Here comes the deprecated stuff
00035 RgbDataSrcLavc(int src, CString srcName, Util::Database* db,
00036 IndexMode mode)
00037 : RgbDataSrcInfo(src, srcName, db,
00038 DetermineInfoName(srcName, mode, db), true)
00039 {
00040 #else // REPOSITORY_USED
00041 RgbDataSrcLavc(int src, const Persistency::RgbDataSrcLocator& loc,
00042 IndexMode mode)
00043 : RgbDataSrcInfo(src, loc, "", true)
00044 {
00045 mLoc = loc;
00046 String srcName = loc.GetName();
00047 #endif // REPOSITORY_USED
00048 mSrcName = StringReplaceAll(srcName, "\\", "/", false);
00049 mMode = mode;
00050
00051 mValid = false;
00052 mBufferedFrameNr = -1;
00053 mLastDecodedFrameNr = -1;
00054
00055 mFixCnt = 0;
00056 mLastFixNr = 0;
00057
00058 mVideoAccessor = 0;
00059
00060 Init();
00061 }
00062
00063 virtual
00064 ~RgbDataSrcLavc()
00065 {
00066 if (mVideoAccessor != 0)
00067 delete mVideoAccessor;
00068 }
00069
00070 virtual char
00071 FrameType() const
00072 {
00073 return mVideoAccessor->FrameType();
00074 }
00075
00076 virtual bool
00077 CurIsIFrame() const
00078 {
00079 return FrameType() == 'I';
00080 }
00081
00082 virtual bool
00083 Valid() const
00084 {
00085 return mValid;
00086 }
00087
00088
00089 private:
00090
00091 bool
00092 IncurExtraLavcInitialization()
00093 {
00094 Reset();
00095 const int firstValidFrame = LeadingBadFrames();
00096 if (!SeekFrame(firstValidFrame))
00097 return false;
00098 mLastDecodedFrameNr = mBufferedFrameNr = mCurrentFrameNr = firstValidFrame;
00099 return true;
00100 }
00101
00102 bool
00103 ReadIndex(bool silent)
00104 {
00105 const int currentFrameCount = mLastFrame + 1;
00106 const int currentBadFramesCount = BadFrames();
00107 const int currentLeadingBadCount = LeadingBadFrames();
00108 const bool wasRead = ReadInfo(silent);
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137 return wasRead;
00138 }
00139
00140 bool
00141 SeekFrame(int seekableFrame)
00142 {
00143 const UInt64 targetPos = GetPos(seekableFrame);
00144 ILOG_DEBUG("Seeking frame " << seekableFrame << " at position " <<
00145 targetPos);
00146 if (!mVideoAccessor->JumpToFramePosition(targetPos))
00147 {
00148 ILOG_ERROR("Jump to frame position " << targetPos << " failed");
00149 return false;
00150 }
00151 return true;
00152 }
00153
00154 void
00155 Init()
00156 {
00157 CmdOptions& options = CmdOptions::GetInstance();
00158 #ifndef REPOSITORY_USED // Here comes the deprecated stuff
00159 String dataServer = options.GetString("dataServer");
00160 #else // REPOSITORY_USED
00161 String dataServer = (mLoc.GetProtocol() == "dataServer") ? "dataserver"
00162 : "";
00163 #endif // REPOSITORY_USED
00164 const String dataSrcAddress =
00165 dataServer.empty() ? mSrcName : "dataserver:" + mSrcName;
00166 Lavc::VideoAccessStrategyFactory factory;
00167 mVideoAccessor = factory.Construct(dataSrcAddress);
00168 if (mVideoAccessor == 0)
00169 {
00170 mValid = false;
00171 return;
00172 }
00173
00174 if (mVideoAccessor->NrOfFrames() >= 0)
00175 mLastFrame = mVideoAccessor->NrOfFrames() - 1;
00176
00177 InitStaticMetadata(*mVideoAccessor);
00178
00179 mData = mVideoAccessor->RgbDataPtr();
00180
00181 if (mMode == SCANONLY)
00182 {
00183 if (!Scan(*mVideoAccessor))
00184 return;
00185 }
00186 else if (mMode == READIDX)
00187 {
00188 int nrOfFramesNow = -1;
00189 bool checkFrameCount = options.GetBool("checkstoredframecount", false);
00190 if (checkFrameCount)
00191 {
00192 if (!Scan(*mVideoAccessor))
00193 return;
00194 nrOfFramesNow = mVideoAccessor->NrOfFrames();
00195 }
00196
00197 if (ReadIndex(false))
00198 {
00199 if (!IncurExtraLavcInitialization())
00200 return;
00201 if (checkFrameCount && (nrOfFramesNow != (LastFrame() + 1)))
00202 {
00203 ILOG_ERROR("Freshly established frame count (" <<
00204 nrOfFramesNow << ") different " <<
00205 "from stored frame count (" << LastFrame() + 1 <<
00206 ") for: " << mSrcName);
00207 return;
00208 }
00209 }
00210 else
00211 {
00212 ILOG_ERROR("Failed while reading index info for: " <<
00213 mSrcName);
00214 return;
00215 }
00216 }
00217 else if (mMode == WITHIDX)
00218 {
00219 if (ReadIndex(true))
00220 {
00221 if (!IncurExtraLavcInitialization())
00222 return;
00223 }
00224 else
00225 {
00226 if (!PopulateIndex(*mVideoAccessor))
00227 return;
00228 }
00229 }
00230 else if (mMode == ADHOCIDX)
00231 {
00232 if (!PopulateIndex(*mVideoAccessor))
00233 return;
00234 }
00235 else if (mMode == WRITEIDX)
00236 {
00237 if (!PopulateIndex(*mVideoAccessor))
00238 return;
00239 WriteInfo();
00240 }
00241
00242 Reset();
00243 mValid = true;
00244 ILOG_DEBUG("Initialization succeeded");
00245 }
00246
00247
00248 void
00249 InitStaticMetadata(const Lavc::VideoAccessStrategy& videoAccessStrategy)
00250 {
00251
00252
00253 const Lavc::VideoAccessObject* const vao =
00254 videoAccessStrategy.VideoAccessObj();
00255
00256
00257 mBitRate = vao->BitRate();
00258 mFormatName = vao->FormatNameShort();
00259 mFormatLName = vao->FormatNameLong();
00260 ILOG_INFO("Format name is: " << mFormatLName << " (" <<
00261 mFormatName << ")");
00262
00263
00264 mStreamCount = vao->StreamCount();
00265 mVideoDuration = vao->VideoDuration();
00266 mTimeBaseNum = vao->VideoTimeBaseNumerator();
00267 mTimeBaseDen = vao->VideoTimeBaseDenominator();
00268 mDuration = ceil(
00269 double(mVideoDuration) * mTimeBaseNum / mTimeBaseDen
00270 );
00271 mDurationSec = mDuration;
00272 mDurationHour = mDurationSec / 3600;
00273 mDurationSec %= 3600;
00274 mDurationMin = mDurationSec / 60;
00275 mDurationSec %= 60;
00276
00277
00278 mFrameRateNum = vao->FrameRateNumerator();
00279 mFrameRateDen = vao->FrameRateDenominator();
00280 const double fractionsPerSec = double(mTimeBaseDen) / mTimeBaseNum;
00281 const double secondsPerFrame = double(mFrameRateDen) / mFrameRateNum;
00282 const double fractionsPerFrame = fractionsPerSec * secondsPerFrame;
00283 const double frameCount = mVideoDuration / fractionsPerFrame;
00284 mFrameCountCalculated = ceil(frameCount);
00285 ILOG_INFO("Frame count estimate based on video duration: " <<
00286 mFrameCountCalculated);
00287
00288 mFrameWidth = vao->FrameWidth();
00289 mFrameHeight = vao->FrameHeight();
00290 mAspectRatioNum = vao->AspectRatioNum();
00291 mAspectRatioDen = vao->AspectRatioDen();
00292
00293 mGopSize = vao->GopSize();
00294
00295 mCodecTag = vao->VideoCodecTag();
00296 mCodecName = vao->VideoCodecName();
00297
00298 ILOG_INFO("Opened codec (id=" << vao->VideoCodecId() <<
00299 ", name=" << mCodecName << ") for: " << mSrcName);
00300 }
00301
00302 void
00303 Reset()
00304 {
00305 mVideoAccessor->ResetVideoSrc();
00306 mLastDecodedFrameNr = mBufferedFrameNr = mCurrentFrameNr = -1;
00307 }
00308
00309 bool PopulateIndex(Lavc::VideoAccessStrategy& accessStrategy)
00310 {
00311 if (!Scan(accessStrategy))
00312 return false;
00313
00314 ILOG_INFO("Starting index population...");
00315 ILOG_INFO("Constructing intermediate index...");
00316 Lavc::VideoIndex* tempIndex = accessStrategy.ConstructIndex();
00317 if (!tempIndex)
00318 {
00319 ILOG_ERROR("Construction of intermediate index failed; " <<
00320 "aborting video population");
00321 return false;
00322 }
00323
00324
00325 const int nrOfFrames = accessStrategy.NrOfFrames();
00326 String frameHash;
00327 int seekableFrameNr;
00328 UInt64 seekableFramePos = 0;
00329 for (int f = 0; f < nrOfFrames; f++)
00330 {
00331 if (accessStrategy.FrameIsValid(f))
00332 {
00333 frameHash = accessStrategy.FrameHash(f);
00334 tempIndex->GetSeekInfo(f, &seekableFrameNr, &seekableFramePos);
00335 }
00336 else
00337 {
00338 MarkBadFrame(f);
00339 frameHash = DUMMY_FRAME_HASH;
00340 seekableFrameNr = -1;
00341 seekableFramePos = -1;
00342 }
00343
00344 ILOG_DEBUG("Adding to index: " << f << ", " << seekableFrameNr <<
00345 ", " << seekableFramePos << ", " << frameHash);
00346 AddIndex(f, seekableFrameNr, seekableFramePos, frameHash);
00347 }
00348
00349 delete tempIndex;
00350 accessStrategy.CleanUp();
00351 mIndexExists = true;
00352 ILOG_INFO("Finished index population");
00353 return true;
00354 }
00355
00356 bool
00357 Scan(Lavc::VideoAccessStrategy& accessStrategy)
00358 {
00359 if (!accessStrategy.Scan())
00360 {
00361 ILOG_ERROR("Failed while scanning: " << mSrcName);
00362 return false;
00363 }
00364
00365 const int frameCnt = accessStrategy.NrOfFrames();
00366 mLastFrame = frameCnt - 1;
00367 for (int f = 0; f < frameCnt; f++)
00368 if (!accessStrategy.FrameIsValid(f))
00369 MarkBadFrame(f);
00370 SetLeadingBadFrames(accessStrategy.LeadingBadFrames());
00371 return true;
00372 }
00373
00374 virtual bool
00375 ReadFrameData()
00376 {
00377 if (mTargetFrameNr == mCurrentFrameNr)
00378 return true;
00379
00380 if (!FrameValid(mTargetFrameNr) || mTargetFrameNr == mBufferedFrameNr)
00381 {
00382 mCurrentFrameNr = mTargetFrameNr;
00383 return true;
00384 }
00385
00386 if (mTargetFrameNr < mBufferedFrameNr)
00387 Reset();
00388
00389 const bool videoSeekable = mIndexExists;
00390 if (videoSeekable)
00391 {
00392 int sFrameNr = GetSeekableFrame(mTargetFrameNr);
00393
00394 if (sFrameNr > mBufferedFrameNr + 1)
00395 {
00396 ILOG_DEBUG("Targeting frame " << mTargetFrameNr <<
00397 " by first seeking to frame " << sFrameNr);
00398 if (!SeekFrame(sFrameNr))
00399 return false;
00400 mLastDecodedFrameNr = mBufferedFrameNr = mCurrentFrameNr =
00401 sFrameNr;
00402 }
00403 }
00404
00405 const bool lastDecodedFrameValid = ReadToTarget();
00406 mCurrentFrameNr = mLastDecodedFrameNr;
00407 if (lastDecodedFrameValid)
00408 {
00409 int result = mVideoAccessor->CurrentFrameToRgb();
00410 mBufferedFrameNr = mCurrentFrameNr;
00411
00412 if (mFormatName != "asf")
00413 if (!CheckMD5Hash(mBufferedFrameNr))
00414 {
00415 ILOG_ERROR("Frame hash failure going to frame " <<
00416 mTargetFrameNr);
00417 return false;
00418 }
00419 }
00420
00421 return true;
00422 }
00423
00424
00425 bool
00426 ReadToTarget()
00427 {
00428 bool lastDecodedFrameIsValid = true;
00429 while (mLastDecodedFrameNr < mTargetFrameNr)
00430 {
00431 const int nextFrameNr = mLastDecodedFrameNr + 1;
00432
00433 if (mVideoAccessor->FrameCanBeRead(nextFrameNr))
00434 {
00435 bool foundValidFrame;
00436 bool isKeyFrame;
00437 const int decodingResult = mVideoAccessor->
00438 DecodeNextFrame(&foundValidFrame, &isKeyFrame, 0);
00439 const bool gotFrame = (decodingResult == 0);
00440 if (!gotFrame)
00441 {
00442
00443 if (mLastFrame == LASTFRAME_UNKNOWN)
00444 {
00445 mLastFrame = mLastDecodedFrameNr;
00446 ILOG_DEBUG("Assuming we arrived at eof; " <<
00447 "frame count established is: " << mLastFrame + 1);
00448 }
00449 return false;
00450 }
00451
00452 lastDecodedFrameIsValid = FrameValid(nextFrameNr);
00453 if (lastDecodedFrameIsValid && !foundValidFrame)
00454 {
00455
00456 MarkBadFrame(nextFrameNr);
00457 lastDecodedFrameIsValid = false;
00458 }
00459 else if (!lastDecodedFrameIsValid && foundValidFrame)
00460 {
00461 ILOG_WARN("Did not expect to read a valid frame for " <<
00462 nextFrameNr);
00463 }
00464 }
00465 else
00466 {
00467 if (FrameValid(nextFrameNr))
00468 {
00469
00470 MarkBadFrame(nextFrameNr);
00471 }
00472 lastDecodedFrameIsValid = false;
00473 }
00474
00475 mLastDecodedFrameNr = nextFrameNr;
00476 }
00477 return lastDecodedFrameIsValid;
00478 }
00479
00480 bool
00481 CheckMD5Hash(int frameNr) const
00482 {
00483 if (!mIndexExists)
00484 return true;
00485
00486 if (!FrameIsStable(frameNr))
00487 return true;
00488
00489 const String refHash = GetHash(frameNr);
00490 const String hash = CalcHash_protected();
00491 mIsFrameAccurate = (hash == refHash);
00492 if (mIsFrameAccurate)
00493 {
00494
00495 return true;
00496 }
00497
00498 ILOG_ERROR("No hash match for frame " << frameNr << "; expected " <<
00499 refHash << " but found " << hash);
00500 return false;
00501 }
00502
00503 bool
00504 FrameIsStable(int frameNr) const
00505 {
00506 return GetHash(frameNr) != mVideoAccessor->UNSTABLE_FRAME_HASH;
00507 }
00508
00509 #ifndef REPOSITORY_USED // Here comes the deprecated stuff
00510 String
00511 DetermineInfoName(CString srcName, IndexMode mode, Util::Database* db) const
00512 {
00513 String infoName = "";
00514 if (Link::DiskImage::DiskImageUsed())
00515 {
00516 String subPath = FileNamePath(srcName);
00517 if (subPath.substr(0, 10) == "diskimage:")
00518 {
00519 int posAfterDiskImageFileName = subPath.find("://", 10);
00520
00521
00522 const String uptoDiskImageToken =
00523 subPath.substr(0, posAfterDiskImageFileName);
00524 int diskImageFileNamePos =
00525 FileNameLastPathSepPos(uptoDiskImageToken) + 1;
00526 if (diskImageFileNamePos == String::npos)
00527 ILOG_ERROR("Disk image file was expected to be prefixed "
00528 << "with a path: " << uptoDiskImageToken);
00529
00530 String subSubPath =
00531 subPath.substr(posAfterDiskImageFileName + 1);
00532 subSubPath = StringReplaceAll(subSubPath,
00533 "0x", "0x30x", false);
00534 subSubPath = StringReplaceAll(subSubPath,
00535 "//", "/0x2F", false);
00536 subSubPath = subSubPath.substr(0, subSubPath.size() - 1);
00537 subPath = subPath.substr(diskImageFileNamePos,
00538 posAfterDiskImageFileName-diskImageFileNamePos)+subSubPath;
00539
00540 String dir = "FramePosIndex/" + subPath;
00541
00542 bool toWrite = (mode == WRITEIDX);
00543 bool silent = (mode != READIDX);
00544
00545 if (toWrite)
00546 db->MakeDir(dir);
00547
00548 String fname = FileNameTail(srcName) + ".info";
00549 infoName = db->GetFilePath(dir, fname, toWrite, silent);
00550 }
00551 else
00552 infoName = srcName + ".info";
00553 }
00554 return infoName;
00555 }
00556 #endif // REPOSITORY_USED
00557
00558 Lavc::VideoAccessStrategy* mVideoAccessor;
00559 Persistency::RgbDataSrcLocator mLoc;
00560
00561 int mBufferedFrameNr;
00562 int mLastDecodedFrameNr;
00563 bool mValid;
00564 uint32_t mFrameCountCalculated;
00565 IndexMode mMode;
00566
00567 int mLastFixNr;
00568 int mFixCnt;
00569
00570 ILOG_VAR_DECL;
00571
00572 };
00573
00574 ILOG_VAR_INIT(RgbDataSrcLavc, Impala.Core.Stream);
00575
00576 }}}
00577
00578 #endif