content/media/MP3FrameParser.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifndef MP3FrameParser_h
michael@0 8 #define MP3FrameParser_h
michael@0 9
michael@0 10 #include <stdint.h>
michael@0 11
michael@0 12 #include "mozilla/Mutex.h"
michael@0 13 #include "nsString.h"
michael@0 14
michael@0 15 namespace mozilla {
michael@0 16
michael@0 17 // Simple parser to tell whether we've found an ID3 header and how long it is,
michael@0 18 // so that we can skip it.
michael@0 19 // XXX maybe actually parse this stuff?
michael@0 20 class ID3Parser
michael@0 21 {
michael@0 22 public:
michael@0 23 ID3Parser();
michael@0 24
michael@0 25 void Reset();
michael@0 26 bool ParseChar(char ch);
michael@0 27 bool IsParsed() const;
michael@0 28 uint32_t GetHeaderLength() const;
michael@0 29
michael@0 30 private:
michael@0 31 uint32_t mCurrentChar;
michael@0 32 uint32_t mHeaderLength;
michael@0 33 };
michael@0 34
michael@0 35 struct MP3Frame {
michael@0 36 uint16_t mSync1 : 8; // Always all set
michael@0 37 uint16_t mProtected : 1; // Ignored
michael@0 38 uint16_t mLayer : 2;
michael@0 39 uint16_t mVersion : 2;
michael@0 40 uint16_t mSync2 : 3; // Always all set
michael@0 41 uint16_t mPrivate : 1; // Ignored
michael@0 42 uint16_t mPad : 1;
michael@0 43 uint16_t mSampleRate : 2; // Index into mpeg_srates above
michael@0 44 uint16_t mBitrate : 4; // Index into mpeg_bitrates above
michael@0 45
michael@0 46 uint16_t CalculateLength();
michael@0 47 };
michael@0 48
michael@0 49 // Buffering parser for MP3 frames.
michael@0 50 class MP3Parser
michael@0 51 {
michael@0 52 public:
michael@0 53 MP3Parser();
michael@0 54
michael@0 55 // Forget all data the parser has seen so far.
michael@0 56 void Reset();
michael@0 57
michael@0 58 // Parse the given byte. If we have found a frame header, return the length of
michael@0 59 // the frame.
michael@0 60 uint16_t ParseFrameLength(uint8_t ch);
michael@0 61
michael@0 62 // Get the sample rate from the current header.
michael@0 63 uint32_t GetSampleRate();
michael@0 64
michael@0 65 // Get the number of samples per frame.
michael@0 66 uint32_t GetSamplesPerFrame();
michael@0 67
michael@0 68 private:
michael@0 69 uint32_t mCurrentChar;
michael@0 70 union {
michael@0 71 uint8_t mRaw[3];
michael@0 72 MP3Frame mFrame;
michael@0 73 } mData;
michael@0 74 };
michael@0 75
michael@0 76
michael@0 77 // A description of the MP3 format and its extensions is available at
michael@0 78 //
michael@0 79 // http://www.codeproject.com/Articles/8295/MPEG-Audio-Frame-Header
michael@0 80 //
michael@0 81 // The data in MP3 streams is split into small frames, with each frame
michael@0 82 // containing a fixed number of samples. The duration of a frame depends
michael@0 83 // on the frame's bit rate and sample rate. Both values can vary among
michael@0 84 // frames, so it is necessary to examine each individual frame of an MP3
michael@0 85 // stream to calculate the stream's overall duration.
michael@0 86 //
michael@0 87 // The MP3 frame parser extracts information from an MP3 data stream. It
michael@0 88 // accepts a range of frames of an MP3 stream as input, and parses all
michael@0 89 // frames for their duration. Callers can query the stream's overall
michael@0 90 // duration from the parser.
michael@0 91 //
michael@0 92 // Call the methods NotifyDataArrived or Parse to add new data. If you added
michael@0 93 // information for a certain stream position, you cannot go back to previous
michael@0 94 // positions. The parser will simply ignore the input. If you skip stream
michael@0 95 // positions, the duration of the related MP3 frames will be estimated from
michael@0 96 // the stream's average.
michael@0 97 //
michael@0 98 // The method GetDuration returns calculated duration of the stream, including
michael@0 99 // estimates for skipped ranges.
michael@0 100 //
michael@0 101 // All public methods are thread-safe.
michael@0 102
michael@0 103 class MP3FrameParser
michael@0 104 {
michael@0 105 public:
michael@0 106 MP3FrameParser(int64_t aLength=-1);
michael@0 107
michael@0 108 bool IsMP3() {
michael@0 109 MutexAutoLock mon(mLock);
michael@0 110 return mIsMP3 != NOT_MP3;
michael@0 111 }
michael@0 112
michael@0 113 void Parse(const char* aBuffer, uint32_t aLength, uint64_t aStreamOffset);
michael@0 114
michael@0 115 // Returns the duration, in microseconds. If the entire stream has not
michael@0 116 // been parsed yet, this is an estimate based on the bitrate of the
michael@0 117 // frames parsed so far.
michael@0 118 int64_t GetDuration();
michael@0 119
michael@0 120 // Returns the offset of the first MP3 frame in the stream, or -1 of
michael@0 121 // no MP3 frame has been detected yet.
michael@0 122 int64_t GetMP3Offset();
michael@0 123
michael@0 124 // Returns true if we've seen the whole first frame of the MP3 stream, and
michael@0 125 // therefore can make an estimate on the stream duration.
michael@0 126 // Otherwise, returns false.
michael@0 127 bool ParsedHeaders();
michael@0 128
michael@0 129 // Returns true if we know the exact duration of the MP3 stream;
michael@0 130 // false otherwise.
michael@0 131 bool HasExactDuration();
michael@0 132
michael@0 133 // Returns true if the parser needs more data for duration estimation.
michael@0 134 bool NeedsData();
michael@0 135
michael@0 136 private:
michael@0 137
michael@0 138 // Parses aBuffer, starting at offset 0. Returns the number of bytes
michael@0 139 // parsed, relative to the start of the buffer. Note this may be
michael@0 140 // greater than aLength if the headers in the buffer indicate that
michael@0 141 // the frame or ID3 tag extends outside of aBuffer. Returns failure
michael@0 142 // if too many non-MP3 bytes are parsed.
michael@0 143 nsresult ParseBuffer(const uint8_t* aBuffer,
michael@0 144 uint32_t aLength,
michael@0 145 int64_t aStreamOffset,
michael@0 146 uint32_t* aOutBytesRead);
michael@0 147
michael@0 148 // A low-contention lock for protecting the parser results
michael@0 149 Mutex mLock;
michael@0 150
michael@0 151 // ID3 header parser. Keeps state between reads in case the header falls
michael@0 152 // in between.
michael@0 153 ID3Parser mID3Parser;
michael@0 154
michael@0 155 // MP3 frame header parser.
michael@0 156 MP3Parser mMP3Parser;
michael@0 157
michael@0 158 // If we read |MAX_SKIPPED_BYTES| from the stream without finding any MP3
michael@0 159 // frames, we give up and report |NOT_MP3|. Here we track the cumulative size
michael@0 160 // of any ID3 headers we've seen so big ID3 sections aren't counted towards
michael@0 161 // skipped bytes.
michael@0 162 uint32_t mTotalID3Size;
michael@0 163
michael@0 164 // All fields below are protected by mLock
michael@0 165
michael@0 166 // We keep stats on the size of all the frames we've seen, as well as how many
michael@0 167 // so that we can estimate the duration of the rest of the stream.
michael@0 168 uint64_t mTotalFrameSize;
michael@0 169 uint64_t mFrameCount;
michael@0 170
michael@0 171 // Offset of the last data parsed. This is the end offset of the last data
michael@0 172 // block parsed, so it's the start offset we expect to get on the next
michael@0 173 // call to Parse().
michael@0 174 uint64_t mOffset;
michael@0 175
michael@0 176 // Total length of the stream in bytes.
michael@0 177 int64_t mLength;
michael@0 178
michael@0 179 // Offset of first MP3 frame in the bitstream. Has value -1 until the
michael@0 180 // first MP3 frame is found.
michael@0 181 int64_t mMP3Offset;
michael@0 182
michael@0 183 // The exact number of frames in this stream, if we know it. -1 otherwise.
michael@0 184 int64_t mNumFrames;
michael@0 185
michael@0 186 // Number of audio samples per second and per frame. Fixed through the whole
michael@0 187 // file. If we know these variables as well as the number of frames in the
michael@0 188 // file, we can get an exact duration for the stream.
michael@0 189 uint16_t mSamplesPerSecond;
michael@0 190 uint16_t mSamplesPerFrame;
michael@0 191
michael@0 192 // If the MP3 has a variable bitrate, then there *should* be metadata about
michael@0 193 // the encoding in the first frame. We buffer the first frame here.
michael@0 194 nsAutoCString mFirstFrame;
michael@0 195
michael@0 196 // While we are reading the first frame, this is the stream offset of the
michael@0 197 // last byte of that frame. -1 at all other times.
michael@0 198 int64_t mFirstFrameEnd;
michael@0 199
michael@0 200 enum eIsMP3 {
michael@0 201 MAYBE_MP3, // We're giving the stream the benefit of the doubt...
michael@0 202 DEFINITELY_MP3, // We've hit at least one ID3 tag or MP3 frame.
michael@0 203 NOT_MP3 // Not found any evidence of the stream being MP3.
michael@0 204 };
michael@0 205
michael@0 206 eIsMP3 mIsMP3;
michael@0 207
michael@0 208 };
michael@0 209
michael@0 210 }
michael@0 211
michael@0 212 #endif

mercurial