| package com.googlecode.mp4parser.authoring.tracks; |
| |
| import com.coremedia.iso.boxes.*; |
| import com.coremedia.iso.boxes.sampleentry.AudioSampleEntry; |
| import com.googlecode.mp4parser.authoring.AbstractTrack; |
| import com.googlecode.mp4parser.authoring.TrackMetaData; |
| import com.googlecode.mp4parser.boxes.AC3SpecificBox; |
| import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitReaderBuffer; |
| |
| import java.io.InputStream; |
| import java.io.IOException; |
| import java.nio.ByteBuffer; |
| import java.util.Date; |
| import java.util.LinkedList; |
| import java.util.List; |
| |
| public class AC3TrackImpl extends AbstractTrack { |
| TrackMetaData trackMetaData = new TrackMetaData(); |
| SampleDescriptionBox sampleDescriptionBox; |
| |
| int samplerate; |
| int bitrate; |
| int channelCount; |
| |
| int fscod; |
| int bsid; |
| int bsmod; |
| int acmod; |
| int lfeon; |
| int frmsizecod; |
| |
| int frameSize; |
| int[][][][] bitRateAndFrameSizeTable; |
| |
| private InputStream inputStream; |
| private List<ByteBuffer> samples; |
| boolean readSamples = false; |
| List<TimeToSampleBox.Entry> stts; |
| private String lang = "und"; |
| |
| public AC3TrackImpl(InputStream fin, String lang) throws IOException { |
| this.lang = lang; |
| parse(fin); |
| } |
| |
| public AC3TrackImpl(InputStream fin) throws IOException { |
| parse(fin); |
| } |
| |
| private void parse(InputStream fin) throws IOException { |
| inputStream = fin; |
| bitRateAndFrameSizeTable = new int[19][2][3][2]; |
| stts = new LinkedList<TimeToSampleBox.Entry>(); |
| initBitRateAndFrameSizeTable(); |
| if (!readVariables()) { |
| throw new IOException(); |
| } |
| |
| sampleDescriptionBox = new SampleDescriptionBox(); |
| AudioSampleEntry audioSampleEntry = new AudioSampleEntry("ac-3"); |
| audioSampleEntry.setChannelCount(2); // According to ETSI TS 102 366 Annex F |
| audioSampleEntry.setSampleRate(samplerate); |
| audioSampleEntry.setDataReferenceIndex(1); |
| audioSampleEntry.setSampleSize(16); |
| |
| AC3SpecificBox ac3 = new AC3SpecificBox(); |
| ac3.setAcmod(acmod); |
| ac3.setBitRateCode(frmsizecod >> 1); |
| ac3.setBsid(bsid); |
| ac3.setBsmod(bsmod); |
| ac3.setFscod(fscod); |
| ac3.setLfeon(lfeon); |
| ac3.setReserved(0); |
| |
| audioSampleEntry.addBox(ac3); |
| sampleDescriptionBox.addBox(audioSampleEntry); |
| |
| trackMetaData.setCreationTime(new Date()); |
| trackMetaData.setModificationTime(new Date()); |
| trackMetaData.setLanguage(lang); |
| trackMetaData.setTimescale(samplerate); // Audio tracks always use samplerate as timescale |
| |
| samples = new LinkedList<ByteBuffer>(); |
| if (!readSamples()) { |
| throw new IOException(); |
| } |
| } |
| |
| |
| public List<ByteBuffer> getSamples() { |
| |
| return samples; |
| } |
| |
| public SampleDescriptionBox getSampleDescriptionBox() { |
| return sampleDescriptionBox; |
| } |
| |
| public List<TimeToSampleBox.Entry> getDecodingTimeEntries() { |
| return stts; |
| } |
| |
| public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() { |
| return null; |
| } |
| |
| public long[] getSyncSamples() { |
| return null; |
| } |
| |
| public List<SampleDependencyTypeBox.Entry> getSampleDependencies() { |
| return null; |
| } |
| |
| public TrackMetaData getTrackMetaData() { |
| return trackMetaData; |
| } |
| |
| public String getHandler() { |
| return "soun"; |
| } |
| |
| public Box getMediaHeaderBox() { |
| return new SoundMediaHeaderBox(); |
| } |
| |
| public SubSampleInformationBox getSubsampleInformationBox() { |
| return null; |
| } |
| |
| private boolean readVariables() throws IOException { |
| byte[] data = new byte[100]; |
| inputStream.mark(100); |
| if (100 != inputStream.read(data, 0, 100)) { |
| return false; |
| } |
| inputStream.reset(); // Rewind |
| ByteBuffer bb = ByteBuffer.wrap(data); |
| BitReaderBuffer brb = new BitReaderBuffer(bb); |
| int syncword = brb.readBits(16); |
| if (syncword != 0xb77) { |
| return false; |
| } |
| brb.readBits(16); // CRC-1 |
| fscod = brb.readBits(2); |
| |
| switch (fscod) { |
| case 0: |
| samplerate = 48000; |
| break; |
| |
| case 1: |
| samplerate = 44100; |
| break; |
| |
| case 2: |
| samplerate = 32000; |
| break; |
| |
| case 3: |
| samplerate = 0; |
| break; |
| |
| } |
| if (samplerate == 0) { |
| return false; |
| } |
| |
| frmsizecod = brb.readBits(6); |
| |
| if (!calcBitrateAndFrameSize(frmsizecod)) { |
| return false; |
| } |
| |
| if (frameSize == 0) { |
| return false; |
| } |
| bsid = brb.readBits(5); |
| bsmod = brb.readBits(3); |
| acmod = brb.readBits(3); |
| |
| if (bsid == 9) { |
| samplerate /= 2; |
| } else if (bsid != 8 && bsid != 6) { |
| return false; |
| } |
| |
| if ((acmod != 1) && ((acmod & 1) == 1)) { |
| brb.readBits(2); |
| } |
| |
| if (0 != (acmod & 4)) { |
| brb.readBits(2); |
| } |
| |
| if (acmod == 2) { |
| brb.readBits(2); |
| } |
| |
| switch (acmod) { |
| case 0: |
| channelCount = 2; |
| break; |
| |
| case 1: |
| channelCount = 1; |
| break; |
| |
| case 2: |
| channelCount = 2; |
| break; |
| |
| case 3: |
| channelCount = 3; |
| break; |
| |
| case 4: |
| channelCount = 3; |
| break; |
| |
| case 5: |
| channelCount = 4; |
| break; |
| |
| case 6: |
| channelCount = 4; |
| break; |
| |
| case 7: |
| channelCount = 5; |
| break; |
| |
| } |
| |
| lfeon = brb.readBits(1); |
| |
| if (lfeon == 1) { |
| channelCount++; |
| } |
| return true; |
| } |
| |
| private boolean calcBitrateAndFrameSize(int code) { |
| int frmsizecode = code >>> 1; |
| int flag = code & 1; |
| if (frmsizecode > 18 || flag > 1 || fscod > 2) { |
| return false; |
| } |
| bitrate = bitRateAndFrameSizeTable[frmsizecode][flag][fscod][0]; |
| frameSize = 2 * bitRateAndFrameSizeTable[frmsizecode][flag][fscod][1]; |
| return true; |
| } |
| |
| private boolean readSamples() throws IOException { |
| if (readSamples) { |
| return true; |
| } |
| readSamples = true; |
| byte[] header = new byte[5]; |
| boolean ret = false; |
| inputStream.mark(5); |
| while (-1 != inputStream.read(header)) { |
| ret = true; |
| int frmsizecode = header[4] & 63; |
| calcBitrateAndFrameSize(frmsizecode); |
| inputStream.reset(); |
| byte[] data = new byte[frameSize]; |
| inputStream.read(data); |
| samples.add(ByteBuffer.wrap(data)); |
| stts.add(new TimeToSampleBox.Entry(1, 1536)); |
| inputStream.mark(5); |
| } |
| return ret; |
| } |
| |
| private void initBitRateAndFrameSizeTable() { |
| // ETSI 102 366 Table 4.13, in frmsizecod, flag, fscod, bitrate/size order. Note that all sizes are in words, and all bitrates in kbps |
| |
| // 48kHz |
| bitRateAndFrameSizeTable[0][0][0][0] = 32; |
| bitRateAndFrameSizeTable[0][1][0][0] = 32; |
| bitRateAndFrameSizeTable[0][0][0][1] = 64; |
| bitRateAndFrameSizeTable[0][1][0][1] = 64; |
| bitRateAndFrameSizeTable[1][0][0][0] = 40; |
| bitRateAndFrameSizeTable[1][1][0][0] = 40; |
| bitRateAndFrameSizeTable[1][0][0][1] = 80; |
| bitRateAndFrameSizeTable[1][1][0][1] = 80; |
| bitRateAndFrameSizeTable[2][0][0][0] = 48; |
| bitRateAndFrameSizeTable[2][1][0][0] = 48; |
| bitRateAndFrameSizeTable[2][0][0][1] = 96; |
| bitRateAndFrameSizeTable[2][1][0][1] = 96; |
| bitRateAndFrameSizeTable[3][0][0][0] = 56; |
| bitRateAndFrameSizeTable[3][1][0][0] = 56; |
| bitRateAndFrameSizeTable[3][0][0][1] = 112; |
| bitRateAndFrameSizeTable[3][1][0][1] = 112; |
| bitRateAndFrameSizeTable[4][0][0][0] = 64; |
| bitRateAndFrameSizeTable[4][1][0][0] = 64; |
| bitRateAndFrameSizeTable[4][0][0][1] = 128; |
| bitRateAndFrameSizeTable[4][1][0][1] = 128; |
| bitRateAndFrameSizeTable[5][0][0][0] = 80; |
| bitRateAndFrameSizeTable[5][1][0][0] = 80; |
| bitRateAndFrameSizeTable[5][0][0][1] = 160; |
| bitRateAndFrameSizeTable[5][1][0][1] = 160; |
| bitRateAndFrameSizeTable[6][0][0][0] = 96; |
| bitRateAndFrameSizeTable[6][1][0][0] = 96; |
| bitRateAndFrameSizeTable[6][0][0][1] = 192; |
| bitRateAndFrameSizeTable[6][1][0][1] = 192; |
| bitRateAndFrameSizeTable[7][0][0][0] = 112; |
| bitRateAndFrameSizeTable[7][1][0][0] = 112; |
| bitRateAndFrameSizeTable[7][0][0][1] = 224; |
| bitRateAndFrameSizeTable[7][1][0][1] = 224; |
| bitRateAndFrameSizeTable[8][0][0][0] = 128; |
| bitRateAndFrameSizeTable[8][1][0][0] = 128; |
| bitRateAndFrameSizeTable[8][0][0][1] = 256; |
| bitRateAndFrameSizeTable[8][1][0][1] = 256; |
| bitRateAndFrameSizeTable[9][0][0][0] = 160; |
| bitRateAndFrameSizeTable[9][1][0][0] = 160; |
| bitRateAndFrameSizeTable[9][0][0][1] = 320; |
| bitRateAndFrameSizeTable[9][1][0][1] = 320; |
| bitRateAndFrameSizeTable[10][0][0][0] = 192; |
| bitRateAndFrameSizeTable[10][1][0][0] = 192; |
| bitRateAndFrameSizeTable[10][0][0][1] = 384; |
| bitRateAndFrameSizeTable[10][1][0][1] = 384; |
| bitRateAndFrameSizeTable[11][0][0][0] = 224; |
| bitRateAndFrameSizeTable[11][1][0][0] = 224; |
| bitRateAndFrameSizeTable[11][0][0][1] = 448; |
| bitRateAndFrameSizeTable[11][1][0][1] = 448; |
| bitRateAndFrameSizeTable[12][0][0][0] = 256; |
| bitRateAndFrameSizeTable[12][1][0][0] = 256; |
| bitRateAndFrameSizeTable[12][0][0][1] = 512; |
| bitRateAndFrameSizeTable[12][1][0][1] = 512; |
| bitRateAndFrameSizeTable[13][0][0][0] = 320; |
| bitRateAndFrameSizeTable[13][1][0][0] = 320; |
| bitRateAndFrameSizeTable[13][0][0][1] = 640; |
| bitRateAndFrameSizeTable[13][1][0][1] = 640; |
| bitRateAndFrameSizeTable[14][0][0][0] = 384; |
| bitRateAndFrameSizeTable[14][1][0][0] = 384; |
| bitRateAndFrameSizeTable[14][0][0][1] = 768; |
| bitRateAndFrameSizeTable[14][1][0][1] = 768; |
| bitRateAndFrameSizeTable[15][0][0][0] = 448; |
| bitRateAndFrameSizeTable[15][1][0][0] = 448; |
| bitRateAndFrameSizeTable[15][0][0][1] = 896; |
| bitRateAndFrameSizeTable[15][1][0][1] = 896; |
| bitRateAndFrameSizeTable[16][0][0][0] = 512; |
| bitRateAndFrameSizeTable[16][1][0][0] = 512; |
| bitRateAndFrameSizeTable[16][0][0][1] = 1024; |
| bitRateAndFrameSizeTable[16][1][0][1] = 1024; |
| bitRateAndFrameSizeTable[17][0][0][0] = 576; |
| bitRateAndFrameSizeTable[17][1][0][0] = 576; |
| bitRateAndFrameSizeTable[17][0][0][1] = 1152; |
| bitRateAndFrameSizeTable[17][1][0][1] = 1152; |
| bitRateAndFrameSizeTable[18][0][0][0] = 640; |
| bitRateAndFrameSizeTable[18][1][0][0] = 640; |
| bitRateAndFrameSizeTable[18][0][0][1] = 1280; |
| bitRateAndFrameSizeTable[18][1][0][1] = 1280; |
| |
| // 44.1 kHz |
| bitRateAndFrameSizeTable[0][0][1][0] = 32; |
| bitRateAndFrameSizeTable[0][1][1][0] = 32; |
| bitRateAndFrameSizeTable[0][0][1][1] = 69; |
| bitRateAndFrameSizeTable[0][1][1][1] = 70; |
| bitRateAndFrameSizeTable[1][0][1][0] = 40; |
| bitRateAndFrameSizeTable[1][1][1][0] = 40; |
| bitRateAndFrameSizeTable[1][0][1][1] = 87; |
| bitRateAndFrameSizeTable[1][1][1][1] = 88; |
| bitRateAndFrameSizeTable[2][0][1][0] = 48; |
| bitRateAndFrameSizeTable[2][1][1][0] = 48; |
| bitRateAndFrameSizeTable[2][0][1][1] = 104; |
| bitRateAndFrameSizeTable[2][1][1][1] = 105; |
| bitRateAndFrameSizeTable[3][0][1][0] = 56; |
| bitRateAndFrameSizeTable[3][1][1][0] = 56; |
| bitRateAndFrameSizeTable[3][0][1][1] = 121; |
| bitRateAndFrameSizeTable[3][1][1][1] = 122; |
| bitRateAndFrameSizeTable[4][0][1][0] = 64; |
| bitRateAndFrameSizeTable[4][1][1][0] = 64; |
| bitRateAndFrameSizeTable[4][0][1][1] = 139; |
| bitRateAndFrameSizeTable[4][1][1][1] = 140; |
| bitRateAndFrameSizeTable[5][0][1][0] = 80; |
| bitRateAndFrameSizeTable[5][1][1][0] = 80; |
| bitRateAndFrameSizeTable[5][0][1][1] = 174; |
| bitRateAndFrameSizeTable[5][1][1][1] = 175; |
| bitRateAndFrameSizeTable[6][0][1][0] = 96; |
| bitRateAndFrameSizeTable[6][1][1][0] = 96; |
| bitRateAndFrameSizeTable[6][0][1][1] = 208; |
| bitRateAndFrameSizeTable[6][1][1][1] = 209; |
| bitRateAndFrameSizeTable[7][0][1][0] = 112; |
| bitRateAndFrameSizeTable[7][1][1][0] = 112; |
| bitRateAndFrameSizeTable[7][0][1][1] = 243; |
| bitRateAndFrameSizeTable[7][1][1][1] = 244; |
| bitRateAndFrameSizeTable[8][0][1][0] = 128; |
| bitRateAndFrameSizeTable[8][1][1][0] = 128; |
| bitRateAndFrameSizeTable[8][0][1][1] = 278; |
| bitRateAndFrameSizeTable[8][1][1][1] = 279; |
| bitRateAndFrameSizeTable[9][0][1][0] = 160; |
| bitRateAndFrameSizeTable[9][1][1][0] = 160; |
| bitRateAndFrameSizeTable[9][0][1][1] = 348; |
| bitRateAndFrameSizeTable[9][1][1][1] = 349; |
| bitRateAndFrameSizeTable[10][0][1][0] = 192; |
| bitRateAndFrameSizeTable[10][1][1][0] = 192; |
| bitRateAndFrameSizeTable[10][0][1][1] = 417; |
| bitRateAndFrameSizeTable[10][1][1][1] = 418; |
| bitRateAndFrameSizeTable[11][0][1][0] = 224; |
| bitRateAndFrameSizeTable[11][1][1][0] = 224; |
| bitRateAndFrameSizeTable[11][0][1][1] = 487; |
| bitRateAndFrameSizeTable[11][1][1][1] = 488; |
| bitRateAndFrameSizeTable[12][0][1][0] = 256; |
| bitRateAndFrameSizeTable[12][1][1][0] = 256; |
| bitRateAndFrameSizeTable[12][0][1][1] = 557; |
| bitRateAndFrameSizeTable[12][1][1][1] = 558; |
| bitRateAndFrameSizeTable[13][0][1][0] = 320; |
| bitRateAndFrameSizeTable[13][1][1][0] = 320; |
| bitRateAndFrameSizeTable[13][0][1][1] = 696; |
| bitRateAndFrameSizeTable[13][1][1][1] = 697; |
| bitRateAndFrameSizeTable[14][0][1][0] = 384; |
| bitRateAndFrameSizeTable[14][1][1][0] = 384; |
| bitRateAndFrameSizeTable[14][0][1][1] = 835; |
| bitRateAndFrameSizeTable[14][1][1][1] = 836; |
| bitRateAndFrameSizeTable[15][0][1][0] = 448; |
| bitRateAndFrameSizeTable[15][1][1][0] = 448; |
| bitRateAndFrameSizeTable[15][0][1][1] = 975; |
| bitRateAndFrameSizeTable[15][1][1][1] = 975; |
| bitRateAndFrameSizeTable[16][0][1][0] = 512; |
| bitRateAndFrameSizeTable[16][1][1][0] = 512; |
| bitRateAndFrameSizeTable[16][0][1][1] = 1114; |
| bitRateAndFrameSizeTable[16][1][1][1] = 1115; |
| bitRateAndFrameSizeTable[17][0][1][0] = 576; |
| bitRateAndFrameSizeTable[17][1][1][0] = 576; |
| bitRateAndFrameSizeTable[17][0][1][1] = 1253; |
| bitRateAndFrameSizeTable[17][1][1][1] = 1254; |
| bitRateAndFrameSizeTable[18][0][1][0] = 640; |
| bitRateAndFrameSizeTable[18][1][1][0] = 640; |
| bitRateAndFrameSizeTable[18][0][1][1] = 1393; |
| bitRateAndFrameSizeTable[18][1][1][1] = 1394; |
| |
| // 32kHz |
| bitRateAndFrameSizeTable[0][0][2][0] = 32; |
| bitRateAndFrameSizeTable[0][1][2][0] = 32; |
| bitRateAndFrameSizeTable[0][0][2][1] = 96; |
| bitRateAndFrameSizeTable[0][1][2][1] = 96; |
| bitRateAndFrameSizeTable[1][0][2][0] = 40; |
| bitRateAndFrameSizeTable[1][1][2][0] = 40; |
| bitRateAndFrameSizeTable[1][0][2][1] = 120; |
| bitRateAndFrameSizeTable[1][1][2][1] = 120; |
| bitRateAndFrameSizeTable[2][0][2][0] = 48; |
| bitRateAndFrameSizeTable[2][1][2][0] = 48; |
| bitRateAndFrameSizeTable[2][0][2][1] = 144; |
| bitRateAndFrameSizeTable[2][1][2][1] = 144; |
| bitRateAndFrameSizeTable[3][0][2][0] = 56; |
| bitRateAndFrameSizeTable[3][1][2][0] = 56; |
| bitRateAndFrameSizeTable[3][0][2][1] = 168; |
| bitRateAndFrameSizeTable[3][1][2][1] = 168; |
| bitRateAndFrameSizeTable[4][0][2][0] = 64; |
| bitRateAndFrameSizeTable[4][1][2][0] = 64; |
| bitRateAndFrameSizeTable[4][0][2][1] = 192; |
| bitRateAndFrameSizeTable[4][1][2][1] = 192; |
| bitRateAndFrameSizeTable[5][0][2][0] = 80; |
| bitRateAndFrameSizeTable[5][1][2][0] = 80; |
| bitRateAndFrameSizeTable[5][0][2][1] = 240; |
| bitRateAndFrameSizeTable[5][1][2][1] = 240; |
| bitRateAndFrameSizeTable[6][0][2][0] = 96; |
| bitRateAndFrameSizeTable[6][1][2][0] = 96; |
| bitRateAndFrameSizeTable[6][0][2][1] = 288; |
| bitRateAndFrameSizeTable[6][1][2][1] = 288; |
| bitRateAndFrameSizeTable[7][0][2][0] = 112; |
| bitRateAndFrameSizeTable[7][1][2][0] = 112; |
| bitRateAndFrameSizeTable[7][0][2][1] = 336; |
| bitRateAndFrameSizeTable[7][1][2][1] = 336; |
| bitRateAndFrameSizeTable[8][0][2][0] = 128; |
| bitRateAndFrameSizeTable[8][1][2][0] = 128; |
| bitRateAndFrameSizeTable[8][0][2][1] = 384; |
| bitRateAndFrameSizeTable[8][1][2][1] = 384; |
| bitRateAndFrameSizeTable[9][0][2][0] = 160; |
| bitRateAndFrameSizeTable[9][1][2][0] = 160; |
| bitRateAndFrameSizeTable[9][0][2][1] = 480; |
| bitRateAndFrameSizeTable[9][1][2][1] = 480; |
| bitRateAndFrameSizeTable[10][0][2][0] = 192; |
| bitRateAndFrameSizeTable[10][1][2][0] = 192; |
| bitRateAndFrameSizeTable[10][0][2][1] = 576; |
| bitRateAndFrameSizeTable[10][1][2][1] = 576; |
| bitRateAndFrameSizeTable[11][0][2][0] = 224; |
| bitRateAndFrameSizeTable[11][1][2][0] = 224; |
| bitRateAndFrameSizeTable[11][0][2][1] = 672; |
| bitRateAndFrameSizeTable[11][1][2][1] = 672; |
| bitRateAndFrameSizeTable[12][0][2][0] = 256; |
| bitRateAndFrameSizeTable[12][1][2][0] = 256; |
| bitRateAndFrameSizeTable[12][0][2][1] = 768; |
| bitRateAndFrameSizeTable[12][1][2][1] = 768; |
| bitRateAndFrameSizeTable[13][0][2][0] = 320; |
| bitRateAndFrameSizeTable[13][1][2][0] = 320; |
| bitRateAndFrameSizeTable[13][0][2][1] = 960; |
| bitRateAndFrameSizeTable[13][1][2][1] = 960; |
| bitRateAndFrameSizeTable[14][0][2][0] = 384; |
| bitRateAndFrameSizeTable[14][1][2][0] = 384; |
| bitRateAndFrameSizeTable[14][0][2][1] = 1152; |
| bitRateAndFrameSizeTable[14][1][2][1] = 1152; |
| bitRateAndFrameSizeTable[15][0][2][0] = 448; |
| bitRateAndFrameSizeTable[15][1][2][0] = 448; |
| bitRateAndFrameSizeTable[15][0][2][1] = 1344; |
| bitRateAndFrameSizeTable[15][1][2][1] = 1344; |
| bitRateAndFrameSizeTable[16][0][2][0] = 512; |
| bitRateAndFrameSizeTable[16][1][2][0] = 512; |
| bitRateAndFrameSizeTable[16][0][2][1] = 1536; |
| bitRateAndFrameSizeTable[16][1][2][1] = 1536; |
| bitRateAndFrameSizeTable[17][0][2][0] = 576; |
| bitRateAndFrameSizeTable[17][1][2][0] = 576; |
| bitRateAndFrameSizeTable[17][0][2][1] = 1728; |
| bitRateAndFrameSizeTable[17][1][2][1] = 1728; |
| bitRateAndFrameSizeTable[18][0][2][0] = 640; |
| bitRateAndFrameSizeTable[18][1][2][0] = 640; |
| bitRateAndFrameSizeTable[18][0][2][1] = 1920; |
| bitRateAndFrameSizeTable[18][1][2][1] = 1920; |
| } |
| } |