author | Eric Phan <eric.phan@ensimag.grenoble-inp.fr> |
Mon, 23 Jun 2014 22:08:34 +1200 | |
changeset 212300 | f14b9781345f400cec5fdbab235ee93e3c8e5177 |
parent 212299 | 080476fd705927fdc1d68a7d790ee510dc4dd0f8 |
child 212301 | ca69915acaf38d6fe40ddf648ab086b73ffec4f1 |
push id | 515 |
push user | raliiev@mozilla.com |
push date | Mon, 06 Oct 2014 12:51:51 +0000 |
treeherder | mozilla-release@267c7a481bef [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | cpearce |
bugs | 1015985 |
milestone | 33.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/content/html/content/src/HTMLMediaElement.cpp +++ b/content/html/content/src/HTMLMediaElement.cpp @@ -2522,17 +2522,16 @@ nsresult HTMLMediaElement::InitializeDec if (!decoder->Init(this)) { LOG(PR_LOG_DEBUG, ("%p Failed to init cloned decoder %p", this, decoder.get())); return NS_ERROR_FAILURE; } double duration = aOriginal->GetDuration(); if (duration >= 0) { decoder->SetDuration(duration); - decoder->SetTransportSeekable(aOriginal->IsTransportSeekable()); decoder->SetMediaSeekable(aOriginal->IsMediaSeekable()); } nsRefPtr<MediaResource> resource = originalResource->CloneData(decoder); if (!resource) { LOG(PR_LOG_DEBUG, ("%p Failed to cloned stream for decoder %p", this, decoder.get())); return NS_ERROR_FAILURE; }
--- a/content/media/AbstractMediaDecoder.h +++ b/content/media/AbstractMediaDecoder.h @@ -75,19 +75,16 @@ public: // Sets the duration of the media in microseconds. The MediaDecoder // fires a durationchange event to its owner (e.g., an HTML audio // tag). virtual void UpdateEstimatedMediaDuration(int64_t aDuration) = 0; // Set the media as being seekable or not. virtual void SetMediaSeekable(bool aMediaSeekable) = 0; - // Set the transport level as being seekable or not. - virtual void SetTransportSeekable(bool aTransportSeekable) = 0; - virtual VideoFrameContainer* GetVideoFrameContainer() = 0; virtual mozilla::layers::ImageContainer* GetImageContainer() = 0; // Return true if the media layer supports seeking. virtual bool IsTransportSeekable() = 0; // Return true if the transport layer supports seeking. virtual bool IsMediaSeekable() = 0;
--- a/content/media/BufferDecoder.cpp +++ b/content/media/BufferDecoder.cpp @@ -115,22 +115,16 @@ BufferDecoder::UpdateEstimatedMediaDurat } void BufferDecoder::SetMediaSeekable(bool aMediaSeekable) { // ignore } -void -BufferDecoder::SetTransportSeekable(bool aTransportSeekable) -{ - // ignore -} - VideoFrameContainer* BufferDecoder::GetVideoFrameContainer() { // no video frame return nullptr; } layers::ImageContainer*
--- a/content/media/BufferDecoder.h +++ b/content/media/BufferDecoder.h @@ -49,18 +49,16 @@ public: virtual int64_t GetMediaDuration() MOZ_OVERRIDE; virtual void SetMediaDuration(int64_t aDuration) MOZ_OVERRIDE; virtual void UpdateEstimatedMediaDuration(int64_t aDuration) MOZ_OVERRIDE; virtual void SetMediaSeekable(bool aMediaSeekable) MOZ_OVERRIDE; - virtual void SetTransportSeekable(bool aTransportSeekable) MOZ_OVERRIDE; - virtual VideoFrameContainer* GetVideoFrameContainer() MOZ_OVERRIDE; virtual layers::ImageContainer* GetImageContainer() MOZ_OVERRIDE; virtual bool IsTransportSeekable() MOZ_OVERRIDE; virtual bool IsMediaSeekable() MOZ_OVERRIDE; virtual void MetadataLoaded(int aChannels, int aRate, bool aHasAudio, bool aHasVideo, MetadataTags* aTags) MOZ_OVERRIDE;
--- a/content/media/MediaDecoder.cpp +++ b/content/media/MediaDecoder.cpp @@ -412,17 +412,16 @@ bool MediaDecoder::IsInfinite() MediaDecoder::MediaDecoder() : mDecoderPosition(0), mPlaybackPosition(0), mCurrentTime(0.0), mInitialVolume(0.0), mInitialPlaybackRate(1.0), mInitialPreservesPitch(true), mDuration(-1), - mTransportSeekable(true), mMediaSeekable(true), mSameOriginMedia(false), mReentrantMonitor("media.decoder"), mIsDormant(false), mIsExitingDormant(false), mPlayState(PLAY_STATE_PAUSED), mNextState(PLAY_STATE_PAUSED), mCalledResourceLoaded(false), @@ -546,18 +545,16 @@ nsresult MediaDecoder::InitializeStateMa MediaDecoder* cloneDonor = static_cast<MediaDecoder*>(aCloneDonor); if (NS_FAILED(mDecoderStateMachine->Init(cloneDonor ? cloneDonor->mDecoderStateMachine : nullptr))) { DECODER_LOG(PR_LOG_WARNING, "Failed to init state machine!"); return NS_ERROR_FAILURE; } { ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - mDecoderStateMachine->SetTransportSeekable(mTransportSeekable); - mDecoderStateMachine->SetMediaSeekable(mMediaSeekable); mDecoderStateMachine->SetDuration(mDuration); mDecoderStateMachine->SetVolume(mInitialVolume); mDecoderStateMachine->SetAudioCaptured(mInitialAudioCaptured); SetPlaybackRate(mInitialPlaybackRate); mDecoderStateMachine->SetPreservesPitch(mInitialPreservesPitch); if (mMinimizePreroll) { mDecoderStateMachine->SetMinimizePrerollUntilPlaybackStarts(); } @@ -1281,35 +1278,24 @@ void MediaDecoder::UpdateEstimatedMediaD NS_ENSURE_TRUE_VOID(GetStateMachine()); GetStateMachine()->UpdateEstimatedDuration(aDuration); } void MediaDecoder::SetMediaSeekable(bool aMediaSeekable) { ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); MOZ_ASSERT(NS_IsMainThread() || OnDecodeThread()); mMediaSeekable = aMediaSeekable; - if (mDecoderStateMachine) { - mDecoderStateMachine->SetMediaSeekable(aMediaSeekable); - } } -void MediaDecoder::SetTransportSeekable(bool aTransportSeekable) +bool +MediaDecoder::IsTransportSeekable() { ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - MOZ_ASSERT(NS_IsMainThread() || OnDecodeThread()); - mTransportSeekable = aTransportSeekable; - if (mDecoderStateMachine) { - mDecoderStateMachine->SetTransportSeekable(aTransportSeekable); - } -} - -bool MediaDecoder::IsTransportSeekable() -{ - MOZ_ASSERT(NS_IsMainThread()); - return mTransportSeekable; + MOZ_ASSERT(OnDecodeThread() || NS_IsMainThread()); + return GetResource()->IsTransportSeekable(); } bool MediaDecoder::IsMediaSeekable() { NS_ENSURE_TRUE(GetStateMachine(), false); ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); MOZ_ASSERT(OnDecodeThread() || NS_IsMainThread()); return mMediaSeekable;
--- a/content/media/MediaDecoder.h +++ b/content/media/MediaDecoder.h @@ -603,17 +603,17 @@ public: // different from the existing duration, the change request is ignored. // If the incoming duration is significantly different, the duration is // changed, this causes a durationchanged event to fire to the media // element. void UpdateEstimatedMediaDuration(int64_t aDuration) MOZ_OVERRIDE; // Set a flag indicating whether seeking is supported virtual void SetMediaSeekable(bool aMediaSeekable) MOZ_OVERRIDE; - virtual void SetTransportSeekable(bool aTransportSeekable) MOZ_FINAL MOZ_OVERRIDE; + // Returns true if this media supports seeking. False for example for WebM // files without an index and chained ogg files. virtual bool IsMediaSeekable() MOZ_FINAL MOZ_OVERRIDE; // Returns true if seeking is supported on a transport level (e.g. the server // supports range requests, we are playing a file, etc.). virtual bool IsTransportSeekable(); // Return the time ranges that can be seeked into. @@ -1032,20 +1032,16 @@ protected: // Duration of the media resource. Set to -1 if unknown. // Set when the metadata is loaded. Accessed on the main thread // only. int64_t mDuration; // True when playback should start with audio captured (not playing). bool mInitialAudioCaptured; - // True if the resource is seekable at a transport level (server supports byte - // range requests, local file, etc.). - bool mTransportSeekable; - // True if the media is seekable (i.e. supports random access). bool mMediaSeekable; // True if the media is same-origin with the element. Data can only be // passed to MediaStreams when this is true. bool mSameOriginMedia; /******
--- a/content/media/MediaDecoderReader.h +++ b/content/media/MediaDecoderReader.h @@ -168,16 +168,20 @@ public: return mDecoder; } AudioData* DecodeToFirstAudioData(); VideoData* DecodeToFirstVideoData(); MediaInfo GetMediaInfo() { return mInfo; } + // Indicates if the media is seekable. + // ReadMetada should be called before calling this method. + virtual bool IsMediaSeekable() = 0; + protected: virtual ~MediaDecoderReader(); // Overrides of this function should decodes an unspecified amount of // audio data, enqueuing the audio data in mAudioQueue. Returns true // when there's more audio to decode, false if the audio is finished, // end of file has been reached, or an un-recoverable read error has // occured. This function blocks until the decode is complete.
--- a/content/media/MediaDecoderStateMachine.cpp +++ b/content/media/MediaDecoderStateMachine.cpp @@ -197,18 +197,16 @@ MediaDecoderStateMachine::MediaDecoderSt mPreservesPitch(true), mBasePosition(0), mAmpleVideoFrames(2), mLowAudioThresholdUsecs(LOW_AUDIO_USECS), mAmpleAudioThresholdUsecs(AMPLE_AUDIO_USECS), mAudioRequestPending(false), mVideoRequestPending(false), mAudioCaptured(false), - mTransportSeekable(true), - mMediaSeekable(true), mPositionChangeQueued(false), mAudioCompleted(false), mGotDurationFromMetaData(false), mDispatchedEventToDecode(false), mStopAudioThread(true), mQuickBuffering(false), mMinimizePreroll(false), mDecodeThreadWaiting(false), @@ -1597,33 +1595,16 @@ void MediaDecoderStateMachine::SetMediaE void MediaDecoderStateMachine::SetFragmentEndTime(int64_t aEndTime) { AssertCurrentThreadInMonitor(); mFragmentEndTime = aEndTime < 0 ? aEndTime : aEndTime + mStartTime; } -void MediaDecoderStateMachine::SetTransportSeekable(bool aTransportSeekable) -{ - NS_ASSERTION(NS_IsMainThread() || OnDecodeThread(), - "Should be on main thread or the decoder thread."); - AssertCurrentThreadInMonitor(); - - mTransportSeekable = aTransportSeekable; -} - -void MediaDecoderStateMachine::SetMediaSeekable(bool aMediaSeekable) -{ - NS_ASSERTION(NS_IsMainThread() || OnDecodeThread(), - "Should be on main thread or the decoder thread."); - - mMediaSeekable = aMediaSeekable; -} - bool MediaDecoderStateMachine::IsDormantNeeded() { return mReader->IsDormantNeeded(); } void MediaDecoderStateMachine::SetDormant(bool aDormant) { NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); @@ -1770,17 +1751,18 @@ void MediaDecoderStateMachine::NotifyDat void MediaDecoderStateMachine::Seek(const SeekTarget& aTarget) { NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); // We need to be able to seek both at a transport level and at a media level // to seek. - if (!mMediaSeekable) { + if (!mDecoder->IsMediaSeekable()) { + NS_WARNING("Seek() function should not be called on a non-seekable state machine"); return; } // MediaDecoder::mPlayState should be SEEKING while we seek, and // in that case MediaDecoder shouldn't be calling us. NS_ASSERTION(mState != DECODER_STATE_SEEKING, "We shouldn't already be seeking"); NS_ASSERTION(mState >= DECODER_STATE_DECODING, "We should have loaded metadata"); @@ -2181,25 +2163,31 @@ nsresult MediaDecoderStateMachine::Decod } nsresult res; MediaInfo info; { ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor()); res = mReader->ReadMetadata(&info, getter_Transfers(mMetadataTags)); } + if (NS_SUCCEEDED(res)) { if (mState == DECODER_STATE_DECODING_METADATA && mReader->IsWaitingMediaResources()) { // change state to DECODER_STATE_WAIT_FOR_RESOURCES StartWaitForResources(); + // affect values only if ReadMetadata succeeds return NS_OK; } } + if (NS_SUCCEEDED(res)) { + mDecoder->SetMediaSeekable(mReader->IsMediaSeekable()); + } + mInfo = info; if (NS_FAILED(res) || (!info.HasValidMedia())) { return NS_ERROR_FAILURE; } mDecoder->StartProgressUpdates(); mGotDurationFromMetaData = (GetDuration() != -1); @@ -2261,23 +2249,26 @@ MediaDecoderStateMachine::FinishDecodeMe if (VideoQueue().GetSize()) { ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor()); RenderVideoFrame(VideoQueue().PeekFront(), TimeStamp::Now()); } } NS_ASSERTION(mStartTime != -1, "Must have start time"); MOZ_ASSERT((!HasVideo() && !HasAudio()) || - !(mMediaSeekable && mTransportSeekable) || mEndTime != -1, - "Active seekable media should have end time"); - MOZ_ASSERT(!(mMediaSeekable && mTransportSeekable) || - GetDuration() != -1, "Seekable media should have duration"); + !(mDecoder->IsMediaSeekable() && mDecoder->IsTransportSeekable()) || + mEndTime != -1, + "Active seekable media should have end time"); + MOZ_ASSERT(!(mDecoder->IsMediaSeekable() && mDecoder->IsTransportSeekable()) || + GetDuration() != -1, + "Seekable media should have duration"); DECODER_LOG(PR_LOG_DEBUG, "Media goes from %lld to %lld (duration %lld) " - "transportSeekable=%d, mediaSeekable=%d", - mStartTime, mEndTime, GetDuration(), mTransportSeekable, mMediaSeekable); + "transportSeekable=%d, mediaSeekable=%d", + mStartTime, mEndTime, GetDuration(), + mDecoder->IsTransportSeekable(), mDecoder->IsMediaSeekable()); if (HasAudio() && !HasVideo()) { // We're playing audio only. We don't need to worry about slow video // decodes causing audio underruns, so don't buffer so much audio in // order to reduce memory usage. mAmpleAudioThresholdUsecs /= NO_VIDEO_AMPLE_AUDIO_DIVISOR; mLowAudioThresholdUsecs /= NO_VIDEO_AMPLE_AUDIO_DIVISOR; }
--- a/content/media/MediaDecoderStateMachine.h +++ b/content/media/MediaDecoderStateMachine.h @@ -204,27 +204,16 @@ public: // monitor must be obtained before calling this. double GetCurrentTime() const; // Clear the flag indicating that a playback position change event // is currently queued. This is called from the main thread and must // be called with the decode monitor held. void ClearPositionChangeFlag(); - // Called from the main thread or the decoder thread to set whether the media - // resource can seek into unbuffered ranges. The decoder monitor must be - // obtained before calling this. - void SetTransportSeekable(bool aSeekable); - - // Called from the main thread or the decoder thread to set whether the media - // can seek to random location. This is not true for chained ogg and WebM - // media without index. The decoder monitor must be obtained before calling - // this. - void SetMediaSeekable(bool aSeekable); - // Update the playback position. This can result in a timeupdate event // and an invalidate of the frame being dispatched asynchronously if // there is no such event currently queued. // Only called on the decoder thread. Must be called with // the decode monitor held. void UpdatePlaybackPosition(int64_t aTime); // Causes the state machine to switch to buffering state, and to @@ -285,26 +274,16 @@ public: void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset); int64_t GetEndMediaTime() const { AssertCurrentThreadInMonitor(); return mEndTime; } - bool IsTransportSeekable() { - AssertCurrentThreadInMonitor(); - return mTransportSeekable; - } - - bool IsMediaSeekable() { - AssertCurrentThreadInMonitor(); - return mMediaSeekable; - } - // Returns the shared state machine thread. nsIEventTarget* GetStateMachineThread(); // Calls ScheduleStateMachine() after taking the decoder lock. Also // notifies the decoder thread in case it's waiting on the decoder lock. void ScheduleStateMachineWithLockAndWakeDecoder(); // Schedules the shared state machine thread to run the state machine @@ -903,24 +882,16 @@ protected: bool mAudioRequestPending; bool mVideoRequestPending; // True if we shouldn't play our audio (but still write it to any capturing // streams). When this is true, mStopAudioThread is always true and // the audio thread will never start again after it has stopped. bool mAudioCaptured; - // True if the media resource can be seeked on a transport level. Accessed - // from the state machine and main threads. Synchronised via decoder monitor. - bool mTransportSeekable; - - // True if the media can be seeked. Accessed from the state machine and main - // threads. Synchronised via decoder monitor. - bool mMediaSeekable; - // True if an event to notify about a change in the playback // position has been queued, but not yet run. It is set to false when // the event is run. This allows coalescing of these events as they can be // produced many times per second. Synchronised via decoder monitor. // Accessed on main and state machine threads. bool mPositionChangeQueued; // True if the audio playback thread has finished. It is finished
--- a/content/media/MediaResource.cpp +++ b/content/media/MediaResource.cpp @@ -343,17 +343,16 @@ ChannelMediaResource::OnStartRequest(nsI if (seekable && boundedSeekLimit) { // If range requests are supported, and we did not see an unbounded // upper range limit, we assume the resource is bounded. dataIsBounded = true; } mDecoder->SetInfinite(!dataIsBounded); } - mDecoder->SetTransportSeekable(seekable); mCacheStream.SetTransportSeekable(seekable); { MutexAutoLock lock(mLock); mIsTransportSeekable = seekable; mChannelStatistics->Start(); }
--- a/content/media/RtspMediaResource.cpp +++ b/content/media/RtspMediaResource.cpp @@ -602,34 +602,31 @@ RtspMediaResource::OnConnected(uint8_t a if (!mDecoder) { return NS_ERROR_FAILURE; } // If the duration is 0, imply the stream is live stream. if (duration) { // Not live stream. mRealTime = false; - bool seekable = true; mDecoder->SetInfinite(false); - mDecoder->SetTransportSeekable(seekable); mDecoder->SetDuration(duration); } else { // Live stream. // Check the preference "media.realtime_decoder.enabled". if (!Preferences::GetBool("media.realtime_decoder.enabled", false)) { // Give up, report error to media element. nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(mDecoder, &MediaDecoder::DecodeError); NS_DispatchToMainThread(event); return NS_ERROR_FAILURE; } else { mRealTime = true; bool seekable = false; mDecoder->SetInfinite(true); - mDecoder->SetTransportSeekable(seekable); mDecoder->SetMediaSeekable(seekable); } } // Fires an initial progress event and sets up the stall counter so stall events // fire if no download occurs within the required time frame. mDecoder->Progress(false); MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
--- a/content/media/apple/AppleMP3Reader.cpp +++ b/content/media/apple/AppleMP3Reader.cpp @@ -324,16 +324,22 @@ AppleMP3Reader::HasAudio() bool AppleMP3Reader::HasVideo() { MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread"); return false; } +bool +AppleMP3Reader::IsMediaSeekable() +{ + // not used + return true; +} /* * Query the MP3 parser for a piece of metadata. */ static nsresult GetProperty(AudioFileStreamID aAudioFileStream, AudioFileStreamPropertyID aPropertyID, void *aData) {
--- a/content/media/apple/AppleMP3Reader.h +++ b/content/media/apple/AppleMP3Reader.h @@ -46,16 +46,18 @@ public: void AudioMetadataCallback(AudioFileStreamID aFileStream, AudioFileStreamPropertyID aPropertyID, UInt32 *aFlags); virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) MOZ_OVERRIDE; + virtual bool IsMediaSeekable() MOZ_OVERRIDE; + private: void SetupDecoder(); nsresult Read(uint32_t *aNumBytes, char *aData); static OSStatus PassthroughInputDataCallback(AudioConverterRef aAudioConverter, UInt32 *aNumDataPackets, AudioBufferList *aData, AudioStreamPacketDescription **aPacketDesc,
--- a/content/media/directshow/DirectShowReader.cpp +++ b/content/media/directshow/DirectShowReader.cpp @@ -206,20 +206,16 @@ DirectShowReader::ReadMetadata(MediaInfo *aTags = nullptr; // Begin decoding! hr = mControl->Run(); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); DWORD seekCaps = 0; hr = mMediaSeeking->GetCapabilities(&seekCaps); - bool canSeek = ((AM_SEEKING_CanSeekAbsolute & seekCaps) == AM_SEEKING_CanSeekAbsolute); - if (!canSeek) { - mDecoder->SetMediaSeekable(false); - } int64_t duration = mMP3FrameParser.GetDuration(); if (SUCCEEDED(hr)) { ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); mDecoder->SetMediaDuration(duration); } LOG("Successfully initialized DirectShow MP3 decoder."); @@ -227,16 +223,25 @@ DirectShowReader::ReadMetadata(MediaInfo mInfo.mAudio.mChannels, mInfo.mAudio.mRate, RefTimeToUsecs(duration), mBytesPerSample); return NS_OK; } +bool +DirectShowReader::IsMediaSeekable() +{ + DWORD seekCaps = 0; + HRESULT hr = mMediaSeeking->GetCapabilities(&seekCaps); + return ((AM_SEEKING_CanSeekAbsolute & seekCaps) == + AM_SEEKING_CanSeekAbsolute); +} + inline float UnsignedByteToAudioSample(uint8_t aValue) { return aValue * (2.0f / UINT8_MAX) - 1.0f; } bool DirectShowReader::Finish(HRESULT aStatus)
--- a/content/media/directshow/DirectShowReader.h +++ b/content/media/directshow/DirectShowReader.h @@ -64,16 +64,18 @@ public: int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) MOZ_OVERRIDE; void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) MOZ_OVERRIDE; + bool IsMediaSeekable() MOZ_OVERRIDE; + private: // Notifies the filter graph that playback is complete. aStatus is // the code to send to the filter graph. Always returns false, so // that we can just "return Finish()" from DecodeAudioData(). bool Finish(HRESULT aStatus); // DirectShow filter graph, and associated playback and seeking
--- a/content/media/fmp4/MP4Reader.cpp +++ b/content/media/fmp4/MP4Reader.cpp @@ -238,29 +238,32 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo } // Get the duration, and report it to the decoder if we have it. Microseconds duration = mDemuxer->Duration(); if (duration != -1) { ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); mDecoder->SetMediaDuration(duration); } - // We can seek if we get a duration *and* the reader reports that it's - // seekable. - if (!mDecoder->GetResource()->IsTransportSeekable() || !mDemuxer->CanSeek()) { - mDecoder->SetMediaSeekable(false); - } *aInfo = mInfo; *aTags = nullptr; return NS_OK; } bool +MP4Reader::IsMediaSeekable() +{ + // We can seek if we get a duration *and* the reader reports that it's + // seekable. + return mDecoder->GetResource()->IsTransportSeekable() && mDemuxer->CanSeek(); +} + +bool MP4Reader::HasAudio() { return mAudio.mActive; } bool MP4Reader::HasVideo() {
--- a/content/media/fmp4/MP4Reader.h +++ b/content/media/fmp4/MP4Reader.h @@ -44,16 +44,19 @@ public: virtual nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) MOZ_OVERRIDE; virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) MOZ_OVERRIDE; + + virtual bool IsMediaSeekable() MOZ_OVERRIDE; + private: // Destroys all decoder resources. void Shutdown(); // Initializes mLayersBackendType if possible. void InitLayersBackendType();
--- a/content/media/gstreamer/GStreamerReader.cpp +++ b/content/media/gstreamer/GStreamerReader.cpp @@ -432,18 +432,16 @@ nsresult GStreamerReader::ReadMetadata(M GstFormat format = GST_FORMAT_TIME; if (gst_element_query_duration(GST_ELEMENT(mPlayBin), &format, &duration) && format == GST_FORMAT_TIME) { #endif ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); LOG(PR_LOG_DEBUG, "have duration %" GST_TIME_FORMAT, GST_TIME_ARGS(duration)); duration = GST_TIME_AS_USECONDS (duration); mDecoder->SetMediaDuration(duration); - } else { - mDecoder->SetMediaSeekable(false); } } int n_video = 0, n_audio = 0; g_object_get(mPlayBin, "n-video", &n_video, "n-audio", &n_audio, nullptr); mInfo.mVideo.mHasVideo = n_video != 0; mInfo.mAudio.mHasAudio = n_audio != 0; @@ -460,16 +458,38 @@ nsresult GStreamerReader::ReadMetadata(M /* set the pipeline to PLAYING so that it starts decoding and queueing data in * the appsinks */ gst_element_set_state(mPlayBin, GST_STATE_PLAYING); return NS_OK; } +bool +GStreamerReader::IsMediaSeekable() +{ + if (mUseParserDuration) { + return true; + } + + gint64 duration; +#if GST_VERSION_MAJOR >= 1 + if (gst_element_query_duration(GST_ELEMENT(mPlayBin), GST_FORMAT_TIME, + &duration)) { +#else + GstFormat format = GST_FORMAT_TIME; + if (gst_element_query_duration(GST_ELEMENT(mPlayBin), &format, &duration) && + format == GST_FORMAT_TIME) { +#endif + return true; + } + + return false; +} + nsresult GStreamerReader::CheckSupportedFormats() { bool done = false; bool unsupported = false; GstIterator* it = gst_bin_iterate_recurse(GST_BIN(mPlayBin)); while (!done) { GstIteratorResult res;
--- a/content/media/gstreamer/GStreamerReader.h +++ b/content/media/gstreamer/GStreamerReader.h @@ -63,16 +63,18 @@ public: } virtual bool HasVideo() { return mInfo.HasVideo(); } layers::ImageContainer* GetImageContainer() { return mDecoder->GetImageContainer(); } + virtual bool IsMediaSeekable() MOZ_OVERRIDE; + private: void ReadAndPushData(guint aLength); nsRefPtr<layers::PlanarYCbCrImage> GetImageFromBuffer(GstBuffer* aBuffer); void CopyIntoImageBuffer(GstBuffer *aBuffer, GstBuffer** aOutBuffer, nsRefPtr<layers::PlanarYCbCrImage> &image); GstCaps* BuildAudioSinkCaps(); void InstallPadCallbacks();
--- a/content/media/mediasource/MediaSourceDecoder.cpp +++ b/content/media/mediasource/MediaSourceDecoder.cpp @@ -138,16 +138,18 @@ public: return mInfo.HasVideo(); } bool HasAudio() MOZ_OVERRIDE { return mInfo.HasAudio(); } + bool IsMediaSeekable() { return true; } + nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) MOZ_OVERRIDE; nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) MOZ_OVERRIDE; nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime) MOZ_OVERRIDE; already_AddRefed<SubBufferDecoder> CreateSubDecoder(const nsACString& aType, MediaSourceDecoder* aParentDecoder, MediaTaskQueue* aTaskQueue); @@ -508,19 +510,16 @@ MediaSourceReader::GetBuffered(dom::Time } aBuffered->Normalize(); return NS_OK; } nsresult MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) { - mDecoder->SetMediaSeekable(true); - mDecoder->SetTransportSeekable(false); - MSE_DEBUG("%p: MSR::ReadMetadata pending=%u", this, mPendingDecoders.Length()); InitializePendingDecoders(); MSE_DEBUG("%p: MSR::ReadMetadata decoders=%u", this, mDecoders.Length()); // XXX: Make subdecoder setup async, so that use cases like bug 989888 can // work. This will require teaching the state machine about dynamic track
--- a/content/media/mediasource/SourceBuffer.cpp +++ b/content/media/mediasource/SourceBuffer.cpp @@ -85,22 +85,16 @@ SubBufferDecoder::UpdateEstimatedMediaDu } void SubBufferDecoder::SetMediaSeekable(bool aMediaSeekable) { //mParentDecoder->SetMediaSeekable(aMediaSeekable); } -void -SubBufferDecoder::SetTransportSeekable(bool aTransportSeekable) -{ - //mParentDecoder->SetTransportSeekable(aTransportSeekable); -} - layers::ImageContainer* SubBufferDecoder::GetImageContainer() { return mParentDecoder->GetImageContainer(); } MediaDecoderOwner* SubBufferDecoder::GetOwner()
--- a/content/media/mediasource/SubBufferDecoder.h +++ b/content/media/mediasource/SubBufferDecoder.h @@ -39,17 +39,16 @@ public: virtual ReentrantMonitor& GetReentrantMonitor() MOZ_OVERRIDE; virtual bool OnStateMachineThread() const MOZ_OVERRIDE; virtual bool OnDecodeThread() const MOZ_OVERRIDE; virtual SourceBufferResource* GetResource() const MOZ_OVERRIDE; virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded) MOZ_OVERRIDE; virtual void SetMediaDuration(int64_t aDuration) MOZ_OVERRIDE; virtual void UpdateEstimatedMediaDuration(int64_t aDuration) MOZ_OVERRIDE; virtual void SetMediaSeekable(bool aMediaSeekable) MOZ_OVERRIDE; - virtual void SetTransportSeekable(bool aTransportSeekable) MOZ_OVERRIDE; virtual layers::ImageContainer* GetImageContainer() MOZ_OVERRIDE; virtual MediaDecoderOwner* GetOwner() MOZ_OVERRIDE; void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) { mReader->NotifyDataArrived(aBuffer, aLength, aOffset); // XXX: Params make no sense to parent decoder as it relates to a
--- a/content/media/ogg/OggReader.cpp +++ b/content/media/ogg/OggReader.cpp @@ -373,31 +373,34 @@ nsresult OggReader::ReadMetadata(MediaIn ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor()); endTime = RangeEndTime(length); } if (endTime != -1) { mDecoder->SetMediaEndTime(endTime); LOG(PR_LOG_DEBUG, ("Got Ogg duration from seeking to end %lld", endTime)); } mDecoder->GetResource()->EndSeekingForMetadata(); - } else if (mDecoder->GetMediaDuration() == -1) { - // We don't have a duration, and we don't know enough about the resource - // to try a seek. Abort trying to get a duration. This happens for example - // when the server says it accepts range requests, but does not give us a - // Content-Length. - mDecoder->SetTransportSeekable(false); } } else { return NS_ERROR_FAILURE; } *aInfo = mInfo; return NS_OK; } +bool +OggReader::IsMediaSeekable() +{ + if (mIsChained) { + return false; + } + return true; +} + nsresult OggReader::DecodeVorbis(ogg_packet* aPacket) { NS_ASSERTION(aPacket->granulepos != -1, "Must know vorbis granulepos!"); if (vorbis_synthesis(&mVorbisState->mBlock, aPacket) != 0) { return NS_ERROR_FAILURE; } if (vorbis_synthesis_blockin(&mVorbisState->mDsp, &mVorbisState->mBlock) != 0)
--- a/content/media/ogg/OggReader.h +++ b/content/media/ogg/OggReader.h @@ -73,16 +73,18 @@ public: return mTheoraState != 0 && mTheoraState->mActive; } virtual nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags); virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime); virtual nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime); + virtual bool IsMediaSeekable() MOZ_OVERRIDE; + private: // This monitor should be taken when reading or writing to mIsChained. ReentrantMonitor mMonitor; // Specialized Reset() method to signal if the seek is // to the start of the stream. nsresult ResetDecode(bool start);
--- a/content/media/omx/MediaOmxReader.cpp +++ b/content/media/omx/MediaOmxReader.cpp @@ -156,19 +156,16 @@ nsresult MediaOmxReader::ReadMetadata(Me // Set the total duration (the max of the audio and video track). int64_t durationUs; mOmxDecoder->GetDuration(&durationUs); if (durationUs) { ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); mDecoder->SetMediaDuration(durationUs); } - // Check the MediaExtract flag if the source is seekable. - mDecoder->SetMediaSeekable(mExtractor->flags() & MediaExtractor::CAN_SEEK); - if (mOmxDecoder->HasVideo()) { int32_t displayWidth, displayHeight, width, height; mOmxDecoder->GetVideoParameters(&displayWidth, &displayHeight, &width, &height); nsIntRect pictureRect(0, 0, width, height); // Validate the container-reported frame and pictureRect sizes. This ensures // that our video frame creation code doesn't overflow. @@ -199,16 +196,23 @@ nsresult MediaOmxReader::ReadMetadata(Me mInfo.mAudio.mRate = sampleRate; } *aInfo = mInfo; return NS_OK; } +bool +MediaOmxReader::IsMediaSeekable() +{ + // Check the MediaExtract flag if the source is seekable. + return (mExtractor->flags() & MediaExtractor::CAN_SEEK); +} + bool MediaOmxReader::DecodeVideoFrame(bool &aKeyframeSkip, int64_t aTimeThreshold) { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); EnsureActive(); // Record number of frames decoded and parsed. Automatically update the // stats counters using the AutoNotifyDecoded stack-based class.
--- a/content/media/omx/MediaOmxReader.h +++ b/content/media/omx/MediaOmxReader.h @@ -79,16 +79,18 @@ public: virtual bool IsDormantNeeded(); virtual void ReleaseMediaResources(); virtual nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags); virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime); + virtual bool IsMediaSeekable() MOZ_OVERRIDE; + virtual void SetIdle() MOZ_OVERRIDE; virtual void Shutdown() MOZ_OVERRIDE; void SetAudioChannel(dom::AudioChannel aAudioChannel) { mAudioChannel = aAudioChannel; }
--- a/content/media/plugins/MediaPluginReader.h +++ b/content/media/plugins/MediaPluginReader.h @@ -56,16 +56,22 @@ public: return mHasAudio; } virtual bool HasVideo() { return mHasVideo; } + virtual bool IsMediaSeekable() + { + // not used + return true; + } + virtual nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags); virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime); virtual void Shutdown() MOZ_OVERRIDE; class ImageBufferCallback : public MPAPI::BufferCallback { typedef mozilla::layers::Image Image;
--- a/content/media/raw/RawReader.cpp +++ b/content/media/raw/RawReader.cpp @@ -107,16 +107,23 @@ nsresult RawReader::ReadMetadata(MediaIn *aInfo = mInfo; *aTags = nullptr; return NS_OK; } +bool +RawReader::IsMediaSeekable() +{ + // not used + return true; +} + bool RawReader::DecodeAudioData() { NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(), "Should be on state machine thread or decode thread."); return false; } // Helper method that either reads until it gets aLength bytes
--- a/content/media/raw/RawReader.h +++ b/content/media/raw/RawReader.h @@ -34,16 +34,18 @@ public: return true; } virtual nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags); virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime); virtual nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime); + virtual bool IsMediaSeekable() MOZ_OVERRIDE; + private: bool ReadFromResource(MediaResource *aResource, uint8_t *aBuf, uint32_t aLength); RawVideoHeader mMetadata; uint32_t mCurrentFrame; double mFrameRate; uint32_t mFrameSize; nsIntRect mPicture;
--- a/content/media/wave/WaveReader.cpp +++ b/content/media/wave/WaveReader.cpp @@ -153,16 +153,23 @@ nsresult WaveReader::ReadMetadata(MediaI ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); mDecoder->SetMediaDuration( static_cast<int64_t>(BytesToTime(GetDataLength()) * USECS_PER_S)); return NS_OK; } +bool +WaveReader::IsMediaSeekable() +{ + // not used + return true; +} + template <typename T> T UnsignedByteToAudioSample(uint8_t aValue); template <typename T> T SignedShortToAudioSample(int16_t aValue); template <> inline float UnsignedByteToAudioSample<float>(uint8_t aValue) { return aValue * (2.0f / UINT8_MAX) - 1.0f; }
--- a/content/media/wave/WaveReader.h +++ b/content/media/wave/WaveReader.h @@ -43,16 +43,18 @@ public: virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime); virtual nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime); // To seek in a buffered range, we just have to seek the stream. virtual bool IsSeekableInBufferedRanges() { return true; } + virtual bool IsMediaSeekable() MOZ_OVERRIDE; + private: bool ReadAll(char* aBuf, int64_t aSize, int64_t* aBytesRead = nullptr); bool LoadRIFFChunk(); bool GetNextChunk(uint32_t* aChunk, uint32_t* aChunkSize); bool LoadFormatChunk(uint32_t aChunkSize); bool FindDataOffset(uint32_t aChunkSize); bool LoadListChunk(uint32_t aChunkSize, nsAutoPtr<dom::HTMLMediaElement::MetadataTags> &aTags); bool LoadAllChunks(nsAutoPtr<dom::HTMLMediaElement::MetadataTags> &aTags);
--- a/content/media/webm/WebMReader.cpp +++ b/content/media/webm/WebMReader.cpp @@ -459,26 +459,29 @@ nsresult WebMReader::ReadMetadata(MediaI #endif } else { Cleanup(); return NS_ERROR_FAILURE; } } } - // We can't seek in buffered regions if we have no cues. - mDecoder->SetMediaSeekable(nestegg_has_cues(mContext) == 1); - *aInfo = mInfo; *aTags = nullptr; return NS_OK; } +bool +WebMReader::IsMediaSeekable() +{ + return mContext && nestegg_has_cues(mContext); +} + #ifdef MOZ_OPUS bool WebMReader::InitOpusDecoder() { int r; NS_ASSERTION(mOpusDecoder == nullptr, "leaking OpusDecoder"); mOpusDecoder = opus_multistream_decoder_create(mOpusParser->mRate,
--- a/content/media/webm/WebMReader.h +++ b/content/media/webm/WebMReader.h @@ -130,16 +130,18 @@ public: } virtual nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags); virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime); virtual nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime); virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset); + virtual bool IsMediaSeekable() MOZ_OVERRIDE; + protected: // Value passed to NextPacket to determine if we are reading a video or an // audio packet. enum TrackType { VIDEO = 0, AUDIO = 1 };
--- a/content/media/wmf/WMFReader.cpp +++ b/content/media/wmf/WMFReader.cpp @@ -536,34 +536,42 @@ WMFReader::ReadMetadata(MediaInfo* aInfo // Get the duration, and report it to the decoder if we have it. int64_t duration = 0; hr = GetSourceReaderDuration(mSourceReader, duration); if (SUCCEEDED(hr)) { ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); mDecoder->SetMediaEndTime(duration); } - // We can seek if we get a duration *and* the reader reports that it's - // seekable. - bool canSeek = false; - if (FAILED(hr) || - FAILED(GetSourceReaderCanSeek(mSourceReader, canSeek)) || - !canSeek) { - mDecoder->SetMediaSeekable(false); - } *aInfo = mInfo; *aTags = nullptr; // aTags can be retrieved using techniques like used here: // http://blogs.msdn.com/b/mf/archive/2010/01/12/mfmediapropdump.aspx return NS_OK; } bool +WMFReader::IsMediaSeekable() +{ + // Get the duration + int64_t duration = 0; + HRESULT hr = GetSourceReaderDuration(mSourceReader, duration); + // We can seek if we get a duration *and* the reader reports that it's + // seekable. + bool canSeek = false; + if (FAILED(hr) || FAILED(GetSourceReaderCanSeek(mSourceReader, canSeek)) || + !canSeek) { + return false; + } + return true; +} + +bool WMFReader::DecodeAudioData() { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); HRESULT hr; hr = mSourceReader->ReadSample(MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, // control flags 0, // read stream index
--- a/content/media/wmf/WMFReader.h +++ b/content/media/wmf/WMFReader.h @@ -42,16 +42,19 @@ public: nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) MOZ_OVERRIDE; nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) MOZ_OVERRIDE; + + bool IsMediaSeekable() MOZ_OVERRIDE; + private: HRESULT CreateSourceReader(); HRESULT ConfigureAudioDecoder(); HRESULT ConfigureVideoDecoder(); HRESULT ConfigureVideoFrameGeometry(IMFMediaType* aMediaType); void GetSupportedAudioCodecs(const GUID** aCodecs, uint32_t* aNumCodecs);