2014-08-13 05:22:00 -07:00
|
|
|
/* -*- mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "MediaSourceReader.h"
|
|
|
|
|
2014-08-21 19:14:36 -07:00
|
|
|
#include "prlog.h"
|
2014-08-13 05:22:00 -07:00
|
|
|
#include "mozilla/dom/TimeRanges.h"
|
|
|
|
#include "DecoderTraits.h"
|
|
|
|
#include "MediaDataDecodedListener.h"
|
|
|
|
#include "MediaDecoderOwner.h"
|
|
|
|
#include "MediaSourceDecoder.h"
|
2014-08-20 01:07:00 -07:00
|
|
|
#include "MediaSourceUtils.h"
|
2014-08-21 19:14:36 -07:00
|
|
|
#include "SourceBufferDecoder.h"
|
2014-09-03 18:57:06 -07:00
|
|
|
#include "TrackBuffer.h"
|
2014-08-13 05:22:00 -07:00
|
|
|
|
|
|
|
#ifdef MOZ_FMP4
|
|
|
|
#include "MP4Decoder.h"
|
|
|
|
#include "MP4Reader.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef PR_LOGGING
|
|
|
|
extern PRLogModuleInfo* GetMediaSourceLog();
|
|
|
|
extern PRLogModuleInfo* GetMediaSourceAPILog();
|
|
|
|
|
|
|
|
#define MSE_DEBUG(...) PR_LOG(GetMediaSourceLog(), PR_LOG_DEBUG, (__VA_ARGS__))
|
|
|
|
#define MSE_DEBUGV(...) PR_LOG(GetMediaSourceLog(), PR_LOG_DEBUG+1, (__VA_ARGS__))
|
|
|
|
#define MSE_API(...) PR_LOG(GetMediaSourceAPILog(), PR_LOG_DEBUG, (__VA_ARGS__))
|
|
|
|
#else
|
|
|
|
#define MSE_DEBUG(...)
|
|
|
|
#define MSE_DEBUGV(...)
|
|
|
|
#define MSE_API(...)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
2014-08-24 21:09:44 -07:00
|
|
|
MediaSourceReader::MediaSourceReader(MediaSourceDecoder* aDecoder)
|
2014-08-13 05:22:00 -07:00
|
|
|
: MediaDecoderReader(aDecoder)
|
2014-09-03 18:57:06 -07:00
|
|
|
, mLastAudioTime(-1)
|
|
|
|
, mLastVideoTime(-1)
|
2014-08-13 05:22:00 -07:00
|
|
|
, mTimeThreshold(-1)
|
2014-08-20 20:14:48 -07:00
|
|
|
, mDropAudioBeforeThreshold(false)
|
2014-08-13 05:22:00 -07:00
|
|
|
, mDropVideoBeforeThreshold(false)
|
2014-08-26 00:25:09 -07:00
|
|
|
, mEnded(false)
|
2014-09-03 02:56:22 -07:00
|
|
|
, mAudioIsSeeking(false)
|
|
|
|
, mVideoIsSeeking(false)
|
2014-09-04 17:04:54 -07:00
|
|
|
, mHasEssentialTrackBuffers(false)
|
2014-08-13 05:22:00 -07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-09-04 17:04:54 -07:00
|
|
|
void
|
|
|
|
MediaSourceReader::PrepareInitialization()
|
|
|
|
{
|
|
|
|
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
|
|
|
MSE_DEBUG("MediaSourceReader(%p)::PrepareInitialization trackBuffers=%u",
|
|
|
|
this, mTrackBuffers.Length());
|
|
|
|
mEssentialTrackBuffers.AppendElements(mTrackBuffers);
|
|
|
|
mHasEssentialTrackBuffers = true;
|
|
|
|
mDecoder->NotifyWaitingForResourcesStatusChanged();
|
|
|
|
}
|
|
|
|
|
2014-08-13 05:22:00 -07:00
|
|
|
bool
|
|
|
|
MediaSourceReader::IsWaitingMediaResources()
|
|
|
|
{
|
2014-09-03 18:57:06 -07:00
|
|
|
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
2014-09-04 17:04:54 -07:00
|
|
|
|
|
|
|
for (uint32_t i = 0; i < mEssentialTrackBuffers.Length(); ++i) {
|
|
|
|
if (!mEssentialTrackBuffers[i]->IsReady()) {
|
2014-09-03 18:57:06 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2014-09-04 17:04:54 -07:00
|
|
|
|
|
|
|
return !mHasEssentialTrackBuffers;
|
2014-08-13 05:22:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaSourceReader::RequestAudioData()
|
|
|
|
{
|
2014-09-03 18:57:06 -07:00
|
|
|
MSE_DEBUGV("MediaSourceReader(%p)::RequestAudioData", this);
|
2014-08-20 20:14:48 -07:00
|
|
|
if (!mAudioReader) {
|
2014-08-13 05:22:00 -07:00
|
|
|
MSE_DEBUG("MediaSourceReader(%p)::RequestAudioData called with no audio reader", this);
|
|
|
|
GetCallback()->OnDecodeError();
|
|
|
|
return;
|
|
|
|
}
|
2014-09-07 21:55:20 -07:00
|
|
|
mAudioIsSeeking = false;
|
2014-09-09 19:27:51 -07:00
|
|
|
SwitchAudioReader(mLastAudioTime);
|
2014-08-20 20:14:48 -07:00
|
|
|
mAudioReader->RequestAudioData();
|
2014-08-13 05:22:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaSourceReader::OnAudioDecoded(AudioData* aSample)
|
|
|
|
{
|
2014-09-07 21:54:52 -07:00
|
|
|
MSE_DEBUGV("MediaSourceReader(%p)::OnAudioDecoded [mTime=%lld mDuration=%lld mDiscontinuity=%d]",
|
2014-09-03 18:57:06 -07:00
|
|
|
this, aSample->mTime, aSample->mDuration, aSample->mDiscontinuity);
|
2014-08-20 20:14:48 -07:00
|
|
|
if (mDropAudioBeforeThreshold) {
|
|
|
|
if (aSample->mTime < mTimeThreshold) {
|
|
|
|
MSE_DEBUG("MediaSourceReader(%p)::OnAudioDecoded mTime=%lld < mTimeThreshold=%lld",
|
|
|
|
this, aSample->mTime, mTimeThreshold);
|
|
|
|
delete aSample;
|
|
|
|
mAudioReader->RequestAudioData();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mDropAudioBeforeThreshold = false;
|
|
|
|
}
|
2014-09-03 02:56:22 -07:00
|
|
|
|
2014-09-07 21:55:20 -07:00
|
|
|
// Any OnAudioDecoded callbacks received while mAudioIsSeeking must be not
|
|
|
|
// update our last used timestamp, as these are emitted by the reader we're
|
|
|
|
// switching away from.
|
|
|
|
if (!mAudioIsSeeking) {
|
|
|
|
mLastAudioTime = aSample->mTime + aSample->mDuration;
|
2014-09-03 02:56:22 -07:00
|
|
|
}
|
2014-08-13 05:22:00 -07:00
|
|
|
GetCallback()->OnAudioDecoded(aSample);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaSourceReader::OnAudioEOS()
|
|
|
|
{
|
2014-09-03 18:57:06 -07:00
|
|
|
MSE_DEBUG("MediaSourceReader(%p)::OnAudioEOS reader=%p (decoders=%u)",
|
|
|
|
this, mAudioReader.get(), mAudioTrack->Decoders().Length());
|
2014-09-09 19:27:51 -07:00
|
|
|
if (SwitchAudioReader(mLastAudioTime)) {
|
2014-08-20 20:14:48 -07:00
|
|
|
// Success! Resume decoding with next audio decoder.
|
|
|
|
RequestAudioData();
|
2014-09-02 20:20:02 -07:00
|
|
|
} else if (IsEnded()) {
|
2014-08-20 20:14:48 -07:00
|
|
|
// End of stream.
|
2014-09-03 18:57:06 -07:00
|
|
|
MSE_DEBUG("MediaSourceReader(%p)::OnAudioEOS reader=%p EOS (decoders=%u)",
|
|
|
|
this, mAudioReader.get(), mAudioTrack->Decoders().Length());
|
2014-08-20 20:14:48 -07:00
|
|
|
GetCallback()->OnAudioEOS();
|
|
|
|
}
|
2014-08-13 05:22:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold)
|
|
|
|
{
|
2014-09-03 18:57:06 -07:00
|
|
|
MSE_DEBUGV("MediaSourceReader(%p)::RequestVideoData(%d, %lld)",
|
|
|
|
this, aSkipToNextKeyframe, aTimeThreshold);
|
2014-08-20 20:14:48 -07:00
|
|
|
if (!mVideoReader) {
|
2014-08-13 05:22:00 -07:00
|
|
|
MSE_DEBUG("MediaSourceReader(%p)::RequestVideoData called with no video reader", this);
|
|
|
|
GetCallback()->OnDecodeError();
|
|
|
|
return;
|
|
|
|
}
|
2014-09-03 18:57:06 -07:00
|
|
|
if (aSkipToNextKeyframe) {
|
|
|
|
mTimeThreshold = aTimeThreshold;
|
|
|
|
mDropAudioBeforeThreshold = true;
|
|
|
|
mDropVideoBeforeThreshold = true;
|
|
|
|
}
|
2014-09-07 21:55:20 -07:00
|
|
|
mVideoIsSeeking = false;
|
2014-09-09 19:27:51 -07:00
|
|
|
SwitchVideoReader(mLastVideoTime);
|
2014-08-20 20:14:48 -07:00
|
|
|
mVideoReader->RequestVideoData(aSkipToNextKeyframe, aTimeThreshold);
|
2014-08-13 05:22:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaSourceReader::OnVideoDecoded(VideoData* aSample)
|
|
|
|
{
|
2014-09-07 21:54:52 -07:00
|
|
|
MSE_DEBUGV("MediaSourceReader(%p)::OnVideoDecoded [mTime=%lld mDuration=%lld mDiscontinuity=%d]",
|
2014-09-03 18:57:06 -07:00
|
|
|
this, aSample->mTime, aSample->mDuration, aSample->mDiscontinuity);
|
2014-08-13 05:22:00 -07:00
|
|
|
if (mDropVideoBeforeThreshold) {
|
|
|
|
if (aSample->mTime < mTimeThreshold) {
|
|
|
|
MSE_DEBUG("MediaSourceReader(%p)::OnVideoDecoded mTime=%lld < mTimeThreshold=%lld",
|
|
|
|
this, aSample->mTime, mTimeThreshold);
|
|
|
|
delete aSample;
|
2014-09-03 18:57:06 -07:00
|
|
|
mVideoReader->RequestVideoData(false, 0);
|
2014-08-13 05:22:00 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
mDropVideoBeforeThreshold = false;
|
|
|
|
}
|
2014-09-03 02:56:22 -07:00
|
|
|
|
2014-09-07 21:55:20 -07:00
|
|
|
// Any OnVideoDecoded callbacks received while mVideoIsSeeking must be not
|
|
|
|
// update our last used timestamp, as these are emitted by the reader we're
|
|
|
|
// switching away from.
|
|
|
|
if (!mVideoIsSeeking) {
|
|
|
|
mLastVideoTime = aSample->mTime + aSample->mDuration;
|
2014-09-03 02:56:22 -07:00
|
|
|
}
|
2014-08-13 05:22:00 -07:00
|
|
|
GetCallback()->OnVideoDecoded(aSample);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaSourceReader::OnVideoEOS()
|
|
|
|
{
|
|
|
|
// End of stream. See if we can switch to another video decoder.
|
2014-09-03 18:57:06 -07:00
|
|
|
MSE_DEBUG("MediaSourceReader(%p)::OnVideoEOS reader=%p (decoders=%u)",
|
|
|
|
this, mVideoReader.get(), mVideoTrack->Decoders().Length());
|
2014-09-09 19:27:51 -07:00
|
|
|
if (SwitchVideoReader(mLastVideoTime)) {
|
2014-08-13 05:22:00 -07:00
|
|
|
// Success! Resume decoding with next video decoder.
|
2014-09-03 18:57:06 -07:00
|
|
|
RequestVideoData(false, 0);
|
2014-08-26 00:25:09 -07:00
|
|
|
} else if (IsEnded()) {
|
2014-08-13 05:22:00 -07:00
|
|
|
// End of stream.
|
2014-09-03 18:57:06 -07:00
|
|
|
MSE_DEBUG("MediaSourceReader(%p)::OnVideoEOS reader=%p EOS (decoders=%u)",
|
|
|
|
this, mVideoReader.get(), mVideoTrack->Decoders().Length());
|
2014-08-13 05:22:00 -07:00
|
|
|
GetCallback()->OnVideoEOS();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaSourceReader::OnDecodeError()
|
|
|
|
{
|
2014-09-03 18:57:06 -07:00
|
|
|
MSE_DEBUG("MediaSourceReader(%p)::OnDecodeError", this);
|
2014-08-13 05:22:00 -07:00
|
|
|
GetCallback()->OnDecodeError();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaSourceReader::Shutdown()
|
|
|
|
{
|
|
|
|
MediaDecoderReader::Shutdown();
|
2014-10-09 22:26:12 -07:00
|
|
|
for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) {
|
|
|
|
mTrackBuffers[i]->Shutdown();
|
|
|
|
}
|
2014-09-03 18:57:06 -07:00
|
|
|
mAudioTrack = nullptr;
|
|
|
|
mAudioReader = nullptr;
|
|
|
|
mVideoTrack = nullptr;
|
|
|
|
mVideoReader = nullptr;
|
2014-08-13 05:22:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaSourceReader::BreakCycles()
|
|
|
|
{
|
|
|
|
MediaDecoderReader::BreakCycles();
|
2014-10-09 22:26:12 -07:00
|
|
|
|
|
|
|
// These were cleared in Shutdown().
|
|
|
|
MOZ_ASSERT(!mAudioTrack);
|
|
|
|
MOZ_ASSERT(!mAudioReader);
|
|
|
|
MOZ_ASSERT(!mVideoTrack);
|
|
|
|
MOZ_ASSERT(!mVideoReader);
|
|
|
|
|
2014-09-07 17:59:36 -07:00
|
|
|
for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) {
|
|
|
|
mTrackBuffers[i]->BreakCycles();
|
|
|
|
}
|
|
|
|
mTrackBuffers.Clear();
|
2014-08-13 05:22:00 -07:00
|
|
|
}
|
|
|
|
|
2014-09-07 17:07:56 -07:00
|
|
|
already_AddRefed<MediaDecoderReader>
|
2014-09-09 19:27:51 -07:00
|
|
|
MediaSourceReader::SelectReader(int64_t aTarget,
|
2014-09-07 17:07:56 -07:00
|
|
|
const nsTArray<nsRefPtr<SourceBufferDecoder>>& aTrackDecoders)
|
|
|
|
{
|
|
|
|
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
|
|
|
|
2014-09-07 17:13:50 -07:00
|
|
|
// Consider decoders in order of newest to oldest, as a newer decoder
|
|
|
|
// providing a given buffered range is expected to replace an older one.
|
|
|
|
for (int32_t i = aTrackDecoders.Length() - 1; i >= 0; --i) {
|
2014-09-07 17:07:56 -07:00
|
|
|
nsRefPtr<MediaDecoderReader> newReader = aTrackDecoders[i]->GetReader();
|
|
|
|
|
|
|
|
nsRefPtr<dom::TimeRanges> ranges = new dom::TimeRanges();
|
|
|
|
aTrackDecoders[i]->GetBuffered(ranges);
|
2014-09-09 19:27:51 -07:00
|
|
|
if (ranges->Find(double(aTarget) / USECS_PER_S) == dom::TimeRanges::NoIndex) {
|
|
|
|
MSE_DEBUGV("MediaSourceReader(%p)::SelectReader(%lld) newReader=%p target not in ranges=%s",
|
2014-09-07 17:07:56 -07:00
|
|
|
this, aTarget, newReader.get(), DumpTimeRanges(ranges).get());
|
|
|
|
continue;
|
2014-09-03 07:14:25 -07:00
|
|
|
}
|
2014-09-07 17:07:56 -07:00
|
|
|
|
|
|
|
return newReader.forget();
|
2014-09-03 07:14:25 -07:00
|
|
|
}
|
2014-08-28 01:18:01 -07:00
|
|
|
|
2014-09-07 17:07:56 -07:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2014-09-09 19:27:51 -07:00
|
|
|
MediaSourceReader::SwitchAudioReader(int64_t aTarget)
|
2014-09-07 17:07:56 -07:00
|
|
|
{
|
|
|
|
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
|
|
|
// XXX: Can't handle adding an audio track after ReadMetadata.
|
|
|
|
if (!mAudioTrack) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-09-09 19:21:17 -07:00
|
|
|
nsRefPtr<MediaDecoderReader> newReader = SelectReader(aTarget, mAudioTrack->Decoders());
|
2014-09-07 21:54:52 -07:00
|
|
|
if (newReader && newReader != mAudioReader) {
|
2014-09-07 17:07:56 -07:00
|
|
|
mAudioReader->SetIdle();
|
|
|
|
mAudioReader = newReader;
|
2014-09-07 21:54:52 -07:00
|
|
|
MSE_DEBUGV("MediaSourceReader(%p)::SwitchAudioReader switched reader to %p", this, mAudioReader.get());
|
|
|
|
return true;
|
2014-09-07 17:07:56 -07:00
|
|
|
}
|
2014-09-07 21:54:52 -07:00
|
|
|
return false;
|
2014-09-03 10:55:55 -07:00
|
|
|
}
|
|
|
|
|
2014-09-03 18:57:06 -07:00
|
|
|
bool
|
2014-09-09 19:27:51 -07:00
|
|
|
MediaSourceReader::SwitchVideoReader(int64_t aTarget)
|
2014-09-03 10:55:55 -07:00
|
|
|
{
|
|
|
|
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
2014-09-07 17:07:56 -07:00
|
|
|
// XXX: Can't handle adding a video track after ReadMetadata.
|
2014-09-03 18:57:06 -07:00
|
|
|
if (!mVideoTrack) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-09-09 19:21:17 -07:00
|
|
|
nsRefPtr<MediaDecoderReader> newReader = SelectReader(aTarget, mVideoTrack->Decoders());
|
2014-09-07 21:54:52 -07:00
|
|
|
if (newReader && newReader != mVideoReader) {
|
2014-09-07 17:07:56 -07:00
|
|
|
mVideoReader->SetIdle();
|
|
|
|
mVideoReader = newReader;
|
2014-09-07 21:54:52 -07:00
|
|
|
MSE_DEBUGV("MediaSourceReader(%p)::SwitchVideoReader switched reader to %p", this, mVideoReader.get());
|
|
|
|
return true;
|
2014-09-03 10:55:55 -07:00
|
|
|
}
|
2014-09-07 21:54:52 -07:00
|
|
|
return false;
|
2014-08-13 05:22:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
MediaDecoderReader*
|
|
|
|
CreateReaderForType(const nsACString& aType, AbstractMediaDecoder* aDecoder)
|
|
|
|
{
|
|
|
|
#ifdef MOZ_FMP4
|
|
|
|
// The MP4Reader that supports fragmented MP4 and uses
|
|
|
|
// PlatformDecoderModules is hidden behind prefs for regular video
|
|
|
|
// elements, but we always want to use it for MSE, so instantiate it
|
|
|
|
// directly here.
|
|
|
|
if ((aType.LowerCaseEqualsLiteral("video/mp4") ||
|
|
|
|
aType.LowerCaseEqualsLiteral("audio/mp4")) &&
|
|
|
|
MP4Decoder::IsEnabled()) {
|
|
|
|
return new MP4Reader(aDecoder);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return DecoderTraits::CreateReader(aType, aDecoder);
|
|
|
|
}
|
|
|
|
|
2014-08-21 19:14:36 -07:00
|
|
|
already_AddRefed<SourceBufferDecoder>
|
2014-08-20 01:07:00 -07:00
|
|
|
MediaSourceReader::CreateSubDecoder(const nsACString& aType)
|
2014-08-13 05:22:00 -07:00
|
|
|
{
|
2014-08-26 17:45:05 -07:00
|
|
|
if (IsShutdown()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2014-08-20 01:07:00 -07:00
|
|
|
MOZ_ASSERT(GetTaskQueue());
|
2014-08-21 19:14:36 -07:00
|
|
|
nsRefPtr<SourceBufferDecoder> decoder =
|
2014-08-24 23:05:48 -07:00
|
|
|
new SourceBufferDecoder(new SourceBufferResource(aType), mDecoder);
|
2014-08-13 05:22:00 -07:00
|
|
|
nsRefPtr<MediaDecoderReader> reader(CreateReaderForType(aType, decoder));
|
|
|
|
if (!reader) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
// Set a callback on the subreader that forwards calls to this reader.
|
|
|
|
// This reader will then forward them onto the state machine via this
|
|
|
|
// reader's callback.
|
|
|
|
RefPtr<MediaDataDecodedListener<MediaSourceReader>> callback =
|
2014-08-17 04:29:00 -07:00
|
|
|
new MediaDataDecodedListener<MediaSourceReader>(this, GetTaskQueue());
|
2014-08-13 05:22:00 -07:00
|
|
|
reader->SetCallback(callback);
|
2014-08-17 04:29:00 -07:00
|
|
|
reader->SetTaskQueue(GetTaskQueue());
|
2014-08-13 05:22:00 -07:00
|
|
|
reader->Init(nullptr);
|
2014-09-03 18:57:06 -07:00
|
|
|
|
2014-08-13 05:22:00 -07:00
|
|
|
MSE_DEBUG("MediaSourceReader(%p)::CreateSubDecoder subdecoder %p subreader %p",
|
|
|
|
this, decoder.get(), reader.get());
|
|
|
|
decoder->SetReader(reader);
|
2014-10-13 15:05:00 -07:00
|
|
|
#ifdef MOZ_EME
|
|
|
|
decoder->SetCDMProxy(mCDMProxy);
|
|
|
|
#endif
|
2014-09-03 18:57:06 -07:00
|
|
|
return decoder.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaSourceReader::AddTrackBuffer(TrackBuffer* aTrackBuffer)
|
|
|
|
{
|
|
|
|
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
|
|
|
MSE_DEBUG("MediaSourceReader(%p)::AddTrackBuffer %p", this, aTrackBuffer);
|
|
|
|
mTrackBuffers.AppendElement(aTrackBuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaSourceReader::RemoveTrackBuffer(TrackBuffer* aTrackBuffer)
|
|
|
|
{
|
|
|
|
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
|
|
|
MSE_DEBUG("MediaSourceReader(%p)::RemoveTrackBuffer %p", this, aTrackBuffer);
|
|
|
|
mTrackBuffers.RemoveElement(aTrackBuffer);
|
|
|
|
if (mAudioTrack == aTrackBuffer) {
|
|
|
|
mAudioTrack = nullptr;
|
|
|
|
}
|
|
|
|
if (mVideoTrack == aTrackBuffer) {
|
|
|
|
mVideoTrack = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaSourceReader::OnTrackBufferConfigured(TrackBuffer* aTrackBuffer, const MediaInfo& aInfo)
|
|
|
|
{
|
|
|
|
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
2014-09-04 17:04:54 -07:00
|
|
|
MOZ_ASSERT(aTrackBuffer->IsReady());
|
2014-09-03 18:57:06 -07:00
|
|
|
MOZ_ASSERT(mTrackBuffers.Contains(aTrackBuffer));
|
|
|
|
if (aInfo.HasAudio() && !mAudioTrack) {
|
|
|
|
MSE_DEBUG("MediaSourceReader(%p)::OnTrackBufferConfigured %p audio", this, aTrackBuffer);
|
|
|
|
mAudioTrack = aTrackBuffer;
|
|
|
|
}
|
|
|
|
if (aInfo.HasVideo() && !mVideoTrack) {
|
|
|
|
MSE_DEBUG("MediaSourceReader(%p)::OnTrackBufferConfigured %p video", this, aTrackBuffer);
|
|
|
|
mVideoTrack = aTrackBuffer;
|
2014-08-13 05:22:00 -07:00
|
|
|
}
|
|
|
|
mDecoder->NotifyWaitingForResourcesStatusChanged();
|
|
|
|
}
|
|
|
|
|
2014-09-07 04:54:00 -07:00
|
|
|
void
|
2014-09-09 19:27:51 -07:00
|
|
|
MediaSourceReader::WaitForTimeRange(int64_t aTime)
|
2014-09-07 04:54:00 -07:00
|
|
|
{
|
2014-09-09 19:27:51 -07:00
|
|
|
MSE_DEBUG("MediaSourceReader(%p)::WaitForTimeRange(%lld)", this, aTime);
|
2014-09-07 04:54:00 -07:00
|
|
|
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
|
|
|
|
|
|
|
// Loop until we have the requested time range in the active TrackBuffers.
|
|
|
|
// Ideally, this wait loop would use an async request and callback
|
|
|
|
// instead. Bug 1056441 covers that change.
|
|
|
|
while (!TrackBuffersContainTime(aTime) && !IsShutdown() && !IsEnded()) {
|
2014-09-09 19:27:51 -07:00
|
|
|
MSE_DEBUG("MediaSourceReader(%p)::WaitForTimeRange(%lld) waiting", this, aTime);
|
2014-09-07 04:54:00 -07:00
|
|
|
mon.Wait();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-13 05:22:00 -07:00
|
|
|
bool
|
2014-09-09 19:27:51 -07:00
|
|
|
MediaSourceReader::TrackBuffersContainTime(int64_t aTime)
|
2014-08-13 05:22:00 -07:00
|
|
|
{
|
2014-09-03 18:57:06 -07:00
|
|
|
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
|
|
|
if (mAudioTrack && !mAudioTrack->ContainsTime(aTime)) {
|
|
|
|
return false;
|
2014-08-28 01:18:01 -07:00
|
|
|
}
|
2014-09-03 18:57:06 -07:00
|
|
|
if (mVideoTrack && !mVideoTrack->ContainsTime(aTime)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
2014-08-13 05:22:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
MediaSourceReader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime,
|
|
|
|
int64_t aCurrentTime)
|
|
|
|
{
|
|
|
|
MSE_DEBUG("MediaSourceReader(%p)::Seek(aTime=%lld, aStart=%lld, aEnd=%lld, aCurrent=%lld)",
|
|
|
|
this, aTime, aStartTime, aEndTime, aCurrentTime);
|
2014-09-03 18:57:06 -07:00
|
|
|
|
|
|
|
ResetDecode();
|
|
|
|
for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) {
|
|
|
|
mTrackBuffers[i]->ResetDecode();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Decoding discontinuity upon seek, reset last times to seek target.
|
|
|
|
mLastAudioTime = aTime;
|
|
|
|
mLastVideoTime = aTime;
|
|
|
|
|
2014-09-09 19:27:51 -07:00
|
|
|
WaitForTimeRange(aTime);
|
2014-08-13 05:22:00 -07:00
|
|
|
|
|
|
|
if (IsShutdown()) {
|
2014-08-26 00:25:09 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
2014-08-13 05:22:00 -07:00
|
|
|
}
|
|
|
|
|
2014-09-03 18:57:06 -07:00
|
|
|
if (mAudioTrack) {
|
2014-09-03 02:56:22 -07:00
|
|
|
mAudioIsSeeking = true;
|
2014-09-09 19:27:51 -07:00
|
|
|
SwitchAudioReader(aTime);
|
2014-08-20 20:14:48 -07:00
|
|
|
nsresult rv = mAudioReader->Seek(aTime, aStartTime, aEndTime, aCurrentTime);
|
2014-08-25 23:22:20 -07:00
|
|
|
MSE_DEBUG("MediaSourceReader(%p)::Seek audio reader=%p rv=%x", this, mAudioReader.get(), rv);
|
2014-08-13 05:22:00 -07:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
}
|
2014-09-03 18:57:06 -07:00
|
|
|
if (mVideoTrack) {
|
2014-09-03 02:56:22 -07:00
|
|
|
mVideoIsSeeking = true;
|
2014-09-09 19:27:51 -07:00
|
|
|
SwitchVideoReader(aTime);
|
2014-08-20 20:14:48 -07:00
|
|
|
nsresult rv = mVideoReader->Seek(aTime, aStartTime, aEndTime, aCurrentTime);
|
2014-08-25 23:22:20 -07:00
|
|
|
MSE_DEBUG("MediaSourceReader(%p)::Seek video reader=%p rv=%x", this, mVideoReader.get(), rv);
|
2014-08-13 05:22:00 -07:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags)
|
|
|
|
{
|
2014-09-15 20:15:58 -07:00
|
|
|
MSE_DEBUG("MediaSourceReader(%p)::ReadMetadata tracks=%u/%u audio=%p video=%p",
|
|
|
|
this, mEssentialTrackBuffers.Length(), mTrackBuffers.Length(),
|
2014-09-04 17:04:54 -07:00
|
|
|
mAudioTrack.get(), mVideoTrack.get());
|
2014-09-15 20:15:58 -07:00
|
|
|
|
2014-09-18 20:55:58 -07:00
|
|
|
{
|
|
|
|
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
|
|
|
mEssentialTrackBuffers.Clear();
|
|
|
|
}
|
2014-09-03 18:57:06 -07:00
|
|
|
if (!mAudioTrack && !mVideoTrack) {
|
|
|
|
MSE_DEBUG("MediaSourceReader(%p)::ReadMetadata missing track: mAudioTrack=%p mVideoTrack=%p",
|
|
|
|
this, mAudioTrack.get(), mVideoTrack.get());
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2014-08-28 01:18:01 -07:00
|
|
|
|
2014-09-03 10:55:55 -07:00
|
|
|
int64_t maxDuration = -1;
|
2014-09-03 18:57:06 -07:00
|
|
|
|
|
|
|
if (mAudioTrack) {
|
|
|
|
MOZ_ASSERT(mAudioTrack->IsReady());
|
|
|
|
mAudioReader = mAudioTrack->Decoders()[0]->GetReader();
|
|
|
|
|
|
|
|
const MediaInfo& info = mAudioReader->GetMediaInfo();
|
|
|
|
MOZ_ASSERT(info.HasAudio());
|
|
|
|
mInfo.mAudio = info.mAudio;
|
|
|
|
maxDuration = std::max(maxDuration, mAudioReader->GetDecoder()->GetMediaDuration());
|
|
|
|
MSE_DEBUG("MediaSourceReader(%p)::ReadMetadata audio reader=%p maxDuration=%lld",
|
|
|
|
this, mAudioReader.get(), maxDuration);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mVideoTrack) {
|
|
|
|
MOZ_ASSERT(mVideoTrack->IsReady());
|
|
|
|
mVideoReader = mVideoTrack->Decoders()[0]->GetReader();
|
|
|
|
|
|
|
|
const MediaInfo& info = mVideoReader->GetMediaInfo();
|
|
|
|
MOZ_ASSERT(info.HasVideo());
|
|
|
|
mInfo.mVideo = info.mVideo;
|
|
|
|
maxDuration = std::max(maxDuration, mVideoReader->GetDecoder()->GetMediaDuration());
|
|
|
|
MSE_DEBUG("MediaSourceReader(%p)::ReadMetadata video reader=%p maxDuration=%lld",
|
|
|
|
this, mVideoReader.get(), maxDuration);
|
2014-08-13 05:22:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (maxDuration != -1) {
|
|
|
|
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
|
|
|
mDecoder->SetMediaDuration(maxDuration);
|
|
|
|
nsRefPtr<nsIRunnable> task (
|
2014-08-24 21:09:44 -07:00
|
|
|
NS_NewRunnableMethodWithArg<double>(static_cast<MediaSourceDecoder*>(mDecoder),
|
|
|
|
&MediaSourceDecoder::SetMediaSourceDuration,
|
2014-08-13 05:22:00 -07:00
|
|
|
static_cast<double>(maxDuration) / USECS_PER_S));
|
|
|
|
NS_DispatchToMainThread(task);
|
|
|
|
}
|
|
|
|
|
|
|
|
*aInfo = mInfo;
|
|
|
|
*aTags = nullptr; // TODO: Handle metadata.
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2014-08-26 00:25:09 -07:00
|
|
|
void
|
|
|
|
MediaSourceReader::Ended()
|
|
|
|
{
|
|
|
|
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
|
|
|
mEnded = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
MediaSourceReader::IsEnded()
|
|
|
|
{
|
|
|
|
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
|
|
|
return mEnded;
|
|
|
|
}
|
|
|
|
|
2014-10-13 15:05:00 -07:00
|
|
|
#ifdef MOZ_EME
|
|
|
|
nsresult
|
|
|
|
MediaSourceReader::SetCDMProxy(CDMProxy* aProxy)
|
|
|
|
{
|
|
|
|
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
|
|
|
|
|
|
|
mCDMProxy = aProxy;
|
|
|
|
for (size_t i = 0; i < mTrackBuffers.Length(); i++) {
|
|
|
|
nsresult rv = mTrackBuffers[i]->SetCDMProxy(aProxy);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-08-13 05:22:00 -07:00
|
|
|
} // namespace mozilla
|