зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset 1704ea727e81 (bug 1163486) for at least b2g bustage
This commit is contained in:
Родитель
79fe86d82b
Коммит
de3872af29
|
@ -66,6 +66,7 @@
|
|||
#include "AppleMP3Reader.h"
|
||||
#endif
|
||||
#ifdef MOZ_FMP4
|
||||
#include "MP4Reader.h"
|
||||
#include "MP4Decoder.h"
|
||||
#include "MP4Demuxer.h"
|
||||
#endif
|
||||
|
@ -653,7 +654,9 @@ MediaDecoderReader* DecoderTraits::CreateReader(const nsACString& aType, Abstrac
|
|||
}
|
||||
#ifdef MOZ_FMP4
|
||||
if (IsMP4SupportedType(aType)) {
|
||||
decoderReader = new MediaFormatReader(aDecoder, new MP4Demuxer(aDecoder->GetResource()));
|
||||
decoderReader = Preferences::GetBool("media.format-reader.mp4", true) ?
|
||||
static_cast<MediaDecoderReader*>(new MediaFormatReader(aDecoder, new MP4Demuxer(aDecoder->GetResource()))) :
|
||||
static_cast<MediaDecoderReader*>(new MP4Reader(aDecoder));
|
||||
} else
|
||||
#endif
|
||||
if (IsMP3SupportedType(aType)) {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "MP4Decoder.h"
|
||||
#include "MP4Reader.h"
|
||||
#include "MediaDecoderStateMachine.h"
|
||||
#include "MediaFormatReader.h"
|
||||
#include "MP4Demuxer.h"
|
||||
|
@ -41,7 +42,11 @@ MP4Decoder::MP4Decoder()
|
|||
|
||||
MediaDecoderStateMachine* MP4Decoder::CreateStateMachine()
|
||||
{
|
||||
MediaDecoderReader* reader = new MediaFormatReader(this, new MP4Demuxer(GetResource()));
|
||||
bool useFormatDecoder =
|
||||
Preferences::GetBool("media.format-reader.mp4", true);
|
||||
nsRefPtr<MediaDecoderReader> reader = useFormatDecoder ?
|
||||
static_cast<MediaDecoderReader*>(new MediaFormatReader(this, new MP4Demuxer(GetResource()))) :
|
||||
static_cast<MediaDecoderReader*>(new MP4Reader(this));
|
||||
|
||||
return new MediaDecoderStateMachine(this, reader);
|
||||
}
|
||||
|
@ -53,8 +58,8 @@ MP4Decoder::SetCDMProxy(CDMProxy* aProxy)
|
|||
nsresult rv = MediaDecoder::SetCDMProxy(aProxy);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (aProxy) {
|
||||
// The MediaFormatReader can't decrypt EME content until it has a CDMProxy,
|
||||
// and the CDMProxy knows the capabilities of the CDM. The MediaFormatReader
|
||||
// The MP4Reader can't decrypt EME content until it has a CDMProxy,
|
||||
// and the CDMProxy knows the capabilities of the CDM. The MP4Reader
|
||||
// remains in "waiting for resources" state until then.
|
||||
CDMCaps::AutoLock caps(aProxy->Capabilites());
|
||||
nsCOMPtr<nsIRunnable> task(
|
||||
|
|
|
@ -20,14 +20,6 @@
|
|||
#include "mp4_demuxer/AnnexB.h"
|
||||
#include "mp4_demuxer/H264.h"
|
||||
|
||||
PRLogModuleInfo* GetDemuxerLog() {
|
||||
static PRLogModuleInfo* log = nullptr;
|
||||
if (!log) {
|
||||
log = PR_NewLogModule("MP4Demuxer");
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Returns true if no SPS was found and search for it should continue.
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,280 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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/. */
|
||||
|
||||
#if !defined(MP4Reader_h_)
|
||||
#define MP4Reader_h_
|
||||
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/TaskQueue.h"
|
||||
|
||||
#include "MediaDecoderReader.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "PlatformDecoderModule.h"
|
||||
#include "mp4_demuxer/mp4_demuxer.h"
|
||||
#include "demuxer/TrackDemuxer.h"
|
||||
|
||||
#include <deque>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
typedef std::deque<nsRefPtr<MediaRawData>> MediaSampleQueue;
|
||||
|
||||
class MP4Stream;
|
||||
|
||||
class MP4Reader final : public MediaDecoderReader
|
||||
{
|
||||
typedef TrackInfo::TrackType TrackType;
|
||||
|
||||
public:
|
||||
explicit MP4Reader(AbstractMediaDecoder* aDecoder, TaskQueue* aBorrowedTaskQueue = nullptr);
|
||||
|
||||
virtual ~MP4Reader();
|
||||
|
||||
virtual nsresult Init(MediaDecoderReader* aCloneDonor) override;
|
||||
|
||||
virtual size_t SizeOfVideoQueueInFrames() override;
|
||||
virtual size_t SizeOfAudioQueueInFrames() override;
|
||||
|
||||
virtual nsRefPtr<VideoDataPromise>
|
||||
RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold, bool aForceDecodeAhead) override;
|
||||
|
||||
virtual nsRefPtr<AudioDataPromise> RequestAudioData() override;
|
||||
|
||||
virtual bool HasAudio() override;
|
||||
virtual bool HasVideo() override;
|
||||
|
||||
virtual nsresult ReadMetadata(MediaInfo* aInfo,
|
||||
MetadataTags** aTags) override;
|
||||
|
||||
virtual void ReadUpdatedMetadata(MediaInfo* aInfo) override;
|
||||
|
||||
virtual nsRefPtr<SeekPromise>
|
||||
Seek(int64_t aTime, int64_t aEndTime) override;
|
||||
|
||||
virtual bool IsMediaSeekable() override;
|
||||
|
||||
virtual int64_t GetEvictionOffset(double aTime) override;
|
||||
|
||||
protected:
|
||||
virtual void NotifyDataArrivedInternal(uint32_t aLength, int64_t aOffset) override;
|
||||
public:
|
||||
|
||||
virtual media::TimeIntervals GetBuffered() override;
|
||||
|
||||
// For Media Resource Management
|
||||
virtual void SetIdle() override;
|
||||
virtual void ReleaseMediaResources() override;
|
||||
virtual void SetSharedDecoderManager(SharedDecoderManager* aManager)
|
||||
override;
|
||||
|
||||
virtual nsresult ResetDecode() override;
|
||||
|
||||
virtual nsRefPtr<ShutdownPromise> Shutdown() override;
|
||||
|
||||
virtual bool IsAsync() const override { return true; }
|
||||
|
||||
virtual bool VideoIsHardwareAccelerated() const override;
|
||||
|
||||
virtual void DisableHardwareAcceleration() override;
|
||||
|
||||
private:
|
||||
|
||||
bool InitDemuxer();
|
||||
void ReturnOutput(MediaData* aData, TrackType aTrack);
|
||||
|
||||
bool EnsureDecodersSetup();
|
||||
|
||||
// Sends input to decoder for aTrack, and output to the state machine,
|
||||
// if necessary.
|
||||
void Update(TrackType aTrack);
|
||||
|
||||
// Enqueues a task to call Update(aTrack) on the decoder task queue.
|
||||
// Lock for corresponding track must be held.
|
||||
void ScheduleUpdate(TrackType aTrack);
|
||||
|
||||
void ExtractCryptoInitData(nsTArray<uint8_t>& aInitData);
|
||||
|
||||
// Initializes mLayersBackendType if possible.
|
||||
void InitLayersBackendType();
|
||||
|
||||
// Blocks until the demuxer produces an sample of specified type.
|
||||
// Returns nullptr on error on EOS. Caller must delete sample.
|
||||
already_AddRefed<MediaRawData> PopSample(TrackType aTrack);
|
||||
already_AddRefed<MediaRawData> PopSampleLocked(TrackType aTrack);
|
||||
|
||||
bool SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& parsed);
|
||||
|
||||
// DecoderCallback proxies the MediaDataDecoderCallback calls to these
|
||||
// functions.
|
||||
void Output(TrackType aType, MediaData* aSample);
|
||||
void InputExhausted(TrackType aTrack);
|
||||
void Error(TrackType aTrack);
|
||||
void Flush(TrackType aTrack);
|
||||
void DrainComplete(TrackType aTrack);
|
||||
void UpdateIndex();
|
||||
bool IsSupportedAudioMimeType(const nsACString& aMimeType);
|
||||
bool IsSupportedVideoMimeType(const nsACString& aMimeType);
|
||||
virtual bool IsWaitingOnCDMResource() override;
|
||||
|
||||
mp4_demuxer::Microseconds GetNextKeyframeTime();
|
||||
bool ShouldSkip(bool aSkipToNextKeyframe, int64_t aTimeThreshold);
|
||||
|
||||
size_t SizeOfQueue(TrackType aTrack);
|
||||
|
||||
nsRefPtr<MP4Stream> mStream;
|
||||
nsRefPtr<mp4_demuxer::MP4Demuxer> mDemuxer;
|
||||
nsRefPtr<PlatformDecoderModule> mPlatform;
|
||||
mp4_demuxer::CryptoFile mCrypto;
|
||||
|
||||
class DecoderCallback : public MediaDataDecoderCallback {
|
||||
public:
|
||||
DecoderCallback(MP4Reader* aReader, TrackType aType)
|
||||
: mReader(aReader)
|
||||
, mType(aType)
|
||||
{
|
||||
}
|
||||
virtual void Output(MediaData* aSample) override {
|
||||
mReader->Output(mType, aSample);
|
||||
}
|
||||
virtual void InputExhausted() override {
|
||||
mReader->InputExhausted(mType);
|
||||
}
|
||||
virtual void Error() override {
|
||||
mReader->Error(mType);
|
||||
}
|
||||
virtual void DrainComplete() override {
|
||||
mReader->DrainComplete(mType);
|
||||
}
|
||||
virtual void ReleaseMediaResources() override {
|
||||
mReader->ReleaseMediaResources();
|
||||
}
|
||||
virtual bool OnReaderTaskQueue() override {
|
||||
return mReader->OnTaskQueue();
|
||||
}
|
||||
private:
|
||||
MP4Reader* mReader;
|
||||
TrackType mType;
|
||||
};
|
||||
|
||||
struct DecoderData {
|
||||
DecoderData(MediaData::Type aType,
|
||||
uint32_t aDecodeAhead)
|
||||
: mType(aType)
|
||||
, mMonitor(aType == MediaData::AUDIO_DATA ? "MP4 audio decoder data"
|
||||
: "MP4 video decoder data")
|
||||
, mNumSamplesInput(0)
|
||||
, mNumSamplesOutput(0)
|
||||
, mDecodeAhead(aDecodeAhead)
|
||||
, mForceDecodeAhead(false)
|
||||
, mActive(false)
|
||||
, mInputExhausted(false)
|
||||
, mError(false)
|
||||
, mIsFlushing(false)
|
||||
, mUpdateScheduled(false)
|
||||
, mDemuxEOS(false)
|
||||
, mDrainComplete(false)
|
||||
, mDiscontinuity(false)
|
||||
{
|
||||
}
|
||||
|
||||
nsAutoPtr<TrackDemuxer> mTrackDemuxer;
|
||||
// The platform decoder.
|
||||
nsRefPtr<MediaDataDecoder> mDecoder;
|
||||
// TaskQueue on which decoder can choose to decode.
|
||||
// Only non-null up until the decoder is created.
|
||||
nsRefPtr<FlushableTaskQueue> mTaskQueue;
|
||||
// Callback that receives output and error notifications from the decoder.
|
||||
nsAutoPtr<DecoderCallback> mCallback;
|
||||
// Decoded samples returned my mDecoder awaiting being returned to
|
||||
// state machine upon request.
|
||||
nsTArray<nsRefPtr<MediaData> > mOutput;
|
||||
// Disambiguate Audio vs Video.
|
||||
MediaData::Type mType;
|
||||
|
||||
// These get overriden in the templated concrete class.
|
||||
virtual bool HasPromise() = 0;
|
||||
virtual void RejectPromise(MediaDecoderReader::NotDecodedReason aReason,
|
||||
const char* aMethodName) = 0;
|
||||
|
||||
// Monitor that protects all non-threadsafe state; the primitives
|
||||
// that follow.
|
||||
Monitor mMonitor;
|
||||
uint64_t mNumSamplesInput;
|
||||
uint64_t mNumSamplesOutput;
|
||||
uint32_t mDecodeAhead;
|
||||
bool mForceDecodeAhead;
|
||||
// Whether this stream exists in the media.
|
||||
bool mActive;
|
||||
bool mInputExhausted;
|
||||
bool mError;
|
||||
bool mIsFlushing;
|
||||
bool mUpdateScheduled;
|
||||
bool mDemuxEOS;
|
||||
bool mDrainComplete;
|
||||
bool mDiscontinuity;
|
||||
};
|
||||
|
||||
template<typename PromiseType>
|
||||
struct DecoderDataWithPromise : public DecoderData {
|
||||
DecoderDataWithPromise(MediaData::Type aType, uint32_t aDecodeAhead) :
|
||||
DecoderData(aType, aDecodeAhead)
|
||||
{
|
||||
mPromise.SetMonitor(&mMonitor);
|
||||
}
|
||||
|
||||
MozPromiseHolder<PromiseType> mPromise;
|
||||
|
||||
bool HasPromise() override { return !mPromise.IsEmpty(); }
|
||||
void RejectPromise(MediaDecoderReader::NotDecodedReason aReason,
|
||||
const char* aMethodName) override
|
||||
{
|
||||
mPromise.Reject(aReason, aMethodName);
|
||||
}
|
||||
};
|
||||
|
||||
DecoderDataWithPromise<AudioDataPromise> mAudio;
|
||||
DecoderDataWithPromise<VideoDataPromise> mVideo;
|
||||
|
||||
// Queued samples extracted by the demuxer, but not yet sent to the platform
|
||||
// decoder.
|
||||
nsRefPtr<MediaRawData> mQueuedVideoSample;
|
||||
|
||||
// Returns true when the decoder for this track needs input.
|
||||
// aDecoder.mMonitor must be locked.
|
||||
bool NeedInput(DecoderData& aDecoder);
|
||||
|
||||
// The last number of decoded output frames that we've reported to
|
||||
// MediaDecoder::NotifyDecoded(). We diff the number of output video
|
||||
// frames every time that DecodeVideoData() is called, and report the
|
||||
// delta there.
|
||||
uint64_t mLastReportedNumDecodedFrames;
|
||||
|
||||
DecoderData& GetDecoderData(TrackType aTrack);
|
||||
|
||||
layers::LayersBackend mLayersBackendType;
|
||||
|
||||
// For use with InvokeAndRetry as an already_refed can't be converted to bool
|
||||
nsRefPtr<MediaRawData> DemuxVideoSample();
|
||||
nsRefPtr<MediaRawData> DemuxAudioSample();
|
||||
|
||||
// True if we've read the streams' metadata.
|
||||
bool mDemuxerInitialized;
|
||||
|
||||
// True if we've gathered telemetry from an SPS.
|
||||
bool mFoundSPSForTelemetry;
|
||||
|
||||
// Synchronized by decoder monitor.
|
||||
bool mIsEncrypted;
|
||||
|
||||
bool mIndexReady;
|
||||
int64_t mLastSeenEnd;
|
||||
Monitor mDemuxerMonitor;
|
||||
nsRefPtr<SharedDecoderManager> mSharedDecoderManager;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
|
@ -7,7 +7,7 @@
|
|||
#ifndef MP4_STREAM_H_
|
||||
#define MP4_STREAM_H_
|
||||
|
||||
#include "mp4_demuxer/Stream.h"
|
||||
#include "mp4_demuxer/mp4_demuxer.h"
|
||||
|
||||
#include "MediaResource.h"
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
EXPORTS += [
|
||||
'MP4Decoder.h',
|
||||
'MP4Demuxer.h',
|
||||
'MP4Reader.h',
|
||||
'MP4Stream.h',
|
||||
]
|
||||
|
||||
|
@ -17,6 +18,7 @@ UNIFIED_SOURCES += [
|
|||
|
||||
SOURCES += [
|
||||
'MP4Demuxer.cpp',
|
||||
'MP4Reader.cpp',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
|
|
@ -12,6 +12,7 @@ UNIFIED_SOURCES += [
|
|||
'TestIntervalSet.cpp',
|
||||
'TestMozPromise.cpp',
|
||||
'TestMP3Demuxer.cpp',
|
||||
'TestMP4Demuxer.cpp',
|
||||
# 'TestMP4Reader.cpp', disabled so we can turn check tests back on (bug 1175752)
|
||||
'TestTrackEncoder.cpp',
|
||||
'TestVideoSegment.cpp',
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "SharedDecoderManager.h"
|
||||
#include "MP4Decoder.h"
|
||||
#include "MP4Demuxer.h"
|
||||
#include "MP4Reader.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WEBM
|
||||
|
@ -700,15 +701,18 @@ CreateReaderForType(const nsACString& aType, AbstractMediaDecoder* aDecoder,
|
|||
TaskQueue* aBorrowedTaskQueue)
|
||||
{
|
||||
#ifdef MOZ_FMP4
|
||||
// The MediaFormatReader that supports fragmented MP4 and uses
|
||||
// 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() && aDecoder) {
|
||||
MediaDecoderReader* reader =
|
||||
new MediaFormatReader(aDecoder, new MP4Demuxer(aDecoder->GetResource()), aBorrowedTaskQueue);
|
||||
bool useFormatDecoder =
|
||||
Preferences::GetBool("media.mediasource.format-reader.mp4", true);
|
||||
MediaDecoderReader* reader = useFormatDecoder ?
|
||||
static_cast<MediaDecoderReader*>(new MediaFormatReader(aDecoder, new MP4Demuxer(aDecoder->GetResource()), aBorrowedTaskQueue)) :
|
||||
static_cast<MediaDecoderReader*>(new MP4Reader(aDecoder, aBorrowedTaskQueue));
|
||||
return reader;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "AppleUtils.h"
|
||||
#include "MP4Reader.h"
|
||||
#include "MP4Decoder.h"
|
||||
#include "mp4_demuxer/Adts.h"
|
||||
#include "MediaInfo.h"
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "PlatformDecoderModule.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "MP4Reader.h"
|
||||
#include "MP4Decoder.h"
|
||||
#include "nsIThread.h"
|
||||
#include "ReorderQueue.h"
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "PlatformDecoderModule.h"
|
||||
#include "FFmpegLibs.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
#include "mp4_demuxer/mp4_demuxer.h"
|
||||
|
||||
namespace mozilla
|
||||
{
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#define WMFAudioOutputSource_h_
|
||||
|
||||
#include "WMF.h"
|
||||
#include "MP4Reader.h"
|
||||
#include "MFTDecoder.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "WMFMediaDataDecoder.h"
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
|
||||
|
||||
#include "WMF.h"
|
||||
#include "MP4Reader.h"
|
||||
#include "MFTDecoder.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "PlatformDecoderModule.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#define WMFVideoMFTManager_h_
|
||||
|
||||
#include "WMF.h"
|
||||
#include "MP4Reader.h"
|
||||
#include "MFTDecoder.h"
|
||||
#include "nsRect.h"
|
||||
#include "WMFMediaDataDecoder.h"
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
PRLogModuleInfo* GetDemuxerLog();
|
||||
#define LOG(...) MOZ_LOG(GetDemuxerLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
|
||||
|
||||
using namespace mp4_demuxer;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using layers::Image;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "PlatformDecoderModule.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
|
||||
#include "mp4_demuxer/mp4_demuxer.h"
|
||||
#include "MediaInfo.h"
|
||||
#include "MediaData.h"
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mp4_demuxer/Box.h"
|
||||
#include "mp4_demuxer/Stream.h"
|
||||
#include "mp4_demuxer/mp4_demuxer.h"
|
||||
#include "mozilla/Endian.h"
|
||||
#include <algorithm>
|
||||
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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 "mp4_demuxer/MP4TrackDemuxer.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
namespace mp4_demuxer {
|
||||
|
||||
void
|
||||
MP4AudioDemuxer::Seek(Microseconds aTime)
|
||||
{
|
||||
mDemuxer->SeekAudio(aTime);
|
||||
}
|
||||
|
||||
already_AddRefed<MediaRawData>
|
||||
MP4AudioDemuxer::DemuxSample()
|
||||
{
|
||||
nsRefPtr<MediaRawData> sample(mDemuxer->DemuxAudioSample());
|
||||
return sample.forget();
|
||||
}
|
||||
|
||||
Microseconds
|
||||
MP4AudioDemuxer::GetNextKeyframeTime()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
MP4VideoDemuxer::Seek(Microseconds aTime)
|
||||
{
|
||||
mDemuxer->SeekVideo(aTime);
|
||||
}
|
||||
|
||||
already_AddRefed<MediaRawData>
|
||||
MP4VideoDemuxer::DemuxSample()
|
||||
{
|
||||
nsRefPtr<MediaRawData> sample(mDemuxer->DemuxVideoSample());
|
||||
return sample.forget();
|
||||
}
|
||||
|
||||
Microseconds
|
||||
MP4VideoDemuxer::GetNextKeyframeTime()
|
||||
{
|
||||
return mDemuxer->GetNextKeyframeTime();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/* 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/. */
|
||||
|
||||
#ifndef MP4_TRACK_DEMUXER_H_
|
||||
#define MP4_TRACK_DEMUXER_H_
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "demuxer/TrackDemuxer.h"
|
||||
|
||||
namespace mp4_demuxer
|
||||
{
|
||||
|
||||
class MP4AudioDemuxer : public mozilla::TrackDemuxer {
|
||||
public:
|
||||
explicit MP4AudioDemuxer(MP4Demuxer* aDemuxer) : mDemuxer(aDemuxer) {}
|
||||
virtual void Seek(Microseconds aTime) override;
|
||||
virtual already_AddRefed<mozilla::MediaRawData> DemuxSample() override;
|
||||
virtual Microseconds GetNextKeyframeTime() override;
|
||||
|
||||
private:
|
||||
nsRefPtr<MP4Demuxer> mDemuxer;
|
||||
};
|
||||
|
||||
class MP4VideoDemuxer : public mozilla::TrackDemuxer {
|
||||
public:
|
||||
explicit MP4VideoDemuxer(MP4Demuxer* aDemuxer) : mDemuxer(aDemuxer) {}
|
||||
virtual void Seek(Microseconds aTime) override;
|
||||
virtual already_AddRefed<mozilla::MediaRawData> DemuxSample() override;
|
||||
virtual Microseconds GetNextKeyframeTime() override;
|
||||
|
||||
private:
|
||||
nsRefPtr<MP4Demuxer> mDemuxer;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -5,16 +5,13 @@
|
|||
#ifndef MOOF_PARSER_H_
|
||||
#define MOOF_PARSER_H_
|
||||
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mp4_demuxer/Atom.h"
|
||||
#include "mp4_demuxer/AtomType.h"
|
||||
#include "mp4_demuxer/mp4_demuxer.h"
|
||||
#include "mp4_demuxer/SinfParser.h"
|
||||
#include "mp4_demuxer/Interval.h"
|
||||
#include "MediaResource.h"
|
||||
|
||||
namespace mp4_demuxer {
|
||||
using mozilla::Monitor;
|
||||
typedef int64_t Microseconds;
|
||||
|
||||
class Stream;
|
||||
class Box;
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/* 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/. */
|
||||
|
||||
#ifndef MP4_DEMUXER_H_
|
||||
#define MP4_DEMUXER_H_
|
||||
|
||||
#include "MediaInfo.h"
|
||||
#include "MediaResource.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
#include "mp4_demuxer/Interval.h"
|
||||
#include "mp4_demuxer/Stream.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mp4_demuxer
|
||||
{
|
||||
class Index;
|
||||
class MP4Metadata;
|
||||
class SampleIterator;
|
||||
using mozilla::Monitor;
|
||||
typedef int64_t Microseconds;
|
||||
|
||||
class MP4Demuxer
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MP4Demuxer)
|
||||
|
||||
explicit MP4Demuxer(Stream* aSource, Monitor* aMonitor);
|
||||
|
||||
bool Init();
|
||||
Microseconds Duration();
|
||||
bool CanSeek();
|
||||
|
||||
bool HasValidAudio();
|
||||
bool HasValidVideo();
|
||||
|
||||
void SeekAudio(Microseconds aTime);
|
||||
void SeekVideo(Microseconds aTime);
|
||||
|
||||
// DemuxAudioSample and DemuxVideoSample functions
|
||||
// return nullptr on end of stream or error.
|
||||
already_AddRefed<mozilla::MediaRawData> DemuxAudioSample();
|
||||
already_AddRefed<mozilla::MediaRawData> DemuxVideoSample();
|
||||
|
||||
const CryptoFile& Crypto() const;
|
||||
const mozilla::AudioInfo& AudioConfig() const { return *mAudioConfig->GetAsAudioInfo(); }
|
||||
const mozilla::VideoInfo& VideoConfig() const { return *mVideoConfig->GetAsVideoInfo(); }
|
||||
|
||||
void UpdateIndex(const nsTArray<mozilla::MediaByteRange>& aByteRanges);
|
||||
|
||||
void ConvertByteRangesToTime(
|
||||
const nsTArray<mozilla::MediaByteRange>& aByteRanges,
|
||||
nsTArray<Interval<Microseconds>>* aIntervals);
|
||||
|
||||
int64_t GetEvictionOffset(Microseconds aTime);
|
||||
|
||||
// Returns timestamp of next keyframe, or -1 if demuxer can't
|
||||
// report this.
|
||||
Microseconds GetNextKeyframeTime();
|
||||
|
||||
protected:
|
||||
~MP4Demuxer();
|
||||
|
||||
private:
|
||||
mozilla::UniquePtr<mozilla::TrackInfo> mAudioConfig;
|
||||
mozilla::UniquePtr<mozilla::TrackInfo> mVideoConfig;
|
||||
|
||||
nsRefPtr<Stream> mSource;
|
||||
nsTArray<mozilla::MediaByteRange> mCachedByteRanges;
|
||||
nsTArray<Interval<Microseconds>> mCachedTimeRanges;
|
||||
Monitor* mMonitor;
|
||||
Microseconds mNextKeyframeTime;
|
||||
mozilla::UniquePtr<MP4Metadata> mMetadata;
|
||||
mozilla::UniquePtr<SampleIterator> mAudioIterator;
|
||||
mozilla::UniquePtr<SampleIterator> mVideoIterator;
|
||||
nsTArray<nsRefPtr<Index>> mIndexes;
|
||||
};
|
||||
|
||||
} // namespace mp4_demuxer
|
||||
|
||||
#endif // MP4_DEMUXER_H_
|
|
@ -0,0 +1,245 @@
|
|||
/* 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 "mp4_demuxer/Index.h"
|
||||
#include "mp4_demuxer/MP4Metadata.h"
|
||||
#include "mp4_demuxer/mp4_demuxer.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
namespace mp4_demuxer
|
||||
{
|
||||
|
||||
MP4Demuxer::MP4Demuxer(Stream* source, Monitor* aMonitor)
|
||||
: mSource(source)
|
||||
, mMonitor(aMonitor)
|
||||
, mNextKeyframeTime(-1)
|
||||
{
|
||||
}
|
||||
|
||||
MP4Demuxer::~MP4Demuxer()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
MP4Demuxer::Init()
|
||||
{
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
|
||||
// Check that we have an entire moov before attempting any new reads to make
|
||||
// the retry system work.
|
||||
if (!MP4Metadata::HasCompleteMetadata(mSource)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mMetadata = mozilla::MakeUnique<MP4Metadata>(mSource);
|
||||
|
||||
if (!mMetadata->GetNumberTracks(mozilla::TrackInfo::kAudioTrack) &&
|
||||
!mMetadata->GetNumberTracks(mozilla::TrackInfo::kVideoTrack)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto audioInfo = mMetadata->GetTrackInfo(mozilla::TrackInfo::kAudioTrack, 0);
|
||||
if (audioInfo) {
|
||||
mAudioConfig = mozilla::Move(audioInfo);
|
||||
FallibleTArray<Index::Indice> indices;
|
||||
if (!mMetadata->ReadTrackIndex(indices, mAudioConfig->mTrackId)) {
|
||||
return false;
|
||||
}
|
||||
nsRefPtr<Index> index =
|
||||
new Index(indices,
|
||||
mSource,
|
||||
mAudioConfig->mTrackId,
|
||||
/* aIsAudio = */ true,
|
||||
mMonitor);
|
||||
mIndexes.AppendElement(index);
|
||||
mAudioIterator = mozilla::MakeUnique<SampleIterator>(index);
|
||||
}
|
||||
|
||||
auto videoInfo = mMetadata->GetTrackInfo(mozilla::TrackInfo::kVideoTrack, 0);
|
||||
if (videoInfo) {
|
||||
mVideoConfig = mozilla::Move(videoInfo);
|
||||
FallibleTArray<Index::Indice> indices;
|
||||
if (!mMetadata->ReadTrackIndex(indices, mVideoConfig->mTrackId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsRefPtr<Index> index =
|
||||
new Index(indices,
|
||||
mSource,
|
||||
mVideoConfig->mTrackId,
|
||||
/* aIsAudio = */ false,
|
||||
mMonitor);
|
||||
mIndexes.AppendElement(index);
|
||||
mVideoIterator = mozilla::MakeUnique<SampleIterator>(index);
|
||||
}
|
||||
|
||||
return mAudioIterator || mVideoIterator;
|
||||
}
|
||||
|
||||
bool
|
||||
MP4Demuxer::HasValidAudio()
|
||||
{
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
return mAudioIterator && mAudioConfig && mAudioConfig->IsValid();
|
||||
}
|
||||
|
||||
bool
|
||||
MP4Demuxer::HasValidVideo()
|
||||
{
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
return mVideoIterator && mVideoConfig && mVideoConfig->IsValid();
|
||||
}
|
||||
|
||||
Microseconds
|
||||
MP4Demuxer::Duration()
|
||||
{
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
int64_t videoDuration = mVideoConfig ? mVideoConfig->mDuration : 0;
|
||||
int64_t audioDuration = mAudioConfig ? mAudioConfig->mDuration : 0;
|
||||
return std::max(videoDuration, audioDuration);
|
||||
}
|
||||
|
||||
bool
|
||||
MP4Demuxer::CanSeek()
|
||||
{
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
return mMetadata->CanSeek();
|
||||
}
|
||||
|
||||
void
|
||||
MP4Demuxer::SeekAudio(Microseconds aTime)
|
||||
{
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
MOZ_ASSERT(mAudioIterator);
|
||||
mAudioIterator->Seek(aTime);
|
||||
}
|
||||
|
||||
void
|
||||
MP4Demuxer::SeekVideo(Microseconds aTime)
|
||||
{
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
MOZ_ASSERT(mVideoIterator);
|
||||
mVideoIterator->Seek(aTime);
|
||||
}
|
||||
|
||||
already_AddRefed<mozilla::MediaRawData>
|
||||
MP4Demuxer::DemuxAudioSample()
|
||||
{
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
MOZ_ASSERT(mAudioIterator);
|
||||
nsRefPtr<mozilla::MediaRawData> sample(mAudioIterator->GetNext());
|
||||
if (sample) {
|
||||
if (sample->mCrypto.mValid) {
|
||||
nsAutoPtr<MediaRawDataWriter> writer(sample->CreateWriter());
|
||||
writer->mCrypto.mMode = mAudioConfig->mCrypto.mMode;
|
||||
writer->mCrypto.mIVSize = mAudioConfig->mCrypto.mIVSize;
|
||||
writer->mCrypto.mKeyId.AppendElements(mAudioConfig->mCrypto.mKeyId);
|
||||
}
|
||||
}
|
||||
return sample.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<MediaRawData>
|
||||
MP4Demuxer::DemuxVideoSample()
|
||||
{
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
MOZ_ASSERT(mVideoIterator);
|
||||
nsRefPtr<mozilla::MediaRawData> sample(mVideoIterator->GetNext());
|
||||
if (sample) {
|
||||
sample->mExtraData = mVideoConfig->GetAsVideoInfo()->mExtraData;
|
||||
if (sample->mCrypto.mValid) {
|
||||
nsAutoPtr<MediaRawDataWriter> writer(sample->CreateWriter());
|
||||
writer->mCrypto.mMode = mVideoConfig->mCrypto.mMode;
|
||||
writer->mCrypto.mKeyId.AppendElements(mVideoConfig->mCrypto.mKeyId);
|
||||
}
|
||||
if (sample->mTime >= mNextKeyframeTime) {
|
||||
mNextKeyframeTime = mVideoIterator->GetNextKeyframeTime();
|
||||
}
|
||||
}
|
||||
return sample.forget();
|
||||
}
|
||||
|
||||
void
|
||||
MP4Demuxer::UpdateIndex(const nsTArray<mozilla::MediaByteRange>& aByteRanges)
|
||||
{
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
for (int i = 0; i < mIndexes.Length(); i++) {
|
||||
mIndexes[i]->UpdateMoofIndex(aByteRanges);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MP4Demuxer::ConvertByteRangesToTime(
|
||||
const nsTArray<mozilla::MediaByteRange>& aByteRanges,
|
||||
nsTArray<Interval<Microseconds>>* aIntervals)
|
||||
{
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
if (mIndexes.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Microseconds lastComposition = 0;
|
||||
nsTArray<Microseconds> endCompositions;
|
||||
for (int i = 0; i < mIndexes.Length(); i++) {
|
||||
Microseconds endComposition =
|
||||
mIndexes[i]->GetEndCompositionIfBuffered(aByteRanges);
|
||||
endCompositions.AppendElement(endComposition);
|
||||
lastComposition = std::max(lastComposition, endComposition);
|
||||
}
|
||||
|
||||
if (aByteRanges != mCachedByteRanges) {
|
||||
mCachedByteRanges = aByteRanges;
|
||||
mCachedTimeRanges.Clear();
|
||||
for (int i = 0; i < mIndexes.Length(); i++) {
|
||||
nsTArray<Interval<Microseconds>> ranges;
|
||||
mIndexes[i]->ConvertByteRangesToTimeRanges(aByteRanges, &ranges);
|
||||
if (lastComposition && endCompositions[i]) {
|
||||
Interval<Microseconds>::SemiNormalAppend(
|
||||
ranges, Interval<Microseconds>(endCompositions[i], lastComposition));
|
||||
}
|
||||
|
||||
if (i) {
|
||||
nsTArray<Interval<Microseconds>> intersection;
|
||||
Interval<Microseconds>::Intersection(mCachedTimeRanges, ranges, &intersection);
|
||||
mCachedTimeRanges = intersection;
|
||||
} else {
|
||||
mCachedTimeRanges = ranges;
|
||||
}
|
||||
}
|
||||
}
|
||||
aIntervals->AppendElements(mCachedTimeRanges);
|
||||
}
|
||||
|
||||
int64_t
|
||||
MP4Demuxer::GetEvictionOffset(Microseconds aTime)
|
||||
{
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
if (mIndexes.IsEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t offset = std::numeric_limits<uint64_t>::max();
|
||||
for (int i = 0; i < mIndexes.Length(); i++) {
|
||||
offset = std::min(offset, mIndexes[i]->GetEvictionOffset(aTime));
|
||||
}
|
||||
return offset == std::numeric_limits<uint64_t>::max() ? 0 : offset;
|
||||
}
|
||||
|
||||
Microseconds
|
||||
MP4Demuxer::GetNextKeyframeTime()
|
||||
{
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
return mNextKeyframeTime;
|
||||
}
|
||||
|
||||
const CryptoFile&
|
||||
MP4Demuxer::Crypto() const
|
||||
{
|
||||
return mMetadata->Crypto();
|
||||
}
|
||||
|
||||
} // namespace mp4_demuxer
|
|
@ -60,7 +60,9 @@ EXPORTS.mp4_demuxer += [
|
|||
'binding/include/mp4_demuxer/Index.h',
|
||||
'binding/include/mp4_demuxer/Interval.h',
|
||||
'binding/include/mp4_demuxer/MoofParser.h',
|
||||
'binding/include/mp4_demuxer/mp4_demuxer.h',
|
||||
'binding/include/mp4_demuxer/MP4Metadata.h',
|
||||
'binding/include/mp4_demuxer/MP4TrackDemuxer.h',
|
||||
'binding/include/mp4_demuxer/ResourceStream.h',
|
||||
'binding/include/mp4_demuxer/SinfParser.h',
|
||||
'binding/include/mp4_demuxer/Stream.h',
|
||||
|
@ -93,7 +95,9 @@ UNIFIED_SOURCES += [
|
|||
'binding/H264.cpp',
|
||||
'binding/Index.cpp',
|
||||
'binding/MoofParser.cpp',
|
||||
'binding/mp4_demuxer.cpp',
|
||||
'binding/MP4Metadata.cpp',
|
||||
'binding/MP4TrackDemuxer.cpp',
|
||||
'binding/ResourceStream.cpp',
|
||||
'binding/SinfParser.cpp',
|
||||
'frameworks/av/media/libstagefright/DataSource.cpp',
|
||||
|
|
|
@ -474,6 +474,11 @@ pref("media.mediasource.webm.enabled", false);
|
|||
// Enable new MediaSource architecture.
|
||||
pref("media.mediasource.format-reader", false);
|
||||
|
||||
// Enable new MediaFormatReader architecture for mp4 in MSE
|
||||
pref("media.mediasource.format-reader.mp4", true);
|
||||
// Enable new MediaFormatReader architecture for plain mp4.
|
||||
pref("media.format-reader.mp4", true);
|
||||
|
||||
// Enable new MediaFormatReader architecture for webm in MSE
|
||||
pref("media.mediasource.format-reader.webm", false);
|
||||
// Enable new MediaFormatReader architecture for plain webm.
|
||||
|
|
Загрузка…
Ссылка в новой задаче