Bug 1015985 - Set decoder seekable members outside of ReadMetadata by StateMachine. r=cpearce

This commit is contained in:
Eric Phan 2014-06-23 22:08:34 +12:00
Родитель dfd6c3f511
Коммит 297a9b2844
35 изменённых файлов: 153 добавлений и 135 удалений

Просмотреть файл

@ -2527,7 +2527,6 @@ nsresult HTMLMediaElement::InitializeDecoderAsClone(MediaDecoder* aOriginal)
double duration = aOriginal->GetDuration();
if (duration >= 0) {
decoder->SetDuration(duration);
decoder->SetTransportSeekable(aOriginal->IsTransportSeekable());
decoder->SetMediaSeekable(aOriginal->IsMediaSeekable());
}

Просмотреть файл

@ -80,9 +80,6 @@ public:
// 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;

Просмотреть файл

@ -120,12 +120,6 @@ BufferDecoder::SetMediaSeekable(bool aMediaSeekable)
// ignore
}
void
BufferDecoder::SetTransportSeekable(bool aTransportSeekable)
{
// ignore
}
VideoFrameContainer*
BufferDecoder::GetVideoFrameContainer()
{

Просмотреть файл

@ -54,8 +54,6 @@ public:
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;

Просмотреть файл

@ -417,7 +417,6 @@ MediaDecoder::MediaDecoder() :
mInitialPlaybackRate(1.0),
mInitialPreservesPitch(true),
mDuration(-1),
mTransportSeekable(true),
mMediaSeekable(true),
mSameOriginMedia(false),
mReentrantMonitor("media.decoder"),
@ -551,8 +550,6 @@ nsresult MediaDecoder::InitializeStateMachine(MediaDecoder* aCloneDonor)
}
{
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
mDecoderStateMachine->SetTransportSeekable(mTransportSeekable);
mDecoderStateMachine->SetMediaSeekable(mMediaSeekable);
mDecoderStateMachine->SetDuration(mDuration);
mDecoderStateMachine->SetVolume(mInitialVolume);
mDecoderStateMachine->SetAudioCaptured(mInitialAudioCaptured);
@ -1286,25 +1283,14 @@ 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()

Просмотреть файл

@ -608,7 +608,7 @@ public:
// 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;
@ -1037,10 +1037,6 @@ protected:
// 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;

Просмотреть файл

@ -173,6 +173,10 @@ public:
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();

Просмотреть файл

@ -202,8 +202,6 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
mAudioRequestPending(false),
mVideoRequestPending(false),
mAudioCaptured(false),
mTransportSeekable(true),
mMediaSeekable(true),
mPositionChangeQueued(false),
mAudioCompleted(false),
mGotDurationFromMetaData(false),
@ -1602,23 +1600,6 @@ void MediaDecoderStateMachine::SetFragmentEndTime(int64_t aEndTime)
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();
@ -1775,7 +1756,8 @@ void MediaDecoderStateMachine::Seek(const SeekTarget& aTarget)
// 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
@ -2186,15 +2168,21 @@ nsresult MediaDecoderStateMachine::DecodeMetadata()
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())) {
@ -2266,13 +2254,16 @@ MediaDecoderStateMachine::FinishDecodeMetadata()
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

Просмотреть файл

@ -209,17 +209,6 @@ public:
// 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.
@ -290,16 +279,6 @@ public:
return mEndTime;
}
bool IsTransportSeekable() {
AssertCurrentThreadInMonitor();
return mTransportSeekable;
}
bool IsMediaSeekable() {
AssertCurrentThreadInMonitor();
return mMediaSeekable;
}
// Returns the shared state machine thread.
nsIEventTarget* GetStateMachineThread();
@ -908,14 +887,6 @@ protected:
// 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

Просмотреть файл

