00001 #ifndef Impala_Core_Stream_RgbDataSrcInfo_h
00002 #define Impala_Core_Stream_RgbDataSrcInfo_h
00003
00004 #include "Basis/FileName.h"
00005 #include "Basis/ILog.h"
00006 #include "Basis/Timer.h"
00007 #include "Util/StringParser.h"
00008 #include "Util/Database.h"
00009 #include "Util/IOBuffer.h"
00010 #include "Core/Stream/RgbDataSrc.h"
00011 #include "Core/Table/TableTem.h"
00012 #include "Core/Table/Write.h"
00013 #include "Core/Table/Read.h"
00014 #include "Core/Column/ColumnTem.h"
00015 #include "Core/Column/FixedStringColumn.h"
00016
00017 namespace Impala
00018 {
00019 namespace Core
00020 {
00021 namespace Stream
00022 {
00023
00024
00025 class RgbDataSrcInfo : public RgbDataSrc
00026 {
00027
00028 typedef Table::TableTem<Column::ColumnTem<Int32>,
00029 Column::ColumnTem<Int32>,
00030 Column::ColumnTem<UInt64>,
00031 Column::FixedStringColumn > IndexTableType;
00032
00033 typedef Column::FixedStringColumn::ColElemType FixedString;
00034
00035 static const int HASH_SIZE = 32;
00036
00037 public:
00038
00039 static const String DUMMY_FRAME_HASH;
00040 static const String MISSING_FRAME_HASH;
00041
00042 #ifndef REPOSITORY_USED // Here comes the deprecated stuff
00043 RgbDataSrcInfo(int src, CString srcName, Util::Database* db,
00044 CString infoName = "", bool newImpl = false)
00045 : RgbDataSrc(src, srcName), mDb(db)
00046 {
00047 #else // REPOSITORY_USED
00048 RgbDataSrcInfo(int src, const Persistency::RgbDataSrcLocator& loc,
00049 CString infoName = "", bool newImpl = false)
00050 : RgbDataSrc(src, loc.GetName())
00051 {
00052 String srcName = loc.GetName();
00053 mLoc = loc;
00054 #endif // REPOSITORY_USED
00055 mNewImpl = newImpl;
00056
00057
00058 if (infoName.empty())
00059 {
00060 #ifdef USE_IFILE
00061 int posAfterProtocol = srcName.find(":") + 1;
00062 mInfoPath = srcName.substr(posAfterProtocol) + ".info";
00063 #else
00064 mInfoPath = srcName + ".info";
00065 #endif
00066 }
00067 else
00068 mInfoPath = infoName;
00069
00070 InitInfo();
00071
00072
00073
00074
00075
00076 if ((src == 18) || (src == 19))
00077 ReadInfo();
00078 if (src == 19)
00079 DumpIndex();
00080 }
00081
00082
00083
00084
00085
00086
00087
00088
00089 virtual
00090 ~RgbDataSrcInfo()
00091 {
00092 delete mIndex;
00093 }
00094
00095 virtual bool
00096 ReadFrameData() = 0;
00097
00098 virtual bool
00099 CurIsIFrame()
00100 {
00101 int f = FrameNr();
00102 return GetSeekableFrame(f) == f;
00103 }
00104
00105 virtual bool
00106 Valid() const
00107 {
00108 return true;
00109 }
00110
00111 Int64
00112 DumpHashValue(char* &buffer, const int maxChars, int bytesWritten,
00113 CString hash) const
00114 {
00115 const int hashLen = hash.size();
00116 if (bytesWritten + hashLen + 1 > maxChars)
00117 {
00118 ILOG_ERROR("Buffer too small (" << maxChars <<
00119 ") to write all index hashes");
00120 return -1;
00121 }
00122 sprintf(buffer, "%s\t", hash.c_str());
00123 buffer += (hashLen + 1);
00124 int written = bytesWritten + (hashLen + 1);
00125 return written;
00126 }
00127
00128 Int64
00129 DumpIndexHashes(char* buffer, const int maxChars) const
00130 {
00131 const int nrOfIndexedFrames = mIndex->Size();
00132 const int maxFrameNr = mIndex->Get1(nrOfIndexedFrames - 1);
00133
00134 int indx = 0;
00135 Int64 bytesWritten = 0;
00136 int frameNr = 0;
00137 while (indx < nrOfIndexedFrames)
00138 {
00139 String hash;
00140 const int frameNrFromIndexEntry = mIndex->Get1(indx);
00141 if (frameNr < frameNrFromIndexEntry)
00142 {
00143 ILOG_WARN("Index contains no entry for frame #" << frameNr);
00144 hash = MISSING_FRAME_HASH;
00145 }
00146 else
00147 {
00148 if (frameNr > frameNrFromIndexEntry)
00149 {
00150 ILOG_ERROR("[DumpIndexHashes] Index contains inconsistency for frame #" <<
00151 frameNrFromIndexEntry << " at table position " << indx <<
00152 " (zero based)");
00153 }
00154 const String hash32(mIndex->Get4(indx).GetData(), HASH_SIZE);
00155 hash = String(hash32.c_str());
00156 indx++;
00157 }
00158 bytesWritten = DumpHashValue(buffer, maxChars, bytesWritten, hash);
00159 if (bytesWritten < 0)
00160 return -1;
00161 frameNr++;
00162 }
00163 return bytesWritten;
00164 }
00165
00166 protected:
00167
00168 String
00169 ReplaceWhite(String result)
00170 {
00171 String replaceWhat=" ";
00172 String replaceWithWhat="_";
00173 while(1)
00174 {
00175 const int pos = result.find(replaceWhat);
00176 if (pos==-1)
00177 break;
00178 result.replace(pos,replaceWhat.size(),replaceWithWhat);
00179 }
00180 if(result=="")
00181 {
00182 ILOG_DEBUG("String was empty, resetting to _");
00183 result="_";
00184 }
00185 return result;
00186
00187 }
00188
00189 String
00190 GetInfoFilePath(bool toWrite, bool silent=true) const
00191 {
00192 return mInfoPath;
00193 }
00194
00195 Util::IOBuffer*
00196 GetInfoIOBuffer(bool toWrite, bool silent=true) const
00197 {
00198 String fname = GetInfoFilePath(toWrite, silent);
00199 if (fname.empty())
00200 {
00201 if (!silent)
00202 ILOG_ERROR("Unable to determine info file name!");
00203 return 0;
00204 }
00205
00206
00207 String tmpFile = (toWrite) ? "tmp" : "";
00208 #ifndef REPOSITORY_USED // Here comes the deprecated stuff
00209 Util::IOBuffer* buf = mDb->GetIOBuffer(fname, !toWrite, false, tmpFile);
00210 #else // REPOSITORY_USED
00211 typedef Persistency::RepositoryInFileSystem RepFS;
00212 Persistency::File file = RepFS::GetInstance().GetFile(mLoc, "", fname,
00213 toWrite, false);
00214 Util::IOBuffer* buf = (toWrite) ? file.GetWriteBuffer()
00215 : file.GetReadBuffer();
00216 #endif // REPOSITORY_USED
00217
00218 if(!buf)
00219 {
00220 ILOG_DEBUG("Invalid File! "<<mInfoPath);
00221 return 0;
00222 }
00223
00224 if(!buf->Valid())
00225 {
00226 ILOG_DEBUG("Invalid File! "<<mInfoPath);
00227 delete buf;
00228 return 0;
00229 }
00230
00231 return buf;
00232 }
00233
00234 void InitInfo()
00235 {
00236 mInfoVersion = "2.2";
00237
00238
00239 mIndexInPlace = true;
00240
00241 mIndex = new IndexTableType(Column::ColumnTem<Int32>(1),
00242 Column::ColumnTem<Int32>(1),
00243 Column::ColumnTem<UInt64>(1),
00244 Column::FixedStringColumn(HASH_SIZE, 1));
00245 mIndex->SetColName(1, "frame_nr");
00246 mIndex->SetColName(2, "key_frame_nr");
00247 mIndex->SetColName(3, "key_frame_pos");
00248 mIndex->SetColName(4, "frame_hash");
00249
00250 mFormatStr = String(
00251 "INFO VERSION : ") + mInfoVersion + "\n"
00252 + "==================================\n"
00253 + "File name : %s\n"
00254 + "\n"
00255 + "Format name : %s\n"
00256 + "Format name (long) : %s\n"
00257 + "Bit rate (bps) : %d \n"
00258 + "Stream count : %d \n"
00259 + "\n"
00260 + "Codec name : %s\n"
00261 + "Codec tag : %s\n"
00262 + "Time base : %d / %d \n"
00263 + "Duration (fractions) : %lld \n"
00264 + "Duration (seconds) : %lld \n"
00265 + "Duration (human) : %lldh %lldm %llds \n"
00266 + "\n"
00267 + "Frame width : %d \n"
00268 + "Frame height : %d \n"
00269 + "Aspect ratio : %d / %d \n"
00270 + "\n"
00271 + "Frame count : %d \n"
00272 + "Frame rate (fps) : %d / %d \n"
00273 + "GOP size : %d \n"
00274 + "Leading bad frames : %d \n"
00275 + "Bad frame ID's : %s \n"
00276 + "\n"
00277 + "Index exists : %s \n";
00278 }
00279
00280 bool ReadInfo(bool silent = false)
00281 {
00282 ILOG_DEBUG("Reading info file");
00283 Timer timer;
00284 Util::IOBuffer* infoBuf = GetInfoIOBuffer(false, silent);
00285 if (!infoBuf)
00286 {
00287 ILOG_WARN("Reading canceled");
00288 return false;
00289 }
00290
00291 char buf[BUFFER_SIZE];
00292 infoBuf->Read(buf, BUFFER_SIZE);
00293 char srcName[100];
00294 char formatName[30];
00295 char formatLName[100];
00296 char codecName[30];
00297 char codecTag[5];
00298 char indexExists[5];
00299
00300 int frameCount;
00301 char badFramesList[10000];
00302 int numberOfLeadingBadFrames;
00303 int res = sscanf(buf, mFormatStr.c_str(),
00304 srcName,
00305 formatName,
00306 formatLName,
00307 &mBitRate,
00308 &mStreamCount,
00309 codecName,
00310 codecTag,
00311 &mTimeBaseNum, &mTimeBaseDen,
00312 &mVideoDuration,
00313 &mDuration,
00314 &mDurationHour, &mDurationMin, &mDurationSec,
00315 &mFrameWidth,
00316 &mFrameHeight,
00317 &mAspectRatioNum, &mAspectRatioDen,
00318 &frameCount,
00319 &mFrameRateNum, &mFrameRateDen,
00320 &mGopSize,
00321 &numberOfLeadingBadFrames,
00322 badFramesList,
00323 indexExists);
00324 if (res != 25)
00325 {
00326 ILOG_ERROR("RGB data source info format not compatible; " <<
00327 "expected version is: " << mInfoVersion);
00328 return false;
00329 }
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340 mLastFrame = frameCount - 1;
00341 mFormatName = formatName;
00342 mFormatLName = formatLName;
00343 mCodecName = codecName;
00344 mCodecTag = codecTag;
00345
00346 SetLeadingBadFrames(numberOfLeadingBadFrames);
00347 mBadFrameNrs.clear();
00348 const String badFramesListString(badFramesList);
00349 if (badFramesListString != "none")
00350 {
00351 Util::StringParser parser(badFramesListString);
00352 while (!parser.TheEnd())
00353 {
00354 const int frameNr = parser.GetInt(';', false, true);
00355 MarkBadFrame(frameNr);
00356 }
00357 }
00358
00359 if (String(indexExists) == "yes")
00360 mIndexExists = true;
00361 else
00362 mIndexExists = false;
00363
00364
00365 {
00366 StringList badFramesString;
00367 for (int i = 0; i < mBadFrameNrs.size(); i++)
00368 badFramesString << MakeString(mBadFrameNrs[i]);
00369
00370 sprintf(buf, mFormatStr.c_str(),
00371 srcName,
00372 formatName,
00373 formatLName,
00374 mBitRate,
00375 mStreamCount,
00376 codecName,
00377 codecTag,
00378 mTimeBaseNum, mTimeBaseDen,
00379 mVideoDuration,
00380 mDuration,
00381 mDurationHour, mDurationMin, mDurationSec,
00382 mFrameWidth,
00383 mFrameHeight,
00384 mAspectRatioNum, mAspectRatioDen,
00385 mLastFrame + 1,
00386 mFrameRateNum, mFrameRateDen,
00387 mGopSize,
00388 mBlankFrames,
00389 badFramesString.ToString(';').c_str(),
00390 indexExists);
00391 ILOG_DEBUG("\n\n" << buf);
00392 }
00393
00394 if (mIndexExists)
00395 {
00396 ILOG_DEBUG("Reading the index attached to info file");
00397 ILOG_DEBUG(" start read " << timer.SplitTime());
00398 Read(mIndex, infoBuf);
00399 ILOG_DEBUG(" done actual read " << timer.SplitTime());
00400 ILOG_DEBUG(mIndex->Size() << " index entries read");
00401 }
00402
00403 delete infoBuf;
00404 return true;
00405 }
00406
00407 void DumpIndex()
00408 {
00409 ILOG_DEBUG("Dumping index entries:");
00410 for (int i = 0; i < mIndex->Size(); i++)
00411 ILOG_DEBUG(i << " : " << mIndex->Get1(i) << " "
00412 << mIndex->Get2(i) << " " << mIndex->Get3(i));
00413 }
00414
00415 void WriteInfo()
00416 {
00417 ILOG_DEBUG("Writing info file");
00418
00419
00420 Util::IOBuffer* infoBuf = GetInfoIOBuffer(true);
00421
00422 if (!infoBuf)
00423 {
00424 ILOG_WARN("Writing canceled: if file already exists, "
00425 << "use the --override switch; "
00426 << "otherwise make sure the directory is writable.");
00427 return;
00428 }
00429
00430
00431 char buf[BUFFER_SIZE];
00432 memset(buf, 0, BUFFER_SIZE);
00433 StringList badFramesStringList;
00434 for (int i = 0; i < mBadFrameNrs.size(); i++)
00435 badFramesStringList << MakeString(mBadFrameNrs[i]);
00436 String badFramesString = badFramesStringList.ToString(';');
00437 if (badFramesString.empty())
00438 badFramesString = "none";
00439 sprintf(buf, mFormatStr.c_str(),
00440 ReplaceWhite(FileNameTail(mSrcName)).c_str(),
00441 ReplaceWhite(mFormatName).c_str(),
00442 ReplaceWhite(mFormatLName).c_str(),
00443 mBitRate,
00444 mStreamCount,
00445 ReplaceWhite(mCodecName).c_str(),
00446 ReplaceWhite(mCodecTag).c_str(),
00447 mTimeBaseNum, mTimeBaseDen,
00448 mVideoDuration,
00449 mDuration,
00450 mDurationHour, mDurationMin, mDurationSec,
00451 mFrameWidth,
00452 mFrameHeight,
00453 mAspectRatioNum, mAspectRatioDen,
00454 mLastFrame + 1,
00455 mFrameRateNum, mFrameRateDen,
00456 mGopSize,
00457 mBlankFrames,
00458 badFramesString.c_str(),
00459 (mIndexExists ? "yes" : "no") );
00460 infoBuf->Write(buf, BUFFER_SIZE);
00461
00462 if (mIndexExists)
00463 {
00464 ILOG_DEBUG("Index exists; writing table");
00465 Write(mIndex, infoBuf, true);
00466 ILOG_DEBUG(mIndex->Size() << " index entries written");
00467 }
00468
00469 delete infoBuf;
00470 }
00471
00472 void
00473 AddIndex(int fr, int key, UInt64 pos, CString hash)
00474 {
00475 if (fr != (mIndex->Size() + (mNewImpl ? 0 : mBlankFrames)))
00476 ILOG_WARN("Frame numbers mismatch " << fr << " != " << mIndex->Size());
00477 FixedString fStr(HASH_SIZE, (char*) hash.c_str(), false);
00478 mIndex->Add(fr, key, pos, fStr);
00479 }
00480
00481 int GetSeekableFrame(int fr) const
00482 {
00483 return mIndex->Get2(fr);
00484 }
00485
00486 void SetKey(int fr, int key)
00487 {
00488 mIndex->Set2(fr, key);
00489 }
00490
00491 UInt64 GetPos(int fr) const
00492 {
00493 const int indexPosition = fr;
00494
00495 if (mIndexExists)
00496 {
00497 if (indexPosition < mIndex->Size())
00498 {
00499 if (GetHash(indexPosition) == DUMMY_FRAME_HASH)
00500 {
00501 ILOG_WARN("No position for invalid frame: " << fr <<
00502 "; returning next frame's position instead");
00503 return GetPos(fr + 1);
00504 }
00505 else
00506 return mIndex->Get3(indexPosition);
00507 }
00508 else
00509 ILOG_ERROR("Index position out of bounds: " << indexPosition);
00510 }
00511 else
00512 {
00513 ILOG_WARN("No external index available; " <<
00514 "cannot lookup seek position for frame: " << fr);
00515 if (!mNewImpl)
00516 return 0;
00517 }
00518
00519 return -1;
00520 }
00521
00522
00523 int GetFrameFromHash(String hash) const
00524 {
00525 for (int i = mBlankFrames; i < mIndex->Size(); i++)
00526 if (GetHash(i) == hash)
00527 return i;
00528
00529 return -1;
00530 }
00531
00532 void SetPos(int fr, UInt64 pos)
00533 {
00534 mIndex->Set3(fr, pos);
00535 }
00536
00537 virtual String
00538 GetHash() const
00539 {
00540 if (HasIndex())
00541 return GetHash(FrameNr());
00542 else
00543 return RgbDataSrc::GetHash();
00544 }
00545
00546 virtual String
00547 GetHash(int fr) const
00548 {
00549 return String(mIndex->Get4(fr).GetData(), HASH_SIZE);
00550 }
00551
00552
00553 virtual const int
00554 BadFrames() const
00555 {
00556 return mBadFrameNrs.size();
00557 }
00558
00559
00560 protected:
00561 #ifndef REPOSITORY_USED // Here comes the deprecated stuff
00562 Util::Database* mDb;
00563 #endif // REPOSITORY_USED
00564 IndexTableType* mIndex;
00565
00566
00567 virtual bool
00568 FrameValid(int frameNr) const
00569 {
00570 if (!RgbDataSrc::FrameValid(frameNr))
00571 return false;
00572
00573 for (int i = 0; i < mBadFrameNrs.size(); i++)
00574 if (mBadFrameNrs[i] == frameNr)
00575 return false;
00576
00577 return true;
00578 }
00579
00580 bool
00581 MarkBadFrame(int frameNr)
00582 {
00583 for (int i = 0; i < mBadFrameNrs.size(); i++)
00584 if (mBadFrameNrs[i] == frameNr)
00585 return false;
00586
00587 mBadFrameNrs.push_back(frameNr);
00588 return true;
00589 }
00590
00591
00592 private:
00593
00594 const static int BUFFER_SIZE = 100000;
00595
00596 String mFormatStr;
00597 String mInfoPath;
00598 String mInfoVersion;
00599 bool mIndexInPlace;
00600
00601 std::vector<int> mBadFrameNrs;
00602 Persistency::RgbDataSrcLocator mLoc;
00603
00604 ILOG_VAR_DEC;
00605
00606 };
00607
00608 ILOG_VAR_INIT(RgbDataSrcInfo, Impala.Core.Stream);
00609
00610
00611 const String RgbDataSrcInfo::DUMMY_FRAME_HASH = "DUMMY_FRAME_HASH________________";
00612 const String RgbDataSrcInfo::MISSING_FRAME_HASH = "MISSING_FRAME_HASH______________";
00613
00614 }
00615 }
00616 }
00617
00618 #endif