Back out 7 changesets (bug 1231793) for Windows crashes in mozilla::MediaDecoderReader::~MediaDecoderReader()

Backed out changeset 273cc690d7cf (bug 1231793)
Backed out changeset d79218caeefc (bug 1231793)
Backed out changeset 75c7942267f8 (bug 1231793)
Backed out changeset 684e62a4d9f5 (bug 1231793)
Backed out changeset a5a15d50a8e4 (bug 1231793)
Backed out changeset 33d6f22d9b1f (bug 1231793)
Backed out changeset cd4fc7f2c80a (bug 1231793)
This commit is contained in:
Phil Ringnalda 2016-02-15 09:46:19 -08:00
parent c22f91b5be
commit 42b4db5e2f
18 changed files with 40 additions and 1483 deletions

View File

@ -96,19 +96,6 @@ FloatToAudioSample<int16_t>(float aValue)
return int16_t(clamped);
}
template <typename T> T UInt8bitToAudioSample(uint8_t aValue);
template <> inline float
UInt8bitToAudioSample<float>(uint8_t aValue)
{
return aValue * (static_cast<float>(2) / UINT8_MAX) - static_cast<float>(1);
}
template <> inline int16_t
UInt8bitToAudioSample<int16_t>(uint8_t aValue)
{
return (int16_t(aValue) << 8) + aValue + INT16_MIN;
}
template <typename T> T IntegerToAudioSample(int16_t aValue);
template <> inline float
@ -122,19 +109,6 @@ IntegerToAudioSample<int16_t>(int16_t aValue)
return aValue;
}
template <typename T> T Int24bitToAudioSample(int32_t aValue);
template <> inline float
Int24bitToAudioSample<float>(int32_t aValue)
{
return aValue / static_cast<float>(1 << 23);
}
template <> inline int16_t
Int24bitToAudioSample<int16_t>(int32_t aValue)
{
return aValue / 256;
}
template<typename SrcT, typename DstT>
inline void
ConvertAudioSample(SrcT aIn, DstT& aOut);

View File

