diff options
author | Moonchild <mcwerewolf@wolfbeast.com> | 2018-12-09 17:28:47 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-12-09 17:28:47 +0100 |
commit | fbbda481dce5c367b4ccdeacc70cdcd7f68ac8af (patch) | |
tree | 5d46ac7b2eec16b46b9c1463baa0de38a06b2f7d | |
parent | d01a5b10f1551bffdb220f4b3d700156008aab7b (diff) | |
parent | 45f442a2a04bfc299c994e2712c3553278d46e6c (diff) | |
download | UXP-fbbda481dce5c367b4ccdeacc70cdcd7f68ac8af.tar UXP-fbbda481dce5c367b4ccdeacc70cdcd7f68ac8af.tar.gz UXP-fbbda481dce5c367b4ccdeacc70cdcd7f68ac8af.tar.lz UXP-fbbda481dce5c367b4ccdeacc70cdcd7f68ac8af.tar.xz UXP-fbbda481dce5c367b4ccdeacc70cdcd7f68ac8af.zip |
Merge pull request #902 from trav90/media-work
Remove the old MP3Parser and reorganize remaining MP3 code
-rw-r--r-- | dom/media/DecoderTraits.cpp | 2 | ||||
-rw-r--r-- | dom/media/MP3FrameParser.cpp | 591 | ||||
-rw-r--r-- | dom/media/MP3FrameParser.h | 219 | ||||
-rw-r--r-- | dom/media/WebVTTListener.h | 1 | ||||
-rw-r--r-- | dom/media/gtest/TestMP3Demuxer.cpp | 1 | ||||
-rw-r--r-- | dom/media/moz.build | 7 | ||||
-rw-r--r-- | dom/media/mp3/MP3Decoder.cpp (renamed from dom/media/MP3Decoder.cpp) | 2 | ||||
-rw-r--r-- | dom/media/mp3/MP3Decoder.h (renamed from dom/media/MP3Decoder.h) | 0 | ||||
-rw-r--r-- | dom/media/mp3/MP3Demuxer.cpp (renamed from dom/media/MP3Demuxer.cpp) | 2 | ||||
-rw-r--r-- | dom/media/mp3/MP3Demuxer.h (renamed from dom/media/MP3Demuxer.h) | 2 | ||||
-rw-r--r-- | dom/media/mp3/moz.build | 17 |
11 files changed, 21 insertions, 823 deletions
diff --git a/dom/media/DecoderTraits.cpp b/dom/media/DecoderTraits.cpp index 473ca9533..477ecf358 100644 --- a/dom/media/DecoderTraits.cpp +++ b/dom/media/DecoderTraits.cpp @@ -432,7 +432,7 @@ MediaDecoderReader* DecoderTraits::CreateReader(const nsACString& aType, Abstrac } else #endif if (IsMP3SupportedType(aType)) { - decoderReader = new MediaFormatReader(aDecoder, new mp3::MP3Demuxer(aDecoder->GetResource())); + decoderReader = new MediaFormatReader(aDecoder, new MP3Demuxer(aDecoder->GetResource())); } else if (IsAACSupportedType(aType)) { decoderReader = new MediaFormatReader(aDecoder, new ADTSDemuxer(aDecoder->GetResource())); diff --git a/dom/media/MP3FrameParser.cpp b/dom/media/MP3FrameParser.cpp deleted file mode 100644 index 242e3df00..000000000 --- a/dom/media/MP3FrameParser.cpp +++ /dev/null @@ -1,591 +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 <algorithm> - -#include "nsMemory.h" -#include "MP3FrameParser.h" -#include "VideoUtils.h" - - -#define FROM_BIG_ENDIAN(X) ((uint32_t)((uint8_t)(X)[0] << 24 | (uint8_t)(X)[1] << 16 | \ - (uint8_t)(X)[2] << 8 | (uint8_t)(X)[3])) - - -namespace mozilla { - -/* - * Following code taken from http://www.hydrogenaudio.org/forums/index.php?showtopic=85125 - * with permission from the author, Nick Wallette <sirnickity@gmail.com>. - */ - -/* BEGIN shameless copy and paste */ - -// Bitrates - use [version][layer][bitrate] -const uint16_t mpeg_bitrates[4][4][16] = { - { // Version 2.5 - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Reserved - { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 }, // Layer 3 - { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 }, // Layer 2 - { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0 } // Layer 1 - }, - { // Reserved - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Invalid - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Invalid - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Invalid - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // Invalid - }, - { // Version 2 - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Reserved - { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 }, // Layer 3 - { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 }, // Layer 2 - { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0 } // Layer 1 - }, - { // Version 1 - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Reserved - { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 }, // Layer 3 - { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0 }, // Layer 2 - { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0 }, // Layer 1 - } -}; - -// Sample rates - use [version][srate] -const uint16_t mpeg_srates[4][4] = { - { 11025, 12000, 8000, 0 }, // MPEG 2.5 - { 0, 0, 0, 0 }, // Reserved - { 22050, 24000, 16000, 0 }, // MPEG 2 - { 44100, 48000, 32000, 0 } // MPEG 1 -}; - -// Samples per frame - use [version][layer] -const uint16_t mpeg_frame_samples[4][4] = { -// Rsvd 3 2 1 < Layer v Version - { 0, 576, 1152, 384 }, // 2.5 - { 0, 0, 0, 0 }, // Reserved - { 0, 576, 1152, 384 }, // 2 - { 0, 1152, 1152, 384 } // 1 -}; - -// Slot size (MPEG unit of measurement) - use [layer] -const uint8_t mpeg_slot_size[4] = { 0, 1, 1, 4 }; // Rsvd, 3, 2, 1 - -uint16_t -MP3Frame::CalculateLength() -{ - // Lookup real values of these fields - uint32_t bitrate = mpeg_bitrates[mVersion][mLayer][mBitrate] * 1000; - uint32_t samprate = mpeg_srates[mVersion][mSampleRate]; - uint16_t samples = mpeg_frame_samples[mVersion][mLayer]; - uint8_t slot_size = mpeg_slot_size[mLayer]; - - // In-between calculations - float bps = (float)samples / 8.0; - float fsize = ( (bps * (float)bitrate) / (float)samprate ) - + ( (mPad) ? slot_size : 0 ); - - // Frame sizes are truncated integers - return (uint16_t)fsize; -} - -/* END shameless copy and paste */ - - -/** MP3Parser methods **/ - -MP3Parser::MP3Parser() - : mCurrentChar(0) -{ } - -void -MP3Parser::Reset() -{ - mCurrentChar = 0; -} - -uint16_t -MP3Parser::ParseFrameLength(uint8_t ch) -{ - mData.mRaw[mCurrentChar] = ch; - - MP3Frame &frame = mData.mFrame; - - // Validate MP3 header as we read. We can't mistake the start of an MP3 frame - // for the middle of another frame due to the sync byte at the beginning - // of the frame. - - // The only valid position for an all-high byte is the sync byte at the - // beginning of the frame. - if (ch == 0xff) { - mCurrentChar = 0; - } - - // Make sure the current byte is valid in context. If not, reset the parser. - if (mCurrentChar == 2) { - if (frame.mBitrate == 0x0f) { - goto fail; - } - } else if (mCurrentChar == 1) { - if (frame.mSync2 != 0x07 - || frame.mVersion == 0x01 - || frame.mLayer == 0x00) { - goto fail; - } - } - - // The only valid character at the beginning of the header is 0xff. Fail if - // it's different. - if (mCurrentChar == 0 && frame.mSync1 != 0xff) { - // Couldn't find the sync byte. Fail. - return 0; - } - - mCurrentChar++; - MOZ_ASSERT(mCurrentChar <= sizeof(MP3Frame)); - - // Don't have a full header yet. - if (mCurrentChar < sizeof(MP3Frame)) { - return 0; - } - - // Woo, valid header. Return the length. - mCurrentChar = 0; - return frame.CalculateLength(); - -fail: - Reset(); - return 0; -} - -uint32_t -MP3Parser::GetSampleRate() -{ - MP3Frame &frame = mData.mFrame; - return mpeg_srates[frame.mVersion][frame.mSampleRate]; -} - -uint32_t -MP3Parser::GetSamplesPerFrame() -{ - MP3Frame &frame = mData.mFrame; - return mpeg_frame_samples[frame.mVersion][frame.mLayer]; -} - - -/** ID3Parser methods **/ - -const char sID3Head[3] = { 'I', 'D', '3' }; -const uint32_t ID3_HEADER_LENGTH = 10; -const uint32_t ID3_FOOTER_LENGTH = 10; -const uint8_t ID3_FOOTER_PRESENT = 0x10; - -ID3Parser::ID3Parser() - : mCurrentChar(0) - , mVersion(0) - , mFlags(0) - , mHeaderLength(0) -{ } - -void -ID3Parser::Reset() -{ - mCurrentChar = mVersion = mFlags = mHeaderLength = 0; -} - -bool -ID3Parser::ParseChar(char ch) -{ - switch (mCurrentChar) { - // The first three bytes of an ID3v2 header must match the string "ID3". - case 0: case 1: case 2: - if (ch != sID3Head[mCurrentChar]) { - goto fail; - } - break; - // The fourth and fifth bytes give the version, between 2 and 4. - case 3: - if (ch < '\2' || ch > '\4') { - goto fail; - } - mVersion = uint8_t(ch); - break; - case 4: - if (ch != '\0') { - goto fail; - } - break; - // The sixth byte gives the flags; valid flags depend on the version. - case 5: - if ((ch & (0xff >> mVersion)) != '\0') { - goto fail; - } - mFlags = uint8_t(ch); - break; - // Bytes seven through ten give the sum of the byte length of the extended - // header, the padding and the frames after unsynchronisation. - // These bytes form a 28-bit integer, with the high bit of each byte unset. - case 6: case 7: case 8: case 9: - if (ch & 0x80) { - goto fail; - } - mHeaderLength <<= 7; - mHeaderLength |= ch; - if (mCurrentChar == 9) { - mHeaderLength += ID3_HEADER_LENGTH; - mHeaderLength += (mFlags & ID3_FOOTER_PRESENT) ? ID3_FOOTER_LENGTH : 0; - } - break; - default: - MOZ_CRASH("Header already fully parsed!"); - } - - mCurrentChar++; - - return IsParsed(); - -fail: - if (mCurrentChar) { - Reset(); - return ParseChar(ch); - } - Reset(); - return false; -} - -bool -ID3Parser::IsParsed() const -{ - return mCurrentChar >= ID3_HEADER_LENGTH; -} - -uint32_t -ID3Parser::GetHeaderLength() const -{ - MOZ_ASSERT(IsParsed(), - "Queried length of ID3 header before parsing finished."); - return mHeaderLength; -} - - -/** VBR header helper stuff **/ - -// Helper function to find a VBR header in an MP3 frame. -// Based on information from -// http://www.codeproject.com/Articles/8295/MPEG-Audio-Frame-Header - -const uint32_t VBRI_TAG = FROM_BIG_ENDIAN("VBRI"); -const uint32_t VBRI_OFFSET = 32 - sizeof(MP3Frame); -const uint32_t VBRI_FRAME_COUNT_OFFSET = VBRI_OFFSET + 14; -const uint32_t VBRI_MIN_FRAME_SIZE = VBRI_OFFSET + 26; - -const uint32_t XING_TAG = FROM_BIG_ENDIAN("Xing"); -enum XingFlags { - XING_HAS_NUM_FRAMES = 0x01, - XING_HAS_NUM_BYTES = 0x02, - XING_HAS_TOC = 0x04, - XING_HAS_VBR_SCALE = 0x08 -}; - -static int64_t -ParseXing(const char *aBuffer) -{ - uint32_t flags = FROM_BIG_ENDIAN(aBuffer + 4); - - if (!(flags & XING_HAS_NUM_FRAMES)) { - NS_WARNING("VBR file without frame count. Duration estimation likely to " - "be totally wrong."); - return -1; - } - - int64_t numFrames = -1; - if (flags & XING_HAS_NUM_FRAMES) { - numFrames = FROM_BIG_ENDIAN(aBuffer + 8); - } - - return numFrames; -} - -static int64_t -FindNumVBRFrames(const nsCString& aFrame) -{ - const char *buffer = aFrame.get(); - const char *bufferEnd = aFrame.get() + aFrame.Length(); - - // VBRI header is nice and well-defined; let's try to find that first. - if (aFrame.Length() > VBRI_MIN_FRAME_SIZE && - FROM_BIG_ENDIAN(buffer + VBRI_OFFSET) == VBRI_TAG) { - return FROM_BIG_ENDIAN(buffer + VBRI_FRAME_COUNT_OFFSET); - } - - // We have to search for the Xing header as its position can change. - for (; buffer + sizeof(XING_TAG) < bufferEnd; buffer++) { - if (FROM_BIG_ENDIAN(buffer) == XING_TAG) { - return ParseXing(buffer); - } - } - - return -1; -} - - -/** MP3FrameParser methods **/ - -// Some MP3's have large ID3v2 tags, up to 150KB, so we allow lots of -// skipped bytes to be read, just in case, before we give up and assume -// we're not parsing an MP3 stream. -static const uint32_t MAX_SKIPPED_BYTES = 4096; - -enum { - MP3_HEADER_LENGTH = 4, -}; - -MP3FrameParser::MP3FrameParser(int64_t aLength) -: mLock("MP3FrameParser.mLock"), - mTotalID3Size(0), - mTotalFrameSize(0), - mFrameCount(0), - mOffset(0), - mLength(aLength), - mMP3Offset(-1), - mSamplesPerSecond(0), - mFirstFrameEnd(-1), - mIsMP3(MAYBE_MP3) -{ } - -nsresult MP3FrameParser::ParseBuffer(const uint8_t* aBuffer, - uint32_t aLength, - int64_t aStreamOffset, - uint32_t* aOutBytesRead) -{ - // Iterate forwards over the buffer, looking for ID3 tag, or MP3 - // Frame headers. - const uint8_t *buffer = aBuffer; - const uint8_t *bufferEnd = aBuffer + aLength; - - // If we haven't found any MP3 frame data yet, there might be ID3 headers - // we can skip over. - if (mMP3Offset < 0) { - for (const uint8_t *ch = buffer; ch < bufferEnd; ch++) { - if (mID3Parser.ParseChar(*ch)) { - // Found an ID3 header. We don't care about the body of the header, so - // just skip past. - buffer = ch + mID3Parser.GetHeaderLength() - (ID3_HEADER_LENGTH - 1); - - if (buffer <= ch) { - return NS_ERROR_FAILURE; - } - - ch = buffer; - - mTotalID3Size += mID3Parser.GetHeaderLength(); - - // Yes, this is an MP3! - mIsMP3 = DEFINITELY_MP3; - - mID3Parser.Reset(); - } - } - } - - // The first MP3 frame in a variable bitrate stream can contain metadata - // for duration estimation and seeking, so we buffer that first frame here. - if (aStreamOffset < mFirstFrameEnd) { - uint64_t copyLen = std::min((int64_t)aLength, mFirstFrameEnd - aStreamOffset); - mFirstFrame.Append((const char *)buffer, copyLen); - buffer += copyLen; - } - - while (buffer < bufferEnd) { - uint16_t frameLen = mMP3Parser.ParseFrameLength(*buffer); - - if (frameLen) { - // We've found an MP3 frame! - // This is the first frame (and the only one we'll bother parsing), so: - // * Mark this stream as MP3; - // * Store the offset at which the MP3 data started; and - // * Start buffering the frame, as it might contain handy metadata. - - // We're now sure this is an MP3 stream. - mIsMP3 = DEFINITELY_MP3; - - // We need to know these to convert the number of frames in the stream - // to the length of the stream in seconds. - mSamplesPerSecond = mMP3Parser.GetSampleRate(); - mSamplesPerFrame = mMP3Parser.GetSamplesPerFrame(); - - // If the stream has a constant bitrate, we should only need the length - // of the first frame and the length (in bytes) of the stream to - // estimate the length (in seconds). - mTotalFrameSize += frameLen; - mFrameCount++; - - // If |mMP3Offset| isn't set then this is the first MP3 frame we have - // seen in the stream, which is useful for duration estimation. - if (mMP3Offset > -1) { - uint16_t skip = frameLen - sizeof(MP3Frame); - buffer += skip ? skip : 1; - continue; - } - - // Remember the offset of the MP3 stream. - // We're at the last byte of an MP3Frame, so MP3 data started - // sizeof(MP3Frame) - 1 bytes ago. - mMP3Offset = aStreamOffset - + (buffer - aBuffer) - - (sizeof(MP3Frame) - 1); - - buffer++; - - // If the stream has a variable bitrate, the first frame has metadata - // we need for duration estimation and seeking. Start buffering it so we - // can parse it later. - mFirstFrameEnd = mMP3Offset + frameLen; - uint64_t currOffset = buffer - aBuffer + aStreamOffset; - uint64_t copyLen = std::min(mFirstFrameEnd - currOffset, - (uint64_t)(bufferEnd - buffer)); - mFirstFrame.Append((const char *)buffer, copyLen); - - buffer += copyLen; - - } else { - // Nothing to see here. Move along. - buffer++; - } - } - - *aOutBytesRead = buffer - aBuffer; - - if (mFirstFrameEnd > -1 && mFirstFrameEnd <= aStreamOffset + buffer - aBuffer) { - // We have our whole first frame. Try to find a VBR header. - mNumFrames = FindNumVBRFrames(mFirstFrame); - mFirstFrameEnd = -1; - } - - return NS_OK; -} - -void MP3FrameParser::Parse(const uint8_t* aBuffer, uint32_t aLength, uint64_t aOffset) -{ - MutexAutoLock mon(mLock); - - if (HasExactDuration()) { - // We know the duration; nothing to do here. - return; - } - - const uint8_t* buffer = aBuffer; - int32_t length = aLength; - uint64_t offset = aOffset; - - // Got some data we have seen already. Skip forward to what we need. - if (aOffset < mOffset) { - buffer += mOffset - aOffset; - length -= mOffset - aOffset; - offset = mOffset; - - if (length <= 0) { - return; - } - } - - // If there is a discontinuity in the input stream, reset the state of the - // parsers so we don't get any partial headers. - if (mOffset < aOffset) { - if (!mID3Parser.IsParsed()) { - // Only reset this if it hasn't finished yet. - mID3Parser.Reset(); - } - - if (mFirstFrameEnd > -1) { - NS_WARNING("Discontinuity in input while buffering first frame."); - mFirstFrameEnd = -1; - } - - mMP3Parser.Reset(); - } - - uint32_t bytesRead = 0; - if (NS_FAILED(ParseBuffer(buffer, - length, - offset, - &bytesRead))) { - return; - } - - MOZ_ASSERT(length <= (int)bytesRead, "All bytes should have been consumed"); - - // Update next data offset - mOffset = offset + bytesRead; - - // If we've parsed lots of data and we still have nothing, just give up. - // We don't count ID3 headers towards the skipped bytes count, as MP3 files - // can have massive ID3 sections. - if (!mID3Parser.IsParsed() && mMP3Offset < 0 && - mOffset - mTotalID3Size > MAX_SKIPPED_BYTES) { - mIsMP3 = NOT_MP3; - } -} - -int64_t MP3FrameParser::GetDuration() -{ - MutexAutoLock mon(mLock); - - if (!ParsedHeaders() || !mSamplesPerSecond) { - // Not a single frame decoded yet. - return -1; - } - - MOZ_ASSERT(mFrameCount > 0 && mTotalFrameSize > 0, - "Frame parser should have seen at least one MP3 frame of positive length."); - - if (!mFrameCount || !mTotalFrameSize) { - // This should never happen. - return -1; - } - - double frames; - if (mNumFrames < 0) { - // Estimate the number of frames in the stream based on the average frame - // size and the length of the MP3 file. - double frameSize = (double)mTotalFrameSize / mFrameCount; - frames = (double)(mLength - mMP3Offset) / frameSize; - } else { - // We know the exact number of frames from the VBR header. - frames = mNumFrames; - } - - // The duration of each frame is constant over a given stream. - double usPerFrame = USECS_PER_S * mSamplesPerFrame / mSamplesPerSecond; - - return frames * usPerFrame; -} - -int64_t MP3FrameParser::GetMP3Offset() -{ - MutexAutoLock mon(mLock); - return mMP3Offset; -} - -bool MP3FrameParser::ParsedHeaders() -{ - // We have seen both the beginning and the end of the first MP3 frame in the - // stream. - return mMP3Offset > -1 && mFirstFrameEnd < 0; -} - -bool MP3FrameParser::HasExactDuration() -{ - return ParsedHeaders() && mNumFrames > -1; -} - -bool MP3FrameParser::NeedsData() -{ - // If we don't know the duration exactly then either: - // - we're still waiting for a VBR header; or - // - we look at all frames to constantly update our duration estimate. - return IsMP3() && !HasExactDuration(); -} - -} // namespace mozilla diff --git a/dom/media/MP3FrameParser.h b/dom/media/MP3FrameParser.h deleted file mode 100644 index d2ba791fd..000000000 --- a/dom/media/MP3FrameParser.h +++ /dev/null @@ -1,219 +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/. */ - -#ifndef MP3FrameParser_h -#define MP3FrameParser_h - -#include <stdint.h> - -#include "mozilla/Mutex.h" -#include "nsString.h" -#include "Intervals.h" - -namespace mozilla { - -// Simple parser to tell whether we've found an ID3 header and how long it is, -// so that we can skip it. -// XXX maybe actually parse this stuff? -class ID3Parser -{ -public: - ID3Parser(); - - void Reset(); - bool ParseChar(char ch); - bool IsParsed() const; - uint32_t GetHeaderLength() const; - -private: - uint32_t mCurrentChar; - uint8_t mVersion; - uint8_t mFlags; - uint32_t mHeaderLength; -}; - -struct MP3Frame { - uint16_t mSync1 : 8; // Always all set - uint16_t mProtected : 1; // Ignored - uint16_t mLayer : 2; - uint16_t mVersion : 2; - uint16_t mSync2 : 3; // Always all set - uint16_t mPrivate : 1; // Ignored - uint16_t mPad : 1; - uint16_t mSampleRate : 2; // Index into mpeg_srates above - uint16_t mBitrate : 4; // Index into mpeg_bitrates above - - uint16_t CalculateLength(); -}; - -// Buffering parser for MP3 frames. -class MP3Parser -{ -public: - MP3Parser(); - - // Forget all data the parser has seen so far. - void Reset(); - - // Parse the given byte. If we have found a frame header, return the length of - // the frame. - uint16_t ParseFrameLength(uint8_t ch); - - // Get the sample rate from the current header. - uint32_t GetSampleRate(); - - // Get the number of samples per frame. - uint32_t GetSamplesPerFrame(); - -private: - uint32_t mCurrentChar; - union { - uint8_t mRaw[3]; - MP3Frame mFrame; - } mData; -}; - - -// A description of the MP3 format and its extensions is available at -// -// http://www.codeproject.com/Articles/8295/MPEG-Audio-Frame-Header -// -// The data in MP3 streams is split into small frames, with each frame -// containing a fixed number of samples. The duration of a frame depends -// on the frame's bit rate and sample rate. Both values can vary among -// frames, so it is necessary to examine each individual frame of an MP3 -// stream to calculate the stream's overall duration. -// -// The MP3 frame parser extracts information from an MP3 data stream. It -// accepts a range of frames of an MP3 stream as input, and parses all -// frames for their duration. Callers can query the stream's overall -// duration from the parser. -// -// Call the methods NotifyDataArrived or Parse to add new data. If you added -// information for a certain stream position, you cannot go back to previous -// positions. The parser will simply ignore the input. If you skip stream -// positions, the duration of the related MP3 frames will be estimated from -// the stream's average. -// -// The method GetDuration returns calculated duration of the stream, including -// estimates for skipped ranges. -// -// All public methods are thread-safe. - -class MP3FrameParser -{ -public: - explicit MP3FrameParser(int64_t aLength=-1); - - bool IsMP3() { - MutexAutoLock mon(mLock); - return mIsMP3 != NOT_MP3; - } - - void Parse(const uint8_t* aBuffer, uint32_t aLength, uint64_t aStreamOffset); - - // Returns the duration, in microseconds. If the entire stream has not - // been parsed yet, this is an estimate based on the bitrate of the - // frames parsed so far. - int64_t GetDuration(); - - // Returns the offset of the first MP3 frame in the stream, or -1 of - // no MP3 frame has been detected yet. - int64_t GetMP3Offset(); - - // Returns true if we've seen the whole first frame of the MP3 stream, and - // therefore can make an estimate on the stream duration. - // Otherwise, returns false. - bool ParsedHeaders(); - - // Returns true if we know the exact duration of the MP3 stream; - // false otherwise. - bool HasExactDuration(); - - // Returns true if the parser needs more data for duration estimation. - bool NeedsData(); - // Assign the total lenght of this mp3 stream - void SetLength(int64_t aLength) { - MutexAutoLock mon(mLock); - mLength = aLength; - } -private: - - // Parses aBuffer, starting at offset 0. Returns the number of bytes - // parsed, relative to the start of the buffer. Note this may be - // greater than aLength if the headers in the buffer indicate that - // the frame or ID3 tag extends outside of aBuffer. Returns failure - // if too many non-MP3 bytes are parsed. - nsresult ParseBuffer(const uint8_t* aBuffer, - uint32_t aLength, - int64_t aStreamOffset, - uint32_t* aOutBytesRead); - - // A low-contention lock for protecting the parser results - Mutex mLock; - - // ID3 header parser. Keeps state between reads in case the header falls - // in between. - ID3Parser mID3Parser; - - // MP3 frame header parser. - MP3Parser mMP3Parser; - - // If we read |MAX_SKIPPED_BYTES| from the stream without finding any MP3 - // frames, we give up and report |NOT_MP3|. Here we track the cumulative size - // of any ID3 headers we've seen so big ID3 sections aren't counted towards - // skipped bytes. - uint32_t mTotalID3Size; - - // All fields below are protected by mLock - - // We keep stats on the size of all the frames we've seen, as well as how many - // so that we can estimate the duration of the rest of the stream. - uint64_t mTotalFrameSize; - uint64_t mFrameCount; - - // Offset of the last data parsed. This is the end offset of the last data - // block parsed, so it's the start offset we expect to get on the next - // call to Parse(). - uint64_t mOffset; - - // Total length of the stream in bytes. - int64_t mLength; - - // Offset of first MP3 frame in the bitstream. Has value -1 until the - // first MP3 frame is found. - int64_t mMP3Offset; - - // The exact number of frames in this stream, if we know it. -1 otherwise. - int64_t mNumFrames; - - // Number of audio samples per second and per frame. Fixed through the whole - // file. If we know these variables as well as the number of frames in the - // file, we can get an exact duration for the stream. - uint16_t mSamplesPerSecond; - uint16_t mSamplesPerFrame; - - // If the MP3 has a variable bitrate, then there *should* be metadata about - // the encoding in the first frame. We buffer the first frame here. - nsCString mFirstFrame; - - // While we are reading the first frame, this is the stream offset of the - // last byte of that frame. -1 at all other times. - int64_t mFirstFrameEnd; - - enum eIsMP3 { - MAYBE_MP3, // We're giving the stream the benefit of the doubt... - DEFINITELY_MP3, // We've hit at least one ID3 tag or MP3 frame. - NOT_MP3 // Not found any evidence of the stream being MP3. - }; - - eIsMP3 mIsMP3; - -}; - -} // namespace mozilla - -#endif diff --git a/dom/media/WebVTTListener.h b/dom/media/WebVTTListener.h index 67271664a..461d7f00d 100644 --- a/dom/media/WebVTTListener.h +++ b/dom/media/WebVTTListener.h @@ -10,6 +10,7 @@ #include "nsIStreamListener.h" #include "nsIChannelEventSink.h" #include "nsIInterfaceRequestor.h" +#include "nsCOMPtr.h" #include "nsCycleCollectionParticipant.h" class nsIWebVTTParserWrapper; diff --git a/dom/media/gtest/TestMP3Demuxer.cpp b/dom/media/gtest/TestMP3Demuxer.cpp index 8d2109f00..934acb60e 100644 --- a/dom/media/gtest/TestMP3Demuxer.cpp +++ b/dom/media/gtest/TestMP3Demuxer.cpp @@ -11,7 +11,6 @@ #include "MockMediaResource.h" using namespace mozilla; -using namespace mozilla::mp3; using media::TimeUnit; diff --git a/dom/media/moz.build b/dom/media/moz.build index b3db05af1..6d2c71f2d 100644 --- a/dom/media/moz.build +++ b/dom/media/moz.build @@ -30,6 +30,7 @@ DIRS += [ 'ipc', 'mediasink', 'mediasource', + 'mp3', 'ogg', 'platforms', 'systemservices', @@ -125,9 +126,6 @@ EXPORTS += [ 'MediaTimer.h', 'MediaTrack.h', 'MediaTrackList.h', - 'MP3Decoder.h', - 'MP3Demuxer.h', - 'MP3FrameParser.h', 'NextFrameSeekTask.h', 'nsIDocumentActivity.h', 'PrincipalChangeObserver.h', @@ -234,9 +232,6 @@ UNIFIED_SOURCES += [ 'MediaTimer.cpp', 'MediaTrack.cpp', 'MediaTrackList.cpp', - 'MP3Decoder.cpp', - 'MP3Demuxer.cpp', - 'MP3FrameParser.cpp', 'NextFrameSeekTask.cpp', 'QueueObject.cpp', 'SeekJob.cpp', diff --git a/dom/media/MP3Decoder.cpp b/dom/media/mp3/MP3Decoder.cpp index b71111e79..074a0866d 100644 --- a/dom/media/MP3Decoder.cpp +++ b/dom/media/mp3/MP3Decoder.cpp @@ -24,7 +24,7 @@ MP3Decoder::Clone(MediaDecoderOwner* aOwner) { MediaDecoderStateMachine* MP3Decoder::CreateStateMachine() { RefPtr<MediaDecoderReader> reader = - new MediaFormatReader(this, new mp3::MP3Demuxer(GetResource())); + new MediaFormatReader(this, new MP3Demuxer(GetResource())); return new MediaDecoderStateMachine(this, reader); } diff --git a/dom/media/MP3Decoder.h b/dom/media/mp3/MP3Decoder.h index 887251065..887251065 100644 --- a/dom/media/MP3Decoder.h +++ b/dom/media/mp3/MP3Decoder.h diff --git a/dom/media/MP3Demuxer.cpp b/dom/media/mp3/MP3Demuxer.cpp index 7d478a41b..5a98cabfe 100644 --- a/dom/media/MP3Demuxer.cpp +++ b/dom/media/mp3/MP3Demuxer.cpp @@ -33,7 +33,6 @@ using mozilla::media::TimeIntervals; using mp4_demuxer::ByteReader; namespace mozilla { -namespace mp3 { // MP3Demuxer @@ -1338,5 +1337,4 @@ ID3Parser::ID3Header::Update(uint8_t c) { return IsValid(mPos++); } -} // namespace mp3 } // namespace mozilla diff --git a/dom/media/MP3Demuxer.h b/dom/media/mp3/MP3Demuxer.h index 03e67b0d9..5331c4d54 100644 --- a/dom/media/MP3Demuxer.h +++ b/dom/media/mp3/MP3Demuxer.h @@ -13,7 +13,6 @@ #include <vector> namespace mozilla { -namespace mp3 { class MP3TrackDemuxer; @@ -468,7 +467,6 @@ private: UniquePtr<AudioInfo> mInfo; }; -} // namespace mp3 } // namespace mozilla #endif diff --git a/dom/media/mp3/moz.build b/dom/media/mp3/moz.build new file mode 100644 index 000000000..596d061f8 --- /dev/null +++ b/dom/media/mp3/moz.build @@ -0,0 +1,17 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +EXPORTS += [ + 'MP3Decoder.h', + 'MP3Demuxer.h', +] + +UNIFIED_SOURCES += [ + 'MP3Decoder.cpp', + 'MP3Demuxer.cpp', +] + +FINAL_LIBRARY = 'xul' |