Mozilla Home
Privacy
Cookies
Legal
Bugzilla
Browse
Advanced Search
New Bug
Reports
Documentation
Log In
Log In with GitHub
or
Remember me
Browse
Advanced Search
New Bug
Reports
Documentation
Attachment 514667 Details for
Bug 580531
[patch]
Patch 1: Demuxing/decoding stats
580531-stats.patch (text/plain), 27.70 KB, created by
Chris Pearce [:cpearce (Not reading bugmail)]
(
hide
)
Description:
Patch 1: Demuxing/decoding stats
Filename:
MIME Type:
Creator:
Chris Pearce [:cpearce (Not reading bugmail)]
Size:
27.70 KB
patch
obsolete
># HG changeset patch ># User Chris Pearce <chris@pearce.org.nz>, Chris Double <chris.double@double.co.nz> ># Parent 62257785dc70999458dfb384a512d023b0476ef8 >Bug 580531 - Add video demuxing/decoding stats. r=? > >diff --git a/content/html/content/src/nsHTMLVideoElement.cpp b/content/html/content/src/nsHTMLVideoElement.cpp >--- a/content/html/content/src/nsHTMLVideoElement.cpp >+++ b/content/html/content/src/nsHTMLVideoElement.cpp >@@ -178,8 +178,31 @@ nsresult nsHTMLVideoElement::SetAcceptHe > "audio/*;q=0.6,*/*;q=0.5"); > > return aChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"), > value, > PR_FALSE); > } > > NS_IMPL_URI_ATTR(nsHTMLVideoElement, Poster, poster) >+ >+/* readonly attribute unsigned long mozDecodedFrames; */ >+NS_IMETHODIMP nsHTMLVideoElement::GetMozParsedFrames(PRUint32 *aMozDecodedFrames) >+{ >+ NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); >+ *aMozDecodedFrames = mDecoder ? mDecoder->GetParsedFrames() : 0; >+ return NS_OK; >+} >+ >+/* readonly attribute unsigned long mozDroppedFrames; */ >+NS_IMETHODIMP nsHTMLVideoElement::GetMozDecodedFrames(PRUint32 *aMozDroppedFrames) >+{ >+ NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); >+ *aMozDroppedFrames = mDecoder ? mDecoder->GetDecodedFrames() : 0; >+ return NS_OK; >+} >+ >+NS_IMETHODIMP nsHTMLVideoElement::GetMozPresentedFrames(PRUint32 *aMozDroppedFrames) >+{ >+ NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); >+ *aMozDroppedFrames = mDecoder ? mDecoder->GetPresentedFrames() : 0; >+ return NS_OK; >+} >diff --git a/content/media/nsBuiltinDecoderReader.cpp b/content/media/nsBuiltinDecoderReader.cpp >--- a/content/media/nsBuiltinDecoderReader.cpp >+++ b/content/media/nsBuiltinDecoderReader.cpp >@@ -373,17 +373,18 @@ nsresult nsBuiltinDecoderReader::DecodeT > { > // Decode forward to the target frame. Start with video, if we have it. > if (HasVideo()) { > PRBool eof = PR_FALSE; > PRInt64 startTime = -1; > while (HasVideo() && !eof) { > while (mVideoQueue.GetSize() == 0 && !eof) { > PRBool skip = PR_FALSE; >- eof = !DecodeVideoFrame(skip, 0); >+ PRUint32 parsed=0, decoded=0; >+ eof = !DecodeVideoFrame(skip, 0, parsed, decoded); > { > MonitorAutoExit exitReaderMon(mMonitor); > MonitorAutoEnter decoderMon(mDecoder->GetMonitor()); > if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) { > return NS_ERROR_FAILURE; > } > } > } >diff --git a/content/media/nsBuiltinDecoderReader.h b/content/media/nsBuiltinDecoderReader.h >--- a/content/media/nsBuiltinDecoderReader.h >+++ b/content/media/nsBuiltinDecoderReader.h >@@ -462,18 +462,20 @@ public: > // in mAudioQueue. Returns PR_TRUE when there's more audio to decode, > // PR_FALSE if the audio is finished, end of file has been reached, > // or an un-recoverable read error has occured. > virtual PRBool DecodeAudioData() = 0; > > // Reads and decodes one video frame. Packets with a timestamp less > // than aTimeThreshold will be decoded (unless they're not keyframes > // and aKeyframeSkip is PR_TRUE), but will not be added to the queue. >- virtual PRBool DecodeVideoFrame(PRBool &aKeyframeSkip, >- PRInt64 aTimeThreshold) = 0; >+ virtual PRBool DecodeVideoFrame(PRBool& aKeyframeSkip, >+ PRInt64 aTimeThreshold, >+ PRUint32& aParsed, >+ PRUint32& aDecoded) = 0; > > virtual PRBool HasAudio() = 0; > virtual PRBool HasVideo() = 0; > > // Read header data for all bitstreams in the file. Fills mInfo with > // the data required to present the media. Returns NS_OK on success, > // or NS_ERROR_FAILURE on failure. > virtual nsresult ReadMetadata() = 0; >@@ -533,17 +535,20 @@ protected: > template<class Data> > Data* DecodeToFirstData(DecodeFn aDecodeFn, > MediaQueue<Data>& aQueue); > > // Wrapper so that DecodeVideoFrame(PRBool&,PRInt64) can be called from > // DecodeToFirstData(). > PRBool DecodeVideoFrame() { > PRBool f = PR_FALSE; >- return DecodeVideoFrame(f, 0); >+ // Ignore parsed/decoded stats, as DecodeVideoFrame() is only called >+ // during seeking, so these aren't relevant to playback performance. >+ PRUint32 parsed=0, decoded=0; >+ return DecodeVideoFrame(f, 0, parsed, decoded); > } > > // Fills aRanges with ByteRanges denoting the sections of the media which > // have been downloaded and are stored in the media cache. The reader > // monitor must must be held with exactly one lock count. The nsMediaStream > // must be pinned while calling this. > nsresult GetBufferedBytes(nsTArray<ByteRange>& aRanges); > >diff --git a/content/media/nsBuiltinDecoderStateMachine.cpp b/content/media/nsBuiltinDecoderStateMachine.cpp >--- a/content/media/nsBuiltinDecoderStateMachine.cpp >+++ b/content/media/nsBuiltinDecoderStateMachine.cpp >@@ -278,43 +278,50 @@ void nsBuiltinDecoderStateMachine::Decod > videoPlaying && > static_cast<PRUint32>(videoQueue.GetSize()) < LOW_VIDEO_FRAMES))) > { > skipToNextKeyframe = PR_TRUE; > LOG(PR_LOG_DEBUG, ("Skipping video decode to the next keyframe")); > } > > // Video decode. >+ PRUint32 parsed = 0, decoded = 0; > if (videoPlaying && > static_cast<PRUint32>(videoQueue.GetSize()) < AMPLE_VIDEO_FRAMES) > { > // Time the video decode, so that if it's slow, we can increase our low > // audio threshold to reduce the chance of an audio underrun while we're > // waiting for a video decode to complete. > TimeDuration decodeTime; > { > PRInt64 currentTime = GetMediaTime(); > MonitorAutoExit exitMon(mDecoder->GetMonitor()); > TimeStamp start = TimeStamp::Now(); >- videoPlaying = mReader->DecodeVideoFrame(skipToNextKeyframe, currentTime); >+ videoPlaying = mReader->DecodeVideoFrame(skipToNextKeyframe, >+ currentTime, >+ parsed, >+ decoded); > decodeTime = TimeStamp::Now() - start; > } > if (!IsDecodeCloseToDownload() && > THRESHOLD_FACTOR * decodeTime.ToMilliseconds() > lowAudioThreshold) > { > lowAudioThreshold = > NS_MIN(static_cast<PRInt64>(THRESHOLD_FACTOR * decodeTime.ToMilliseconds()), > static_cast<PRInt64>(AMPLE_AUDIO_MS)); > ampleAudioThreshold = NS_MAX(THRESHOLD_FACTOR * lowAudioThreshold, > ampleAudioThreshold); > LOG(PR_LOG_DEBUG, > ("Slow video decode, set lowAudioThreshold=%lld ampleAudioThreshold=%lld", > lowAudioThreshold, ampleAudioThreshold)); > } > } >+ if (parsed || decoded) { >+ mDecoder->NotifyDecodedFrames(parsed, decoded); >+ } > > // Audio decode. > if (audioPlaying && > (GetDecodedAudioDuration() < ampleAudioThreshold || audioQueue.GetSize() == 0)) > { > MonitorAutoExit exitMon(mDecoder->GetMonitor()); > audioPlaying = mReader->DecodeAudioData(); > } >@@ -1276,17 +1283,19 @@ void nsBuiltinDecoderStateMachine::Rende > > if (aData->mDuplicate) { > return; > } > > nsRefPtr<Image> image = aData->mImage; > if (image) { > const nsVideoInfo& info = mReader->GetInfo(); >- mDecoder->SetVideoData(gfxIntSize(info.mDisplay.width, info.mDisplay.height), info.mPixelAspectRatio, image); >+ mDecoder->SetVideoData(gfxIntSize(info.mDisplay.width, info.mDisplay.height), >+ info.mPixelAspectRatio, >+ image); > } > } > > PRInt64 > nsBuiltinDecoderStateMachine::GetAudioClock() > { > NS_ASSERTION(IsCurrentThread(mDecoder->mStateMachineThread), "Should be on state machine thread."); > if (!mAudioStream || !HasAudio()) >@@ -1364,16 +1373,17 @@ void nsBuiltinDecoderStateMachine::Advan > // Decode one frame and display it > NS_ASSERTION(currentFrame->mTime >= mStartTime, "Should have positive frame time"); > { > MonitorAutoExit exitMon(mDecoder->GetMonitor()); > // If we have video, we want to increment the clock in steps of the frame > // duration. > RenderVideoFrame(currentFrame); > } >+ mDecoder->NotifyPresentedFrame(); > PRInt64 now = (TimeStamp::Now() - mPlayStartTime + mPlayDuration).ToMilliseconds(); > remainingTime = currentFrame->mEndTime - mStartTime - now; > currentFrame = nsnull; > } > > // Kick the decode thread in case it filled its buffers and put itself > // to sleep. > mDecoder->GetMonitor().NotifyAll(); >diff --git a/content/media/nsMediaDecoder.cpp b/content/media/nsMediaDecoder.cpp >--- a/content/media/nsMediaDecoder.cpp >+++ b/content/media/nsMediaDecoder.cpp >@@ -70,16 +70,20 @@ > // nsMediaDecoder::CanPlayThrough() calculation more stable in the case of > // fluctuating bitrates. > #define CAN_PLAY_THROUGH_MARGIN 10 > > nsMediaDecoder::nsMediaDecoder() : > mElement(0), > mRGBWidth(-1), > mRGBHeight(-1), >+ mStatsMonitor("nsMediaDecoder.stats"), >+ mParsedFrames(0), >+ mDecodedFrames(0), >+ mPresentedFrames(0), > mVideoUpdateLock(nsnull), > mPixelAspectRatio(1.0), > mFrameBufferLength(0), > mPinnedForSeek(PR_FALSE), > mSizeChanged(PR_FALSE), > mImageContainerSizeChanged(PR_FALSE), > mShuttingDown(PR_FALSE) > { >@@ -319,8 +323,29 @@ PRBool nsMediaDecoder::CanPlayThrough() > // playback position, so that if the bitrate of the media fluctuates, or if > // our download rate or decode rate estimation is otherwise inaccurate, > // we don't suddenly discover that we need to buffer. This is particularly > // required near the start of the media, when not much data is downloaded. > PRInt64 readAheadMargin = stats.mPlaybackRate * CAN_PLAY_THROUGH_MARGIN; > return stats.mTotalBytes == stats.mDownloadPosition || > stats.mDownloadPosition > stats.mPlaybackPosition + readAheadMargin; > } >+ >+void nsMediaDecoder::NotifyPresentedFrame() { >+ mozilla::MonitorAutoEnter mon(mStatsMonitor); >+ ++mPresentedFrames; >+} >+ >+void nsMediaDecoder::NotifyDecodedFrames(PRUint32 aParsed, PRUint32 aDecoded) { >+ mozilla::MonitorAutoEnter mon(mStatsMonitor); >+ mParsedFrames += aParsed; >+ mDecodedFrames += aDecoded; >+} >+ >+#define IMPL_GET_STAT_METHOD(X) \ >+PRUint32 nsMediaDecoder::Get##X##Frames() { \ >+ mozilla::MonitorAutoEnter mon(mStatsMonitor); \ >+ return m##X##Frames; \ >+} >+ >+IMPL_GET_STAT_METHOD(Parsed); >+IMPL_GET_STAT_METHOD(Decoded); >+IMPL_GET_STAT_METHOD(Presented); >diff --git a/content/media/nsMediaDecoder.h b/content/media/nsMediaDecoder.h >--- a/content/media/nsMediaDecoder.h >+++ b/content/media/nsMediaDecoder.h >@@ -42,16 +42,17 @@ > > #include "nsIPrincipal.h" > #include "nsSize.h" > #include "prlog.h" > #include "gfxContext.h" > #include "gfxRect.h" > #include "nsITimer.h" > #include "ImageLayers.h" >+#include "mozilla/Monitor.h" > > class nsHTMLMediaElement; > class nsMediaStream; > class nsIStreamListener; > class nsTimeRanges; > > // The size to use for audio data frames in MozAudioAvailable events. > // This value is per channel, and is chosen to give ~43 fps of events, >@@ -82,16 +83,17 @@ private: > // which can be called from any thread. > class nsMediaDecoder : public nsIObserver > { > public: > typedef mozilla::TimeStamp TimeStamp; > typedef mozilla::TimeDuration TimeDuration; > typedef mozilla::layers::ImageContainer ImageContainer; > typedef mozilla::layers::Image Image; >+ typedef mozilla::Monitor Monitor; > > nsMediaDecoder(); > virtual ~nsMediaDecoder(); > > // Create a new decoder of the same type as this one. > virtual nsMediaDecoder* Clone() = 0; > > // Perform any initialization required for the decoder. >@@ -286,16 +288,34 @@ public: > // to buffer, given the current download and playback rates. > PRBool CanPlayThrough(); > > // Called by the nsMediaStream when a read on the stream by the decoder > // is about to block due to insuffient data. Decoders may want to pause > // playback and go into buffering mode when this is called. > virtual void NotifyDataExhausted() = 0; > >+ // Returns number of frames which have been parsed from the media. >+ // Can be called on any thread. >+ PRUint32 GetParsedFrames(); >+ >+ // Returns the number of parsed frames which have been decoded. >+ // Can be called on any thread. >+ PRUint32 GetDecodedFrames(); >+ >+ // Returns the number of decoded frames which have been sent to the rendering >+ // pipeline for painting ("presented"). >+ // Can be called on any thread. >+ PRUint32 GetPresentedFrames(); >+ >+ // Playback statistics gathering functions. Called when frames reach various >+ // stages through the decode/rendering pipeline. Can be called on any thread. >+ void NotifyDecodedFrames(PRUint32 aParsed, PRUint32 aDecoded); >+ void NotifyPresentedFrame(); >+ > protected: > > // Start timer to update download progress information. > nsresult StartProgress(); > > // Stop progress information timer. > nsresult StopProgress(); > >@@ -312,16 +332,24 @@ protected: > // This should only ever be accessed from the main thread. > // It is set in Init and cleared in Shutdown when the element goes away. > // The decoder does not add a reference the element. > nsHTMLMediaElement* mElement; > > PRInt32 mRGBWidth; > PRInt32 mRGBHeight; > >+ // Monitor to protect access of playback statistics. >+ Monitor mStatsMonitor; >+ >+ // Playback statistics counters. Access protected by mStatsMonitor; >+ PRUint32 mParsedFrames; >+ PRUint32 mDecodedFrames; >+ PRUint32 mPresentedFrames; >+ > nsRefPtr<ImageContainer> mImageContainer; > > // Time that the last progress event was fired. Read/Write from the > // main thread only. > TimeStamp mProgressTime; > > // Time that data was last read from the media resource. Used for > // computing if the download has stalled and to rate limit progress events >diff --git a/content/media/ogg/nsOggReader.cpp b/content/media/ogg/nsOggReader.cpp >--- a/content/media/ogg/nsOggReader.cpp >+++ b/content/media/ogg/nsOggReader.cpp >@@ -576,19 +576,22 @@ nsresult nsOggReader::DecodeTheora(nsTAr > } > if (!aFrames.AppendElement(v)) { > delete v; > } > } > return NS_OK; > } > >-PRBool nsOggReader::DecodeVideoFrame(PRBool &aKeyframeSkip, >- PRInt64 aTimeThreshold) >+PRBool nsOggReader::DecodeVideoFrame(PRBool& aKeyframeSkip, >+ PRInt64 aTimeThreshold, >+ PRUint32& aParsed, >+ PRUint32& aDecoded) > { >+ aParsed = aDecoded = 0; > MonitorAutoEnter mon(mMonitor); > NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(), > "Should be on state machine or AV thread."); > // We chose to keep track of the Theora granulepos ourselves, rather than > // rely on th_decode_packetin() to do it for us. This is because > // th_decode_packetin() simply works by incrementing a counter every time > // it's called, so if we drop frames and don't call it, subsequent granulepos > // will be wrong. Whenever we read a packet which has a granulepos, we use >@@ -608,16 +611,17 @@ PRBool nsOggReader::DecodeVideoFrame(PRB > // Failed to read another page, must be the end of file. We can't have > // already encountered an end of bitstream packet, else we wouldn't be > // here, so this bitstream must be missing its end of stream packet, or > // is otherwise corrupt (oggz-chop can output files like this). Inform > // the queue that there will be no more frames. > mVideoQueue.Finish(); > return PR_FALSE; > } >+ aParsed++; > > if (packet.granulepos > 0) { > // We've found a packet with a granulepos, we can now determine the > // buffered packet's timestamps, as well as the timestamps for any > // packets we read subsequently. > mTheoraGranulepos = packet.granulepos; > } > >@@ -694,16 +698,17 @@ PRBool nsOggReader::DecodeVideoFrame(PRB > NS_ASSERTION(mTheoraGranulepos > 0, "We must Theora granulepos!"); > > if (!ReadOggPacket(mTheoraState, &packet)) { > // Failed to read from file, so EOF or other premature failure. > // Inform the queue that there will be no more frames. > mVideoQueue.Finish(); > return PR_FALSE; > } >+ aParsed++; > > endOfStream = packet.e_o_s != 0; > > // Maintain the Theora granulepos. We must do this even if we drop frames, > // otherwise our clock will be wrong after we've skipped frames. > if (packet.granulepos != -1) { > // Incoming packet has a granulepos, use that as it's granulepos. > mTheoraGranulepos = packet.granulepos; >@@ -746,16 +751,17 @@ PRBool nsOggReader::DecodeVideoFrame(PRB > for (PRUint32 i = 0; i < frames.Length(); i++) { > nsAutoPtr<VideoData> data(frames[i].forget()); > if (aKeyframeSkip && data->mKeyframe) { > aKeyframeSkip = PR_FALSE; > } > > if (!aKeyframeSkip) { > mVideoQueue.Push(data.forget()); >+ aDecoded++; > } > } > > if (endOfStream) { > // We've encountered an end of bitstream packet. Inform the queue that > // there will be no more frames. > mVideoQueue.Finish(); > } >@@ -1119,17 +1125,18 @@ nsresult nsOggReader::SeekInBufferedRang > return res; > } > > // We have an active Theora bitstream. Decode the next Theora frame, and > // extract its keyframe's time. > PRBool eof; > do { > PRBool skip = PR_FALSE; >- eof = !DecodeVideoFrame(skip, 0); >+ PRUint32 parsed, decoded; >+ eof = !DecodeVideoFrame(skip, 0, parsed, decoded); > { > MonitorAutoExit exitReaderMon(mMonitor); > MonitorAutoEnter decoderMon(mDecoder->GetMonitor()); > if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) { > return NS_ERROR_FAILURE; > } > } > } while (!eof && >diff --git a/content/media/ogg/nsOggReader.h b/content/media/ogg/nsOggReader.h >--- a/content/media/ogg/nsOggReader.h >+++ b/content/media/ogg/nsOggReader.h >@@ -63,18 +63,20 @@ public: > > virtual nsresult Init(nsBuiltinDecoderReader* aCloneDonor); > virtual nsresult ResetDecode(); > virtual PRBool DecodeAudioData(); > > // If the Theora granulepos has not been captured, it may read several packets > // until one with a granulepos has been captured, to ensure that all packets > // read have valid time info. >- virtual PRBool DecodeVideoFrame(PRBool &aKeyframeSkip, >- PRInt64 aTimeThreshold); >+ virtual PRBool DecodeVideoFrame(PRBool& aKeyframeSkip, >+ PRInt64 aTimeThreshold, >+ PRUint32& aParsed, >+ PRUint32& aDecoded); > > virtual VideoData* FindStartTime(PRInt64 aOffset, > PRInt64& aOutStartTime); > > // Get the end time of aEndOffset. This is the playback position we'd reach > // after playback finished at aEndOffset. > virtual PRInt64 FindEndTime(PRInt64 aEndOffset); > >diff --git a/content/media/raw/nsRawReader.cpp b/content/media/raw/nsRawReader.cpp >--- a/content/media/raw/nsRawReader.cpp >+++ b/content/media/raw/nsRawReader.cpp >@@ -163,18 +163,21 @@ PRBool nsRawReader::ReadFromStream(nsMed > aLength -= bytesRead; > aBuf += bytesRead; > } > > return PR_TRUE; > } > > PRBool nsRawReader::DecodeVideoFrame(PRBool &aKeyframeSkip, >- PRInt64 aTimeThreshold) >+ PRInt64 aTimeThreshold, >+ PRUint32& aParsed, >+ PRUint32& aDecoded) > { >+ aParsed = aDecoded = 0; > mozilla::MonitorAutoEnter autoEnter(mMonitor); > NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(), > "Should be on state machine thread or decode thread."); > > if (!mFrameSize) > return PR_FALSE; // Metadata read failed. We should refuse to play. > > PRInt64 currentFrameTime = 1000 * mCurrentFrame / mFrameRate; >@@ -194,16 +197,18 @@ PRBool nsRawReader::DecodeVideoFrame(PRB > !(header.packetID == 0xFF && header.codecID == RAW_ID /* "YUV" */)) { > return PR_FALSE; > } > > if (!ReadFromStream(stream, buffer, length)) { > return PR_FALSE; > } > >+ aParsed++; >+ > if (currentFrameTime >= aTimeThreshold) > break; > > mCurrentFrame++; > currentFrameTime += 1000.0 / mFrameRate; > } > > VideoData::YCbCrBuffer b; >@@ -232,16 +237,17 @@ PRBool nsRawReader::DecodeVideoFrame(PRB > b, > 1, // In raw video every frame is a keyframe > -1); > if (!v) > return PR_FALSE; > > mVideoQueue.Push(v); > mCurrentFrame++; >+ aDecoded++; > currentFrameTime += 1000 / mFrameRate; > > return PR_TRUE; > } > > nsresult nsRawReader::Seek(PRInt64 aTime, PRInt64 aStartTime, PRInt64 aEndTime, PRInt64 aCurrentTime) > { > mozilla::MonitorAutoEnter autoEnter(mMonitor); >@@ -264,17 +270,18 @@ nsresult nsRawReader::Seek(PRInt64 aTime > > nsresult rv = stream->Seek(nsISeekableStream::NS_SEEK_SET, offset); > NS_ENSURE_SUCCESS(rv, rv); > > mVideoQueue.Erase(); > > while(mVideoQueue.GetSize() == 0) { > PRBool keyframeSkip = PR_FALSE; >- if (!DecodeVideoFrame(keyframeSkip, 0)) { >+ PRUint32 parsed, decoded; >+ if (!DecodeVideoFrame(keyframeSkip, 0, parsed, decoded)) { > mCurrentFrame = frame; > return NS_ERROR_FAILURE; > } > > { > mozilla::MonitorAutoExit autoMonitorExit(mMonitor); > mozilla::MonitorAutoEnter autoMonitor(mDecoder->GetMonitor()); > if (mDecoder->GetDecodeState() == >diff --git a/content/media/raw/nsRawReader.h b/content/media/raw/nsRawReader.h >--- a/content/media/raw/nsRawReader.h >+++ b/content/media/raw/nsRawReader.h >@@ -92,18 +92,20 @@ class nsRawReader : public nsBuiltinDeco > public: > nsRawReader(nsBuiltinDecoder* aDecoder); > ~nsRawReader(); > > virtual nsresult Init(nsBuiltinDecoderReader* aCloneDonor); > virtual nsresult ResetDecode(); > virtual PRBool DecodeAudioData(); > >- virtual PRBool DecodeVideoFrame(PRBool &aKeyframeSkip, >- PRInt64 aTimeThreshold); >+ virtual PRBool DecodeVideoFrame(PRBool& aKeyframeSkip, >+ PRInt64 aTimeThreshold, >+ PRUint32& aParsed, >+ PRUint32& aDecoded); > > virtual PRBool HasAudio() > { > return PR_FALSE; > } > > virtual PRBool HasVideo() > { >diff --git a/content/media/webm/nsWebMReader.cpp b/content/media/webm/nsWebMReader.cpp >--- a/content/media/webm/nsWebMReader.cpp >+++ b/content/media/webm/nsWebMReader.cpp >@@ -602,19 +602,22 @@ PRBool nsWebMReader::DecodeAudioData() > if (!holder) { > mAudioQueue.Finish(); > return PR_FALSE; > } > > return DecodeAudioPacket(holder->mPacket, holder->mOffset); > } > >-PRBool nsWebMReader::DecodeVideoFrame(PRBool &aKeyframeSkip, >- PRInt64 aTimeThreshold) >+PRBool nsWebMReader::DecodeVideoFrame(PRBool& aKeyframeSkip, >+ PRInt64 aTimeThreshold, >+ PRUint32& aParsed, >+ PRUint32& aDecoded) > { >+ aParsed = aDecoded = 0; > MonitorAutoEnter mon(mMonitor); > NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(), > "Should be on state machine or decode thread."); > > nsAutoRef<NesteggPacketHolder> holder(NextPacket(VIDEO)); > if (!holder) { > mVideoQueue.Finish(); > return PR_FALSE; >@@ -675,38 +678,40 @@ PRBool nsWebMReader::DecodeVideoFrame(PR > } > > vpx_codec_stream_info_t si; > memset(&si, 0, sizeof(si)); > si.sz = sizeof(si); > vpx_codec_peek_stream_info(&vpx_codec_vp8_dx_algo, data, length, &si); > if ((aKeyframeSkip && !si.is_kf) || (aKeyframeSkip && si.is_kf && tstamp_ms < aTimeThreshold)) { > aKeyframeSkip = PR_TRUE; >+ aParsed++; // Assume 1 frame per chunk. > break; > } > > if (aKeyframeSkip && si.is_kf) { > aKeyframeSkip = PR_FALSE; > } > >- if(vpx_codec_decode(&mVP8, data, length, NULL, 0)) { >+ if (vpx_codec_decode(&mVP8, data, length, NULL, 0)) { > return PR_FALSE; > } > > // If the timestamp of the video frame is less than > // the time threshold required then it is not added > // to the video queue and won't be displayed. > if (tstamp_ms < aTimeThreshold) { >+ aParsed++; // Assume 1 frame per chunk. > continue; > } > > vpx_codec_iter_t iter = NULL; > vpx_image_t *img; > >- while((img = vpx_codec_get_frame(&mVP8, &iter))) { >+ while ((img = vpx_codec_get_frame(&mVP8, &iter))) { > NS_ASSERTION(img->fmt == IMG_FMT_I420, "WebM image format is not I420"); > > // Chroma shifts are rounded down as per the decoding examples in the VP8 SDK > VideoData::YCbCrBuffer b; > b.mPlanes[0].mData = img->planes[0]; > b.mPlanes[0].mStride = img->stride[0]; > b.mPlanes[0].mHeight = img->d_h; > b.mPlanes[0].mWidth = img->d_w; >@@ -727,16 +732,20 @@ PRBool nsWebMReader::DecodeVideoFrame(PR > tstamp_ms, > next_tstamp / NS_PER_MS, > b, > si.is_kf, > -1); > if (!v) { > return PR_FALSE; > } >+ aParsed++; >+ aDecoded++; >+ NS_ASSERTION(aDecoded <= aParsed, >+ "Expect only 1 frame per chunk per packet in WebM..."); > mVideoQueue.Push(v); > } > } > > return PR_TRUE; > } > > PRBool nsWebMReader::CanDecodeToTarget(PRInt64 aTarget, >diff --git a/content/media/webm/nsWebMReader.h b/content/media/webm/nsWebMReader.h >--- a/content/media/webm/nsWebMReader.h >+++ b/content/media/webm/nsWebMReader.h >@@ -133,18 +133,20 @@ public: > > virtual nsresult Init(nsBuiltinDecoderReader* aCloneDonor); > virtual nsresult ResetDecode(); > virtual PRBool DecodeAudioData(); > > // If the Theora granulepos has not been captured, it may read several packets > // until one with a granulepos has been captured, to ensure that all packets > // read have valid time info. >- virtual PRBool DecodeVideoFrame(PRBool &aKeyframeSkip, >- PRInt64 aTimeThreshold); >+ virtual PRBool DecodeVideoFrame(PRBool& aKeyframeSkip, >+ PRInt64 aTimeThreshold, >+ PRUint32& aParsed, >+ PRUint32& aDecoded); > > virtual PRBool HasAudio() > { > mozilla::MonitorAutoEnter mon(mMonitor); > return mHasAudio; > } > > virtual PRBool HasVideo() >diff --git a/dom/interfaces/html/nsIDOMHTMLVideoElement.idl b/dom/interfaces/html/nsIDOMHTMLVideoElement.idl >--- a/dom/interfaces/html/nsIDOMHTMLVideoElement.idl >+++ b/dom/interfaces/html/nsIDOMHTMLVideoElement.idl >@@ -43,18 +43,32 @@ > * <video> element. > * > * For more information on this interface, please see > * http://www.whatwg.org/specs/web-apps/current-work/#video > * > * @status UNDER_DEVELOPMENT > */ > >-[scriptable, uuid(edf468dc-42eb-4494-920b-56a315172640)] >+[scriptable, uuid(8a2e5756-e9a3-404f-9592-4e5b5830de85)] > interface nsIDOMHTMLVideoElement : nsIDOMHTMLMediaElement > { > attribute long width; > attribute long height; > readonly attribute unsigned long videoWidth; > readonly attribute unsigned long videoHeight; > attribute DOMString poster; >+ >+ // A count of the number of video frames that have demuxed from the media >+ // resource. If we were playing perfectly, we'd be able to paint this many >+ // frames. >+ readonly attribute unsigned long mozParsedFrames; >+ >+ // A count of the number of frames that have been decoded. We may drop >+ // frames if the decode is taking too much time. >+ readonly attribute unsigned long mozDecodedFrames; >+ >+ // A count of the number of frames that have been presented to the rendering >+ // pipeline. We may drop frames if they arrive late at the renderer. >+ readonly attribute unsigned long mozPresentedFrames; >+ > }; >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
Flags:
roc
: review+
Actions:
View
|
Diff
|
Review
Attachments on
bug 580531
:
458935
|
458937
|
465555
|
465556
|
468611
|
468612
|
468617
|
495942
|
496253
|
496254
|
496258
|
514667
|
515506
|
515799
|
516082
|
516083
|
516105
|
516139
|
516418
|
516419