Adts.cpp (10305B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "Adts.h" 6 7 #include "ADTSDemuxer.h" 8 #include "BitWriter.h" 9 #include "MediaData.h" 10 #include "MediaDataDemuxer.h" 11 #include "PlatformDecoderModule.h" 12 #include "mozilla/Array.h" 13 #include "mozilla/Logging.h" 14 15 #define LOG(msg, ...) \ 16 MOZ_LOG(gMediaDemuxerLog, LogLevel::Debug, msg, ##__VA_ARGS__) 17 #define ADTSLOG(msg, ...) \ 18 DDMOZ_LOG(gMediaDemuxerLog, LogLevel::Debug, msg, ##__VA_ARGS__) 19 #define ADTSLOGV(msg, ...) \ 20 DDMOZ_LOG(gMediaDemuxerLog, LogLevel::Verbose, msg, ##__VA_ARGS__) 21 22 namespace mozilla { 23 namespace ADTS { 24 25 static const int kADTSHeaderSize = 7; 26 27 constexpr std::array FREQ_LOOKUP{96000, 88200, 64000, 48000, 44100, 28 32000, 24000, 22050, 16000, 12000, 29 11025, 8000, 7350, 0}; 30 31 Result<uint8_t, bool> GetFrequencyIndex(uint32_t aSamplesPerSecond) { 32 auto found = 33 std::find(FREQ_LOOKUP.begin(), FREQ_LOOKUP.end(), aSamplesPerSecond); 34 35 if (found == FREQ_LOOKUP.end()) { 36 return Err(false); 37 } 38 39 return std::distance(FREQ_LOOKUP.begin(), found); 40 } 41 42 bool ConvertSample(uint16_t aChannelCount, uint8_t aFrequencyIndex, 43 uint8_t aProfile, MediaRawData* aSample) { 44 size_t newSize = aSample->Size() + kADTSHeaderSize; 45 46 MOZ_LOG(sPDMLog, LogLevel::Debug, 47 ("Converting sample to ADTS format: newSize: %zu, ch: %u, " 48 "profile: %u, freq index: %d", 49 newSize, aChannelCount, aProfile, aFrequencyIndex)); 50 51 // ADTS header uses 13 bits for packet size. 52 if (newSize >= (1 << 13) || aChannelCount > 15 || aProfile < 1 || 53 aProfile > 4 || aFrequencyIndex >= FREQ_LOOKUP.size()) { 54 MOZ_LOG(sPDMLog, LogLevel::Debug, 55 ("Couldn't convert sample to ADTS format: newSize: %zu, ch: %u, " 56 "profile: %u, freq index: %d", 57 newSize, aChannelCount, aProfile, aFrequencyIndex)); 58 return false; 59 } 60 61 Array<uint8_t, kADTSHeaderSize> header; 62 header[0] = 0xff; 63 header[1] = 0xf1; 64 header[2] = 65 ((aProfile - 1) << 6) + (aFrequencyIndex << 2) + (aChannelCount >> 2); 66 header[3] = ((aChannelCount & 0x3) << 6) + (newSize >> 11); 67 header[4] = (newSize & 0x7ff) >> 3; 68 header[5] = ((newSize & 7) << 5) + 0x1f; 69 header[6] = 0xfc; 70 71 UniquePtr<MediaRawDataWriter> writer(aSample->CreateWriter()); 72 if (!writer->Prepend(&header[0], std::size(header))) { 73 return false; 74 } 75 76 if (aSample->mCrypto.IsEncrypted()) { 77 if (aSample->mCrypto.mPlainSizes.Length() == 0) { 78 writer->mCrypto.mPlainSizes.AppendElement(kADTSHeaderSize); 79 writer->mCrypto.mEncryptedSizes.AppendElement(aSample->Size() - 80 kADTSHeaderSize); 81 } else { 82 writer->mCrypto.mPlainSizes[0] += kADTSHeaderSize; 83 } 84 } 85 86 return true; 87 } 88 89 bool StripHeader(MediaRawData* aSample) { 90 if (aSample->Size() < kADTSHeaderSize) { 91 return false; 92 } 93 94 FrameHeader header; 95 auto data = Span{aSample->Data(), aSample->Size()}; 96 MOZ_ASSERT(FrameHeader::MatchesSync(data), 97 "Don't attempt to strip the ADTS header of a raw AAC packet."); 98 99 bool crcPresent = header.mHaveCrc; 100 101 LOG(("Stripping ADTS, crc %spresent", crcPresent ? "" : "not ")); 102 103 size_t toStrip = crcPresent ? kADTSHeaderSize + 2 : kADTSHeaderSize; 104 105 UniquePtr<MediaRawDataWriter> writer(aSample->CreateWriter()); 106 writer->PopFront(toStrip); 107 108 if (aSample->mCrypto.IsEncrypted()) { 109 if (aSample->mCrypto.mPlainSizes.Length() > 0 && 110 writer->mCrypto.mPlainSizes[0] >= kADTSHeaderSize) { 111 writer->mCrypto.mPlainSizes[0] -= kADTSHeaderSize; 112 } 113 } 114 115 return true; 116 } 117 118 bool RevertSample(MediaRawData* aSample) { 119 if (aSample->Size() < kADTSHeaderSize) { 120 return false; 121 } 122 123 { 124 const uint8_t* header = aSample->Data(); 125 if (header[0] != 0xff || header[1] != 0xf1 || header[6] != 0xfc) { 126 // Not ADTS. 127 return false; 128 } 129 } 130 131 UniquePtr<MediaRawDataWriter> writer(aSample->CreateWriter()); 132 writer->PopFront(kADTSHeaderSize); 133 134 if (aSample->mCrypto.IsEncrypted()) { 135 if (aSample->mCrypto.mPlainSizes.Length() > 0 && 136 writer->mCrypto.mPlainSizes[0] >= kADTSHeaderSize) { 137 writer->mCrypto.mPlainSizes[0] -= kADTSHeaderSize; 138 } 139 } 140 141 return true; 142 } 143 144 bool FrameHeader::MatchesSync(const Span<const uint8_t>& aData) { 145 return aData.Length() >= 2 && aData[0] == 0xFF && (aData[1] & 0xF6) == 0xF0; 146 } 147 148 FrameHeader::FrameHeader() { Reset(); } 149 150 // Header size 151 uint64_t FrameHeader::HeaderSize() const { return (mHaveCrc) ? 9 : 7; } 152 153 bool FrameHeader::IsValid() const { return mFrameLength > 0; } 154 155 // Resets the state to allow for a new parsing session. 156 void FrameHeader::Reset() { PodZero(this); } 157 158 // Returns whether the byte creates a valid sequence up to this point. 159 bool FrameHeader::Parse(const Span<const uint8_t>& aData) { 160 if (!MatchesSync(aData)) { 161 return false; 162 } 163 164 // AAC has 1024 samples per frame per channel. 165 mSamples = 1024; 166 167 mHaveCrc = !(aData[1] & 0x01); 168 mObjectType = ((aData[2] & 0xC0) >> 6) + 1; 169 mSamplingIndex = (aData[2] & 0x3C) >> 2; 170 mChannelConfig = (aData[2] & 0x01) << 2 | (aData[3] & 0xC0) >> 6; 171 mFrameLength = 172 static_cast<uint32_t>((aData[3] & 0x03) << 11 | (aData[4] & 0xFF) << 3 | 173 (aData[5] & 0xE0) >> 5); 174 mNumAACFrames = (aData[6] & 0x03) + 1; 175 176 static const uint32_t SAMPLE_RATES[] = {96000, 88200, 64000, 48000, 44100, 177 32000, 24000, 22050, 16000, 12000, 178 11025, 8000, 7350}; 179 if (mSamplingIndex >= std::size(SAMPLE_RATES)) { 180 LOG(("ADTS: Init() failure: invalid sample-rate index value: %" PRIu32 ".", 181 mSamplingIndex)); 182 // This marks the header as invalid. 183 mFrameLength = 0; 184 return false; 185 } 186 mSampleRate = SAMPLE_RATES[mSamplingIndex]; 187 188 MOZ_ASSERT(mChannelConfig < 8); 189 mChannels = (mChannelConfig == 7) ? 8 : mChannelConfig; 190 191 return true; 192 } 193 194 Frame::Frame() : mOffset(0), mHeader() {} 195 uint64_t Frame::Offset() const { return mOffset; } 196 size_t Frame::Length() const { 197 // TODO: If fields are zero'd when invalid, this check wouldn't be 198 // necessary. 199 if (!mHeader.IsValid()) { 200 return 0; 201 } 202 203 return mHeader.mFrameLength; 204 } 205 206 // Returns the offset to the start of frame's raw data. 207 uint64_t Frame::PayloadOffset() const { return mOffset + mHeader.HeaderSize(); } 208 209 // Returns the length of the frame's raw data (excluding the header) in bytes. 210 size_t Frame::PayloadLength() const { 211 // TODO: If fields are zero'd when invalid, this check wouldn't be 212 // necessary. 213 if (!mHeader.IsValid()) { 214 return 0; 215 } 216 217 return mHeader.mFrameLength - mHeader.HeaderSize(); 218 } 219 220 // Returns the parsed frame header. 221 const FrameHeader& Frame::Header() const { return mHeader; } 222 223 bool Frame::IsValid() const { return mHeader.IsValid(); } 224 225 // Resets the frame header and data. 226 void Frame::Reset() { 227 mHeader.Reset(); 228 mOffset = 0; 229 } 230 231 // Returns whether the valid 232 bool Frame::Parse(uint64_t aOffset, const uint8_t* aStart, 233 const uint8_t* aEnd) { 234 MOZ_ASSERT(aStart && aEnd && aStart <= aEnd); 235 236 bool found = false; 237 const uint8_t* ptr = aStart; 238 // Require at least 7 bytes of data at the end of the buffer for the minimum 239 // ADTS frame header. 240 while (ptr < aEnd - 7 && !found) { 241 found = mHeader.Parse(Span(ptr, aEnd)); 242 ptr++; 243 } 244 245 mOffset = aOffset + (static_cast<size_t>(ptr - aStart)) - 1u; 246 247 return found; 248 } 249 250 const Frame& FrameParser::CurrentFrame() { return mFrame; } 251 252 const Frame& FrameParser::FirstFrame() const { return mFirstFrame; } 253 254 void FrameParser::Reset() { 255 EndFrameSession(); 256 mFirstFrame.Reset(); 257 } 258 259 void FrameParser::EndFrameSession() { mFrame.Reset(); } 260 261 bool FrameParser::Parse(uint64_t aOffset, const uint8_t* aStart, 262 const uint8_t* aEnd) { 263 const bool found = mFrame.Parse(aOffset, aStart, aEnd); 264 265 if (mFrame.Length() && !mFirstFrame.Length()) { 266 mFirstFrame = mFrame; 267 } 268 269 return found; 270 } 271 272 // Initialize the AAC AudioSpecificConfig. 273 // Only handles two-byte version for AAC-LC. 274 void InitAudioSpecificConfig(const ADTS::Frame& frame, 275 MediaByteBuffer* aBuffer) { 276 const ADTS::FrameHeader& header = frame.Header(); 277 MOZ_ASSERT(header.IsValid()); 278 279 int audioObjectType = header.mObjectType; 280 int samplingFrequencyIndex = header.mSamplingIndex; 281 int channelConfig = header.mChannelConfig; 282 283 uint8_t asc[2]; 284 asc[0] = (audioObjectType & 0x1F) << 3 | (samplingFrequencyIndex & 0x0E) >> 1; 285 asc[1] = (samplingFrequencyIndex & 0x01) << 7 | (channelConfig & 0x0F) << 3; 286 287 aBuffer->AppendElements(asc, 2); 288 } 289 290 // https://wiki.multimedia.cx/index.php/MPEG-4_Audio#Audio_Specific_Config 291 Result<already_AddRefed<MediaByteBuffer>, nsresult> MakeSpecificConfig( 292 uint8_t aObjectType, uint32_t aFrequency, uint32_t aChannelCount) { 293 if (aObjectType > 45 /* USAC */ || aObjectType == 0x1F /* Escape value */) { 294 return Err(NS_ERROR_INVALID_ARG); 295 } 296 297 if (aFrequency > 0x00FFFFFF /* max value of 24 bits */) { 298 return Err(NS_ERROR_INVALID_ARG); 299 } 300 301 if (aChannelCount > 8 || aChannelCount == 7) { 302 return Err(NS_ERROR_INVALID_ARG); 303 } 304 305 uint8_t index = GetFrequencyIndex(aFrequency) 306 .unwrapOr(0x0F /* frequency is written explictly */); 307 MOZ_ASSERT(index <= 0x0F /* index needs only 4 bits */); 308 309 uint8_t channelConfig = 310 aChannelCount == 8 ? aChannelCount - 1 : aChannelCount; 311 312 RefPtr<MediaByteBuffer> buffer = new MediaByteBuffer(); 313 BitWriter bw(buffer); 314 315 if (aObjectType < 0x1F /* Escape value */) { 316 bw.WriteBits(aObjectType, 5); 317 } else { // If object type needs more than 5 bits 318 MOZ_ASSERT(aObjectType >= 32); 319 bw.WriteBits(0x1F, 5); 320 // Since aObjectType < 0x3F + 32, it's safe to put it into 6 bits. 321 bw.WriteBits(aObjectType - 32, 6); 322 } 323 324 bw.WriteBits(index, 4); 325 if (index == 0x0F /* frequency is written explictly */) { 326 bw.WriteBits(aFrequency, 24); 327 } 328 329 bw.WriteBits(channelConfig, 4); 330 331 // Skip extension configuration for now. 332 333 return buffer.forget(); 334 } 335 336 }; // namespace ADTS 337 }; // namespace mozilla 338 339 #undef LOG 340 #undef ADTSLOG 341 #undef ADTSLOGV