Bug 579812. Recompute frame end time when recomputing frame start time in DecodeVideoFrame. r=doublec
authorMatthew Gregan <kinetik@flim.org>
Tue, 20 Jul 2010 13:29:30 +1200
changeset 47961 c4ec8505a4d42e72a0cb376b3f0a20052a71654d
parent 47960 10f6355b84759e8a628deaf0d6c0268a47e92adc
child 47962 24e7b07abd21cd6e7a20af54db29a787120fe738
push idunknown
push userunknown
push dateunknown
reviewersdoublec
bugs579812
milestone2.0b2pre
Bug 579812. Recompute frame end time when recomputing frame start time in DecodeVideoFrame. r=doublec
content/media/nsBuiltinDecoderReader.h
content/media/nsBuiltinDecoderStateMachine.cpp
content/media/ogg/nsOggReader.cpp
--- a/content/media/nsBuiltinDecoderReader.h
+++ b/content/media/nsBuiltinDecoderReader.h
@@ -221,33 +221,33 @@ public:
     : mOffset(aOffset),
       mTime(aTime),
       mEndTime(aEndTime),
       mTimecode(aTimecode),
       mDuplicate(PR_TRUE),
       mKeyframe(PR_FALSE)
   {
     MOZ_COUNT_CTOR(VideoData);
-    NS_ASSERTION(aEndTime > aTime, "Frame must start before it ends.");
+    NS_ASSERTION(aEndTime >= aTime, "Frame must start before it ends.");
   }
 
   VideoData(PRInt64 aOffset,
             PRInt64 aTime,
             PRInt64 aEndTime,
             PRBool aKeyframe,
             PRInt64 aTimecode)
     : mOffset(aOffset),
       mTime(aTime),
       mEndTime(aEndTime),
       mTimecode(aTimecode),
       mDuplicate(PR_FALSE),
       mKeyframe(aKeyframe)
   {
     MOZ_COUNT_CTOR(VideoData);
-    NS_ASSERTION(aEndTime > aTime, "Frame must start before it ends.");
+    NS_ASSERTION(aEndTime >= aTime, "Frame must start before it ends.");
   }
 
 };
 
 // Thread and type safe wrapper around nsDeque.
 template <class T>
 class MediaQueueDeallocator : public nsDequeFunctor {
   virtual void* operator() (void* anObject) {
--- a/content/media/nsBuiltinDecoderStateMachine.cpp
+++ b/content/media/nsBuiltinDecoderStateMachine.cpp
@@ -1140,16 +1140,17 @@ void nsBuiltinDecoderStateMachine::Advan
     }
 
     // If the number of audio/video samples queued has changed, either by
     // this function popping and playing a video sample, or by the audio
     // thread popping and playing an audio sample, we may need to update our
     // ready state. Post an update to do so.
     UpdateReadyState();
 
+    NS_ASSERTION(frameDuration >= 0, "Frame duration must be positive.");
     Wait(frameDuration);
   } else {
     if (IsPlaying()) {
       StopPlayback(AUDIO_PAUSE);
       mDecoder->GetMonitor().NotifyAll();
     }
 
     if (mState == DECODER_STATE_DECODING ||
--- a/content/media/ogg/nsOggReader.cpp
+++ b/content/media/ogg/nsOggReader.cpp
@@ -465,20 +465,21 @@ nsresult nsOggReader::DecodeTheora(nsTAr
                                    ogg_packet* aPacket)
 {
   int ret = th_decode_packetin(mTheoraState->mCtx, aPacket, 0);
   if (ret != 0 && ret != TH_DUPFRAME) {
     return NS_ERROR_FAILURE;
   }
   PRInt64 time = (aPacket->granulepos != -1)
     ? mTheoraState->StartTime(aPacket->granulepos) : -1;
+  PRInt64 endTime = time != -1 ? time + mTheoraState->mFrameDuration : -1;
   if (ret == TH_DUPFRAME) {
     aFrames.AppendElement(VideoData::CreateDuplicate(mPageOffset,
                                                      time,
-                                                     time + mTheoraState->mFrameDuration,
+                                                     endTime,
                                                      aPacket->granulepos));
   } else if (ret == 0) {
     th_ycbcr_buffer buffer;
     ret = th_decode_ycbcr_out(mTheoraState->mCtx, buffer);
     NS_ASSERTION(ret == 0, "th_decode_ycbcr_out failed");
     PRBool isKeyframe = th_packet_iskeyframe(aPacket) == 1;
     VideoData::YCbCrBuffer b;
     for (PRUint32 i=0; i < 3; ++i) {
@@ -486,17 +487,17 @@ nsresult nsOggReader::DecodeTheora(nsTAr
       b.mPlanes[i].mHeight = buffer[i].height;
       b.mPlanes[i].mWidth = buffer[i].width;
       b.mPlanes[i].mStride = buffer[i].stride;
     }
     VideoData *v = VideoData::Create(mInfo,
                                      mDecoder->GetImageContainer(),
                                      mPageOffset,
                                      time,
-                                     time + mTheoraState->mFrameDuration,
+                                     endTime,
                                      b,
                                      isKeyframe,
                                      aPacket->granulepos);
     if (!v) {
       // There may be other reasons for this error, but for
       // simplicity just assume the worst case: out of memory.
       NS_WARNING("Failed to allocate memory for video frame");
       Clear(aFrames);
@@ -602,16 +603,18 @@ PRBool nsOggReader::DecodeVideoFrame(PRB
           }
         }
         // Check that the frame's granule number (it's frame number) is
         // one less than the successor frame.
         NS_ASSERTION(th_granule_frame(mTheoraState->mCtx, succGranulepos) ==
                      th_granule_frame(mTheoraState->mCtx, granulepos) + 1,
                      "Granulepos calculation is incorrect!");
         frames[i]->mTime = mTheoraState->StartTime(granulepos);
+        frames[i]->mEndTime = frames[i]->mTime + mTheoraState->mFrameDuration;
+        NS_ASSERTION(frames[i]->mEndTime >= frames[i]->mTime, "Frame must start before it ends.");
         frames[i]->mTimecode = granulepos;
         succGranulepos = granulepos;
         NS_ASSERTION(frames[i]->mTime < frames[i+1]->mTime, "Times should increase");      
       }
       NS_ASSERTION(AllFrameTimesIncrease(frames), "All frames must have granulepos");
     }
   } else {