@ -348,7 +348,6 @@ ChannelMediaResource::OnStartRequest(nsIRequest* aRequest)
mDecoder->SetInfinite(!dataIsBounded);
}
mDecoder->SetTransportSeekable(seekable);
mCacheStream.SetTransportSeekable(seekable);
{

Просмотреть файл

@ -607,9 +607,7 @@ RtspMediaResource::OnConnected(uint8_t aTrackIdx,
if (duration) {
// Not live stream.
mRealTime = false;
bool seekable = true;
mDecoder->SetInfinite(false);
mDecoder->SetTransportSeekable(seekable);
mDecoder->SetDuration(duration);
} else {
// Live stream.
@ -624,7 +622,6 @@ RtspMediaResource::OnConnected(uint8_t aTrackIdx,
mRealTime = true;
bool seekable = false;
mDecoder->SetInfinite(true);
mDecoder->SetTransportSeekable(seekable);
mDecoder->SetMediaSeekable(seekable);
}
}

Просмотреть файл

@ -329,6 +329,12 @@ AppleMP3Reader::HasVideo()
return false;
}
bool
AppleMP3Reader::IsMediaSeekable()
{
// not used
return true;
}
/*
* Query the MP3 parser for a piece of metadata.

Просмотреть файл

@ -51,6 +51,8 @@ public:
uint32_t aLength,
int64_t aOffset) MOZ_OVERRIDE;
virtual bool IsMediaSeekable() MOZ_OVERRIDE;
private:
void SetupDecoder();
nsresult Read(uint32_t *aNumBytes, char *aData);

Просмотреть файл

@ -211,10 +211,6 @@ DirectShowReader::ReadMetadata(MediaInfo* aInfo,
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)) {
@ -232,6 +228,15 @@ DirectShowReader::ReadMetadata(MediaInfo* aInfo,
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)
{

Просмотреть файл

@ -69,6 +69,8 @@ public:
uint32_t aLength,
int64_t aOffset) MOZ_OVERRIDE;
bool IsMediaSeekable() MOZ_OVERRIDE;
private:
// Notifies the filter graph that playback is complete. aStatus is

Просмотреть файл

@ -243,11 +243,6 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
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;
@ -255,6 +250,14 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
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()
{

Просмотреть файл

@ -49,6 +49,9 @@ public:
int64_t aStartTime,
int64_t aEndTime,
int64_t aCurrentTime) MOZ_OVERRIDE;
virtual bool IsMediaSeekable() MOZ_OVERRIDE;
private:
// Destroys all decoder resources.

Просмотреть файл

@ -437,8 +437,6 @@ nsresult GStreamerReader::ReadMetadata(MediaInfo* aInfo,
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);
}
}
@ -465,6 +463,28 @@ nsresult GStreamerReader::ReadMetadata(MediaInfo* aInfo,
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;

Просмотреть файл

@ -68,6 +68,8 @@ public:
layers::ImageContainer* GetImageContainer() { return mDecoder->GetImageContainer(); }
virtual bool IsMediaSeekable() MOZ_OVERRIDE;
private:
void ReadAndPushData(guint aLength);

Просмотреть файл

@ -143,6 +143,8 @@ public:
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;
@ -513,9 +515,6 @@ MediaSourceReader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
nsresult
MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags)
{
mDecoder->SetMediaSeekable(true);
mDecoder->SetTransportSeekable(false);
MSE_DEBUG("%p: MSR::ReadMetadata pending=%u", this, mPendingDecoders.Length());
InitializePendingDecoders();

Просмотреть файл

@ -90,12 +90,6 @@ SubBufferDecoder::SetMediaSeekable(bool aMediaSeekable)
//mParentDecoder->SetMediaSeekable(aMediaSeekable);
}
void
SubBufferDecoder::SetTransportSeekable(bool aTransportSeekable)
{
//mParentDecoder->SetTransportSeekable(aTransportSeekable);
}
layers::ImageContainer*
SubBufferDecoder::GetImageContainer()
{

Просмотреть файл

@ -44,7 +44,6 @@ public:
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;

Просмотреть файл

@ -378,12 +378,6 @@ nsresult OggReader::ReadMetadata(MediaInfo* aInfo,
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;
@ -393,6 +387,15 @@ nsresult OggReader::ReadMetadata(MediaInfo* aInfo,
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!");

Просмотреть файл

@ -78,6 +78,8 @@ 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);
virtual bool IsMediaSeekable() MOZ_OVERRIDE;
private:
// This monitor should be taken when reading or writing to mIsChained.
ReentrantMonitor mMonitor;

Просмотреть файл

@ -161,9 +161,6 @@ nsresult MediaOmxReader::ReadMetadata(MediaInfo* aInfo,
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,
@ -204,6 +201,13 @@ nsresult MediaOmxReader::ReadMetadata(MediaInfo* aInfo,
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)
{

Просмотреть файл

@ -84,6 +84,8 @@ public:
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;

Просмотреть файл

@ -61,6 +61,12 @@ public:
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);

Просмотреть файл

@ -112,6 +112,13 @@ nsresult RawReader::ReadMetadata(MediaInfo* aInfo,
return NS_OK;
}
bool
RawReader::IsMediaSeekable()
{
// not used
return true;
}
bool RawReader::DecodeAudioData()
{
NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),

Просмотреть файл

@ -39,6 +39,8 @@ 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);
virtual bool IsMediaSeekable() MOZ_OVERRIDE;
private:
bool ReadFromResource(MediaResource *aResource, uint8_t *aBuf, uint32_t aLength);

Просмотреть файл

@ -158,6 +158,13 @@ nsresult WaveReader::ReadMetadata(MediaInfo* aInfo,
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);

Просмотреть файл

@ -48,6 +48,8 @@ public:
return true;
}
virtual bool IsMediaSeekable() MOZ_OVERRIDE;
private:
bool ReadAll(char* aBuf, int64_t aSize, int64_t* aBytesRead = nullptr);
bool LoadRIFFChunk();

Просмотреть файл

@ -464,9 +464,6 @@ nsresult WebMReader::ReadMetadata(MediaInfo* aInfo,
}
}
// We can't seek in buffered regions if we have no cues.
mDecoder->SetMediaSeekable(nestegg_has_cues(mContext) == 1);
*aInfo = mInfo;
*aTags = nullptr;
@ -474,6 +471,12 @@ nsresult WebMReader::ReadMetadata(MediaInfo* aInfo,
return NS_OK;
}
bool
WebMReader::IsMediaSeekable()
{
return mContext && nestegg_has_cues(mContext);
}
#ifdef MOZ_OPUS
bool WebMReader::InitOpusDecoder()
{

Просмотреть файл

@ -135,6 +135,8 @@ public:
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.

Просмотреть файл

@ -541,14 +541,6 @@ WMFReader::ReadMetadata(MediaInfo* aInfo,
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;
@ -558,6 +550,22 @@ WMFReader::ReadMetadata(MediaInfo* aInfo,
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()
{

Просмотреть файл

@ -47,6 +47,9 @@ public:
int64_t aStartTime,
int64_t aEndTime,
int64_t aCurrentTime) MOZ_OVERRIDE;
bool IsMediaSeekable() MOZ_OVERRIDE;
private:
HRESULT CreateSourceReader();