00001 #ifndef Impala_Core_Stream_Lavc_StrategyUsingNativeIndex_h
00002 #define Impala_Core_Stream_Lavc_StrategyUsingNativeIndex_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 StrategyUsingNativeIndex : public VideoAccessStrategy
00017 {
00018
00019 public:
00020
00021 StrategyUsingNativeIndex(const Lavc::VideoAccessObject* const vao)
00022 : VideoAccessStrategy(vao)
00023 {
00024 SetNrOfFrames(vao->NativeIndexSize());
00025
00026 ILOG_DEBUG("Applying video access strategy using libavcodec's " <<
00027 "native frame index, measuring in PTS");
00028 }
00029
00030 virtual bool
00031 FrameCanBeRead(int frameNr) const
00032 {
00033
00034 return !FrameIsBadInNativeIndex(frameNr);
00035 }
00036
00037
00038 protected:
00039
00040 virtual int
00041 GetJumpFlags() const
00042 {
00043
00044 return AVSEEK_FLAG_ANY;
00045 }
00046
00047 virtual bool
00048 ScanProtected()
00049 {
00050 const AVIndexEntry* const nativeIndex = mVao->NativeIndexEntries();
00051 const int nativeIndexSize = mVao->NativeIndexSize();
00052 ILOG_INFO("Native index has size " << nativeIndexSize);
00053
00054
00055
00056 int offset = 0;
00057 for (int e = offset; e <= offset + 10 && e <= nativeIndexSize; e++)
00058 ILOG_DEBUG("index entry " << e << ": size=" <<
00059 nativeIndex[e].size << ", flags=" << nativeIndex[e].flags <<
00060 ", timestamp=" << nativeIndex[e].timestamp << ", pos=" <<
00061 nativeIndex[e].pos << ", min_distance=" <<
00062 nativeIndex[e].min_distance << ")");
00063
00064
00065 int nrOfBadFrames = 0;
00066 int nrOfLeadingBadFrames = 0;
00067 for (int indexPos = 0; indexPos < nativeIndexSize; indexPos++)
00068
00069
00070
00071 {
00072 if (indexPos % 250 == 0)
00073 ILOG_DEBUG("Scanning using native index entry " << indexPos);
00074
00075 const int indexFlags = nativeIndex[indexPos].flags;
00076 const bool isKeyFrameAccToIndex = (indexFlags == AVINDEX_KEYFRAME);
00077
00078 if (FrameIsBadInNativeIndex(indexPos))
00079 {
00080
00081 ProcessFrame(false, false, indexPos);
00082 nrOfBadFrames++;
00083 if (indexPos < nrOfBadFrames)
00084 nrOfLeadingBadFrames++;
00085 continue;
00086 }
00087
00088 if (isKeyFrameAccToIndex)
00089 {
00090 const UInt64& pts = nativeIndex[indexPos].timestamp;
00091 if (!mVao->Seek(pts, AVSEEK_FLAG_ANY))
00092 {
00093 ILOG_ERROR("Failed on PTS based seek for frame " <<
00094 indexPos << "; native index flags: " << indexFlags << ")");
00095 return false;
00096 }
00097 }
00098
00099
00100
00101 bool isValidFrame = true;
00102 bool isKeyFrame = isKeyFrameAccToIndex;
00103
00104
00105
00106
00107
00108
00109
00110 if (!DecodeNextValidFrame(isKeyFrameAccToIndex, 0))
00111 {
00112 ILOG_ERROR("Failed to read valid frame " << indexPos);
00113 return false;
00114 }
00115 if (!isKeyFrameAccToIndex && mVao->FrameIsKey())
00116 {
00117 ILOG_WARN("Frame read is a key frame but not expected to be: " <<
00118 indexPos);
00119
00120 }
00121
00122 if (isValidFrame)
00123 {
00124 if (isKeyFrameAccToIndex && !isKeyFrame)
00125 {
00126 ILOG_ERROR("Key frame " << indexPos <<
00127 " according to native index, appears not to be " <<
00128 "a key frame upon decoding");
00129 return false;
00130 }
00131
00132 if (!isKeyFrameAccToIndex && isKeyFrame)
00133 {
00134 ILOG_ERROR("Non-key frame " << indexPos <<
00135 " according to native index, appears to be " <<
00136 "a key frame upon decoding");
00137 return false;
00138 }
00139 }
00140
00141 ProcessFrame(isValidFrame, isKeyFrame, indexPos);
00142 }
00143
00144 ILOG_DEBUG("Bad frames according to native index: " <<
00145 nrOfBadFrames << " (of which are " <<
00146 "leading: " << nrOfLeadingBadFrames << ")");
00147 mBadFrameCount = nrOfBadFrames;
00148 mLeadingBadFrameCount = nrOfLeadingBadFrames;
00149 return true;
00150 }
00151
00157 virtual VideoIndex*
00158 ConstructIndexProtected() const
00159 {
00160 const AVIndexEntry* const idx = mVao->NativeIndexEntries();
00161 const int nativeIndexSize = mVao->NativeIndexSize();
00162 VideoIndex* videoIndex = new VideoIndex();
00163
00164
00165
00166 int prevSeekableFrame = -1;
00167 for (int frameNr = 0; frameNr < nativeIndexSize; frameNr++)
00168
00169
00170 {
00171
00172
00173
00174
00175
00176
00177
00178
00179 if (!FrameIsValid(frameNr))
00180 {
00181
00182
00183
00184
00185
00186
00187
00188 if (idx[frameNr].size > 0 &&
00189 ((idx[frameNr].flags | AVINDEX_KEYFRAME) == AVINDEX_KEYFRAME))
00190 {
00191 bool lookForKeyFrame = (idx[frameNr].flags == AVINDEX_KEYFRAME);
00192
00193
00194 bool isValidFrame;
00195 bool isKeyFrame;
00196 int res = DecodeNextFrame(&isValidFrame, &isKeyFrame, 0);
00197
00198 if (res >= 0 && isValidFrame)
00199 {
00200 String hash = mVao->CurrentHash();
00201 ILOG_WARN("Unexpectedly able to successfully read a (" <<
00202 mVao->FrameType() << ") frame for (invalid) frame " <<
00203 frameNr << ", having hash value " << hash <<
00204 "; frame data will be ignored");
00205 }
00206
00207
00208 }
00209
00210 continue;
00211 }
00212
00213 const UInt64& pts = idx[frameNr].timestamp;
00214 bool isKeyFrame = FrameIsKey(frameNr);
00215 if (isKeyFrame)
00216 {
00217 if (!mVao->Seek(pts, AVSEEK_FLAG_ANY))
00218 {
00219 ILOG_ERROR("Failed on PTS based seek for frame: " <<
00220 frameNr << (isKeyFrame ? " (is key frame)" : ""));
00221 return 0;
00222 }
00223 }
00224
00225
00226
00227
00228
00229
00230
00232
00233
00234
00235
00236
00237
00238
00239
00240 if (!DecodeNextValidFrame(isKeyFrame, 0))
00241 {
00242 ILOG_ERROR("Failed to read valid frame " << frameNr);
00243 return 0;
00244 }
00245
00246 mVao->CurrentFrameToRgb();
00247
00248
00249
00250
00251 if (!isKeyFrame)
00252 {
00253 if (prevSeekableFrame >= 0)
00254 {
00255
00256
00257
00258 if (CurrentFrameMatchesFrame(frameNr, 0))
00259 {
00260
00261 continue;
00262 }
00263 else
00264 {
00265 ILOG_ERROR("Non-reproducable frame: " << frameNr <<
00266 ", current hash value is " << mVao->CurrentHash());
00267 return 0;
00268 }
00269 }
00270 }
00271
00272 if (!CurrentFrameMatchesFrame(frameNr, 0))
00273 {
00274 ILOG_ERROR("Non-reproducable key frame: " << frameNr <<
00275 ", current hash value is " << mVao->CurrentHash());
00276 return 0;
00277 }
00278
00279
00280 videoIndex->AddFrame(frameNr, true, pts);
00281 ILOG_DEBUG("Indexed frame: " << frameNr << " " <<
00282 frameNr << " " << true << " " << pts);
00283 prevSeekableFrame = frameNr;
00284
00285 }
00286
00287 return videoIndex;
00288 }
00289
00290 virtual bool
00291 NextFrameMatchesFrame(int frameNr, const VideoIndex& videoIndex) const
00292 {
00293 return true;
00294 }
00295
00296
00297 private:
00298
00299
00300
00301 bool
00302 FrameIsBadInNativeIndex(int frameNr) const
00303 {
00304 const AVIndexEntry* const nativeIndex = mVao->NativeIndexEntries();
00305 const int indexFlags = nativeIndex[frameNr].flags;
00306 const bool isBad = (nativeIndex[frameNr].size <= 0) ||
00307 (indexFlags != 0 && indexFlags != AVINDEX_KEYFRAME);
00308 return isBad;
00309 }
00310
00311
00312 ILOG_VAR_DECL;
00313
00314 };
00315
00316 ILOG_VAR_INIT(StrategyUsingNativeIndex, Impala.Core.Stream.Lavc);
00317
00318 }}}}
00319
00320 #endif