@ -13,6 +13,9 @@
#include "OggDecoder.h"
#include "OggReader.h"
#include "WaveDecoder.h"
#include "WaveReader.h"
#include "WebMDecoder.h"
#include "WebMDemuxer.h"
@ -48,9 +51,6 @@
#include "MP3Decoder.h"
#include "MP3Demuxer.h"
#include "WaveDecoder.h"
#include "WaveDemuxer.h"
#include "ADTSDecoder.h"
#include "ADTSDemuxer.h"
@ -333,13 +333,6 @@ IsAACSupportedType(const nsACString& aType,
return ADTSDecoder::CanHandleMediaType(aType, aCodecs);
}
static bool
IsWAVSupportedType(const nsACString& aType,
const nsAString& aCodecs = EmptyString())
{
return WaveDecoder::CanHandleMediaType(aType, aCodecs);
}
/* static */
bool DecoderTraits::ShouldHandleMediaType(const char* aMIMEType)
{
@ -625,9 +618,6 @@ MediaDecoderReader* DecoderTraits::CreateReader(const nsACString& aType, Abstrac
if (IsAACSupportedType(aType)) {
decoderReader = new MediaFormatReader(aDecoder, new ADTSDemuxer(aDecoder->GetResource()));
} else
if (IsWAVSupportedType(aType)) {
decoderReader = new MediaFormatReader(aDecoder, new WAVDemuxer(aDecoder->GetResource()));
}
#ifdef MOZ_RAW
if (IsRawType(aType)) {
decoderReader = new RawReader(aDecoder);
@ -636,6 +626,9 @@ MediaDecoderReader* DecoderTraits::CreateReader(const nsACString& aType, Abstrac
if (IsOggType(aType)) {
decoderReader = new OggReader(aDecoder);
} else
if (IsWaveType(aType)) {
decoderReader = new WaveReader(aDecoder);
} else
#ifdef MOZ_OMX_DECODER
if (IsOmxSupportedType(aType)) {
decoderReader = new MediaOmxReader(aDecoder);

View File

@ -341,7 +341,7 @@ MediaFormatReader::OnDemuxerInitDone(nsresult)
mInitDone = true;
RefPtr<MetadataHolder> metadata = new MetadataHolder();
metadata->mInfo = mInfo;
metadata->mTags = tags->Count() ? tags.release() : nullptr;
metadata->mTags = nullptr;
mMetadataPromise.Resolve(metadata, __func__);
}

View File

@ -8,7 +8,6 @@
#include "OpusDecoder.h"
#include "VorbisDecoder.h"
#include "VPXDecoder.h"
#include "WAVDecoder.h"
namespace mozilla {
@ -17,8 +16,7 @@ AgnosticDecoderModule::SupportsMimeType(const nsACString& aMimeType) const
{
return VPXDecoder::IsVPX(aMimeType) ||
OpusDataDecoder::IsOpus(aMimeType) ||
VorbisDataDecoder::IsVorbis(aMimeType) ||
WaveDataDecoder::IsWave(aMimeType);
VorbisDataDecoder::IsVorbis(aMimeType);
}
already_AddRefed<MediaDataDecoder>
@ -55,10 +53,6 @@ AgnosticDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig,
m = new OpusDataDecoder(*aConfig.GetAsAudioInfo(),
aAudioTaskQueue,
aCallback);
} else if (WaveDataDecoder::IsWave(aConfig.mMimeType)) {
m = new WaveDataDecoder(*aConfig.GetAsAudioInfo(),
aAudioTaskQueue,
aCallback);
}
return m.forget();

View File

@ -1,139 +0,0 @@
/* -*- 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 "WAVDecoder.h"
#include "AudioSampleFormat.h"
#include "nsAutoPtr.h"
using mp4_demuxer::ByteReader;
namespace mozilla {
WaveDataDecoder::WaveDataDecoder(const AudioInfo& aConfig,
FlushableTaskQueue* aTaskQueue,
MediaDataDecoderCallback* aCallback)
: mInfo(aConfig)
, mTaskQueue(aTaskQueue)
, mCallback(aCallback)
, mFrames(0)
{
}
nsresult
WaveDataDecoder::Shutdown()
{
return NS_OK;
}
RefPtr<MediaDataDecoder::InitPromise>
WaveDataDecoder::Init()
{
return InitPromise::CreateAndResolve(TrackInfo::kAudioTrack, __func__);
}
nsresult
WaveDataDecoder::Input(MediaRawData* aSample)
{
nsCOMPtr<nsIRunnable> runnable(
NS_NewRunnableMethodWithArg<RefPtr<MediaRawData>>(
this, &WaveDataDecoder::Decode,
RefPtr<MediaRawData>(aSample)));
mTaskQueue->Dispatch(runnable.forget());
return NS_OK;
}
void
WaveDataDecoder::Decode(MediaRawData* aSample)
{
if (!DoDecode(aSample)) {
mCallback->Error();
} else if (mTaskQueue->IsEmpty()) {
mCallback->InputExhausted();
}
}
bool
WaveDataDecoder::DoDecode(MediaRawData* aSample)
{
size_t aLength = aSample->Size();
ByteReader aReader = ByteReader(aSample->Data(), aLength);
int64_t aOffset = aSample->mOffset;
uint64_t aTstampUsecs = aSample->mTime;
int32_t frames = aLength * 8 / mInfo.mBitDepth / mInfo.mChannels;
auto buffer = MakeUnique<AudioDataValue[]>(frames * mInfo.mChannels);
for (int i = 0; i < frames; ++i) {
for (unsigned int j = 0; j < mInfo.mChannels; ++j) {
if (mInfo.mBitDepth == 8) {
uint8_t v = aReader.ReadU8();
buffer[i * mInfo.mChannels + j] =
UInt8bitToAudioSample<AudioDataValue>(v);
} else if (mInfo.mBitDepth == 16) {
int16_t v = aReader.ReadLE16();
buffer[i * mInfo.mChannels + j] =
IntegerToAudioSample<AudioDataValue>(v);
} else if (mInfo.mBitDepth == 24) {
int32_t v = aReader.ReadLE24();
buffer[i * mInfo.mChannels + j] =
Int24bitToAudioSample<AudioDataValue>(v);
}
}
}
aReader.DiscardRemaining();
int64_t duration = frames / mInfo.mRate;
mCallback->Output(new AudioData(aOffset,
aTstampUsecs,
duration,
frames,
Move(buffer),
mInfo.mChannels,
mInfo.mRate));
mFrames += frames;
return true;
}
void
WaveDataDecoder::DoDrain()
{
mCallback->DrainComplete();
}
nsresult
WaveDataDecoder::Drain()
{
nsCOMPtr<nsIRunnable> runnable(
NS_NewRunnableMethod(this, &WaveDataDecoder::DoDrain));
mTaskQueue->Dispatch(runnable.forget());
return NS_OK;
}
nsresult
WaveDataDecoder::Flush()
{
mTaskQueue->Flush();
mFrames = 0;
return NS_OK;
}
/* static */
bool
WaveDataDecoder::IsWave(const nsACString& aMimeType)
{
// Some WebAudio uses "audio/x-wav",
// WAVdemuxer uses "audio/wave; codecs=aNum".
return aMimeType.EqualsLiteral("audio/x-wav") ||
aMimeType.EqualsLiteral("audio/wave; codecs=1") ||
aMimeType.EqualsLiteral("audio/wave; codecs=65534");
}
} // namespace mozilla
#undef LOG

View File

@ -1,48 +0,0 @@
/* -*- 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(WaveDecoder_h_)
#define WaveDecoder_h_
#include "PlatformDecoderModule.h"
#include "mp4_demuxer/ByteReader.h"
namespace mozilla {
class WaveDataDecoder : public MediaDataDecoder
{
public:
WaveDataDecoder(const AudioInfo& aConfig,
FlushableTaskQueue* aTaskQueue,
MediaDataDecoderCallback* aCallback);
RefPtr<InitPromise> Init() override;
nsresult Input(MediaRawData* aSample) override;
nsresult Flush() override;
nsresult Drain() override;
nsresult Shutdown() override;
const char* GetDescriptionName() const override
{
return "wave audio decoder";
}
// Return true if mimetype is Wave
static bool IsWave(const nsACString& aMimeType);
private:
void Decode (MediaRawData* aSample);
bool DoDecode (MediaRawData* aSample);
void DoDrain ();
const AudioInfo& mInfo;
RefPtr<FlushableTaskQueue> mTaskQueue;
MediaDataDecoderCallback* mCallback;
int64_t mFrames;
};
} // namespace mozilla
#endif

View File

@ -258,15 +258,6 @@ AndroidDecoderModule::SupportsMimeType(const nsACString& aMimeType) const
return true;
}
// When checking "audio/x-wav", CreateDecoder can cause a JNI ERROR by
// Accessing a stale local reference leading to a SIGSEGV crash.
// To avoid this we check for wav types here.
if (aMimeType.EqualsLiteral("audio/x-wav") ||
aMimeType.EqualsLiteral("audio/wave; codecs=1") ||
aMimeType.EqualsLiteral("audio/wave; codecs=65534")) {
return false;
}
return widget::HardwareCodecCapabilityUtils::FindDecoderCodecInfoForMimeType(
nsCString(TranslateMimeType(aMimeType)));
}

View File

@ -21,7 +21,6 @@ UNIFIED_SOURCES += [
'agnostic/OpusDecoder.cpp',
'agnostic/VorbisDecoder.cpp',
'agnostic/VPXDecoder.cpp',
'agnostic/WAVDecoder.cpp',
'PDMFactory.cpp',
'PlatformDecoderModule.cpp',
'wrappers/FuzzingWrapper.cpp',

View File

@ -681,7 +681,6 @@ var gMetadataTests = [
{ name:"wave_metadata_bad_len.wav", tags: {
name:"Track Title",
artist:"Artist Name",
comments:"Comments",
}
},
{ name:"wave_metadata_bad_no_null.wav", tags: {

View File

@ -20,19 +20,24 @@ function startTest(test, token) {
ok(el.error, "Element 'error' attr expected to have a value");
ok(el.error instanceof MediaError, "Element 'error' attr expected to be MediaError");
is(el.error.code, MediaError.MEDIA_ERR_DECODE, "Expected a decode error");
is(el.networkState, HTMLMediaElement.NETWORK_EMPTY, "networkState should be EMPTY");
el._sawError = true;
}, false);
v.addEventListener("emptied", function (event) {
var el = event.currentTarget;
is(el.networkState, HTMLMediaElement.NETWORK_EMPTY, "networkState should be EMPTY");
ok(el._sawError, "Expected error event");
manager.finished(token);
}, false);
v.addEventListener("loadeddata", function () {
ok(false, "Unexpected loadeddata event");
manager.finished(token);
v.addEventListener("loadedmetadata", function () {
ok(false, "Unexpected loadedmetadata event");
}, false);
v.autoplay = true;
v.addEventListener("ended", function () {
ok(false, "Unexpected ended event");
manager.finished(token);
}, false);
v.src = test.name; // implicitly starts a load.

View File

@ -3,58 +3,15 @@
/* 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 "WaveDemuxer.h"
#include "mozilla/Preferences.h"
#include "MediaDecoderStateMachine.h"
#include "WaveReader.h"
#include "WaveDecoder.h"
#include "MediaFormatReader.h"
#include "PDMFactory.h"
namespace mozilla {
MediaDecoder*
WaveDecoder::Clone(MediaDecoderOwner* aOwner)
MediaDecoderStateMachine* WaveDecoder::CreateStateMachine()
{
if (!IsEnabled())
return nullptr;
return new WaveDecoder(aOwner);
}
MediaDecoderStateMachine*
WaveDecoder::CreateStateMachine()
{
if (Preferences::GetBool("media.wave.decoder.enabled")) {
RefPtr<MediaDecoderReader> reader =
new MediaFormatReader(this, new WAVDemuxer(GetResource()));
return new MediaDecoderStateMachine(this, reader);
} else {
return new MediaDecoderStateMachine(this, new WaveReader(this));
}
}
/* static */
bool
WaveDecoder::IsEnabled()
{
PDMFactory::Init();
RefPtr<PDMFactory> platform = new PDMFactory();
return platform->SupportsMimeType(NS_LITERAL_CSTRING("audio/x-wav"));
}
/* static */
bool
WaveDecoder::CanHandleMediaType(const nsACString& aType,
const nsAString& aCodecs)
{
if (aType.EqualsASCII("audio/wave") || aType.EqualsASCII("audio/x-wav") ||
aType.EqualsASCII("audio/wav") || aType.EqualsASCII("audio/x-pn-wav")) {
return IsEnabled() && (aCodecs.IsEmpty() || aCodecs.EqualsASCII("1"));
}
return false;
return new MediaDecoderStateMachine(this, new WaveReader(this));
}
} // namespace mozilla

View File

@ -8,20 +8,30 @@
#include "MediaDecoder.h"
/**
* The decoder implementation is currently limited to Linear PCM encoded
* audio data with one or two channels of 8- or 16-bit samples at sample
* rates from 100 Hz to 96 kHz. The number of channels is limited by what
* the audio backend (via AudioStream) currently supports. The supported
* sample rate is artificially limited to arbitrarily selected sane values.
* Support for additional channels (and other new features) would
* require extending WaveDecoder to support parsing the newer
* WAVE_FORMAT_EXTENSIBLE chunk format.
**/
namespace mozilla {
class WaveDecoder : public MediaDecoder {
class WaveDecoder : public MediaDecoder
{
public:
// MediaDecoder interface.
explicit WaveDecoder(MediaDecoderOwner* aOwner) : MediaDecoder(aOwner) {}
MediaDecoder* Clone(MediaDecoderOwner* aOwner) override;
MediaDecoder* Clone(MediaDecoderOwner* aOwner) override {
if (!IsWaveEnabled()) {
return nullptr;
}
return new WaveDecoder(aOwner);
}
MediaDecoderStateMachine* CreateStateMachine() override;
// Returns true if the WAV backend is pref'ed on, and we're running on a
// platform that is likely to have decoders for the format.
static bool IsEnabled();
static bool CanHandleMediaType(const nsACString& aType,
const nsAString& aCodecs);
};
} // namespace mozilla

View File

@ -1,889 +0,0 @@
/* -*- 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 "WaveDemuxer.h"
#include <inttypes.h>
#include <algorithm>
#include "mozilla/Assertions.h"
#include "mozilla/Endian.h"
#include "VideoUtils.h"
#include "TimeUnits.h"
#include "prenv.h"
using mozilla::media::TimeUnit;
using mozilla::media::TimeIntervals;
using mp4_demuxer::ByteReader;
namespace mozilla {
// WAVDemuxer
WAVDemuxer::WAVDemuxer(MediaResource* aSource)
: mSource(aSource)
{
}
bool
WAVDemuxer::InitInternal()
{
if (!mTrackDemuxer) {
mTrackDemuxer = new WAVTrackDemuxer(mSource);
}
return mTrackDemuxer->Init();
}
RefPtr<WAVDemuxer::InitPromise>
WAVDemuxer::Init()
{
if (!InitInternal()) {
return InitPromise::CreateAndReject(
DemuxerFailureReason::DEMUXER_ERROR, __func__);
}
return InitPromise::CreateAndResolve(NS_OK, __func__);
}
bool
WAVDemuxer::HasTrackType(TrackInfo::TrackType aType) const
{
return aType == TrackInfo::kAudioTrack;
}
uint32_t
WAVDemuxer::GetNumberTracks(TrackInfo::TrackType aType) const
{
return aType == TrackInfo::kAudioTrack ? 1u : 0u;
}
already_AddRefed<MediaTrackDemuxer>
WAVDemuxer::GetTrackDemuxer(TrackInfo::TrackType aType, uint32_t aTrackNumber)
{
if (!mTrackDemuxer) {
return nullptr;
}
return RefPtr<WAVTrackDemuxer>(mTrackDemuxer).forget();
}
bool
WAVDemuxer::IsSeekable() const
{
return true;
}
// WAVTrackDemuxer
WAVTrackDemuxer::WAVTrackDemuxer(MediaResourceIndex aSource)
: mSource(aSource)
, mOffset(0)
, mFirstChunkOffset(0)
, mNumParsedChunks(0)
, mChunkIndex(0)
, mTotalChunkLen(0)
, mSamplesPerChunk(0)
, mSamplesPerSecond(0)
, mChannels(0)
{
Reset();
}
bool
WAVTrackDemuxer::Init()
{
Reset();
FastSeek(TimeUnit());
if (!mInfo) {
mInfo = MakeUnique<AudioInfo>();
}
if (!RIFFParserInit()) {
return false;
}
while (true) {
if (!HeaderParserInit()) {
return false;
}
uint32_t aChunkName = mHeaderParser.GiveHeader().ChunkName();
uint32_t aChunkSize = mHeaderParser.GiveHeader().ChunkSize();
aChunkSize += aChunkSize % 2;
if (aChunkName == FRMT_CODE) {
if (!FmtChunkParserInit()) {
return false;
}
} else if (aChunkName == LIST_CODE) {
mHeaderParser.Reset();
uint32_t endOfListChunk = mOffset + aChunkSize;
if (!ListChunkParserInit(aChunkSize)) {
mOffset = endOfListChunk;
}
} else if (aChunkName == DATA_CODE) {
mDataLength = aChunkSize;
if (mFirstChunkOffset != mOffset) {
mFirstChunkOffset = mOffset;
}
break;
} else {
mOffset += aChunkSize; // Skip other irrelevant chunks.
}
mHeaderParser.Reset();
}
if (mDataLength > StreamLength() - mFirstChunkOffset) {
mDataLength = StreamLength() - mFirstChunkOffset;
}
mSamplesPerSecond = mFmtParser.FmtChunk().SampleRate();
mChannels = mFmtParser.FmtChunk().Channels();
mSampleFormat = mFmtParser.FmtChunk().SampleFormat();
mSamplesPerChunk = DATA_CHUNK_SIZE * 8 / mChannels / mSampleFormat;
mInfo->mRate = mSamplesPerSecond;
mInfo->mChannels = mChannels;
mInfo->mBitDepth = mSampleFormat;
mInfo->mProfile = mFmtParser.FmtChunk().WaveFormat() & 0x00FF;
mInfo->mExtendedProfile = (mFmtParser.FmtChunk().WaveFormat() & 0xFF00) >> 8;
mInfo->mMimeType = "audio/wave; codecs=";
mInfo->mMimeType.AppendInt(mFmtParser.FmtChunk().WaveFormat());
mInfo->mDuration = Duration().ToMicroseconds();
return !!(mInfo->mDuration);
}
bool
WAVTrackDemuxer::RIFFParserInit()
{
RefPtr<MediaRawData> riffHeader = GetFileHeader(FindRIFFHeader());
if (!riffHeader) {
return false;
}
ByteReader RIFFReader = ByteReader(riffHeader->Data(), 12);
mRIFFParser.Parse(RIFFReader);
return mRIFFParser.RiffHeader().IsValid(11);
}
bool
WAVTrackDemuxer::HeaderParserInit()
{
RefPtr<MediaRawData> header = GetFileHeader(FindChunkHeader());
if (!header) {
return false;
}
ByteReader HeaderReader = ByteReader(header->Data(), 8);
mHeaderParser.Parse(HeaderReader);
return true;
}
bool
WAVTrackDemuxer::FmtChunkParserInit()
{
RefPtr<MediaRawData> fmtChunk = GetFileHeader(FindFmtChunk());
if (!fmtChunk) {
return false;
}
ByteReader fmtReader = ByteReader(fmtChunk->Data(),
mHeaderParser.GiveHeader().ChunkSize());
mFmtParser.Parse(fmtReader);
return true;
}
bool
WAVTrackDemuxer::ListChunkParserInit(uint32_t aChunkSize)
{
uint32_t bytesRead = 0;
RefPtr<MediaRawData> infoTag = GetFileHeader(FindInfoTag());
if (!infoTag) {
return false;
}
ByteReader infoTagReader = ByteReader(infoTag->Data(), 4);
if (!infoTagReader.CanRead32() || infoTagReader.ReadU32() != INFO_CODE) {
return false;
}
bytesRead += 4;
while (bytesRead < aChunkSize) {
if (!HeaderParserInit()) {
return false;
}
bytesRead += 8;
uint32_t id = mHeaderParser.GiveHeader().ChunkName();
uint32_t length = mHeaderParser.GiveHeader().ChunkSize();
// SubChunk Length Cannot Exceed List Chunk length.
if (length > aChunkSize - bytesRead) {
length = aChunkSize - bytesRead;
}
MediaByteRange mRange = { mOffset, mOffset + length };
RefPtr<MediaRawData> mChunkData = GetFileHeader(mRange);
if (!mChunkData) {
return false;
}
const char* mRawData = reinterpret_cast<const char*>(mChunkData->Data());
nsCString val(mRawData, length);
if (length > 0 && val[length - 1] == '\0') {
val.SetLength(length - 1);
}
if (length % 2) {
mOffset += 1;
length += length % 2;
}
bytesRead += length;
if (!IsUTF8(val)) {
mHeaderParser.Reset();
continue;
}
switch (id) {
case 0x49415254: // IART
mInfo->mTags.AppendElement(MetadataTag(NS_LITERAL_CSTRING("artist"), val));
break;
case 0x49434d54: // ICMT
mInfo->mTags.AppendElement(MetadataTag(NS_LITERAL_CSTRING("comments"), val));
break;
case 0x49474e52: // IGNR
mInfo->mTags.AppendElement(MetadataTag(NS_LITERAL_CSTRING("genre"), val));
break;
case 0x494e414d: // INAM
mInfo->mTags.AppendElement(MetadataTag(NS_LITERAL_CSTRING("name"), val));
break;
}
mHeaderParser.Reset();
}
return true;
}
media::TimeUnit
WAVTrackDemuxer::SeekPosition() const
{
TimeUnit pos = Duration(mChunkIndex);
if (Duration() > TimeUnit()) {
pos = std::min(Duration(), pos);
}
return pos;
}
RefPtr<MediaRawData>
WAVTrackDemuxer::DemuxSample()
{
return GetNextChunk(FindNextChunk());
}
UniquePtr<TrackInfo>
WAVTrackDemuxer::GetInfo() const
{
return mInfo->Clone();
}
RefPtr<WAVTrackDemuxer::SeekPromise>
WAVTrackDemuxer::Seek(TimeUnit aTime)
{
FastSeek(aTime);
const TimeUnit seekTime = ScanUntil(aTime);
return SeekPromise::CreateAndResolve(seekTime, __func__);
}
TimeUnit
WAVTrackDemuxer::FastSeek(const TimeUnit& aTime)
{
if (aTime.ToMicroseconds()) {
mChunkIndex = ChunkIndexFromTime(aTime);
} else {
mChunkIndex = 0;
}
mOffset = OffsetFromChunkIndex(mChunkIndex);
if (mOffset > mFirstChunkOffset && StreamLength() > 0) {
mOffset = std::min(StreamLength() - 1, mOffset);
}
return Duration(mChunkIndex);
}
TimeUnit
WAVTrackDemuxer::ScanUntil(const TimeUnit& aTime)
{
if (!aTime.ToMicroseconds()) {
return FastSeek(aTime);
}
if (Duration(mChunkIndex) > aTime) {
FastSeek(aTime);
}
return SeekPosition();
}
RefPtr<WAVTrackDemuxer::SamplesPromise>
WAVTrackDemuxer::GetSamples(int32_t aNumSamples)
{
if (!aNumSamples) {
return SamplesPromise::CreateAndReject(
DemuxerFailureReason::DEMUXER_ERROR, __func__);
}
RefPtr<SamplesHolder> datachunks = new SamplesHolder();
while (aNumSamples--) {
RefPtr<MediaRawData> datachunk = GetNextChunk(FindNextChunk());
if (!datachunk) {
break;
}
datachunks->mSamples.AppendElement(datachunk);
}
if (datachunks->mSamples.IsEmpty()) {
return SamplesPromise::CreateAndReject(
DemuxerFailureReason::END_OF_STREAM, __func__);
}
return SamplesPromise::CreateAndResolve(datachunks, __func__);
}
void
WAVTrackDemuxer::Reset()
{
FastSeek(TimeUnit());
mParser.Reset();
mHeaderParser.Reset();
mRIFFParser.Reset();
mFmtParser.Reset();
}
RefPtr<WAVTrackDemuxer::SkipAccessPointPromise>
WAVTrackDemuxer::SkipToNextRandomAccessPoint(TimeUnit aTimeThreshold)
{
return SkipAccessPointPromise::CreateAndReject(
SkipFailureHolder(DemuxerFailureReason::DEMUXER_ERROR, 0), __func__);
}
int64_t
WAVTrackDemuxer::GetResourceOffset() const
{
return mOffset;
}
TimeIntervals
WAVTrackDemuxer::GetBuffered()
{
TimeUnit duration = Duration();
if (duration <= TimeUnit()) {
return TimeIntervals();
}
AutoPinned<MediaResource> stream(mSource.GetResource());
return GetEstimatedBufferedTimeRanges(stream, duration.ToMicroseconds());
}
int64_t
WAVTrackDemuxer::StreamLength() const
{
return mSource.GetLength();
}
TimeUnit
WAVTrackDemuxer::Duration() const
{
if (!mDataLength) {
return TimeUnit();
}
int64_t numSamples = mDataLength * 8 / mChannels / mSampleFormat;
int64_t numUSeconds = USECS_PER_S * numSamples / mSamplesPerSecond;
if (USECS_PER_S * numSamples % mSamplesPerSecond > mSamplesPerSecond / 2) {
numUSeconds++;
}
return TimeUnit::FromMicroseconds(numUSeconds);
}
TimeUnit
WAVTrackDemuxer::Duration(int64_t aNumDataChunks) const
{
if (!mSamplesPerSecond) {
return TimeUnit();
}
const double usPerDataChunk = USECS_PER_S * mSamplesPerChunk /
mSamplesPerSecond;
return TimeUnit::FromMicroseconds(aNumDataChunks * usPerDataChunk);
}
TimeUnit
WAVTrackDemuxer::DurationFromBytes(uint32_t aNumBytes) const
{
if (!mSamplesPerSecond) {
return TimeUnit();
}
int64_t numSamples = aNumBytes * 8 / mChannels / mSampleFormat;
int64_t numUSeconds = USECS_PER_S * numSamples / mSamplesPerSecond;
if (USECS_PER_S * numSamples % mSamplesPerSecond > mSamplesPerSecond / 2) {
numUSeconds++;
}
return TimeUnit::FromMicroseconds(numUSeconds);
}
MediaByteRange
WAVTrackDemuxer::FindNextChunk()
{
if (mOffset + DATA_CHUNK_SIZE < mFirstChunkOffset + mDataLength) {
return { mOffset, mOffset + DATA_CHUNK_SIZE };
} else {
return { mOffset, mFirstChunkOffset + mDataLength };
}
}
MediaByteRange
WAVTrackDemuxer::FindChunkHeader()
{
return { mOffset, mOffset + CHUNK_HEAD_SIZE };
}
MediaByteRange
WAVTrackDemuxer::FindRIFFHeader()
{
return { mOffset, mOffset + RIFF_CHUNK_SIZE };
}
MediaByteRange
WAVTrackDemuxer::FindFmtChunk()
{
return { mOffset, mOffset + mHeaderParser.GiveHeader().ChunkSize() };
}
MediaByteRange
WAVTrackDemuxer::FindListChunk()
{
return { mOffset, mOffset + mHeaderParser.GiveHeader().ChunkSize() };
}
MediaByteRange
WAVTrackDemuxer::FindInfoTag()
{
return { mOffset, mOffset + 4 };
}
bool
WAVTrackDemuxer::SkipNextChunk(const MediaByteRange& aRange)
{
UpdateState(aRange);
return true;
}
already_AddRefed<MediaRawData>
WAVTrackDemuxer::GetNextChunk(const MediaByteRange& aRange)
{
if (!aRange.Length()) {
return nullptr;
}
RefPtr<MediaRawData> datachunk = new MediaRawData();
datachunk->mOffset = aRange.mStart;
nsAutoPtr<MediaRawDataWriter> chunkWriter(datachunk->CreateWriter());
if (!chunkWriter->SetSize(aRange.Length())) {
return nullptr;
}
const uint32_t read = Read(chunkWriter->Data(),
datachunk->mOffset,
datachunk->Size());
if (read != aRange.Length()) {
return nullptr;
}
UpdateState(aRange);
++mNumParsedChunks;
++mChunkIndex;
datachunk->mTime = Duration(mChunkIndex - 1).ToMicroseconds();
if (static_cast<uint32_t>(mChunkIndex) * DATA_CHUNK_SIZE < mDataLength) {
datachunk->mDuration = Duration(1).ToMicroseconds();
} else {
uint32_t mBytesRemaining =
mDataLength - mChunkIndex * DATA_CHUNK_SIZE;
datachunk->mDuration = DurationFromBytes(mBytesRemaining).ToMicroseconds();
}
datachunk->mTimecode = datachunk->mTime;
datachunk->mKeyframe = true;
MOZ_ASSERT(datachunk->mTime >= 0);
MOZ_ASSERT(datachunk->mDuration >= 0);
return datachunk.forget();
}
already_AddRefed<MediaRawData>
WAVTrackDemuxer::GetFileHeader(const MediaByteRange& aRange)
{
if (!aRange.Length()) {
return nullptr;
}
RefPtr<MediaRawData> fileHeader = new MediaRawData();
fileHeader->mOffset = aRange.mStart;
nsAutoPtr<MediaRawDataWriter> headerWriter(fileHeader->CreateWriter());
if (!headerWriter->SetSize(aRange.Length())) {
return nullptr;
}
const uint32_t read = Read(headerWriter->Data(),
fileHeader->mOffset,
fileHeader->Size());
if (read != aRange.Length()) {
return nullptr;
}
UpdateState(aRange);
return fileHeader.forget();
}
int64_t
WAVTrackDemuxer::OffsetFromChunkIndex(int64_t aChunkIndex) const
{
return mFirstChunkOffset + aChunkIndex * DATA_CHUNK_SIZE;
}
int64_t
WAVTrackDemuxer::ChunkIndexFromOffset(int64_t aOffset) const
{
int64_t chunkIndex = (aOffset - mFirstChunkOffset) / DATA_CHUNK_SIZE;
return std::max<int64_t>(0, chunkIndex);
}
int64_t
WAVTrackDemuxer::ChunkIndexFromTime(const media::TimeUnit& aTime) const
{
int64_t chunkIndex =
(aTime.ToSeconds() * mSamplesPerSecond / mSamplesPerChunk) - 1;
return chunkIndex;
}
void
WAVTrackDemuxer::UpdateState(const MediaByteRange& aRange)
{
// Full chunk parsed, move offset to its end.
mOffset = aRange.mEnd;
mTotalChunkLen += aRange.Length();
}
int32_t
WAVTrackDemuxer::Read(uint8_t* aBuffer, int64_t aOffset, int32_t aSize)
{
const int64_t streamLen = StreamLength();
if (mInfo && streamLen > 0) {
aSize = std::min<int64_t>(aSize, streamLen - aOffset);
}
uint32_t read = 0;
const nsresult rv = mSource.ReadAt(aOffset,
reinterpret_cast<char*>(aBuffer),
static_cast<uint32_t>(aSize),
&read);
NS_ENSURE_SUCCESS(rv, 0);
return static_cast<int32_t>(read);
}
// RIFFParser
uint32_t
RIFFParser::Parse(ByteReader& aReader)
{
MOZ_ASSERT(&aReader);
while (aReader.CanRead8() && !mRiffHeader.ParseNext(aReader.ReadU8())) { }
if (mRiffHeader.IsValid()) {
return RIFF_CHUNK_SIZE;
}
return 0;
}
void
RIFFParser::Reset()
{
mRiffHeader.Reset();
}
const RIFFParser::RIFFHeader&
RIFFParser::RiffHeader() const
{
return mRiffHeader;
}
// RIFFParser::RIFFHeader
RIFFParser::RIFFHeader::RIFFHeader()
{
Reset();
}
void
RIFFParser::RIFFHeader::Reset()
{
mPos = 0;
}
bool
RIFFParser::RIFFHeader::ParseNext(uint8_t c)
{
if (!Update(c)) {
Reset();
if (!Update(c)) {
Reset();
}
}
return IsValid();
}
bool
RIFFParser::RIFFHeader::IsValid(int aPos) const
{
if (aPos > -1 && aPos < 4) {
return RIFF[aPos] == mRaw[aPos];
} else if (aPos > 7 && aPos < 12) {
return WAVE[aPos - 8] == mRaw[aPos];
} else {
return true;
}
}
bool
RIFFParser::RIFFHeader::IsValid() const
{
return mPos >= RIFF_CHUNK_SIZE;
}
bool
RIFFParser::RIFFHeader::Update(uint8_t c)
{
if (mPos < RIFF_CHUNK_SIZE) {
mRaw[mPos] = c;
}
return IsValid(mPos++);
}
// HeaderParser
uint32_t
HeaderParser::Parse(ByteReader& aReader)
{
while (aReader.CanRead8() && !mHeader.ParseNext(aReader.ReadU8())) { }
if (mHeader.IsValid()) {
return CHUNK_HEAD_SIZE;
}
return 0;
}
void
HeaderParser::Reset()
{
mHeader.Reset();
}
const HeaderParser::ChunkHeader&
HeaderParser::GiveHeader() const
{
return mHeader;
}
// HeaderParser::ChunkHeader
HeaderParser::ChunkHeader::ChunkHeader()
{
Reset();
}
void
HeaderParser::ChunkHeader::Reset()
{
mPos = 0;
}
bool
HeaderParser::ChunkHeader::ParseNext(uint8_t c)
{
Update(c);
return IsValid();
}
bool
HeaderParser::ChunkHeader::IsValid() const
{
return mPos >= CHUNK_HEAD_SIZE;
}
uint32_t
HeaderParser::ChunkHeader::ChunkName() const
{
return ((mRaw[0] << 24) | (mRaw[1] << 16) |
(mRaw[2] << 8 ) | (mRaw[3]));
}
uint32_t
HeaderParser::ChunkHeader::ChunkSize() const
{
return ((mRaw[7] << 24) | (mRaw[6] << 16) |
(mRaw[5] << 8 ) | (mRaw[4]));
}
void
HeaderParser::ChunkHeader::Update(uint8_t c)
{
if (mPos < CHUNK_HEAD_SIZE) {
mRaw[mPos++] = c;
}
}
// FormatParser
uint32_t
FormatParser::Parse(ByteReader& aReader)
{
MOZ_ASSERT(&aReader);
while (aReader.CanRead8() && !mFmtChunk.ParseNext(aReader.ReadU8())) { }
if (mFmtChunk.IsValid()) {
return FMT_CHUNK_MIN_SIZE;
}
return 0;
}
void
FormatParser::Reset()
{
mFmtChunk.Reset();
}
const FormatParser::FormatChunk&
FormatParser::FmtChunk() const
{
return mFmtChunk;
}
// FormatParser::FormatChunk
FormatParser::FormatChunk::FormatChunk()
{
Reset();
}
void
FormatParser::FormatChunk::Reset()
{
mPos = 0;
}
uint16_t
FormatParser::FormatChunk::WaveFormat() const
{
return (mRaw[1] << 8) | (mRaw[0]);
}
uint16_t
FormatParser::FormatChunk::Channels() const
{
return (mRaw[3] << 8) | (mRaw[2]);
}
uint32_t
FormatParser::FormatChunk::SampleRate() const
{
return (mRaw[7] << 24) | (mRaw[6] << 16) |
(mRaw[5] << 8 ) | (mRaw[4]);
}
uint16_t
FormatParser::FormatChunk::FrameSize() const
{
return (mRaw[13] << 8) | (mRaw[12]);
}
uint16_t
FormatParser::FormatChunk::SampleFormat() const
{
return (mRaw[15] << 8) | (mRaw[14]);
}
bool
FormatParser::FormatChunk::ParseNext(uint8_t c)
{
Update(c);
return IsValid();
}
bool
FormatParser::FormatChunk::IsValid() const
{
return (FrameSize() == SampleRate() * Channels() / 8) &&
(mPos >= FMT_CHUNK_MIN_SIZE);
}
void
FormatParser::FormatChunk::Update(uint8_t c)
{
if (mPos < FMT_CHUNK_MIN_SIZE) {
mRaw[mPos++] = c;
}
}
// DataParser
DataParser::DataParser()
{
}
void
DataParser::Reset()
{
mChunk.Reset();
}
const DataParser::DataChunk&
DataParser::CurrentChunk() const
{
return mChunk;
}
// DataParser::DataChunk
void
DataParser::DataChunk::Reset()
{
mPos = 0;
}
} // namespace mozilla

View File

@ -1,262 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* Licence, 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 WAV_DEMUXER_H_
#define WAV_DEMUXER_H_
#include "mozilla/Attributes.h"
#include "mozilla/Maybe.h"
#include "MediaDataDemuxer.h"
#include "MediaResource.h"
#include "mp4_demuxer/ByteReader.h"
using mp4_demuxer::ByteReader;
namespace mozilla {
static const uint32_t FRMT_CODE = 0x666d7420;
static const uint32_t DATA_CODE = 0x64617461;
static const uint32_t LIST_CODE = 0x4c495354;
static const uint32_t INFO_CODE = 0x494e464f;
static const uint8_t RIFF[4] = {'R', 'I', 'F', 'F'};
static const uint8_t WAVE[4] = {'W', 'A', 'V', 'E'};
static const uint16_t RIFF_CHUNK_SIZE = 12;
static const uint16_t CHUNK_HEAD_SIZE = 8;
static const uint16_t FMT_CHUNK_MIN_SIZE = 16;
static const uint16_t DATA_CHUNK_SIZE = 768;
class WAVTrackDemuxer;
class WAVDemuxer : public MediaDataDemuxer {
public:
// MediaDataDemuxer interface.
explicit WAVDemuxer(MediaResource* aSource);
RefPtr<InitPromise> Init() override;
bool HasTrackType(TrackInfo::TrackType aType) const override;
uint32_t GetNumberTracks(TrackInfo::TrackType aType) const override;
already_AddRefed<MediaTrackDemuxer> GetTrackDemuxer(
TrackInfo::TrackType aType, uint32_t aTrackNumber) override;
bool IsSeekable() const override;
private:
// Synchronous Initialization.
bool InitInternal();
MediaResourceIndex mSource;
RefPtr<WAVTrackDemuxer> mTrackDemuxer;
};
class RIFFParser {
private:
class RIFFHeader;
public:
const RIFFHeader& RiffHeader() const;
uint32_t Parse(ByteReader& aReader);
void Reset();
private:
class RIFFHeader {
public:
RIFFHeader();
void Reset();
bool IsValid() const;
bool IsValid(int aPos) const;
bool ParseNext(uint8_t c);
private:
bool Update(uint8_t c);
uint8_t mRaw[RIFF_CHUNK_SIZE];
int mPos;
};
RIFFHeader mRiffHeader;
};
class HeaderParser {
private:
class ChunkHeader;
public:
const ChunkHeader& GiveHeader() const;
uint32_t Parse(ByteReader& aReader);
void Reset();
private:
class ChunkHeader {
public:
ChunkHeader();
void Reset();
bool IsValid() const;
uint32_t ChunkName() const;
uint32_t ChunkSize() const;
bool ParseNext(uint8_t c);
private:
void Update(uint8_t c);
uint8_t mRaw[CHUNK_HEAD_SIZE];
int mPos;
};
ChunkHeader mHeader;
};
class FormatParser {
private:
class FormatChunk;
public:
const FormatChunk& FmtChunk() const;
uint32_t Parse(ByteReader& aReader);
void Reset();
private:
class FormatChunk {
public:
FormatChunk();
void Reset();
uint16_t WaveFormat() const;
uint16_t Channels() const;
uint32_t SampleRate() const;
uint16_t FrameSize() const;
uint16_t SampleFormat() const;
bool IsValid() const;
bool ParseNext(uint8_t c);
private:
void Update(uint8_t c);
uint8_t mRaw[FMT_CHUNK_MIN_SIZE];
int mPos;
};
FormatChunk mFmtChunk;
};
class DataParser {
private:
class DataChunk;
public:
DataParser();
const DataChunk& CurrentChunk() const;
void Reset();
private:
class DataChunk {
public:
void Reset();
private:
int mPos; // To Check Alignment
};
DataChunk mChunk;
};
class WAVTrackDemuxer : public MediaTrackDemuxer {
public:
explicit WAVTrackDemuxer(MediaResourceIndex aSource);
bool Init();
int64_t StreamLength() const;
media::TimeUnit Duration() const;
media::TimeUnit Duration(int64_t aNumDataChunks) const;
media::TimeUnit DurationFromBytes(uint32_t aNumBytes) const;
media::TimeUnit SeekPosition() const;
RefPtr<MediaRawData> DemuxSample();
// MediaTrackDemuxer interface.
UniquePtr<TrackInfo> GetInfo() const override;
RefPtr<SeekPromise> Seek(media::TimeUnit aTime) override;
RefPtr<SamplesPromise> GetSamples(int32_t aNumSamples) override;
void Reset() override;
RefPtr<SkipAccessPointPromise> SkipToNextRandomAccessPoint(
media::TimeUnit aTimeThreshold) override;
int64_t GetResourceOffset() const override;
media::TimeIntervals GetBuffered() override;
private:
~WAVTrackDemuxer() {}
media::TimeUnit FastSeek(const media::TimeUnit& aTime);
media::TimeUnit ScanUntil(const media::TimeUnit& aTime);
MediaByteRange FindNextChunk();
MediaByteRange FindChunkHeader();
MediaByteRange FindRIFFHeader();
MediaByteRange FindFmtChunk();
MediaByteRange FindListChunk();
MediaByteRange FindInfoTag();
bool RIFFParserInit();
bool HeaderParserInit();
bool FmtChunkParserInit();
bool ListChunkParserInit(uint32_t aChunkSize);
bool SkipNextChunk(const MediaByteRange& aRange);
already_AddRefed<MediaRawData> GetNextChunk(const MediaByteRange& aRange);
already_AddRefed<MediaRawData> GetFileHeader(const MediaByteRange& aRange);
void UpdateState(const MediaByteRange& aRange);
int64_t OffsetFromChunkIndex(int64_t aChunkIndex) const;
int64_t ChunkIndexFromOffset(int64_t aOffet) const;
int64_t ChunkIndexFromTime(const media::TimeUnit& aTime) const;
int32_t Read(uint8_t* aBuffer, int64_t aOffset, int32_t aSize);
MediaResourceIndex mSource;
DataParser mParser;
RIFFParser mRIFFParser;
HeaderParser mHeaderParser;
FormatParser mFmtParser;
// ListChunkParser mListChunkParser;
int64_t mOffset;
int64_t mFirstChunkOffset;
uint32_t mNumParsedChunks;
int32_t mChunkIndex;
uint32_t mDataLength;
uint64_t mTotalChunkLen;
int32_t mSamplesPerChunk;
int32_t mSamplesPerSecond;
int32_t mChannels;
int32_t mSampleFormat;
UniquePtr<AudioInfo> mInfo;
};
} // namespace mozilla
#endif

View File

@ -6,13 +6,11 @@
EXPORTS += [
'WaveDecoder.h',
'WaveDemuxer.h',
'WaveReader.h',
]
UNIFIED_SOURCES += [
'WaveDecoder.cpp',
'WaveDemuxer.cpp',
'WaveReader.cpp',
]

View File

@ -23,11 +23,11 @@ function finishTest(a) {
function decodeUsingAudioElement() {
var a = new Audio();
a.addEventListener("error", function() {
ok(false, "Error loading metadata");
ok(true, "We should not be able to decode this file using an HTMLAudioElement");
finishTest(a);
});
a.addEventListener("loadedmetadata", function() {
ok(true, "Metadata Loaded");
ok(false, "We should not be able to decode this file using an HTMLMediaElement.");
finishTest(a);
});

View File

@ -87,16 +87,6 @@ public:
return mozilla::BigEndian::readUint16(ptr);
}
int16_t ReadLE16()
{
auto ptr = Read(2);
if (!ptr) {
MOZ_ASSERT(false);
return 0;
}
return mozilla::LittleEndian::readInt16(ptr);
}
uint32_t ReadU24()
{
auto ptr = Read(3);
@ -112,20 +102,6 @@ public:
return (uint32_t)ReadU24();
}
int32_t ReadLE24()
{
auto ptr = Read(3);
if (!ptr) {
MOZ_ASSERT(false);
return 0;
}
int32_t result = int32_t(ptr[2] << 16 | ptr[1] << 8 | ptr[0]);
if (result & 0x00800000u) {
result -= 0x1000000;
}
return result;
}
bool CanRead32() { return mRemaining >= 4; }
uint32_t ReadU32()

View File

@ -349,7 +349,6 @@ pref("media.raw.enabled", true);
pref("media.ogg.enabled", true);
pref("media.opus.enabled", true);
pref("media.wave.enabled", true);
pref("media.wave.decoder.enabled", true);
pref("media.webm.enabled", true);
#if defined(MOZ_FMP4) && defined(MOZ_WMF)
pref("media.webm.intel_decoder.enabled", false);