Bug 1065219 - Move track format rejection from switch to init time. r=cajbir

This commit is contained in:
Matthew Gregan 2014-09-10 14:21:17 +12:00
parent aac36c1acd
commit 925a080866
4 changed files with 63 additions and 81 deletions

View File

@ -227,44 +227,8 @@ MediaSourceReader::BreakCycles()
mTrackBuffers.Clear();
}
bool
MediaSourceReader::CanSelectAudioReader(MediaDecoderReader* aNewReader)
{
AudioInfo currentInfo = mAudioReader->GetMediaInfo().mAudio;
AudioInfo newInfo = aNewReader->GetMediaInfo().mAudio;
// TODO: We can't handle switching audio formats yet.
if (currentInfo.mRate != newInfo.mRate ||
currentInfo.mChannels != newInfo.mChannels) {
MSE_DEBUGV("MediaSourceReader(%p)::CanSelectAudioReader(%p) skip reader due to format mismatch",
this, aNewReader);
return false;
}
if (aNewReader->AudioQueue().AtEndOfStream()) {
MSE_DEBUGV("MediaSourceReader(%p)::CanSelectAudioReader(%p) skip reader due to queue EOS",
this, aNewReader);
return false;
}
return true;
}
bool
MediaSourceReader::CanSelectVideoReader(MediaDecoderReader* aNewReader)
{
if (aNewReader->VideoQueue().AtEndOfStream()) {
MSE_DEBUGV("MediaSourceReader(%p)::CanSelectVideoReader(%p) skip reader due to queue EOS",
this, aNewReader);
return false;
}
return true;
}
already_AddRefed<MediaDecoderReader>
MediaSourceReader::SelectReader(int64_t aTarget,
bool (MediaSourceReader::*aCanSelectReader)(MediaDecoderReader*),
const nsTArray<nsRefPtr<SourceBufferDecoder>>& aTrackDecoders)
{
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
@ -274,13 +238,6 @@ MediaSourceReader::SelectReader(int64_t aTarget,
for (int32_t i = aTrackDecoders.Length() - 1; i >= 0; --i) {
nsRefPtr<MediaDecoderReader> newReader = aTrackDecoders[i]->GetReader();
// Check the track-type-specific aspects first, as it's assumed these
// are cheaper than a buffered range comparison, which seems worthwhile
// to avoid on any reader we'd subsequently reject.
if (!(this->*aCanSelectReader)(newReader)) {
continue;
}
nsRefPtr<dom::TimeRanges> ranges = new dom::TimeRanges();
aTrackDecoders[i]->GetBuffered(ranges);
if (ranges->Find(double(aTarget) / USECS_PER_S) == dom::TimeRanges::NoIndex) {
@ -303,9 +260,7 @@ MediaSourceReader::SwitchAudioReader(int64_t aTarget)
if (!mAudioTrack) {
return false;
}
nsRefPtr<MediaDecoderReader> newReader = SelectReader(aTarget,
&MediaSourceReader::CanSelectAudioReader,
mAudioTrack->Decoders());
nsRefPtr<MediaDecoderReader> newReader = SelectReader(aTarget, mAudioTrack->Decoders());
if (newReader && newReader != mAudioReader) {
mAudioReader->SetIdle();
mAudioReader = newReader;
@ -323,9 +278,7 @@ MediaSourceReader::SwitchVideoReader(int64_t aTarget)
if (!mVideoTrack) {
return false;
}
nsRefPtr<MediaDecoderReader> newReader = SelectReader(aTarget,
&MediaSourceReader::CanSelectVideoReader,
mVideoTrack->Decoders());
nsRefPtr<MediaDecoderReader> newReader = SelectReader(aTarget, mVideoTrack->Decoders());
if (newReader && newReader != mVideoReader) {
mVideoReader->SetIdle();
mVideoReader = newReader;

View File

@ -105,22 +105,11 @@ private:
bool SwitchAudioReader(int64_t aTarget);
bool SwitchVideoReader(int64_t aTarget);
// Return a reader from the set available in aTrackDecoders that is considered
// usable by the aCanUserReader callback and has data available in the range
// requested by aTarget.
// aCanSelectReader is passed each reader available in aTrackDecoders and is
// expected to return true if the reader is considerable selectable.
// Return a reader from the set available in aTrackDecoders that has data
// available in the range requested by aTarget.
already_AddRefed<MediaDecoderReader> SelectReader(int64_t aTarget,
bool (MediaSourceReader::*aCanSelectReader)(MediaDecoderReader*),
const nsTArray<nsRefPtr<SourceBufferDecoder>>& aTrackDecoders);
// Passed to SelectReader to enforce any track format specific requirements.
// In the case of CanSelectAudioReader, verifies that aNewReader has a
// matching audio format to the existing reader, as format switching is not
// yet supported.
bool CanSelectAudioReader(MediaDecoderReader* aNewReader);
bool CanSelectVideoReader(MediaDecoderReader* aNewReader);
// Waits on the decoder monitor for aTime to become available in the active
// TrackBuffers. Used to block a Seek call until the necessary data has been
// provided to the relevant SourceBuffers.

View File

@ -49,8 +49,6 @@ TrackBuffer::TrackBuffer(MediaSourceDecoder* aParentDecoder, const nsACString& a
, mLastStartTimestamp(0)
, mLastEndTimestamp(0)
, mHasInit(false)
, mHasAudio(false)
, mHasVideo(false)
{
MOZ_COUNT_CTOR(TrackBuffer);
mTaskQueue = new MediaTaskQueue(GetMediaDecodeThreadPool());
@ -218,11 +216,7 @@ TrackBuffer::InitializeDecoder(nsRefPtr<SourceBufferDecoder> aDecoder)
MSE_DEBUG("TrackBuffer(%p): Reader %p failed to initialize rv=%x audio=%d video=%d",
this, reader, rv, mi.HasAudio(), mi.HasVideo());
aDecoder->SetTaskQueue(nullptr);
{
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
mDecoders.RemoveElement(aDecoder);
}
NS_DispatchToMainThread(new ReleaseDecoderTask(aDecoder));
RemoveDecoder(aDecoder);
return;
}
@ -235,11 +229,36 @@ TrackBuffer::InitializeDecoder(nsRefPtr<SourceBufferDecoder> aDecoder)
this, reader, mi.mAudio.mRate, mi.mAudio.mChannels);
}
if (!RegisterDecoder(aDecoder)) {
// XXX: Need to signal error back to owning SourceBuffer.
MSE_DEBUG("TrackBuffer(%p): Reader %p not activated", this, reader);
RemoveDecoder(aDecoder);
return;
}
MSE_DEBUG("TrackBuffer(%p): Reader %p activated", this, reader);
RegisterDecoder(aDecoder);
}
void
bool
TrackBuffer::ValidateTrackFormats(const MediaInfo& aInfo)
{
if (mInfo.HasAudio() != aInfo.HasAudio() ||
mInfo.HasVideo() != aInfo.HasVideo()) {
MSE_DEBUG("TrackBuffer(%p)::ValidateTrackFormats audio/video track mismatch", this);
return false;
}
// TODO: Support dynamic audio format changes.
if (mInfo.HasAudio() &&
(mInfo.mAudio.mRate != aInfo.mAudio.mRate ||
mInfo.mAudio.mChannels != aInfo.mAudio.mChannels)) {
MSE_DEBUG("TrackBuffer(%p)::ValidateTrackFormats audio format mismatch", this);
return false;
}
return true;
}
bool
TrackBuffer::RegisterDecoder(nsRefPtr<SourceBufferDecoder> aDecoder)
{
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
@ -247,14 +266,16 @@ TrackBuffer::RegisterDecoder(nsRefPtr<SourceBufferDecoder> aDecoder)
const MediaInfo& info = aDecoder->GetReader()->GetMediaInfo();
// Initialize the track info since this is the first decoder.
if (mInitializedDecoders.IsEmpty()) {
mHasAudio = info.HasAudio();
mHasVideo = info.HasVideo();
mParentDecoder->OnTrackBufferConfigured(this, info);
} else if ((info.HasAudio() && !mHasAudio) || (info.HasVideo() && !mHasVideo)) {
mInfo = info;
mParentDecoder->OnTrackBufferConfigured(this, mInfo);
}
if (!ValidateTrackFormats(info)) {
MSE_DEBUG("TrackBuffer(%p)::RegisterDecoder with mismatched audio/video tracks", this);
return false;
}
mInitializedDecoders.AppendElement(aDecoder);
mParentDecoder->NotifyTimeRangesChanged();
return true;
}
void
@ -287,8 +308,8 @@ bool
TrackBuffer::IsReady()
{
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
MOZ_ASSERT((mHasAudio || mHasVideo) || mInitializedDecoders.IsEmpty());
return HasInitSegment() && (mHasAudio || mHasVideo);
MOZ_ASSERT((mInfo.HasAudio() || mInfo.HasVideo()) || mInitializedDecoders.IsEmpty());
return HasInitSegment() && (mInfo.HasAudio() || mInfo.HasVideo());
}
void
@ -373,4 +394,13 @@ TrackBuffer::Dump(const char* aPath)
}
#endif
void
TrackBuffer::RemoveDecoder(nsRefPtr<SourceBufferDecoder> aDecoder)
{
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
MOZ_ASSERT(!mInitializedDecoders.Contains(aDecoder));
mDecoders.RemoveElement(aDecoder);
NS_DispatchToMainThread(new ReleaseDecoderTask(aDecoder));
}
} // namespace mozilla

View File

@ -98,8 +98,19 @@ private:
// Adds a successfully initialized decoder to mDecoders and (if it's the
// first decoder initialized), initializes mHasAudio/mHasVideo. Called
// from the decode thread pool.
void RegisterDecoder(nsRefPtr<SourceBufferDecoder> aDecoder);
// from the decode thread pool. Return true if the decoder was
// successfully registered.
bool RegisterDecoder(nsRefPtr<SourceBufferDecoder> aDecoder);
// Returns true if aInfo is considered a supported or the same format as
// the TrackBuffer was initialized as.
bool ValidateTrackFormats(const MediaInfo& aInfo);
// Remove aDecoder from mDecoders and dispatch an event to the main thread
// to clean up the decoder. If aDecoder was added to
// mInitializedDecoders, it must have been removed before calling this
// function.
void RemoveDecoder(nsRefPtr<SourceBufferDecoder> aDecoder);
// A task queue using the shared media thread pool. Used exclusively to
// initialize (i.e. call ReadMetadata on) decoders as they are created via
@ -131,8 +142,7 @@ private:
// Set when the first decoder used by this TrackBuffer is initialized.
// Protected by mParentDecoder's monitor.
bool mHasAudio;
bool mHasVideo;
MediaInfo mInfo;
};
} // namespace mozilla