mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
Bug 1325707: P4. Fix coding style of MediaDataDemuxers. r=gerald
MozReview-Commit-ID: AV2lXwVZqLV --HG-- extra : rebase_source : f66559f4d104516c8dfd2c9a146dfba8672dce33
This commit is contained in:
parent
16bf821b42
commit
71e0f46c33
@ -53,7 +53,8 @@ namespace adts {
|
||||
// maximum compatibility always use 1 AAC frame per ADTS
|
||||
// frame
|
||||
// Q 16 CRC if protection absent is 0
|
||||
class FrameHeader {
|
||||
class FrameHeader
|
||||
{
|
||||
public:
|
||||
uint32_t mFrameLength;
|
||||
uint32_t mSampleRate;
|
||||
@ -66,7 +67,8 @@ public:
|
||||
bool mHaveCrc;
|
||||
|
||||
// Returns whether aPtr matches a valid ADTS header sync marker
|
||||
static bool MatchesSync(const uint8_t* aPtr) {
|
||||
static bool MatchesSync(const uint8_t* aPtr)
|
||||
{
|
||||
return aPtr[0] == 0xFF && (aPtr[1] & 0xF6) == 0xF0;
|
||||
}
|
||||
|
||||
@ -81,7 +83,8 @@ public:
|
||||
void Reset() { PodZero(this); }
|
||||
|
||||
// Returns whether the byte creates a valid sequence up to this point.
|
||||
bool Parse(const uint8_t* aPtr) {
|
||||
bool Parse(const uint8_t* aPtr)
|
||||
{
|
||||
const uint8_t* p = aPtr;
|
||||
|
||||
if (!MatchesSync(p)) {
|
||||
@ -95,7 +98,8 @@ public:
|
||||
mObjectType = ((p[2] & 0xC0) >> 6) + 1;
|
||||
mSamplingIndex = (p[2] & 0x3C) >> 2;
|
||||
mChannelConfig = (p[2] & 0x01) << 2 | (p[3] & 0xC0) >> 6;
|
||||
mFrameLength = (p[3] & 0x03) << 11 | (p[4] & 0xFF) << 3 | (p[5] & 0xE0) >> 5;
|
||||
mFrameLength =
|
||||
(p[3] & 0x03) << 11 | (p[4] & 0xFF) << 3 | (p[5] & 0xE0) >> 5;
|
||||
mNumAACFrames = (p[6] & 0x03) + 1;
|
||||
|
||||
static const int32_t SAMPLE_RATES[16] = {
|
||||
@ -116,13 +120,16 @@ public:
|
||||
|
||||
// adts::Frame - Frame meta container used to parse and hold a frame
|
||||
// header and side info.
|
||||
class Frame {
|
||||
class Frame
|
||||
{
|
||||
public:
|
||||
Frame() : mOffset(0), mHeader() {}
|
||||
Frame() : mOffset(0), mHeader() { }
|
||||
|
||||
int64_t Offset() const { return mOffset; }
|
||||
size_t Length() const {
|
||||
// TODO: If fields are zero'd when invalid, this check wouldn't be necessary.
|
||||
size_t Length() const
|
||||
{
|
||||
// TODO: If fields are zero'd when invalid, this check wouldn't be
|
||||
// necessary.
|
||||
if (!mHeader.IsValid()) {
|
||||
return 0;
|
||||
}
|
||||
@ -131,13 +138,13 @@ public:
|
||||
}
|
||||
|
||||
// Returns the offset to the start of frame's raw data.
|
||||
int64_t PayloadOffset() const {
|
||||
return mOffset + mHeader.HeaderSize();
|
||||
}
|
||||
int64_t PayloadOffset() const { return mOffset + mHeader.HeaderSize(); }
|
||||
|
||||
// Returns the length of the frame's raw data (excluding the header) in bytes.
|
||||
size_t PayloadLength() const {
|
||||
// TODO: If fields are zero'd when invalid, this check wouldn't be necessary.
|
||||
size_t PayloadLength() const
|
||||
{
|
||||
// TODO: If fields are zero'd when invalid, this check wouldn't be
|
||||
// necessary.
|
||||
if (!mHeader.IsValid()) {
|
||||
return 0;
|
||||
}
|
||||
@ -146,16 +153,13 @@ public:
|
||||
}
|
||||
|
||||
// Returns the parsed frame header.
|
||||
const FrameHeader& Header() const {
|
||||
return mHeader;
|
||||
}
|
||||
const FrameHeader& Header() const { return mHeader; }
|
||||
|
||||
bool IsValid() const {
|
||||
return mHeader.IsValid();
|
||||
}
|
||||
bool IsValid() const { return mHeader.IsValid(); }
|
||||
|
||||
// Resets the frame header and data.
|
||||
void Reset() {
|
||||
void Reset()
|
||||
{
|
||||
mHeader.Reset();
|
||||
mOffset = 0;
|
||||
}
|
||||
@ -187,7 +191,8 @@ private:
|
||||
};
|
||||
|
||||
|
||||
class FrameParser {
|
||||
class FrameParser
|
||||
{
|
||||
public:
|
||||
|
||||
// Returns the currently parsed frame. Reset via Reset or EndFrameSession.
|
||||
@ -198,7 +203,8 @@ public:
|
||||
const Frame& FirstFrame() const { return mFirstFrame; }
|
||||
|
||||
// Resets the parser. Don't use between frames as first frame data is reset.
|
||||
void Reset() {
|
||||
void Reset()
|
||||
{
|
||||
EndFrameSession();
|
||||
mFirstFrame.Reset();
|
||||
}
|
||||
@ -207,15 +213,17 @@ public:
|
||||
// - sets PrevFrame to CurrentFrame
|
||||
// - resets the CurrentFrame
|
||||
// - resets ID3Header if no valid header was parsed yet
|
||||
void EndFrameSession() {
|
||||
void EndFrameSession()
|
||||
{
|
||||
mFrame.Reset();
|
||||
}
|
||||
|
||||
// Parses contents of given ByteReader for a valid frame header and returns true
|
||||
// if one was found. After returning, the variable passed to 'aBytesToSkip' holds
|
||||
// the amount of bytes to be skipped (if any) in order to jump across a large
|
||||
// ID3v2 tag spanning multiple buffers.
|
||||
bool Parse(int64_t aOffset, uint8_t* aStart, uint8_t* aEnd) {
|
||||
// Parses contents of given ByteReader for a valid frame header and returns
|
||||
// true if one was found. After returning, the variable passed to
|
||||
// 'aBytesToSkip' holds the amount of bytes to be skipped (if any) in order to
|
||||
// jump across a large ID3v2 tag spanning multiple buffers.
|
||||
bool Parse(int64_t aOffset, uint8_t* aStart, uint8_t* aEnd)
|
||||
{
|
||||
const bool found = mFrame.Parse(aOffset, aStart, aEnd);
|
||||
|
||||
if (mFrame.Length() && !mFirstFrame.Length()) {
|
||||
@ -300,7 +308,8 @@ InitAudioSpecificConfig(const Frame& frame,
|
||||
|
||||
ADTSDemuxer::ADTSDemuxer(MediaResource* aSource)
|
||||
: mSource(aSource)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
ADTSDemuxer::InitInternal()
|
||||
@ -375,13 +384,11 @@ ADTSTrackDemuxer::ADTSTrackDemuxer(MediaResource* aSource)
|
||||
ADTSTrackDemuxer::~ADTSTrackDemuxer()
|
||||
{
|
||||
delete mParser;
|
||||
mParser = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
ADTSTrackDemuxer::Init()
|
||||
{
|
||||
|
||||
FastSeek(media::TimeUnit());
|
||||
// Read the first frame to fetch sample rate and other meta data.
|
||||
RefPtr<MediaRawData> frame(GetNextFrame(FindNextFrame(true)));
|
||||
@ -420,7 +427,8 @@ ADTSTrackDemuxer::Init()
|
||||
mInfo->mExtendedProfile = mParser->FirstFrame().Header().mObjectType;
|
||||
InitAudioSpecificConfig(mParser->FirstFrame(), mInfo->mCodecSpecificConfig);
|
||||
|
||||
ADTSLOG("Init mInfo={mRate=%u mChannels=%u mBitDepth=%u mDuration=%" PRId64 "}",
|
||||
ADTSLOG("Init mInfo={mRate=%u mChannels=%u mBitDepth=%u mDuration=%" PRId64
|
||||
"}",
|
||||
mInfo->mRate, mInfo->mChannels, mInfo->mBitDepth, mInfo->mDuration);
|
||||
|
||||
return mSamplesPerSecond && mChannels;
|
||||
@ -510,10 +518,11 @@ RefPtr<ADTSTrackDemuxer::SamplesPromise>
|
||||
ADTSTrackDemuxer::GetSamples(int32_t aNumSamples)
|
||||
{
|
||||
ADTSLOGV("GetSamples(%d) Begin mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
|
||||
" mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64 " mSamplesPerFrame=%d "
|
||||
"mSamplesPerSecond=%d mChannels=%d",
|
||||
aNumSamples, mOffset, mNumParsedFrames, mFrameIndex, mTotalFrameLen,
|
||||
mSamplesPerFrame, mSamplesPerSecond, mChannels);
|
||||
" mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64
|
||||
" mSamplesPerFrame=%d "
|
||||
"mSamplesPerSecond=%d mChannels=%d",
|
||||
aNumSamples, mOffset, mNumParsedFrames, mFrameIndex, mTotalFrameLen,
|
||||
mSamplesPerFrame, mSamplesPerSecond, mChannels);
|
||||
|
||||
MOZ_ASSERT(aNumSamples);
|
||||
|
||||
@ -528,12 +537,13 @@ ADTSTrackDemuxer::GetSamples(int32_t aNumSamples)
|
||||
}
|
||||
|
||||
ADTSLOGV("GetSamples() End mSamples.Size()=%d aNumSamples=%d mOffset=%" PRIu64
|
||||
" mNumParsedFrames=%" PRIu64 " mFrameIndex=%" PRId64
|
||||
" mTotalFrameLen=%" PRIu64 " mSamplesPerFrame=%d mSamplesPerSecond=%d "
|
||||
"mChannels=%d",
|
||||
frames->mSamples.Length(), aNumSamples, mOffset, mNumParsedFrames,
|
||||
mFrameIndex, mTotalFrameLen, mSamplesPerFrame, mSamplesPerSecond,
|
||||
mChannels);
|
||||
" mNumParsedFrames=%" PRIu64 " mFrameIndex=%" PRId64
|
||||
" mTotalFrameLen=%" PRIu64
|
||||
" mSamplesPerFrame=%d mSamplesPerSecond=%d "
|
||||
"mChannels=%d",
|
||||
frames->mSamples.Length(), aNumSamples, mOffset, mNumParsedFrames,
|
||||
mFrameIndex, mTotalFrameLen, mSamplesPerFrame, mSamplesPerSecond,
|
||||
mChannels);
|
||||
|
||||
if (frames->mSamples.IsEmpty()) {
|
||||
return SamplesPromise::CreateAndReject(
|
||||
@ -555,7 +565,8 @@ ADTSTrackDemuxer::Reset()
|
||||
}
|
||||
|
||||
RefPtr<ADTSTrackDemuxer::SkipAccessPointPromise>
|
||||
ADTSTrackDemuxer::SkipToNextRandomAccessPoint(const media::TimeUnit& aTimeThreshold)
|
||||
ADTSTrackDemuxer::SkipToNextRandomAccessPoint(
|
||||
const media::TimeUnit& aTimeThreshold)
|
||||
{
|
||||
// Will not be called for audio-only resources.
|
||||
return SkipAccessPointPromise::CreateAndReject(
|
||||
@ -654,7 +665,8 @@ ADTSTrackDemuxer::FindNextFrame(bool findFirstFrame /*= false*/)
|
||||
// possible to find sync marker in AAC data. If sync marker
|
||||
// exists after the current frame then we've found a frame
|
||||
// header.
|
||||
int64_t nextFrameHeaderOffset = currentFrame.Offset() + currentFrame.Length();
|
||||
int64_t nextFrameHeaderOffset =
|
||||
currentFrame.Offset() + currentFrame.Length();
|
||||
int32_t read = Read(buffer, nextFrameHeaderOffset, 2);
|
||||
if (read != 2 || !adts::FrameHeader::MatchesSync(buffer)) {
|
||||
frameHeaderOffset = currentFrame.Offset() + 1;
|
||||
@ -752,10 +764,10 @@ ADTSTrackDemuxer::GetNextFrame(const adts::Frame& aFrame)
|
||||
MOZ_ASSERT(frame->mDuration > 0);
|
||||
|
||||
ADTSLOGV("GetNext() End mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
|
||||
" mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64
|
||||
" mSamplesPerFrame=%d mSamplesPerSecond=%d mChannels=%d",
|
||||
mOffset, mNumParsedFrames, mFrameIndex, mTotalFrameLen,
|
||||
mSamplesPerFrame, mSamplesPerSecond, mChannels);
|
||||
" mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64
|
||||
" mSamplesPerFrame=%d mSamplesPerSecond=%d mChannels=%d",
|
||||
mOffset, mNumParsedFrames, mFrameIndex, mTotalFrameLen,
|
||||
mSamplesPerFrame, mSamplesPerSecond, mChannels);
|
||||
|
||||
return frame.forget();
|
||||
}
|
||||
@ -766,7 +778,8 @@ ADTSTrackDemuxer::FrameIndexFromOffset(int64_t aOffset) const
|
||||
int64_t frameIndex = 0;
|
||||
|
||||
if (AverageFrameLength() > 0) {
|
||||
frameIndex = (aOffset - mParser->FirstFrame().Offset()) / AverageFrameLength();
|
||||
frameIndex =
|
||||
(aOffset - mParser->FirstFrame().Offset()) / AverageFrameLength();
|
||||
}
|
||||
|
||||
ADTSLOGV("FrameIndexFromOffset(%" PRId64 ") -> %" PRId64, aOffset, frameIndex);
|
||||
@ -781,7 +794,8 @@ ADTSTrackDemuxer::FrameIndexFromTime(const media::TimeUnit& aTime) const
|
||||
frameIndex = aTime.ToSeconds() * mSamplesPerSecond / mSamplesPerFrame - 1;
|
||||
}
|
||||
|
||||
ADTSLOGV("FrameIndexFromOffset(%fs) -> %" PRId64, aTime.ToSeconds(), frameIndex);
|
||||
ADTSLOGV("FrameIndexFromOffset(%fs) -> %" PRId64,
|
||||
aTime.ToSeconds(), frameIndex);
|
||||
return std::max<int64_t>(0, frameIndex);
|
||||
}
|
||||
|
||||
@ -816,7 +830,8 @@ ADTSTrackDemuxer::UpdateState(const adts::Frame& aFrame)
|
||||
int32_t
|
||||
ADTSTrackDemuxer::Read(uint8_t* aBuffer, int64_t aOffset, int32_t aSize)
|
||||
{
|
||||
ADTSLOGV("ADTSTrackDemuxer::Read(%p %" PRId64 " %d)", aBuffer, aOffset, aSize);
|
||||
ADTSLOGV("ADTSTrackDemuxer::Read(%p %" PRId64 " %d)",
|
||||
aBuffer, aOffset, aSize);
|
||||
|
||||
const int64_t streamLen = StreamLength();
|
||||
if (mInfo && streamLen > 0) {
|
||||
|
@ -22,15 +22,16 @@ class FrameParser;
|
||||
|
||||
class ADTSTrackDemuxer;
|
||||
|
||||
class ADTSDemuxer : public MediaDataDemuxer {
|
||||
class ADTSDemuxer : public MediaDataDemuxer
|
||||
{
|
||||
public:
|
||||
// MediaDataDemuxer interface.
|
||||
explicit ADTSDemuxer(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;
|
||||
already_AddRefed<MediaTrackDemuxer>
|
||||
GetTrackDemuxer(TrackInfo::TrackType aType, uint32_t aTrackNumber) override;
|
||||
bool IsSeekable() const override;
|
||||
|
||||
private:
|
||||
@ -40,7 +41,8 @@ private:
|
||||
RefPtr<ADTSTrackDemuxer> mTrackDemuxer;
|
||||
};
|
||||
|
||||
class ADTSTrackDemuxer : public MediaTrackDemuxer {
|
||||
class ADTSTrackDemuxer : public MediaTrackDemuxer
|
||||
{
|
||||
public:
|
||||
explicit ADTSTrackDemuxer(MediaResource* aSource);
|
||||
|
||||
|
@ -37,12 +37,11 @@ namespace mp3 {
|
||||
|
||||
// MP3Demuxer
|
||||
|
||||
MP3Demuxer::MP3Demuxer(MediaResource* aSource)
|
||||
: mSource(aSource)
|
||||
{}
|
||||
MP3Demuxer::MP3Demuxer(MediaResource* aSource) : mSource(aSource) { }
|
||||
|
||||
bool
|
||||
MP3Demuxer::InitInternal() {
|
||||
MP3Demuxer::InitInternal()
|
||||
{
|
||||
if (!mTrackDemuxer) {
|
||||
mTrackDemuxer = new MP3TrackDemuxer(mSource);
|
||||
}
|
||||
@ -50,7 +49,8 @@ MP3Demuxer::InitInternal() {
|
||||
}
|
||||
|
||||
RefPtr<MP3Demuxer::InitPromise>
|
||||
MP3Demuxer::Init() {
|
||||
MP3Demuxer::Init()
|
||||
{
|
||||
if (!InitInternal()) {
|
||||
MP3LOG("MP3Demuxer::Init() failure: waiting for data");
|
||||
|
||||
@ -63,17 +63,20 @@ MP3Demuxer::Init() {
|
||||
}
|
||||
|
||||
bool
|
||||
MP3Demuxer::HasTrackType(TrackInfo::TrackType aType) const {
|
||||
MP3Demuxer::HasTrackType(TrackInfo::TrackType aType) const
|
||||
{
|
||||
return aType == TrackInfo::kAudioTrack;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
MP3Demuxer::GetNumberTracks(TrackInfo::TrackType aType) const {
|
||||
MP3Demuxer::GetNumberTracks(TrackInfo::TrackType aType) const
|
||||
{
|
||||
return aType == TrackInfo::kAudioTrack ? 1u : 0u;
|
||||
}
|
||||
|
||||
already_AddRefed<MediaTrackDemuxer>
|
||||
MP3Demuxer::GetTrackDemuxer(TrackInfo::TrackType aType, uint32_t aTrackNumber) {
|
||||
MP3Demuxer::GetTrackDemuxer(TrackInfo::TrackType aType, uint32_t aTrackNumber)
|
||||
{
|
||||
if (!mTrackDemuxer) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -81,19 +84,22 @@ MP3Demuxer::GetTrackDemuxer(TrackInfo::TrackType aType, uint32_t aTrackNumber) {
|
||||
}
|
||||
|
||||
bool
|
||||
MP3Demuxer::IsSeekable() const {
|
||||
MP3Demuxer::IsSeekable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
MP3Demuxer::NotifyDataArrived() {
|
||||
MP3Demuxer::NotifyDataArrived()
|
||||
{
|
||||
// TODO: bug 1169485.
|
||||
NS_WARNING("Unimplemented function NotifyDataArrived");
|
||||
MP3LOGV("NotifyDataArrived()");
|
||||
}
|
||||
|
||||
void
|
||||
MP3Demuxer::NotifyDataRemoved() {
|
||||
MP3Demuxer::NotifyDataRemoved()
|
||||
{
|
||||
// TODO: bug 1169485.
|
||||
NS_WARNING("Unimplemented function NotifyDataRemoved");
|
||||
MP3LOGV("NotifyDataRemoved()");
|
||||
@ -117,7 +123,8 @@ MP3TrackDemuxer::MP3TrackDemuxer(MediaResource* aSource)
|
||||
}
|
||||
|
||||
bool
|
||||
MP3TrackDemuxer::Init() {
|
||||
MP3TrackDemuxer::Init()
|
||||
{
|
||||
Reset();
|
||||
FastSeek(TimeUnit());
|
||||
// Read the first frame to fetch sample rate and other meta data.
|
||||
@ -151,7 +158,8 @@ MP3TrackDemuxer::Init() {
|
||||
}
|
||||
|
||||
media::TimeUnit
|
||||
MP3TrackDemuxer::SeekPosition() const {
|
||||
MP3TrackDemuxer::SeekPosition() const
|
||||
{
|
||||
TimeUnit pos = Duration(mFrameIndex);
|
||||
if (Duration() > TimeUnit()) {
|
||||
pos = std::min(Duration(), pos);
|
||||
@ -160,32 +168,38 @@ MP3TrackDemuxer::SeekPosition() const {
|
||||
}
|
||||
|
||||
const FrameParser::Frame&
|
||||
MP3TrackDemuxer::LastFrame() const {
|
||||
MP3TrackDemuxer::LastFrame() const
|
||||
{
|
||||
return mParser.PrevFrame();
|
||||
}
|
||||
|
||||
RefPtr<MediaRawData>
|
||||
MP3TrackDemuxer::DemuxSample() {
|
||||
MP3TrackDemuxer::DemuxSample()
|
||||
{
|
||||
return GetNextFrame(FindNextFrame());
|
||||
}
|
||||
|
||||
const ID3Parser::ID3Header&
|
||||
MP3TrackDemuxer::ID3Header() const {
|
||||
MP3TrackDemuxer::ID3Header() const
|
||||
{
|
||||
return mParser.ID3Header();
|
||||
}
|
||||
|
||||
const FrameParser::VBRHeader&
|
||||
MP3TrackDemuxer::VBRInfo() const {
|
||||
MP3TrackDemuxer::VBRInfo() const
|
||||
{
|
||||
return mParser.VBRInfo();
|
||||
}
|
||||
|
||||
UniquePtr<TrackInfo>
|
||||
MP3TrackDemuxer::GetInfo() const {
|
||||
MP3TrackDemuxer::GetInfo() const
|
||||
{
|
||||
return mInfo->Clone();
|
||||
}
|
||||
|
||||
RefPtr<MP3TrackDemuxer::SeekPromise>
|
||||
MP3TrackDemuxer::Seek(const TimeUnit& aTime) {
|
||||
MP3TrackDemuxer::Seek(const TimeUnit& aTime)
|
||||
{
|
||||
// Efficiently seek to the position.
|
||||
FastSeek(aTime);
|
||||
// Correct seek position by scanning the next frames.
|
||||
@ -195,7 +209,8 @@ MP3TrackDemuxer::Seek(const TimeUnit& aTime) {
|
||||
}
|
||||
|
||||
TimeUnit
|
||||
MP3TrackDemuxer::FastSeek(const TimeUnit& aTime) {
|
||||
MP3TrackDemuxer::FastSeek(const TimeUnit& aTime)
|
||||
{
|
||||
MP3LOG("FastSeek(%" PRId64 ") avgFrameLen=%f mNumParsedFrames=%" PRIu64
|
||||
" mFrameIndex=%" PRId64 " mOffset=%" PRIu64,
|
||||
aTime.ToMicroseconds(), AverageFrameLength(), mNumParsedFrames,
|
||||
@ -232,7 +247,8 @@ MP3TrackDemuxer::FastSeek(const TimeUnit& aTime) {
|
||||
}
|
||||
|
||||
TimeUnit
|
||||
MP3TrackDemuxer::ScanUntil(const TimeUnit& aTime) {
|
||||
MP3TrackDemuxer::ScanUntil(const TimeUnit& aTime)
|
||||
{
|
||||
MP3LOG("ScanUntil(%" PRId64 ") avgFrameLen=%f mNumParsedFrames=%" PRIu64
|
||||
" mFrameIndex=%" PRId64 " mOffset=%" PRIu64,
|
||||
aTime.ToMicroseconds(), AverageFrameLength(), mNumParsedFrames,
|
||||
@ -267,10 +283,11 @@ MP3TrackDemuxer::ScanUntil(const TimeUnit& aTime) {
|
||||
}
|
||||
|
||||
RefPtr<MP3TrackDemuxer::SamplesPromise>
|
||||
MP3TrackDemuxer::GetSamples(int32_t aNumSamples) {
|
||||
MP3TrackDemuxer::GetSamples(int32_t aNumSamples)
|
||||
{
|
||||
MP3LOGV("GetSamples(%d) Begin mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
|
||||
" mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64 " mSamplesPerFrame=%d "
|
||||
"mSamplesPerSecond=%d mChannels=%d",
|
||||
" mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64
|
||||
" mSamplesPerFrame=%d mSamplesPerSecond=%d mChannels=%d",
|
||||
aNumSamples, mOffset, mNumParsedFrames, mFrameIndex, mTotalFrameLen,
|
||||
mSamplesPerFrame, mSamplesPerSecond, mChannels);
|
||||
|
||||
@ -306,7 +323,8 @@ MP3TrackDemuxer::GetSamples(int32_t aNumSamples) {
|
||||
}
|
||||
|
||||
void
|
||||
MP3TrackDemuxer::Reset() {
|
||||
MP3TrackDemuxer::Reset()
|
||||
{
|
||||
MP3LOG("Reset()");
|
||||
|
||||
FastSeek(TimeUnit());
|
||||
@ -314,19 +332,22 @@ MP3TrackDemuxer::Reset() {
|
||||
}
|
||||
|
||||
RefPtr<MP3TrackDemuxer::SkipAccessPointPromise>
|
||||
MP3TrackDemuxer::SkipToNextRandomAccessPoint(const TimeUnit& aTimeThreshold) {
|
||||
MP3TrackDemuxer::SkipToNextRandomAccessPoint(const TimeUnit& aTimeThreshold)
|
||||
{
|
||||
// Will not be called for audio-only resources.
|
||||
return SkipAccessPointPromise::CreateAndReject(
|
||||
SkipFailureHolder(NS_ERROR_DOM_MEDIA_DEMUXER_ERR, 0), __func__);
|
||||
}
|
||||
|
||||
int64_t
|
||||
MP3TrackDemuxer::GetResourceOffset() const {
|
||||
MP3TrackDemuxer::GetResourceOffset() const
|
||||
{
|
||||
return mOffset;
|
||||
}
|
||||
|
||||
TimeIntervals
|
||||
MP3TrackDemuxer::GetBuffered() {
|
||||
MP3TrackDemuxer::GetBuffered()
|
||||
{
|
||||
AutoPinned<MediaResource> stream(mSource.GetResource());
|
||||
TimeIntervals buffered;
|
||||
|
||||
@ -357,12 +378,14 @@ MP3TrackDemuxer::GetBuffered() {
|
||||
}
|
||||
|
||||
int64_t
|
||||
MP3TrackDemuxer::StreamLength() const {
|
||||
MP3TrackDemuxer::StreamLength() const
|
||||
{
|
||||
return mSource.GetLength();
|
||||
}
|
||||
|
||||
TimeUnit
|
||||
MP3TrackDemuxer::Duration() const {
|
||||
MP3TrackDemuxer::Duration() const
|
||||
{
|
||||
if (!mNumParsedFrames) {
|
||||
return TimeUnit::FromMicroseconds(-1);
|
||||
}
|
||||
@ -386,7 +409,8 @@ MP3TrackDemuxer::Duration() const {
|
||||
}
|
||||
|
||||
TimeUnit
|
||||
MP3TrackDemuxer::Duration(int64_t aNumFrames) const {
|
||||
MP3TrackDemuxer::Duration(int64_t aNumFrames) const
|
||||
{
|
||||
if (!mSamplesPerSecond) {
|
||||
return TimeUnit::FromMicroseconds(-1);
|
||||
}
|
||||
@ -396,13 +420,15 @@ MP3TrackDemuxer::Duration(int64_t aNumFrames) const {
|
||||
}
|
||||
|
||||
MediaByteRange
|
||||
MP3TrackDemuxer::FindFirstFrame() {
|
||||
MP3TrackDemuxer::FindFirstFrame()
|
||||
{
|
||||
static const int MIN_SUCCESSIVE_FRAMES = 4;
|
||||
|
||||
MediaByteRange candidateFrame = FindNextFrame();
|
||||
int numSuccFrames = candidateFrame.Length() > 0;
|
||||
MediaByteRange currentFrame = candidateFrame;
|
||||
MP3LOGV("FindFirst() first candidate frame: mOffset=%" PRIu64 " Length()=%" PRIu64,
|
||||
MP3LOGV("FindFirst() first candidate frame: mOffset=%" PRIu64
|
||||
" Length()=%" PRIu64,
|
||||
candidateFrame.mStart, candidateFrame.Length());
|
||||
|
||||
while (candidateFrame.Length() && numSuccFrames < MIN_SUCCESSIVE_FRAMES) {
|
||||
@ -419,16 +445,17 @@ MP3TrackDemuxer::FindFirstFrame() {
|
||||
|
||||
if (!currentFrame.Length() || frameSeparation != 0) {
|
||||
MP3LOGV("FindFirst() not enough successive frames detected, "
|
||||
"rejecting candidate frame: successiveFrames=%d, last Length()=%" PRIu64
|
||||
", last frameSeparation=%" PRId64, numSuccFrames, currentFrame.Length(),
|
||||
frameSeparation);
|
||||
"rejecting candidate frame: successiveFrames=%d, last "
|
||||
"Length()=%" PRIu64 ", last frameSeparation=%" PRId64,
|
||||
numSuccFrames, currentFrame.Length(), frameSeparation);
|
||||
|
||||
mParser.ResetFrameData();
|
||||
mOffset = candidateFrame.mStart + 1;
|
||||
candidateFrame = FindNextFrame();
|
||||
numSuccFrames = candidateFrame.Length() > 0;
|
||||
currentFrame = candidateFrame;
|
||||
MP3LOGV("FindFirst() new candidate frame: mOffset=%" PRIu64 " Length()=%" PRIu64,
|
||||
MP3LOGV("FindFirst() new candidate frame: mOffset=%" PRIu64
|
||||
" Length()=%" PRIu64,
|
||||
candidateFrame.mStart, candidateFrame.Length());
|
||||
}
|
||||
}
|
||||
@ -443,23 +470,26 @@ MP3TrackDemuxer::FindFirstFrame() {
|
||||
}
|
||||
|
||||
static bool
|
||||
VerifyFrameConsistency(
|
||||
const FrameParser::Frame& aFrame1, const FrameParser::Frame& aFrame2) {
|
||||
VerifyFrameConsistency(const FrameParser::Frame& aFrame1,
|
||||
const FrameParser::Frame& aFrame2)
|
||||
{
|
||||
const auto& h1 = aFrame1.Header();
|
||||
const auto& h2 = aFrame2.Header();
|
||||
|
||||
return h1.IsValid() && h2.IsValid() &&
|
||||
h1.Layer() == h2.Layer() &&
|
||||
h1.SlotSize() == h2.SlotSize() &&
|
||||
h1.SamplesPerFrame() == h2.SamplesPerFrame() &&
|
||||
h1.Channels() == h2.Channels() &&
|
||||
h1.SampleRate() == h2.SampleRate() &&
|
||||
h1.RawVersion() == h2.RawVersion() &&
|
||||
h1.RawProtection() == h2.RawProtection();
|
||||
return h1.IsValid()
|
||||
&& h2.IsValid()
|
||||
&& h1.Layer() == h2.Layer()
|
||||
&& h1.SlotSize() == h2.SlotSize()
|
||||
&& h1.SamplesPerFrame() == h2.SamplesPerFrame()
|
||||
&& h1.Channels() == h2.Channels()
|
||||
&& h1.SampleRate() == h2.SampleRate()
|
||||
&& h1.RawVersion() == h2.RawVersion()
|
||||
&& h1.RawProtection() == h2.RawProtection();
|
||||
}
|
||||
|
||||
MediaByteRange
|
||||
MP3TrackDemuxer::FindNextFrame() {
|
||||
MP3TrackDemuxer::FindNextFrame()
|
||||
{
|
||||
static const int BUFFER_SIZE = 64;
|
||||
static const int MAX_SKIPPED_BYTES = 1024 * BUFFER_SIZE;
|
||||
|
||||
@ -477,9 +507,9 @@ MP3TrackDemuxer::FindNextFrame() {
|
||||
|
||||
// Check whether we've found a valid MPEG frame.
|
||||
while (!foundFrame) {
|
||||
if ((!mParser.FirstFrame().Length() &&
|
||||
mOffset - mParser.ID3Header().Size() > MAX_SKIPPED_BYTES) ||
|
||||
(read = Read(buffer, mOffset, BUFFER_SIZE)) == 0) {
|
||||
if ((!mParser.FirstFrame().Length()
|
||||
&& mOffset - mParser.ID3Header().Size() > MAX_SKIPPED_BYTES)
|
||||
|| (read = Read(buffer, mOffset, BUFFER_SIZE)) == 0) {
|
||||
MP3LOG("FindNext() EOS or exceeded MAX_SKIPPED_BYTES without a frame");
|
||||
// This is not a valid MPEG audio stream or we've reached EOS, give up.
|
||||
break;
|
||||
@ -488,14 +518,16 @@ MP3TrackDemuxer::FindNextFrame() {
|
||||
ByteReader reader(buffer, read);
|
||||
uint32_t bytesToSkip = 0;
|
||||
foundFrame = mParser.Parse(&reader, &bytesToSkip);
|
||||
frameHeaderOffset = mOffset + reader.Offset() - FrameParser::FrameHeader::SIZE;
|
||||
frameHeaderOffset =
|
||||
mOffset + reader.Offset() - FrameParser::FrameHeader::SIZE;
|
||||
|
||||
// If we've found neither an MPEG frame header nor an ID3v2 tag,
|
||||
// the reader shouldn't have any bytes remaining.
|
||||
MOZ_ASSERT(foundFrame || bytesToSkip || !reader.Remaining());
|
||||
|
||||
if (foundFrame && mParser.FirstFrame().Length() &&
|
||||
!VerifyFrameConsistency(mParser.FirstFrame(), mParser.CurrentFrame())) {
|
||||
if (foundFrame && mParser.FirstFrame().Length()
|
||||
&& !VerifyFrameConsistency(mParser.FirstFrame(),
|
||||
mParser.CurrentFrame())) {
|
||||
// We've likely hit a false-positive, ignore it and proceed with the
|
||||
// search for the next valid frame.
|
||||
foundFrame = false;
|
||||
@ -527,7 +559,8 @@ MP3TrackDemuxer::FindNextFrame() {
|
||||
}
|
||||
|
||||
bool
|
||||
MP3TrackDemuxer::SkipNextFrame(const MediaByteRange& aRange) {
|
||||
MP3TrackDemuxer::SkipNextFrame(const MediaByteRange& aRange)
|
||||
{
|
||||
if (!mNumParsedFrames || !aRange.Length()) {
|
||||
// We can't skip the first frame, since it could contain VBR headers.
|
||||
RefPtr<MediaRawData> frame(GetNextFrame(aRange));
|
||||
@ -546,7 +579,8 @@ MP3TrackDemuxer::SkipNextFrame(const MediaByteRange& aRange) {
|
||||
}
|
||||
|
||||
already_AddRefed<MediaRawData>
|
||||
MP3TrackDemuxer::GetNextFrame(const MediaByteRange& aRange) {
|
||||
MP3TrackDemuxer::GetNextFrame(const MediaByteRange& aRange)
|
||||
{
|
||||
MP3LOG("GetNext() Begin({mStart=%" PRId64 " Length()=%" PRId64 "})",
|
||||
aRange.mStart, aRange.Length());
|
||||
if (!aRange.Length()) {
|
||||
@ -562,7 +596,8 @@ MP3TrackDemuxer::GetNextFrame(const MediaByteRange& aRange) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const uint32_t read = Read(frameWriter->Data(), frame->mOffset, frame->Size());
|
||||
const uint32_t read =
|
||||
Read(frameWriter->Data(), frame->mOffset, frame->Size());
|
||||
|
||||
if (read != aRange.Length()) {
|
||||
MP3LOG("GetNext() Exit read=%u frame->Size()=%u", read, frame->Size());
|
||||
@ -596,13 +631,15 @@ MP3TrackDemuxer::GetNextFrame(const MediaByteRange& aRange) {
|
||||
}
|
||||
|
||||
int64_t
|
||||
MP3TrackDemuxer::OffsetFromFrameIndex(int64_t aFrameIndex) const {
|
||||
MP3TrackDemuxer::OffsetFromFrameIndex(int64_t aFrameIndex) const
|
||||
{
|
||||
int64_t offset = 0;
|
||||
const auto& vbr = mParser.VBRInfo();
|
||||
|
||||
if (vbr.IsComplete()) {
|
||||
offset = mFirstFrameOffset + aFrameIndex * vbr.NumBytes().value() /
|
||||
vbr.NumAudioFrames().value();
|
||||
offset = mFirstFrameOffset
|
||||
+ aFrameIndex * vbr.NumBytes().value()
|
||||
/ vbr.NumAudioFrames().value();
|
||||
} else if (AverageFrameLength() > 0) {
|
||||
offset = mFirstFrameOffset + aFrameIndex * AverageFrameLength();
|
||||
}
|
||||
@ -612,13 +649,15 @@ MP3TrackDemuxer::OffsetFromFrameIndex(int64_t aFrameIndex) const {
|
||||
}
|
||||
|
||||
int64_t
|
||||
MP3TrackDemuxer::FrameIndexFromOffset(int64_t aOffset) const {
|
||||
MP3TrackDemuxer::FrameIndexFromOffset(int64_t aOffset) const
|
||||
{
|
||||
int64_t frameIndex = 0;
|
||||
const auto& vbr = mParser.VBRInfo();
|
||||
|
||||
if (vbr.IsComplete()) {
|
||||
frameIndex = static_cast<float>(aOffset - mFirstFrameOffset) /
|
||||
vbr.NumBytes().value() * vbr.NumAudioFrames().value();
|
||||
frameIndex = static_cast<float>(aOffset - mFirstFrameOffset)
|
||||
/ vbr.NumBytes().value()
|
||||
* vbr.NumAudioFrames().value();
|
||||
frameIndex = std::min<int64_t>(vbr.NumAudioFrames().value(), frameIndex);
|
||||
} else if (AverageFrameLength() > 0) {
|
||||
frameIndex = (aOffset - mFirstFrameOffset) / AverageFrameLength();
|
||||
@ -629,18 +668,21 @@ MP3TrackDemuxer::FrameIndexFromOffset(int64_t aOffset) const {
|
||||
}
|
||||
|
||||
int64_t
|
||||
MP3TrackDemuxer::FrameIndexFromTime(const media::TimeUnit& aTime) const {
|
||||
MP3TrackDemuxer::FrameIndexFromTime(const media::TimeUnit& aTime) const
|
||||
{
|
||||
int64_t frameIndex = 0;
|
||||
if (mSamplesPerSecond > 0 && mSamplesPerFrame > 0) {
|
||||
frameIndex = aTime.ToSeconds() * mSamplesPerSecond / mSamplesPerFrame - 1;
|
||||
}
|
||||
|
||||
MP3LOGV("FrameIndexFromOffset(%fs) -> %" PRId64, aTime.ToSeconds(), frameIndex);
|
||||
MP3LOGV("FrameIndexFromOffset(%fs) -> %" PRId64, aTime.ToSeconds(),
|
||||
frameIndex);
|
||||
return std::max<int64_t>(0, frameIndex);
|
||||
}
|
||||
|
||||
void
|
||||
MP3TrackDemuxer::UpdateState(const MediaByteRange& aRange) {
|
||||
MP3TrackDemuxer::UpdateState(const MediaByteRange& aRange)
|
||||
{
|
||||
// Prevent overflow.
|
||||
if (mTotalFrameLen + aRange.Length() < mTotalFrameLen) {
|
||||
// These variables have a linear dependency and are only used to derive the
|
||||
@ -669,7 +711,8 @@ MP3TrackDemuxer::UpdateState(const MediaByteRange& aRange) {
|
||||
}
|
||||
|
||||
int32_t
|
||||
MP3TrackDemuxer::Read(uint8_t* aBuffer, int64_t aOffset, int32_t aSize) {
|
||||
MP3TrackDemuxer::Read(uint8_t* aBuffer, int64_t aOffset, int32_t aSize)
|
||||
{
|
||||
MP3LOGV("MP3TrackDemuxer::Read(%p %" PRId64 " %d)", aBuffer, aOffset, aSize);
|
||||
|
||||
const int64_t streamLen = StreamLength();
|
||||
@ -687,14 +730,15 @@ MP3TrackDemuxer::Read(uint8_t* aBuffer, int64_t aOffset, int32_t aSize) {
|
||||
}
|
||||
|
||||
double
|
||||
MP3TrackDemuxer::AverageFrameLength() const {
|
||||
MP3TrackDemuxer::AverageFrameLength() const
|
||||
{
|
||||
if (mNumParsedFrames) {
|
||||
return static_cast<double>(mTotalFrameLen) / mNumParsedFrames;
|
||||
}
|
||||
const auto& vbr = mParser.VBRInfo();
|
||||
if (vbr.IsComplete() && vbr.NumAudioFrames().value() + 1) {
|
||||
return static_cast<double>(vbr.NumBytes().value()) /
|
||||
(vbr.NumAudioFrames().value() + 1);
|
||||
return static_cast<double>(vbr.NumBytes().value())
|
||||
/ (vbr.NumAudioFrames().value() + 1);
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
@ -714,20 +758,23 @@ FrameParser::FrameParser()
|
||||
}
|
||||
|
||||
void
|
||||
FrameParser::Reset() {
|
||||
FrameParser::Reset()
|
||||
{
|
||||
mID3Parser.Reset();
|
||||
mFrame.Reset();
|
||||
}
|
||||
|
||||
void
|
||||
FrameParser::ResetFrameData() {
|
||||
FrameParser::ResetFrameData()
|
||||
{
|
||||
mFrame.Reset();
|
||||
mFirstFrame.Reset();
|
||||
mPrevFrame.Reset();
|
||||
}
|
||||
|
||||
void
|
||||
FrameParser::EndFrameSession() {
|
||||
FrameParser::EndFrameSession()
|
||||
{
|
||||
if (!mID3Parser.Header().IsValid()) {
|
||||
// Reset ID3 tags only if we have not parsed a valid ID3 header yet.
|
||||
mID3Parser.Reset();
|
||||
@ -737,32 +784,38 @@ FrameParser::EndFrameSession() {
|
||||
}
|
||||
|
||||
const FrameParser::Frame&
|
||||
FrameParser::CurrentFrame() const {
|
||||
FrameParser::CurrentFrame() const
|
||||
{
|
||||
return mFrame;
|
||||
}
|
||||
|
||||
const FrameParser::Frame&
|
||||
FrameParser::PrevFrame() const {
|
||||
FrameParser::PrevFrame() const
|
||||
{
|
||||
return mPrevFrame;
|
||||
}
|
||||
|
||||
const FrameParser::Frame&
|
||||
FrameParser::FirstFrame() const {
|
||||
FrameParser::FirstFrame() const
|
||||
{
|
||||
return mFirstFrame;
|
||||
}
|
||||
|
||||
const ID3Parser::ID3Header&
|
||||
FrameParser::ID3Header() const {
|
||||
FrameParser::ID3Header() const
|
||||
{
|
||||
return mID3Parser.Header();
|
||||
}
|
||||
|
||||
const FrameParser::VBRHeader&
|
||||
FrameParser::VBRInfo() const {
|
||||
FrameParser::VBRInfo() const
|
||||
{
|
||||
return mVBRHeader;
|
||||
}
|
||||
|
||||
bool
|
||||
FrameParser::Parse(ByteReader* aReader, uint32_t* aBytesToSkip) {
|
||||
FrameParser::Parse(ByteReader* aReader, uint32_t* aBytesToSkip)
|
||||
{
|
||||
MOZ_ASSERT(aReader && aBytesToSkip);
|
||||
*aBytesToSkip = 0;
|
||||
|
||||
@ -777,8 +830,9 @@ FrameParser::Parse(ByteReader* aReader, uint32_t* aBytesToSkip) {
|
||||
const uint32_t skipSize = tagSize - ID3Parser::ID3Header::SIZE;
|
||||
|
||||
if (skipSize > aReader->Remaining()) {
|
||||
// Skipping across the ID3v2 tag would take us past the end of the buffer, therefore we
|
||||
// return immediately and let the calling function handle skipping the rest of the tag.
|
||||
// Skipping across the ID3v2 tag would take us past the end of the
|
||||
// buffer, therefore we return immediately and let the calling function
|
||||
// handle skipping the rest of the tag.
|
||||
MP3LOGV("ID3v2 tag detected, size=%d,"
|
||||
" needing to skip %d bytes past the current buffer",
|
||||
tagSize, skipSize - aReader->Remaining());
|
||||
@ -788,7 +842,8 @@ FrameParser::Parse(ByteReader* aReader, uint32_t* aBytesToSkip) {
|
||||
MP3LOGV("ID3v2 tag detected, size=%d", tagSize);
|
||||
aReader->Read(skipSize);
|
||||
} else {
|
||||
// No ID3v2 tag found, rewinding reader in order to search for a MPEG frame header.
|
||||
// No ID3v2 tag found, rewinding reader in order to search for a MPEG
|
||||
// frame header.
|
||||
aReader->Seek(prevReaderOffset);
|
||||
}
|
||||
}
|
||||
@ -814,64 +869,76 @@ FrameParser::FrameHeader::FrameHeader()
|
||||
}
|
||||
|
||||
uint8_t
|
||||
FrameParser::FrameHeader::Sync1() const {
|
||||
FrameParser::FrameHeader::Sync1() const
|
||||
{
|
||||
return mRaw[frame_header::SYNC1];
|
||||
}
|
||||
|
||||
uint8_t
|
||||
FrameParser::FrameHeader::Sync2() const {
|
||||
FrameParser::FrameHeader::Sync2() const
|
||||
{
|
||||
return 0x7 & mRaw[frame_header::SYNC2_VERSION_LAYER_PROTECTION] >> 5;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
FrameParser::FrameHeader::RawVersion() const {
|
||||
FrameParser::FrameHeader::RawVersion() const
|
||||
{
|
||||
return 0x3 & mRaw[frame_header::SYNC2_VERSION_LAYER_PROTECTION] >> 3;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
FrameParser::FrameHeader::RawLayer() const {
|
||||
FrameParser::FrameHeader::RawLayer() const
|
||||
{
|
||||
return 0x3 & mRaw[frame_header::SYNC2_VERSION_LAYER_PROTECTION] >> 1;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
FrameParser::FrameHeader::RawProtection() const {
|
||||
FrameParser::FrameHeader::RawProtection() const
|
||||
{
|
||||
return 0x1 & mRaw[frame_header::SYNC2_VERSION_LAYER_PROTECTION] >> 6;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
FrameParser::FrameHeader::RawBitrate() const {
|
||||
FrameParser::FrameHeader::RawBitrate() const
|
||||
{
|
||||
return 0xF & mRaw[frame_header::BITRATE_SAMPLERATE_PADDING_PRIVATE] >> 4;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
FrameParser::FrameHeader::RawSampleRate() const {
|
||||
FrameParser::FrameHeader::RawSampleRate() const
|
||||
{
|
||||
return 0x3 & mRaw[frame_header::BITRATE_SAMPLERATE_PADDING_PRIVATE] >> 2;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
FrameParser::FrameHeader::Padding() const {
|
||||
FrameParser::FrameHeader::Padding() const
|
||||
{
|
||||
return 0x1 & mRaw[frame_header::BITRATE_SAMPLERATE_PADDING_PRIVATE] >> 1;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
FrameParser::FrameHeader::Private() const {
|
||||
FrameParser::FrameHeader::Private() const
|
||||
{
|
||||
return 0x1 & mRaw[frame_header::BITRATE_SAMPLERATE_PADDING_PRIVATE];
|
||||
}
|
||||
|
||||
uint8_t
|
||||
FrameParser::FrameHeader::RawChannelMode() const {
|
||||
FrameParser::FrameHeader::RawChannelMode() const
|
||||
{
|
||||
return 0x3 & mRaw[frame_header::CHANNELMODE_MODEEXT_COPY_ORIG_EMPH] >> 6;
|
||||
}
|
||||
|
||||
int32_t
|
||||
FrameParser::FrameHeader::Layer() const {
|
||||
FrameParser::FrameHeader::Layer() const
|
||||
{
|
||||
static const uint8_t LAYERS[4] = { 0, 3, 2, 1 };
|
||||
|
||||
return LAYERS[RawLayer()];
|
||||
}
|
||||
|
||||
int32_t
|
||||
FrameParser::FrameHeader::SampleRate() const {
|
||||
FrameParser::FrameHeader::SampleRate() const
|
||||
{
|
||||
// Sample rates - use [version][srate]
|
||||
static const uint16_t SAMPLE_RATE[4][4] = {
|
||||
{ 11025, 12000, 8000, 0 }, // MPEG 2.5
|
||||
@ -884,14 +951,16 @@ FrameParser::FrameHeader::SampleRate() const {
|
||||
}
|
||||
|
||||
int32_t
|
||||
FrameParser::FrameHeader::Channels() const {
|
||||
FrameParser::FrameHeader::Channels() const
|
||||
{
|
||||
// 3 is single channel (mono), any other value is some variant of dual
|
||||
// channel.
|
||||
return RawChannelMode() == 3 ? 1 : 2;
|
||||
}
|
||||
|
||||
int32_t
|
||||
FrameParser::FrameHeader::SamplesPerFrame() const {
|
||||
FrameParser::FrameHeader::SamplesPerFrame() const
|
||||
{
|
||||
// Samples per frame - use [version][layer]
|
||||
static const uint16_t FRAME_SAMPLE[4][4] = {
|
||||
// Layer 3 2 1 Version
|
||||
@ -905,7 +974,8 @@ FrameParser::FrameHeader::SamplesPerFrame() const {
|
||||
}
|
||||
|
||||
int32_t
|
||||
FrameParser::FrameHeader::Bitrate() const {
|
||||
FrameParser::FrameHeader::Bitrate() const
|
||||
{
|
||||
// Bitrates - use [version][layer][bitrate]
|
||||
static const uint16_t BITRATE[4][4][16] = {
|
||||
{ // Version 2.5
|
||||
@ -938,7 +1008,8 @@ FrameParser::FrameHeader::Bitrate() const {
|
||||
}
|
||||
|
||||
int32_t
|
||||
FrameParser::FrameHeader::SlotSize() const {
|
||||
FrameParser::FrameHeader::SlotSize() const
|
||||
{
|
||||
// Slot size (MPEG unit of measurement) - use [layer]
|
||||
static const uint8_t SLOT_SIZE[4] = { 0, 1, 1, 4 }; // Rsvd, 3, 2, 1
|
||||
|
||||
@ -946,7 +1017,8 @@ FrameParser::FrameHeader::SlotSize() const {
|
||||
}
|
||||
|
||||
bool
|
||||
FrameParser::FrameHeader::ParseNext(uint8_t c) {
|
||||
FrameParser::FrameHeader::ParseNext(uint8_t c)
|
||||
{
|
||||
if (!Update(c)) {
|
||||
Reset();
|
||||
if (!Update(c)) {
|
||||
@ -957,7 +1029,8 @@ FrameParser::FrameHeader::ParseNext(uint8_t c) {
|
||||
}
|
||||
|
||||
bool
|
||||
FrameParser::FrameHeader::IsValid(int aPos) const {
|
||||
FrameParser::FrameHeader::IsValid(int aPos) const
|
||||
{
|
||||
if (aPos >= SIZE) {
|
||||
return true;
|
||||
}
|
||||
@ -977,17 +1050,20 @@ FrameParser::FrameHeader::IsValid(int aPos) const {
|
||||
}
|
||||
|
||||
bool
|
||||
FrameParser::FrameHeader::IsValid() const {
|
||||
FrameParser::FrameHeader::IsValid() const
|
||||
{
|
||||
return mPos >= SIZE;
|
||||
}
|
||||
|
||||
void
|
||||
FrameParser::FrameHeader::Reset() {
|
||||
FrameParser::FrameHeader::Reset()
|
||||
{
|
||||
mPos = 0;
|
||||
}
|
||||
|
||||
bool
|
||||
FrameParser::FrameHeader::Update(uint8_t c) {
|
||||
FrameParser::FrameHeader::Update(uint8_t c)
|
||||
{
|
||||
if (mPos < SIZE) {
|
||||
mRaw[mPos] = c;
|
||||
}
|
||||
@ -1007,53 +1083,62 @@ FrameParser::VBRHeader::VBRHeader()
|
||||
}
|
||||
|
||||
FrameParser::VBRHeader::VBRHeaderType
|
||||
FrameParser::VBRHeader::Type() const {
|
||||
FrameParser::VBRHeader::Type() const
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
const Maybe<uint32_t>&
|
||||
FrameParser::VBRHeader::NumAudioFrames() const {
|
||||
FrameParser::VBRHeader::NumAudioFrames() const
|
||||
{
|
||||
return mNumAudioFrames;
|
||||
}
|
||||
|
||||
const Maybe<uint32_t>&
|
||||
FrameParser::VBRHeader::NumBytes() const {
|
||||
FrameParser::VBRHeader::NumBytes() const
|
||||
{
|
||||
return mNumBytes;
|
||||
}
|
||||
|
||||
const Maybe<uint32_t>&
|
||||
FrameParser::VBRHeader::Scale() const {
|
||||
FrameParser::VBRHeader::Scale() const
|
||||
{
|
||||
return mScale;
|
||||
}
|
||||
|
||||
bool
|
||||
FrameParser::VBRHeader::IsTOCPresent() const {
|
||||
FrameParser::VBRHeader::IsTOCPresent() const
|
||||
{
|
||||
return mTOC.size() == vbr_header::TOC_SIZE;
|
||||
}
|
||||
|
||||
bool
|
||||
FrameParser::VBRHeader::IsValid() const {
|
||||
FrameParser::VBRHeader::IsValid() const
|
||||
{
|
||||
return mType != NONE;
|
||||
}
|
||||
|
||||
bool
|
||||
FrameParser::VBRHeader::IsComplete() const {
|
||||
return IsValid() &&
|
||||
mNumAudioFrames.valueOr(0) > 0 &&
|
||||
mNumBytes.valueOr(0) > 0 &&
|
||||
FrameParser::VBRHeader::IsComplete() const
|
||||
{
|
||||
return IsValid()
|
||||
&& mNumAudioFrames.valueOr(0) > 0
|
||||
&& mNumBytes.valueOr(0) > 0
|
||||
// We don't care about the scale for any computations here.
|
||||
// mScale < 101 &&
|
||||
true;
|
||||
// && mScale < 101
|
||||
&& true;
|
||||
}
|
||||
|
||||
int64_t
|
||||
FrameParser::VBRHeader::Offset(float aDurationFac) const {
|
||||
FrameParser::VBRHeader::Offset(float aDurationFac) const
|
||||
{
|
||||
if (!IsTOCPresent()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Constrain the duration percentage to [0, 99].
|
||||
const float durationPer = 100.0f * std::min(0.99f, std::max(0.0f, aDurationFac));
|
||||
const float durationPer =
|
||||
100.0f * std::min(0.99f, std::max(0.0f, aDurationFac));
|
||||
const size_t fullPer = durationPer;
|
||||
const float rest = durationPer - fullPer;
|
||||
|
||||
@ -1068,11 +1153,13 @@ FrameParser::VBRHeader::Offset(float aDurationFac) const {
|
||||
}
|
||||
|
||||
bool
|
||||
FrameParser::VBRHeader::ParseXing(ByteReader* aReader) {
|
||||
FrameParser::VBRHeader::ParseXing(ByteReader* aReader)
|
||||
{
|
||||
static const uint32_t XING_TAG = BigEndian::readUint32("Xing");
|
||||
static const uint32_t INFO_TAG = BigEndian::readUint32("Info");
|
||||
|
||||
enum Flags {
|
||||
enum Flags
|
||||
{
|
||||
NUM_FRAMES = 0x01,
|
||||
NUM_BYTES = 0x02,
|
||||
TOC = 0x04,
|
||||
@ -1124,15 +1211,17 @@ FrameParser::VBRHeader::ParseXing(ByteReader* aReader) {
|
||||
}
|
||||
|
||||
bool
|
||||
FrameParser::VBRHeader::ParseVBRI(ByteReader* aReader) {
|
||||
FrameParser::VBRHeader::ParseVBRI(ByteReader* aReader)
|
||||
{
|
||||
static const uint32_t TAG = BigEndian::readUint32("VBRI");
|
||||
static const uint32_t OFFSET = 32 + FrameParser::FrameHeader::SIZE;
|
||||
static const uint32_t FRAME_COUNT_OFFSET = OFFSET + 14;
|
||||
static const uint32_t MIN_FRAME_SIZE = OFFSET + 26;
|
||||
|
||||
MOZ_ASSERT(aReader);
|
||||
// ParseVBRI assumes that the ByteReader offset points to the beginning of a frame,
|
||||
// therefore as a simple check, we look for the presence of a frame sync at that position.
|
||||
// ParseVBRI assumes that the ByteReader offset points to the beginning of a
|
||||
// frame, therefore as a simple check, we look for the presence of a frame
|
||||
// sync at that position.
|
||||
MOZ_ASSERT((aReader->PeekU16() & 0xFFE0) == 0xFFE0);
|
||||
const size_t prevReaderOffset = aReader->Offset();
|
||||
|
||||
@ -1152,7 +1241,8 @@ FrameParser::VBRHeader::ParseVBRI(ByteReader* aReader) {
|
||||
}
|
||||
|
||||
bool
|
||||
FrameParser::VBRHeader::Parse(ByteReader* aReader) {
|
||||
FrameParser::VBRHeader::Parse(ByteReader* aReader)
|
||||
{
|
||||
const bool rv = ParseVBRI(aReader) || ParseXing(aReader);
|
||||
if (rv) {
|
||||
MP3LOG("VBRHeader::Parse found valid VBR/CBR header: type=%s"
|
||||
@ -1166,35 +1256,40 @@ FrameParser::VBRHeader::Parse(ByteReader* aReader) {
|
||||
// FrameParser::Frame
|
||||
|
||||
void
|
||||
FrameParser::Frame::Reset() {
|
||||
FrameParser::Frame::Reset()
|
||||
{
|
||||
mHeader.Reset();
|
||||
}
|
||||
|
||||
int32_t
|
||||
FrameParser::Frame::Length() const {
|
||||
FrameParser::Frame::Length() const
|
||||
{
|
||||
if (!mHeader.IsValid() || !mHeader.SampleRate()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const float bitsPerSample = mHeader.SamplesPerFrame() / 8.0f;
|
||||
const int32_t frameLen = bitsPerSample * mHeader.Bitrate() /
|
||||
mHeader.SampleRate() +
|
||||
mHeader.Padding() * mHeader.SlotSize();
|
||||
const int32_t frameLen = bitsPerSample * mHeader.Bitrate()
|
||||
/ mHeader.SampleRate()
|
||||
+ mHeader.Padding() * mHeader.SlotSize();
|
||||
return frameLen;
|
||||
}
|
||||
|
||||
bool
|
||||
FrameParser::Frame::ParseNext(uint8_t c) {
|
||||
FrameParser::Frame::ParseNext(uint8_t c)
|
||||
{
|
||||
return mHeader.ParseNext(c);
|
||||
}
|
||||
|
||||
const FrameParser::FrameHeader&
|
||||
FrameParser::Frame::Header() const {
|
||||
FrameParser::Frame::Header() const
|
||||
{
|
||||
return mHeader;
|
||||
}
|
||||
|
||||
bool
|
||||
FrameParser::ParseVBRHeader(ByteReader* aReader) {
|
||||
FrameParser::ParseVBRHeader(ByteReader* aReader)
|
||||
{
|
||||
return mVBRHeader.Parse(aReader);
|
||||
}
|
||||
|
||||
@ -1219,7 +1314,8 @@ static const uint8_t MAX_MAJOR_VER = 4;
|
||||
} // namespace id3_header
|
||||
|
||||
uint32_t
|
||||
ID3Parser::Parse(ByteReader* aReader) {
|
||||
ID3Parser::Parse(ByteReader* aReader)
|
||||
{
|
||||
MOZ_ASSERT(aReader);
|
||||
|
||||
while (aReader->CanRead8() && !mHeader.ParseNext(aReader->ReadU8())) { }
|
||||
@ -1232,12 +1328,14 @@ ID3Parser::Parse(ByteReader* aReader) {
|
||||
}
|
||||
|
||||
void
|
||||
ID3Parser::Reset() {
|
||||
ID3Parser::Reset()
|
||||
{
|
||||
mHeader.Reset();
|
||||
}
|
||||
|
||||
const ID3Parser::ID3Header&
|
||||
ID3Parser::Header() const {
|
||||
ID3Parser::Header() const
|
||||
{
|
||||
return mHeader;
|
||||
}
|
||||
|
||||
@ -1249,28 +1347,33 @@ ID3Parser::ID3Header::ID3Header()
|
||||
}
|
||||
|
||||
void
|
||||
ID3Parser::ID3Header::Reset() {
|
||||
ID3Parser::ID3Header::Reset()
|
||||
{
|
||||
mSize = 0;
|
||||
mPos = 0;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
ID3Parser::ID3Header::MajorVersion() const {
|
||||
ID3Parser::ID3Header::MajorVersion() const
|
||||
{
|
||||
return mRaw[id3_header::ID_END];
|
||||
}
|
||||
|
||||
uint8_t
|
||||
ID3Parser::ID3Header::MinorVersion() const {
|
||||
ID3Parser::ID3Header::MinorVersion() const
|
||||
{
|
||||
return mRaw[id3_header::ID_END + 1];
|
||||
}
|
||||
|
||||
uint8_t
|
||||
ID3Parser::ID3Header::Flags() const {
|
||||
ID3Parser::ID3Header::Flags() const
|
||||
{
|
||||
return mRaw[id3_header::FLAGS_END - id3_header::FLAGS_LEN];
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ID3Parser::ID3Header::Size() const {
|
||||
ID3Parser::ID3Header::Size() const
|
||||
{
|
||||
if (!IsValid()) {
|
||||
return 0;
|
||||
}
|
||||
@ -1278,7 +1381,8 @@ ID3Parser::ID3Header::Size() const {
|
||||
}
|
||||
|
||||
uint8_t
|
||||
ID3Parser::ID3Header::FooterSize() const {
|
||||
ID3Parser::ID3Header::FooterSize() const
|
||||
{
|
||||
if (Flags() & (1 << 4)) {
|
||||
return SIZE;
|
||||
}
|
||||
@ -1286,7 +1390,8 @@ ID3Parser::ID3Header::FooterSize() const {
|
||||
}
|
||||
|
||||
bool
|
||||
ID3Parser::ID3Header::ParseNext(uint8_t c) {
|
||||
ID3Parser::ID3Header::ParseNext(uint8_t c)
|
||||
{
|
||||
if (!Update(c)) {
|
||||
Reset();
|
||||
if (!Update(c)) {
|
||||
@ -1297,7 +1402,8 @@ ID3Parser::ID3Header::ParseNext(uint8_t c) {
|
||||
}
|
||||
|
||||
bool
|
||||
ID3Parser::ID3Header::IsValid(int aPos) const {
|
||||
ID3Parser::ID3Header::IsValid(int aPos) const
|
||||
{
|
||||
if (aPos >= SIZE) {
|
||||
return true;
|
||||
}
|
||||
@ -1307,8 +1413,8 @@ ID3Parser::ID3Header::IsValid(int aPos) const {
|
||||
// Expecting "ID3".
|
||||
return id3_header::ID[aPos] == c;
|
||||
case 3:
|
||||
return MajorVersion() >= id3_header::MIN_MAJOR_VER &&
|
||||
MajorVersion() <= id3_header::MAX_MAJOR_VER;
|
||||
return MajorVersion() >= id3_header::MIN_MAJOR_VER
|
||||
&& MajorVersion() <= id3_header::MAX_MAJOR_VER;
|
||||
case 4:
|
||||
return MinorVersion() < 0xFF;
|
||||
case 5:
|
||||
@ -1321,14 +1427,16 @@ ID3Parser::ID3Header::IsValid(int aPos) const {
|
||||
}
|
||||
|
||||
bool
|
||||
ID3Parser::ID3Header::IsValid() const {
|
||||
ID3Parser::ID3Header::IsValid() const
|
||||
{
|
||||
return mPos >= SIZE;
|
||||
}
|
||||
|
||||
bool
|
||||
ID3Parser::ID3Header::Update(uint8_t c) {
|
||||
if (mPos >= id3_header::SIZE_END - id3_header::SIZE_LEN &&
|
||||
mPos < id3_header::SIZE_END) {
|
||||
ID3Parser::ID3Header::Update(uint8_t c)
|
||||
{
|
||||
if (mPos >= id3_header::SIZE_END - id3_header::SIZE_LEN
|
||||
&& mPos < id3_header::SIZE_END) {
|
||||
mSize <<= 7;
|
||||
mSize |= c;
|
||||
}
|
||||
|
@ -17,7 +17,8 @@ namespace mp3 {
|
||||
|
||||
class MP3TrackDemuxer;
|
||||
|
||||
class MP3Demuxer : public MediaDataDemuxer {
|
||||
class MP3Demuxer : public MediaDataDemuxer
|
||||
{
|
||||
public:
|
||||
// MediaDataDemuxer interface.
|
||||
explicit MP3Demuxer(MediaResource* aSource);
|
||||
@ -42,10 +43,12 @@ private:
|
||||
// The header contains the following format (one byte per term):
|
||||
// 'I' 'D' '3' MajorVersion MinorVersion Flags Size1 Size2 Size3 Size4
|
||||
// For more details see http://id3.org/id3v2.3.0.
|
||||
class ID3Parser {
|
||||
class ID3Parser
|
||||
{
|
||||
public:
|
||||
// Holds the ID3 header and its parsing state.
|
||||
class ID3Header {
|
||||
class ID3Header
|
||||
{
|
||||
public:
|
||||
// The header size is static, see class comment.
|
||||
static const int SIZE = 10;
|
||||
@ -130,10 +133,12 @@ private:
|
||||
// T - Copyright (0->disabled, 1->enabled)
|
||||
// O - Original (0->copy, 1->original)
|
||||
// HH - Emphasis (0->none, 1->50/15 ms, 2->reserved, 3->CCIT J.17)
|
||||
class FrameParser {
|
||||
class FrameParser
|
||||
{
|
||||
public:
|
||||
// Holds the frame header and its parsing state.
|
||||
class FrameHeader {
|
||||
class FrameHeader
|
||||
{
|
||||
public:
|
||||
// The header size is static, see class comments.
|
||||
static const int SIZE = 4;
|
||||
@ -200,10 +205,12 @@ public:
|
||||
|
||||
// VBR frames may contain Xing or VBRI headers for additional info, we use
|
||||
// this class to parse them and access this info.
|
||||
class VBRHeader {
|
||||
class VBRHeader
|
||||
{
|
||||
public:
|
||||
// Synchronize with vbr_header TYPE_STR on change.
|
||||
enum VBRHeaderType {
|
||||
enum VBRHeaderType
|
||||
{
|
||||
NONE = 0,
|
||||
XING,
|
||||
VBRI
|
||||
@ -231,7 +238,8 @@ public:
|
||||
// Returns whether the header is valid (type XING or VBRI).
|
||||
bool IsValid() const;
|
||||
|
||||
// Returns whether the header is valid and contains reasonable non-zero field values.
|
||||
// Returns whether the header is valid and contains reasonable non-zero
|
||||
// field values.
|
||||
bool IsComplete() const;
|
||||
|
||||
// Returns the byte offset for the given duration percentage as a factor
|
||||
@ -239,9 +247,9 @@ public:
|
||||
int64_t Offset(float aDurationFac) const;
|
||||
|
||||
// Parses contents of given ByteReader for a valid VBR header.
|
||||
// The offset of the passed ByteReader needs to point to an MPEG frame begin,
|
||||
// as a VBRI-style header is searched at a fixed offset relative to frame begin.
|
||||
// Returns whether a valid VBR header was found in the range.
|
||||
// The offset of the passed ByteReader needs to point to an MPEG frame
|
||||
// begin, as a VBRI-style header is searched at a fixed offset relative to
|
||||
// frame begin. Returns whether a valid VBR header was found in the range.
|
||||
bool Parse(mp4_demuxer::ByteReader* aReader);
|
||||
|
||||
private:
|
||||
@ -274,7 +282,8 @@ public:
|
||||
};
|
||||
|
||||
// Frame meta container used to parse and hold a frame header and side info.
|
||||
class Frame {
|
||||
class Frame
|
||||
{
|
||||
public:
|
||||
// Returns the length of the frame excluding the header in bytes.
|
||||
int32_t Length() const;
|
||||
@ -325,16 +334,16 @@ public:
|
||||
// - resets ID3Header if no valid header was parsed yet
|
||||
void EndFrameSession();
|
||||
|
||||
// Parses contents of given ByteReader for a valid frame header and returns true
|
||||
// if one was found. After returning, the variable passed to 'aBytesToSkip' holds
|
||||
// the amount of bytes to be skipped (if any) in order to jump across a large
|
||||
// ID3v2 tag spanning multiple buffers.
|
||||
// Parses contents of given ByteReader for a valid frame header and returns
|
||||
// true if one was found. After returning, the variable passed to
|
||||
// 'aBytesToSkip' holds the amount of bytes to be skipped (if any) in order to
|
||||
// jump across a large ID3v2 tag spanning multiple buffers.
|
||||
bool Parse(mp4_demuxer::ByteReader* aReader, uint32_t* aBytesToSkip);
|
||||
|
||||
// Parses contents of given ByteReader for a valid VBR header.
|
||||
// The offset of the passed ByteReader needs to point to an MPEG frame begin,
|
||||
// as a VBRI-style header is searched at a fixed offset relative to frame begin.
|
||||
// Returns whether a valid VBR header was found.
|
||||
// as a VBRI-style header is searched at a fixed offset relative to frame
|
||||
// begin. Returns whether a valid VBR header was found.
|
||||
bool ParseVBRHeader(mp4_demuxer::ByteReader* aReader);
|
||||
|
||||
private:
|
||||
@ -353,7 +362,8 @@ private:
|
||||
|
||||
// The MP3 demuxer used to extract MPEG frames and side information out of
|
||||
// MPEG streams.
|
||||
class MP3TrackDemuxer : public MediaTrackDemuxer {
|
||||
class MP3TrackDemuxer : public MediaTrackDemuxer
|
||||
{
|
||||
public:
|
||||
// Constructor, expecting a valid media resource.
|
||||
explicit MP3TrackDemuxer(MediaResource* aSource);
|
||||
|
@ -41,7 +41,8 @@ namespace flac {
|
||||
#define FLAC_MAX_FRAME_SIZE (FLAC_MAX_FRAME_HEADER_SIZE \
|
||||
+FLAC_MAX_BLOCKSIZE*FLAC_MAX_CHANNELS*3)
|
||||
|
||||
class FrameHeader {
|
||||
class FrameHeader
|
||||
{
|
||||
public:
|
||||
const AudioInfo& Info() const { return mInfo; }
|
||||
|
||||
@ -159,7 +160,8 @@ public:
|
||||
|
||||
private:
|
||||
friend class Frame;
|
||||
enum {
|
||||
enum
|
||||
{
|
||||
FLAC_CHMODE_INDEPENDENT = 0,
|
||||
FLAC_CHMODE_LEFT_SIDE,
|
||||
FLAC_CHMODE_RIGHT_SIDE,
|
||||
@ -180,7 +182,8 @@ private:
|
||||
};
|
||||
|
||||
const int FrameHeader::FlacSampleRateTable[16] =
|
||||
{ 0,
|
||||
{
|
||||
0,
|
||||
88200, 176400, 192000,
|
||||
8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000,
|
||||
0, 0, 0, 0
|
||||
@ -232,7 +235,8 @@ const uint8_t FrameHeader::CRC8Table[256] =
|
||||
|
||||
// flac::Frame - Frame meta container used to parse and hold a frame
|
||||
// header and side info.
|
||||
class Frame {
|
||||
class Frame
|
||||
{
|
||||
public:
|
||||
|
||||
// The FLAC signature is made of 14 bits set to 1; however the 15th bit is
|
||||
@ -384,7 +388,8 @@ private:
|
||||
|
||||
};
|
||||
|
||||
class FrameParser {
|
||||
class FrameParser
|
||||
{
|
||||
public:
|
||||
|
||||
// Returns the currently parsed frame. Reset via EndFrameSession.
|
||||
@ -563,9 +568,7 @@ private:
|
||||
|
||||
// FlacDemuxer
|
||||
|
||||
FlacDemuxer::FlacDemuxer(MediaResource* aSource)
|
||||
: mSource(aSource)
|
||||
{}
|
||||
FlacDemuxer::FlacDemuxer(MediaResource* aSource) : mSource(aSource) { }
|
||||
|
||||
bool
|
||||
FlacDemuxer::InitInternal()
|
||||
@ -638,7 +641,8 @@ FlacTrackDemuxer::Init()
|
||||
|
||||
// First check if we have a valid Flac start.
|
||||
char buffer[BUFFER_SIZE];
|
||||
const uint8_t* ubuffer = reinterpret_cast<uint8_t*>(buffer); // only needed due to type constraints of ReadAt.
|
||||
const uint8_t* ubuffer = // only needed due to type constraints of ReadAt.
|
||||
reinterpret_cast<uint8_t*>(buffer);
|
||||
int64_t offset = 0;
|
||||
|
||||
do {
|
||||
@ -762,7 +766,8 @@ FlacTrackDemuxer::FastSeek(const TimeUnit& aTime)
|
||||
int64_t pivot =
|
||||
aTime.ToSeconds() * AverageFrameLength() + mParser->FirstFrame().Offset();
|
||||
|
||||
// Time in seconds where we can stop seeking and will continue using ScanUntil.
|
||||
// Time in seconds where we can stop seeking and will continue using
|
||||
// ScanUntil.
|
||||
static const int GAP_THRESHOLD = 5;
|
||||
int64_t first = mParser->FirstFrame().Offset();
|
||||
int64_t last = mSource.GetLength();
|
||||
|
@ -19,7 +19,8 @@ class FrameParser;
|
||||
class FlacTrackDemuxer;
|
||||
|
||||
|
||||
class FlacDemuxer : public MediaDataDemuxer {
|
||||
class FlacDemuxer : public MediaDataDemuxer
|
||||
{
|
||||
public:
|
||||
// MediaDataDemuxer interface.
|
||||
explicit FlacDemuxer(MediaResource* aSource);
|
||||
@ -40,7 +41,8 @@ private:
|
||||
RefPtr<FlacTrackDemuxer> mTrackDemuxer;
|
||||
};
|
||||
|
||||
class FlacTrackDemuxer : public MediaTrackDemuxer {
|
||||
class FlacTrackDemuxer : public MediaTrackDemuxer
|
||||
{
|
||||
public:
|
||||
explicit FlacTrackDemuxer(MediaResource* aSource);
|
||||
|
||||
@ -71,7 +73,8 @@ private:
|
||||
// Fast approximate seeking to given time.
|
||||
media::TimeUnit FastSeek(const media::TimeUnit& aTime);
|
||||
|
||||
// Seeks by scanning the stream up to the given time for more accurate results.
|
||||
// Seeks by scanning the stream up to the given time for more accurate
|
||||
// results.
|
||||
media::TimeUnit ScanUntil(const media::TimeUnit& aTime);
|
||||
|
||||
// Finds the next valid frame and return it.
|
||||
|
@ -9,22 +9,22 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "MP4Demuxer.h"
|
||||
#include "mp4_demuxer/MoofParser.h"
|
||||
#include "mp4_demuxer/MP4Metadata.h"
|
||||
#include "mp4_demuxer/ResourceStream.h"
|
||||
#include "mp4_demuxer/BufferStream.h"
|
||||
#include "mp4_demuxer/Index.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
// Used for telemetry
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mp4_demuxer/AnnexB.h"
|
||||
#include "mp4_demuxer/H264.h"
|
||||
|
||||
#include "mp4_demuxer/MoofParser.h"
|
||||
#include "mp4_demuxer/MP4Metadata.h"
|
||||
#include "mp4_demuxer/ResourceStream.h"
|
||||
#include "mp4_demuxer/BufferStream.h"
|
||||
#include "mp4_demuxer/Index.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
extern mozilla::LazyLogModule gMediaDemuxerLog;
|
||||
mozilla::LogModule* GetDemuxerLog() {
|
||||
mozilla::LogModule* GetDemuxerLog()
|
||||
{
|
||||
return gMediaDemuxerLog;
|
||||
}
|
||||
|
||||
@ -82,12 +82,12 @@ AccumulateSPSTelemetry(const MediaByteBuffer* aExtradata)
|
||||
{
|
||||
mp4_demuxer::SPSData spsdata;
|
||||
if (mp4_demuxer::H264::DecodeSPSFromExtraData(aExtradata, spsdata)) {
|
||||
uint8_t constraints = (spsdata.constraint_set0_flag ? (1 << 0) : 0) |
|
||||
(spsdata.constraint_set1_flag ? (1 << 1) : 0) |
|
||||
(spsdata.constraint_set2_flag ? (1 << 2) : 0) |
|
||||
(spsdata.constraint_set3_flag ? (1 << 3) : 0) |
|
||||
(spsdata.constraint_set4_flag ? (1 << 4) : 0) |
|
||||
(spsdata.constraint_set5_flag ? (1 << 5) : 0);
|
||||
uint8_t constraints = (spsdata.constraint_set0_flag ? (1 << 0) : 0)
|
||||
| (spsdata.constraint_set1_flag ? (1 << 1) : 0)
|
||||
| (spsdata.constraint_set2_flag ? (1 << 2) : 0)
|
||||
| (spsdata.constraint_set3_flag ? (1 << 3) : 0)
|
||||
| (spsdata.constraint_set4_flag ? (1 << 4) : 0)
|
||||
| (spsdata.constraint_set5_flag ? (1 << 5) : 0);
|
||||
Telemetry::Accumulate(Telemetry::VIDEO_DECODED_H264_SPS_CONSTRAINT_SET_FLAG,
|
||||
constraints);
|
||||
|
||||
@ -98,8 +98,9 @@ AccumulateSPSTelemetry(const MediaByteBuffer* aExtradata)
|
||||
// Make sure level_idc represents a value between levels 1 and 5.2,
|
||||
// otherwise collect 0 for unknown level.
|
||||
Telemetry::Accumulate(Telemetry::VIDEO_DECODED_H264_SPS_LEVEL,
|
||||
(spsdata.level_idc >= 10 && spsdata.level_idc <= 52) ?
|
||||
spsdata.level_idc : 0);
|
||||
(spsdata.level_idc >= 10 && spsdata.level_idc <= 52)
|
||||
? spsdata.level_idc
|
||||
: 0);
|
||||
|
||||
// max_num_ref_frames should be between 0 and 16, anything larger will
|
||||
// be treated as invalid.
|
||||
@ -126,13 +127,15 @@ MP4Demuxer::Init()
|
||||
|
||||
// Check that we have enough data to read the metadata.
|
||||
if (!mp4_demuxer::MP4Metadata::HasCompleteMetadata(stream)) {
|
||||
return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_DEMUXER_ERR, __func__);
|
||||
return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_DEMUXER_ERR,
|
||||
__func__);
|
||||
}
|
||||
|
||||
mInitData = mp4_demuxer::MP4Metadata::Metadata(stream);
|
||||
if (!mInitData) {
|
||||
// OOM
|
||||
return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_DEMUXER_ERR, __func__);
|
||||
return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_DEMUXER_ERR,
|
||||
__func__);
|
||||
}
|
||||
|
||||
RefPtr<mp4_demuxer::BufferStream> bufferstream =
|
||||
@ -140,9 +143,10 @@ MP4Demuxer::Init()
|
||||
|
||||
mMetadata = MakeUnique<mp4_demuxer::MP4Metadata>(bufferstream);
|
||||
|
||||
if (!mMetadata->GetNumberTracks(mozilla::TrackInfo::kAudioTrack) &&
|
||||
!mMetadata->GetNumberTracks(mozilla::TrackInfo::kVideoTrack)) {
|
||||
return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_DEMUXER_ERR, __func__);
|
||||
if (!mMetadata->GetNumberTracks(mozilla::TrackInfo::kAudioTrack)
|
||||
&& !mMetadata->GetNumberTracks(mozilla::TrackInfo::kVideoTrack)) {
|
||||
return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_DEMUXER_ERR,
|
||||
__func__);
|
||||
}
|
||||
|
||||
return InitPromise::CreateAndResolve(NS_OK, __func__);
|
||||
@ -243,16 +247,16 @@ MP4TrackDemuxer::MP4TrackDemuxer(MP4Demuxer* aParent,
|
||||
|
||||
VideoInfo* videoInfo = mInfo->GetAsVideoInfo();
|
||||
// Collect telemetry from h264 AVCC SPS.
|
||||
if (videoInfo &&
|
||||
(mInfo->mMimeType.EqualsLiteral("video/mp4") ||
|
||||
mInfo->mMimeType.EqualsLiteral("video/avc"))) {
|
||||
if (videoInfo
|
||||
&& (mInfo->mMimeType.EqualsLiteral("video/mp4")
|
||||
|| mInfo->mMimeType.EqualsLiteral("video/avc"))) {
|
||||
mIsH264 = true;
|
||||
RefPtr<MediaByteBuffer> extraData = videoInfo->mExtraData;
|
||||
mNeedSPSForTelemetry = AccumulateSPSTelemetry(extraData);
|
||||
mp4_demuxer::SPSData spsdata;
|
||||
if (mp4_demuxer::H264::DecodeSPSFromExtraData(extraData, spsdata) &&
|
||||
spsdata.pic_width > 0 && spsdata.pic_height > 0 &&
|
||||
mp4_demuxer::H264::EnsureSPSIsSane(spsdata)) {
|
||||
if (mp4_demuxer::H264::DecodeSPSFromExtraData(extraData, spsdata)
|
||||
&& spsdata.pic_width > 0 && spsdata.pic_height > 0
|
||||
&& mp4_demuxer::H264::EnsureSPSIsSane(spsdata)) {
|
||||
videoInfo->mImage.width = spsdata.pic_width;
|
||||
videoInfo->mImage.height = spsdata.pic_height;
|
||||
videoInfo->mDisplay.width = spsdata.display_width;
|
||||
@ -299,7 +303,8 @@ MP4TrackDemuxer::Seek(const media::TimeUnit& aTime)
|
||||
do {
|
||||
sample = GetNextSample();
|
||||
if (!sample) {
|
||||
return SeekPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
|
||||
return SeekPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_END_OF_STREAM,
|
||||
__func__);
|
||||
}
|
||||
if (!sample->Size()) {
|
||||
// This sample can't be decoded, continue searching.
|
||||
@ -313,7 +318,8 @@ MP4TrackDemuxer::Seek(const media::TimeUnit& aTime)
|
||||
|
||||
SetNextKeyFrameTime();
|
||||
|
||||
return SeekPromise::CreateAndResolve(media::TimeUnit::FromMicroseconds(seekTime), __func__);
|
||||
return SeekPromise::CreateAndResolve(
|
||||
media::TimeUnit::FromMicroseconds(seekTime), __func__);
|
||||
}
|
||||
|
||||
already_AddRefed<MediaRawData>
|
||||
@ -334,20 +340,20 @@ MP4TrackDemuxer::GetNextSample()
|
||||
{
|
||||
bool keyframe = type == mp4_demuxer::H264::FrameType::I_FRAME;
|
||||
if (sample->mKeyframe != keyframe) {
|
||||
NS_WARNING(nsPrintfCString("Frame incorrectly marked as %skeyframe @ pts:%lld dur:%u dts:%lld",
|
||||
keyframe ? "" : "non-",
|
||||
sample->mTime,
|
||||
sample->mDuration,
|
||||
sample->mTimecode).get());
|
||||
NS_WARNING(nsPrintfCString("Frame incorrectly marked as %skeyframe "
|
||||
"@ pts:%lld dur:%u dts:%lld",
|
||||
keyframe ? "" : "non-", sample->mTime,
|
||||
sample->mDuration, sample->mTimecode)
|
||||
.get());
|
||||
sample->mKeyframe = keyframe;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case mp4_demuxer::H264::FrameType::INVALID:
|
||||
NS_WARNING(nsPrintfCString("Invalid H264 frame @ pts:%lld dur:%u dts:%lld",
|
||||
sample->mTime,
|
||||
sample->mDuration,
|
||||
sample->mTimecode).get());
|
||||
NS_WARNING(
|
||||
nsPrintfCString("Invalid H264 frame @ pts:%lld dur:%u dts:%lld",
|
||||
sample->mTime, sample->mDuration, sample->mTimecode)
|
||||
.get());
|
||||
// We could reject the sample now, however demuxer errors are fatal.
|
||||
// So we keep the invalid frame, relying on the H264 decoder to
|
||||
// handle the error later.
|
||||
@ -377,7 +383,8 @@ MP4TrackDemuxer::GetSamples(int32_t aNumSamples)
|
||||
EnsureUpToDateIndex();
|
||||
RefPtr<SamplesHolder> samples = new SamplesHolder;
|
||||
if (!aNumSamples) {
|
||||
return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_DEMUXER_ERR, __func__);
|
||||
return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_DEMUXER_ERR,
|
||||
__func__);
|
||||
}
|
||||
|
||||
if (mQueuedSample) {
|
||||
@ -397,7 +404,8 @@ MP4TrackDemuxer::GetSamples(int32_t aNumSamples)
|
||||
}
|
||||
|
||||
if (samples->mSamples.IsEmpty()) {
|
||||
return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
|
||||
return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_END_OF_STREAM,
|
||||
__func__);
|
||||
} else {
|
||||
for (const auto& sample : samples->mSamples) {
|
||||
// Collect telemetry from h264 Annex B SPS.
|
||||
@ -408,8 +416,9 @@ MP4TrackDemuxer::GetSamples(int32_t aNumSamples)
|
||||
}
|
||||
}
|
||||
|
||||
if (mNextKeyframeTime.isNothing() ||
|
||||
samples->mSamples.LastElement()->mTime >= mNextKeyframeTime.value().ToMicroseconds()) {
|
||||
if (mNextKeyframeTime.isNothing()
|
||||
|| samples->mSamples.LastElement()->mTime
|
||||
>= mNextKeyframeTime.value().ToMicroseconds()) {
|
||||
SetNextKeyFrameTime();
|
||||
}
|
||||
return SamplesPromise::CreateAndResolve(samples, __func__);
|
||||
@ -450,7 +459,8 @@ MP4TrackDemuxer::GetNextRandomAccessPoint(media::TimeUnit* aTime)
|
||||
}
|
||||
|
||||
RefPtr<MP4TrackDemuxer::SkipAccessPointPromise>
|
||||
MP4TrackDemuxer::SkipToNextRandomAccessPoint(const media::TimeUnit& aTimeThreshold)
|
||||
MP4TrackDemuxer::SkipToNextRandomAccessPoint(
|
||||
const media::TimeUnit& aTimeThreshold)
|
||||
{
|
||||
mQueuedSample = nullptr;
|
||||
// Loop until we reach the next keyframe after the threshold.
|
||||
|
@ -33,8 +33,8 @@ public:
|
||||
|
||||
uint32_t GetNumberTracks(TrackInfo::TrackType aType) const override;
|
||||
|
||||
already_AddRefed<MediaTrackDemuxer> GetTrackDemuxer(TrackInfo::TrackType aType,
|
||||
uint32_t aTrackNumber) override;
|
||||
already_AddRefed<MediaTrackDemuxer>
|
||||
GetTrackDemuxer(TrackInfo::TrackType aType, uint32_t aTrackNumber) override;
|
||||
|
||||
bool IsSeekable() const override;
|
||||
|
||||
|
@ -269,8 +269,8 @@ MediaSourceDecoder::NextFrameBufferedStatus()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mMediaSource ||
|
||||
mMediaSource->ReadyState() == dom::MediaSourceReadyState::Closed) {
|
||||
if (!mMediaSource
|
||||
|| mMediaSource->ReadyState() == dom::MediaSourceReadyState::Closed) {
|
||||
return MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
|
||||
}
|
||||
|
||||
@ -304,7 +304,8 @@ MediaSourceDecoder::CanPlayThrough()
|
||||
TimeUnit duration = TimeUnit::FromSeconds(mMediaSource->Duration());
|
||||
TimeUnit currentPosition = TimeUnit::FromMicroseconds(CurrentPosition());
|
||||
if (duration.IsInfinite()) {
|
||||
// We can't make an informed decision and just assume that it's a live stream
|
||||
// We can't make an informed decision and just assume that it's a live
|
||||
// stream
|
||||
return true;
|
||||
} else if (duration <= currentPosition) {
|
||||
return true;
|
||||
|
@ -35,8 +35,8 @@ public:
|
||||
|
||||
uint32_t GetNumberTracks(TrackInfo::TrackType aType) const override;
|
||||
|
||||
already_AddRefed<MediaTrackDemuxer> GetTrackDemuxer(TrackInfo::TrackType aType,
|
||||
uint32_t aTrackNumber) override;
|
||||
already_AddRefed<MediaTrackDemuxer>
|
||||
GetTrackDemuxer(TrackInfo::TrackType aType, uint32_t aTrackNumber) override;
|
||||
|
||||
bool IsSeekable() const override;
|
||||
|
||||
@ -105,7 +105,8 @@ public:
|
||||
|
||||
nsresult GetNextRandomAccessPoint(media::TimeUnit* aTime) override;
|
||||
|
||||
RefPtr<SkipAccessPointPromise> SkipToNextRandomAccessPoint(const media::TimeUnit& aTimeThreshold) override;
|
||||
RefPtr<SkipAccessPointPromise> SkipToNextRandomAccessPoint(
|
||||
const media::TimeUnit& aTimeThreshold) override;
|
||||
|
||||
media::TimeIntervals GetBuffered() override;
|
||||
|
||||
@ -119,7 +120,8 @@ public:
|
||||
private:
|
||||
RefPtr<SeekPromise> DoSeek(const media::TimeUnit& aTime);
|
||||
RefPtr<SamplesPromise> DoGetSamples(int32_t aNumSamples);
|
||||
RefPtr<SkipAccessPointPromise> DoSkipToNextRandomAccessPoint(const media::TimeUnit& aTimeThreadshold);
|
||||
RefPtr<SkipAccessPointPromise> DoSkipToNextRandomAccessPoint(
|
||||
const media::TimeUnit& aTimeThreadshold);
|
||||
already_AddRefed<MediaRawData> GetSample(MediaResult& aError);
|
||||
// Return the timestamp of the next keyframe after mLastSampleIndex.
|
||||
media::TimeUnit GetNextRandomAccessPoint();
|
||||
|
@ -197,7 +197,8 @@ WAVTrackDemuxer::FmtChunkParserInit()
|
||||
if (!fmtChunk) {
|
||||
return false;
|
||||
}
|
||||
ByteReader fmtReader(fmtChunk->Data(), mHeaderParser.GiveHeader().ChunkSize());
|
||||
ByteReader fmtReader(fmtChunk->Data(),
|
||||
mHeaderParser.GiveHeader().ChunkSize());
|
||||
mFmtParser.Parse(fmtReader);
|
||||
return true;
|
||||
}
|
||||
@ -260,16 +261,20 @@ WAVTrackDemuxer::ListChunkParserInit(uint32_t aChunkSize)
|
||||
|
||||
switch (id) {
|
||||
case 0x49415254: // IART
|
||||
mInfo->mTags.AppendElement(MetadataTag(NS_LITERAL_CSTRING("artist"), val));
|
||||
mInfo->mTags.AppendElement(
|
||||
MetadataTag(NS_LITERAL_CSTRING("artist"), val));
|
||||
break;
|
||||
case 0x49434d54: // ICMT
|
||||
mInfo->mTags.AppendElement(MetadataTag(NS_LITERAL_CSTRING("comments"), val));
|
||||
mInfo->mTags.AppendElement(
|
||||
MetadataTag(NS_LITERAL_CSTRING("comments"), val));
|
||||
break;
|
||||
case 0x49474e52: // IGNR
|
||||
mInfo->mTags.AppendElement(MetadataTag(NS_LITERAL_CSTRING("genre"), val));
|
||||
mInfo->mTags.AppendElement(
|
||||
MetadataTag(NS_LITERAL_CSTRING("genre"), val));
|
||||
break;
|
||||
case 0x494e414d: // INAM
|
||||
mInfo->mTags.AppendElement(MetadataTag(NS_LITERAL_CSTRING("name"), val));
|
||||
mInfo->mTags.AppendElement(
|
||||
MetadataTag(NS_LITERAL_CSTRING("name"), val));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -357,7 +362,7 @@ WAVTrackDemuxer::GetSamples(int32_t aNumSamples)
|
||||
|
||||
if (datachunks->mSamples.IsEmpty()) {
|
||||
return SamplesPromise::CreateAndReject(
|
||||
NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
|
||||
NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
|
||||
}
|
||||
|
||||
return SamplesPromise::CreateAndResolve(datachunks, __func__);
|
||||
@ -430,9 +435,8 @@ WAVTrackDemuxer::Duration(int64_t aNumDataChunks) const
|
||||
if (!mSamplesPerSecond || !mSamplesPerChunk) {
|
||||
return TimeUnit();
|
||||
}
|
||||
const double usPerDataChunk = USECS_PER_S *
|
||||
static_cast<double>(mSamplesPerChunk) /
|
||||
mSamplesPerSecond;
|
||||
const double usPerDataChunk =
|
||||
USECS_PER_S * static_cast<double>(mSamplesPerChunk) / mSamplesPerSecond;
|
||||
return TimeUnit::FromMicroseconds(aNumDataChunks * usPerDataChunk);
|
||||
}
|
||||
|
||||
@ -516,9 +520,8 @@ WAVTrackDemuxer::GetNextChunk(const MediaByteRange& aRange)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const uint32_t read = Read(chunkWriter->Data(),
|
||||
datachunk->mOffset,
|
||||
datachunk->Size());
|
||||
const uint32_t read =
|
||||
Read(chunkWriter->Data(), datachunk->mOffset, datachunk->Size());
|
||||
|
||||
if (read != aRange.Length()) {
|
||||
return nullptr;
|
||||
@ -561,9 +564,8 @@ WAVTrackDemuxer::GetFileHeader(const MediaByteRange& aRange)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const uint32_t read = Read(headerWriter->Data(),
|
||||
fileHeader->mOffset,
|
||||
fileHeader->Size());
|
||||
const uint32_t read =
|
||||
Read(headerWriter->Data(), fileHeader->mOffset, fileHeader->Size());
|
||||
|
||||
if (read != aRange.Length()) {
|
||||
return nullptr;
|
||||
@ -757,15 +759,19 @@ HeaderParser::ChunkHeader::IsValid() const
|
||||
uint32_t
|
||||
HeaderParser::ChunkHeader::ChunkName() const
|
||||
{
|
||||
return ((mRaw[0] << 24) | (mRaw[1] << 16) |
|
||||
(mRaw[2] << 8 ) | (mRaw[3]));
|
||||
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]));
|
||||
return ((mRaw[7] << 24)
|
||||
| (mRaw[6] << 16)
|
||||
| (mRaw[5] << 8 )
|
||||
| (mRaw[4]));
|
||||
}
|
||||
|
||||
void
|
||||
@ -831,8 +837,10 @@ FormatParser::FormatChunk::Channels() const
|
||||
uint32_t
|
||||
FormatParser::FormatChunk::SampleRate() const
|
||||
{
|
||||
return (mRaw[7] << 24) | (mRaw[6] << 16) |
|
||||
(mRaw[5] << 8 ) | (mRaw[4]);
|
||||
return (mRaw[7] << 24)
|
||||
| (mRaw[6] << 16)
|
||||
| (mRaw[5] << 8)
|
||||
| (mRaw[4]);
|
||||
}
|
||||
|
||||
uint16_t
|
||||
@ -857,8 +865,8 @@ FormatParser::FormatChunk::ParseNext(uint8_t c)
|
||||
bool
|
||||
FormatParser::FormatChunk::IsValid() const
|
||||
{
|
||||
return (FrameSize() == SampleRate() * Channels() / 8) &&
|
||||
(mPos >= FMT_CHUNK_MIN_SIZE);
|
||||
return (FrameSize() == SampleRate() * Channels() / 8)
|
||||
&& (mPos >= FMT_CHUNK_MIN_SIZE);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -30,7 +30,8 @@ static const uint16_t DATA_CHUNK_SIZE = 768;
|
||||
|
||||
class WAVTrackDemuxer;
|
||||
|
||||
class WAVDemuxer : public MediaDataDemuxer {
|
||||
class WAVDemuxer : public MediaDataDemuxer
|
||||
{
|
||||
public:
|
||||
// MediaDataDemuxer interface.
|
||||
explicit WAVDemuxer(MediaResource* aSource);
|
||||
@ -38,7 +39,7 @@ public:
|
||||
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;
|
||||
TrackInfo::TrackType aType, uint32_t aTrackNumber) override;
|
||||
bool IsSeekable() const override;
|
||||
|
||||
private:
|
||||
@ -49,7 +50,8 @@ private:
|
||||
RefPtr<WAVTrackDemuxer> mTrackDemuxer;
|
||||
};
|
||||
|
||||
class RIFFParser {
|
||||
class RIFFParser
|
||||
{
|
||||
private:
|
||||
class RIFFHeader;
|
||||
public:
|
||||
@ -60,7 +62,8 @@ public:
|
||||
void Reset();
|
||||
|
||||
private:
|
||||
class RIFFHeader {
|
||||
class RIFFHeader
|
||||
{
|
||||
public:
|
||||
RIFFHeader();
|
||||
void Reset();
|
||||
@ -81,7 +84,8 @@ private:
|
||||
RIFFHeader mRiffHeader;
|
||||
};
|
||||
|
||||
class HeaderParser {
|
||||
class HeaderParser
|
||||
{
|
||||
private:
|
||||
class ChunkHeader;
|
||||
public:
|
||||
@ -92,7 +96,8 @@ public:
|
||||
void Reset();
|
||||
|
||||
private:
|
||||
class ChunkHeader {
|
||||
class ChunkHeader
|
||||
{
|
||||
public:
|
||||
ChunkHeader();
|
||||
void Reset();
|
||||
@ -115,7 +120,8 @@ private:
|
||||
ChunkHeader mHeader;
|
||||
};
|
||||
|
||||
class FormatParser {
|
||||
class FormatParser
|
||||
{
|
||||
private:
|
||||
class FormatChunk;
|
||||
public:
|
||||
@ -126,7 +132,8 @@ public:
|
||||
void Reset();
|
||||
|
||||
private:
|
||||
class FormatChunk {
|
||||
class FormatChunk
|
||||
{
|
||||
public:
|
||||
FormatChunk();
|
||||
void Reset();
|
||||
@ -151,7 +158,8 @@ private:
|
||||
FormatChunk mFmtChunk;
|
||||
};
|
||||
|
||||
class DataParser {
|
||||
class DataParser
|
||||
{
|
||||
private:
|
||||
class DataChunk;
|
||||
public:
|
||||
@ -162,7 +170,8 @@ public:
|
||||
void Reset();
|
||||
|
||||
private:
|
||||
class DataChunk {
|
||||
class DataChunk
|
||||
{
|
||||
public:
|
||||
void Reset();
|
||||
private:
|
||||
@ -172,7 +181,8 @@ private:
|
||||
DataChunk mChunk;
|
||||
};
|
||||
|
||||
class WAVTrackDemuxer : public MediaTrackDemuxer {
|
||||
class WAVTrackDemuxer : public MediaTrackDemuxer
|
||||
{
|
||||
public:
|
||||
explicit WAVTrackDemuxer(MediaResourceIndex aSource);
|
||||
|
||||
@ -199,7 +209,7 @@ public:
|
||||
media::TimeIntervals GetBuffered() override;
|
||||
|
||||
private:
|
||||
~WAVTrackDemuxer() {}
|
||||
~WAVTrackDemuxer() { }
|
||||
|
||||
media::TimeUnit FastSeek(const media::TimeUnit& aTime);
|
||||
media::TimeUnit ScanUntil(const media::TimeUnit& aTime);
|
||||
|
Loading…
Reference in New Issue
Block a user