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