2013-09-26 22:22:37 -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 "MediaSourceDecoder.h"
|
|
|
|
|
|
|
|
#include "AbstractMediaDecoder.h"
|
|
|
|
#include "MediaDecoderReader.h"
|
|
|
|
#include "MediaDecoderStateMachine.h"
|
|
|
|
#include "mozilla/Assertions.h"
|
2013-10-05 01:04:39 -07:00
|
|
|
#include "mozilla/FloatingPoint.h"
|
2013-09-26 22:22:37 -07:00
|
|
|
#include "mozilla/dom/HTMLMediaElement.h"
|
2013-10-05 01:04:39 -07:00
|
|
|
#include "mozilla/dom/TimeRanges.h"
|
2013-09-26 22:22:37 -07:00
|
|
|
#include "mozilla/mozalloc.h"
|
|
|
|
#include "nsISupports.h"
|
|
|
|
#include "prlog.h"
|
2013-10-05 01:04:39 -07:00
|
|
|
#include "MediaSource.h"
|
2013-09-26 22:22:37 -07:00
|
|
|
#include "SubBufferDecoder.h"
|
|
|
|
#include "SourceBufferResource.h"
|
|
|
|
|
|
|
|
#ifdef PR_LOGGING
|
|
|
|
extern PRLogModuleInfo* gMediaSourceLog;
|
|
|
|
#define LOG(type, msg) PR_LOG(gMediaSourceLog, type, msg)
|
|
|
|
#else
|
|
|
|
#define LOG(type, msg)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
|
|
|
namespace dom {
|
|
|
|
|
|
|
|
class TimeRanges;
|
|
|
|
|
|
|
|
} // namespace dom
|
|
|
|
|
|
|
|
class MediaSourceReader : public MediaDecoderReader
|
|
|
|
{
|
|
|
|
public:
|
2013-09-26 22:22:38 -07:00
|
|
|
MediaSourceReader(MediaSourceDecoder* aDecoder)
|
2013-09-26 22:22:37 -07:00
|
|
|
: MediaDecoderReader(aDecoder)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult Init(MediaDecoderReader* aCloneDonor) MOZ_OVERRIDE
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DecodeAudioData() MOZ_OVERRIDE
|
|
|
|
{
|
|
|
|
if (GetAudioReader()) {
|
|
|
|
return GetAudioReader()->DecodeAudioData();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DecodeVideoFrame(bool& aKeyFrameSkip, int64_t aTimeThreshold) MOZ_OVERRIDE
|
|
|
|
{
|
|
|
|
if (GetVideoReader()) {
|
|
|
|
return GetVideoReader()->DecodeVideoFrame(aKeyFrameSkip, aTimeThreshold);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool HasVideo() MOZ_OVERRIDE
|
|
|
|
{
|
2013-09-26 22:22:38 -07:00
|
|
|
return mInfo.HasVideo();
|
2013-09-26 22:22:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool HasAudio() MOZ_OVERRIDE
|
|
|
|
{
|
2013-09-26 22:22:38 -07:00
|
|
|
return mInfo.HasAudio();
|
2013-09-26 22:22:37 -07:00
|
|
|
}
|
|
|
|
|
2013-09-26 22:22:38 -07:00
|
|
|
nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) MOZ_OVERRIDE;
|
2013-09-26 22:22:37 -07:00
|
|
|
|
|
|
|
nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime,
|
|
|
|
int64_t aCurrentTime) MOZ_OVERRIDE
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime) MOZ_OVERRIDE
|
|
|
|
{
|
|
|
|
// XXX: Merge result with audio reader.
|
|
|
|
return GetVideoReader()->GetBuffered(aBuffered, aStartTime);
|
|
|
|
}
|
|
|
|
|
|
|
|
MediaQueue<AudioData>& AudioQueue() MOZ_OVERRIDE
|
|
|
|
{
|
|
|
|
// TODO: Share AudioQueue with SubReaders.
|
|
|
|
if (GetAudioReader()) {
|
|
|
|
return GetAudioReader()->AudioQueue();
|
|
|
|
}
|
|
|
|
return MediaDecoderReader::AudioQueue();
|
|
|
|
}
|
|
|
|
|
|
|
|
MediaQueue<VideoData>& VideoQueue() MOZ_OVERRIDE
|
|
|
|
{
|
|
|
|
// TODO: Share VideoQueue with SubReaders.
|
|
|
|
if (GetVideoReader()) {
|
|
|
|
return GetVideoReader()->VideoQueue();
|
|
|
|
}
|
|
|
|
return MediaDecoderReader::VideoQueue();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
MediaDecoderReader* GetVideoReader()
|
|
|
|
{
|
|
|
|
MediaSourceDecoder* decoder = static_cast<MediaSourceDecoder*>(mDecoder);
|
|
|
|
return decoder->GetVideoReader();
|
|
|
|
}
|
|
|
|
|
|
|
|
MediaDecoderReader* GetAudioReader()
|
|
|
|
{
|
|
|
|
MediaSourceDecoder* decoder = static_cast<MediaSourceDecoder*>(mDecoder);
|
|
|
|
return decoder->GetAudioReader();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-11-17 20:22:47 -08:00
|
|
|
MediaSourceDecoder::MediaSourceDecoder(dom::HTMLMediaElement* aElement)
|
2013-09-26 22:22:37 -07:00
|
|
|
: mMediaSource(nullptr)
|
|
|
|
, mVideoReader(nullptr),
|
|
|
|
mAudioReader(nullptr)
|
|
|
|
{
|
|
|
|
Init(aElement);
|
|
|
|
}
|
|
|
|
|
|
|
|
MediaDecoder*
|
|
|
|
MediaSourceDecoder::Clone()
|
|
|
|
{
|
|
|
|
// TODO: Sort out cloning.
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
MediaDecoderStateMachine*
|
|
|
|
MediaSourceDecoder::CreateStateMachine()
|
|
|
|
{
|
|
|
|
return new MediaDecoderStateMachine(this, new MediaSourceReader(this));
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
MediaSourceDecoder::Load(nsIStreamListener**, MediaDecoder*)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-10-05 01:04:39 -07:00
|
|
|
nsresult
|
2013-11-17 20:22:47 -08:00
|
|
|
MediaSourceDecoder::GetSeekable(dom::TimeRanges* aSeekable)
|
2013-10-05 01:04:39 -07:00
|
|
|
{
|
|
|
|
double duration = mMediaSource->Duration();
|
|
|
|
if (IsNaN(duration)) {
|
|
|
|
// Return empty range.
|
|
|
|
} else if (duration > 0 && mozilla::IsInfinite(duration)) {
|
2013-11-17 20:22:47 -08:00
|
|
|
nsRefPtr<dom::TimeRanges> bufferedRanges = new dom::TimeRanges();
|
2013-10-05 01:04:39 -07:00
|
|
|
GetBuffered(bufferedRanges);
|
|
|
|
aSeekable->Add(0, bufferedRanges->GetFinalEndTime());
|
|
|
|
} else {
|
|
|
|
aSeekable->Add(0, duration);
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-09-26 22:22:37 -07:00
|
|
|
void
|
2013-11-17 20:22:47 -08:00
|
|
|
MediaSourceDecoder::AttachMediaSource(dom::MediaSource* aMediaSource)
|
2013-09-26 22:22:37 -07:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(!mMediaSource && !mDecoderStateMachine);
|
|
|
|
mMediaSource = aMediaSource;
|
|
|
|
mDecoderStateMachine = CreateStateMachine();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaSourceDecoder::DetachMediaSource()
|
|
|
|
{
|
|
|
|
mMediaSource = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
SubBufferDecoder*
|
|
|
|
MediaSourceDecoder::CreateSubDecoder(const nsACString& aType)
|
|
|
|
{
|
|
|
|
MediaResource* resource = new SourceBufferResource(nullptr, aType);
|
|
|
|
nsRefPtr<SubBufferDecoder> decoder = new SubBufferDecoder(resource, this);
|
|
|
|
nsAutoPtr<MediaDecoderReader> reader(DecoderTraits::CreateReader(aType, decoder));
|
|
|
|
reader->Init(nullptr);
|
|
|
|
|
|
|
|
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
|
|
|
mDecoders.AppendElement(decoder);
|
|
|
|
mReaders.AppendElement(reader);
|
|
|
|
LOG(PR_LOG_DEBUG, ("Registered subdecoder %p subreader %p", decoder.get(), reader.get()));
|
|
|
|
mon.NotifyAll();
|
|
|
|
|
|
|
|
decoder->SetReader(reader.forget());
|
|
|
|
return decoder;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2013-09-26 22:22:38 -07:00
|
|
|
MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags)
|
2013-09-26 22:22:37 -07:00
|
|
|
{
|
|
|
|
mDecoder->SetMediaSeekable(true);
|
|
|
|
mDecoder->SetTransportSeekable(false);
|
|
|
|
|
|
|
|
MediaSourceDecoder* decoder = static_cast<MediaSourceDecoder*>(mDecoder);
|
|
|
|
const nsTArray<MediaDecoderReader*>& readers = decoder->GetReaders();
|
|
|
|
for (uint32_t i = 0; i < readers.Length(); ++i) {
|
|
|
|
MediaDecoderReader* reader = readers[i];
|
2013-09-26 22:22:38 -07:00
|
|
|
MediaInfo mi;
|
|
|
|
nsresult rv = reader->ReadMetadata(&mi, aTags);
|
2013-09-26 22:22:37 -07:00
|
|
|
LOG(PR_LOG_DEBUG, ("ReadMetadata on SB reader %p", reader));
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2013-09-26 22:22:38 -07:00
|
|
|
if (mi.HasVideo() && !mInfo.HasVideo()) {
|
|
|
|
mInfo.mVideo = mi.mVideo;
|
2013-09-26 22:22:37 -07:00
|
|
|
decoder->SetVideoReader(reader);
|
|
|
|
}
|
2013-09-26 22:22:38 -07:00
|
|
|
if (mi.HasAudio() && !mInfo.HasAudio()) {
|
|
|
|
mInfo.mAudio = mi.mAudio;
|
2013-09-26 22:22:37 -07:00
|
|
|
decoder->SetAudioReader(reader);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*aInfo = mInfo;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace mozilla
|