1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.google.android.exoplayer2.audio; 17 18 import androidx.annotation.Nullable; 19 import com.google.android.exoplayer2.C; 20 import com.google.android.exoplayer2.Format; 21 import com.google.android.exoplayer2.drm.DrmInitData; 22 import com.google.android.exoplayer2.util.MimeTypes; 23 import com.google.android.exoplayer2.util.ParsableBitArray; 24 import com.google.android.exoplayer2.util.ParsableByteArray; 25 import java.nio.ByteBuffer; 26 27 /** Utility methods for parsing AC-4 frames, which are access units in AC-4 bitstreams. */ 28 public final class Ac4Util { 29 30 /** Holds sample format information as presented by a syncframe header. */ 31 public static final class SyncFrameInfo { 32 33 /** The bitstream version. */ 34 public final int bitstreamVersion; 35 /** The audio sampling rate in Hz. */ 36 public final int sampleRate; 37 /** The number of audio channels */ 38 public final int channelCount; 39 /** The size of the frame. */ 40 public final int frameSize; 41 /** Number of audio samples in the frame. */ 42 public final int sampleCount; 43 SyncFrameInfo( int bitstreamVersion, int channelCount, int sampleRate, int frameSize, int sampleCount)44 private SyncFrameInfo( 45 int bitstreamVersion, int channelCount, int sampleRate, int frameSize, int sampleCount) { 46 this.bitstreamVersion = bitstreamVersion; 47 this.channelCount = channelCount; 48 this.sampleRate = sampleRate; 49 this.frameSize = frameSize; 50 this.sampleCount = sampleCount; 51 } 52 } 53 54 public static final int AC40_SYNCWORD = 0xAC40; 55 public static final int AC41_SYNCWORD = 0xAC41; 56 57 /** Maximum rate for an AC-4 audio stream, in bytes per second. */ 58 public static final int MAX_RATE_BYTES_PER_SECOND = 2688 * 1000 / 8; 59 60 /** The channel count of AC-4 stream. */ 61 // TODO: Parse AC-4 stream channel count. 62 private static final int CHANNEL_COUNT_2 = 2; 63 /** 64 * The AC-4 sync frame header size for extractor. The seven bytes are 0xAC, 0x40, 0xFF, 0xFF, 65 * sizeByte1, sizeByte2, sizeByte3. See ETSI TS 103 190-1 V1.3.1, Annex G 66 */ 67 public static final int SAMPLE_HEADER_SIZE = 7; 68 /** 69 * The header size for AC-4 parser. Only needs to be as big as we need to read, not the full 70 * header size. 71 */ 72 public static final int HEADER_SIZE_FOR_PARSER = 16; 73 /** 74 * Number of audio samples in the frame. Defined in IEC61937-14:2017 table 5 and 6. This table 75 * provides the number of samples per frame at the playback sampling frequency of 48 kHz. For 44.1 76 * kHz, only frame_rate_index(13) is valid and corresponding sample count is 2048. 77 */ 78 private static final int[] SAMPLE_COUNT = 79 new int[] { 80 /* [ 0] 23.976 fps */ 2002, 81 /* [ 1] 24 fps */ 2000, 82 /* [ 2] 25 fps */ 1920, 83 /* [ 3] 29.97 fps */ 1601, // 1601 | 1602 | 1601 | 1602 | 1602 84 /* [ 4] 30 fps */ 1600, 85 /* [ 5] 47.95 fps */ 1001, 86 /* [ 6] 48 fps */ 1000, 87 /* [ 7] 50 fps */ 960, 88 /* [ 8] 59.94 fps */ 800, // 800 | 801 | 801 | 801 | 801 89 /* [ 9] 60 fps */ 800, 90 /* [10] 100 fps */ 480, 91 /* [11] 119.88 fps */ 400, // 400 | 400 | 401 | 400 | 401 92 /* [12] 120 fps */ 400, 93 /* [13] 23.438 fps */ 2048 94 }; 95 96 /** 97 * Returns the AC-4 format given {@code data} containing the AC4SpecificBox according to ETSI TS 98 * 103 190-1 Annex E. The reading position of {@code data} will be modified. 99 * 100 * @param data The AC4SpecificBox to parse. 101 * @param trackId The track identifier to set on the format. 102 * @param language The language to set on the format. 103 * @param drmInitData {@link DrmInitData} to be included in the format. 104 * @return The AC-4 format parsed from data in the header. 105 */ parseAc4AnnexEFormat( ParsableByteArray data, String trackId, String language, @Nullable DrmInitData drmInitData)106 public static Format parseAc4AnnexEFormat( 107 ParsableByteArray data, String trackId, String language, @Nullable DrmInitData drmInitData) { 108 data.skipBytes(1); // ac4_dsi_version, bitstream_version[0:5] 109 int sampleRate = ((data.readUnsignedByte() & 0x20) >> 5 == 1) ? 48000 : 44100; 110 return new Format.Builder() 111 .setId(trackId) 112 .setSampleMimeType(MimeTypes.AUDIO_AC4) 113 .setChannelCount(CHANNEL_COUNT_2) 114 .setSampleRate(sampleRate) 115 .setDrmInitData(drmInitData) 116 .setLanguage(language) 117 .build(); 118 } 119 120 /** 121 * Returns AC-4 format information given {@code data} containing a syncframe. The reading position 122 * of {@code data} will be modified. 123 * 124 * @param data The data to parse, positioned at the start of the syncframe. 125 * @return The AC-4 format data parsed from the header. 126 */ parseAc4SyncframeInfo(ParsableBitArray data)127 public static SyncFrameInfo parseAc4SyncframeInfo(ParsableBitArray data) { 128 int headerSize = 0; 129 int syncWord = data.readBits(16); 130 headerSize += 2; 131 int frameSize = data.readBits(16); 132 headerSize += 2; 133 if (frameSize == 0xFFFF) { 134 frameSize = data.readBits(24); 135 headerSize += 3; // Extended frame_size 136 } 137 frameSize += headerSize; 138 if (syncWord == AC41_SYNCWORD) { 139 frameSize += 2; // crc_word 140 } 141 int bitstreamVersion = data.readBits(2); 142 if (bitstreamVersion == 3) { 143 bitstreamVersion += readVariableBits(data, /* bitsPerRead= */ 2); 144 } 145 int sequenceCounter = data.readBits(10); 146 if (data.readBit()) { // b_wait_frames 147 if (data.readBits(3) > 0) { // wait_frames 148 data.skipBits(2); // reserved 149 } 150 } 151 int sampleRate = data.readBit() ? 48000 : 44100; 152 int frameRateIndex = data.readBits(4); 153 int sampleCount = 0; 154 if (sampleRate == 44100 && frameRateIndex == 13) { 155 sampleCount = SAMPLE_COUNT[frameRateIndex]; 156 } else if (sampleRate == 48000 && frameRateIndex < SAMPLE_COUNT.length) { 157 sampleCount = SAMPLE_COUNT[frameRateIndex]; 158 switch (sequenceCounter % 5) { 159 case 1: // fall through 160 case 3: 161 if (frameRateIndex == 3 || frameRateIndex == 8) { 162 sampleCount++; 163 } 164 break; 165 case 2: 166 if (frameRateIndex == 8 || frameRateIndex == 11) { 167 sampleCount++; 168 } 169 break; 170 case 4: 171 if (frameRateIndex == 3 || frameRateIndex == 8 || frameRateIndex == 11) { 172 sampleCount++; 173 } 174 break; 175 default: 176 break; 177 } 178 } 179 return new SyncFrameInfo(bitstreamVersion, CHANNEL_COUNT_2, sampleRate, frameSize, sampleCount); 180 } 181 182 /** 183 * Returns the size in bytes of the given AC-4 syncframe. 184 * 185 * @param data The syncframe to parse. 186 * @param syncword The syncword value for the syncframe. 187 * @return The syncframe size in bytes, or {@link C#LENGTH_UNSET} if the input is invalid. 188 */ parseAc4SyncframeSize(byte[] data, int syncword)189 public static int parseAc4SyncframeSize(byte[] data, int syncword) { 190 if (data.length < 7) { 191 return C.LENGTH_UNSET; 192 } 193 int headerSize = 2; // syncword 194 int frameSize = ((data[2] & 0xFF) << 8) | (data[3] & 0xFF); 195 headerSize += 2; 196 if (frameSize == 0xFFFF) { 197 frameSize = ((data[4] & 0xFF) << 16) | ((data[5] & 0xFF) << 8) | (data[6] & 0xFF); 198 headerSize += 3; 199 } 200 if (syncword == AC41_SYNCWORD) { 201 headerSize += 2; 202 } 203 frameSize += headerSize; 204 return frameSize; 205 } 206 207 /** 208 * Reads the number of audio samples represented by the given AC-4 syncframe. The buffer's 209 * position is not modified. 210 * 211 * @param buffer The {@link ByteBuffer} from which to read the syncframe. 212 * @return The number of audio samples represented by the syncframe. 213 */ parseAc4SyncframeAudioSampleCount(ByteBuffer buffer)214 public static int parseAc4SyncframeAudioSampleCount(ByteBuffer buffer) { 215 byte[] bufferBytes = new byte[HEADER_SIZE_FOR_PARSER]; 216 int position = buffer.position(); 217 buffer.get(bufferBytes); 218 buffer.position(position); 219 return parseAc4SyncframeInfo(new ParsableBitArray(bufferBytes)).sampleCount; 220 } 221 222 /** Populates {@code buffer} with an AC-4 sample header for a sample of the specified size. */ getAc4SampleHeader(int size, ParsableByteArray buffer)223 public static void getAc4SampleHeader(int size, ParsableByteArray buffer) { 224 // See ETSI TS 103 190-1 V1.3.1, Annex G. 225 buffer.reset(SAMPLE_HEADER_SIZE); 226 buffer.data[0] = (byte) 0xAC; 227 buffer.data[1] = 0x40; 228 buffer.data[2] = (byte) 0xFF; 229 buffer.data[3] = (byte) 0xFF; 230 buffer.data[4] = (byte) ((size >> 16) & 0xFF); 231 buffer.data[5] = (byte) ((size >> 8) & 0xFF); 232 buffer.data[6] = (byte) (size & 0xFF); 233 } 234 readVariableBits(ParsableBitArray data, int bitsPerRead)235 private static int readVariableBits(ParsableBitArray data, int bitsPerRead) { 236 int value = 0; 237 while (true) { 238 value += data.readBits(bitsPerRead); 239 if (!data.readBit()) { 240 break; 241 } 242 value++; 243 value <<= bitsPerRead; 244 } 245 return value; 246 } 247 Ac4Util()248 private Ac4Util() {} 249 } 250