/*
* @(#)AudioFormatAC3.java - parse Audioheaders, ac3
*
* Copyright (c) 2003-2009 by dvb.matt, All Rights Reserved.
*
* This file is part of ProjectX, a free Java based demux utility.
* By the authors, ProjectX is intended for educational purposes only,
* as a non-commercial test project.
*
* The part of audio parsing was derived from
* ATSC A/52 in a special modified manner.
*
* crc computing derived from:
* The simplest AC3 encoder, Copyright (c) 2000 Fabrice Bellard.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package net.sourceforge.dvb.projectx.audio;
import java.util.Arrays;
import net.sourceforge.dvb.projectx.parser.CommonParsing;
public class AudioFormatAC3 extends AudioFormat {
public AudioFormatAC3()
{
super();
initCRCTable();
}
private int bsid = 0;
private int CRC16_POLY = 0x18005; //((1 << 0) | (1 << 2) | (1 << 15) | (1 << 16));
private int[] crc_table = new int[256];
private int[] ac3_frequency_index = { 48000, 44100, 32000, 0 };
private int[] ac3_bitrate_index = {
32000, 40000, 48000, 56000, 64000, 80000, 96000,
112000, 128000, 160000, 192000, 224000, 256000,
320000, 384000, 448000, 512000, 576000, 640000,
0,0,0,0,0,0,0,0,0,0,0,0,0 // (fix4)
};
private int[][] ac3_size_table = {
{ 128,160,192,224,256,320,384,448,512,640,768,896,1024,1280,1536,1792,2048,2304,2560 }, //48khz
{ 138,174,208,242,278,348,416,486,556,696,834,974,1114,1392,1670,1950,2228,2506,2786 }, //44.1khz
{ 192,240,288,336,384,480,576,672,768,960,1152,1344,1536,1920,2304,2688,3120,3456,3840 } //32khz
};
private String[] bsmod = { ", CM" , ", ME" , ", K:VI" , ", K:HI" , ", K:D" , ", K:C" , ", K:E" , ", K:VO" };
private String[] cmixlev = { "", ", cm -3.0dB", ", cm -4.5dB", ", cm -6.0dB", ", cm -4.5dB" };
private String[] surmixlev = { "", ", sm -3dB", ", sm -6dB", ", sm 0dB", ", sm -6dB" };
private String[] dsurmod = { "" , ", notDS" , ", DS" , "" };
private String[] acmod = { "1+1", "1/0", "2/0", "3/0", "2/1", "3/1", "2/2", "3/2" };
private String[][] lfe = {{ ".0", ".1" },{ "", "lfe" }};
private int[] ac3_channels = { 2, 1, 2, 3, 3, 4, 4, 5 };
/**
* parse ac3 Header
*/
public int parseHeader(byte[] frame, int pos)
{
if ( !hasAC3Syncword(frame, pos))
return -1;
setID(0);
setEmphasis(0);
setPrivateBit(0);
// setProtectionBit(0 ^ 1);
setSamplingFrequency(getAC3SamplingFrequency(frame, pos));
if (getSamplingFrequency() < 1)
return -4;
setBitrate(getAC3Bitrate(frame, pos));
if (getBitrate() < 1)
return -3;
setProtectionBit((0x1F & frame[pos + 5]>>3)); //bsid
setLayer(getAC3Bsmod(frame, pos)); //bsmod
setPaddingBit(1 & frame[pos + 4]);
setMode(getAC3Mode(frame, pos));
setModeExtension(0);
int mode = (0xFF & frame[pos + 6])<<8 | (0xFF & frame[pos + 7]);
int skip=0;
if ((getMode() & 1) > 0 && getMode() != 1) // cmix
{
setEmphasis(1 + (3 & frame[pos + 6]>>>3));
skip++;
}
if ((getMode() & 4) > 0) //surmix
{
setPrivateBit(1 + (3 & frame[pos + 6]>>>(skip > 0 ? 1 : 3)));
skip++;
}
if (getMode() == 2)
{
setModeExtension(getModeExtension() | (6 & mode>>>(10 - (2 * skip)))); //DS
skip++;
}
if (skip < 4)
{
setModeExtension(getModeExtension() | (1 & mode>>>(12 - (2 * skip)))); //lfe
setOriginal(0x1F & mode>>>(7 - (2 * skip))); //dialnorm
}
setChannel(ac3_channels[getMode()] + (1 & getModeExtension()));
setCopyright(0);
setFrameTimeLength(138240000.0 / getSamplingFrequency());
setSizeBase(ac3_size_table[3 & frame[pos + 4]>>>6][0x1F & frame[pos + 4]>>>1]);
setSize(getSamplingFrequency() == ac3_frequency_index[1] ? getSizeBase() + (getPaddingBit() * 2) : getSizeBase());
return 1;
}
/**
* parse next ac3 Header
*/
public int parseNextHeader(byte[] frame, int pos)
{
if ( !hasAC3Syncword(frame, pos))
return -1;
setNextID(0);
setNextEmphasis(0);
setNextPrivateBit(0);
// setNextProtectionBit(0 ^ 1);
setNextSamplingFrequency(getAC3SamplingFrequency(frame, pos));
if (getNextSamplingFrequency() < 1)
return -4;
setNextBitrate(getAC3Bitrate(frame, pos));
if (getNextBitrate() < 1)
return -3;
setNextProtectionBit((0x1F & frame[pos + 5]>>3)); //bsid
setNextLayer(getAC3Bsmod(frame, pos)); //bsmod
setNextPaddingBit(1 & frame[pos + 4]);
setNextMode(getAC3Mode(frame, pos));
setNextModeExtension(0);
//
int mode = (0xFF & frame[pos + 6])<<8 | (0xFF & frame[pos + 7]);
int skip=0;
if ((getNextMode() & 1) > 0 && getNextMode() != 1) // cmix
{
setNextEmphasis(1 + (3 & frame[pos + 6]>>>3));
skip++;
}
if ((getNextMode() & 4) > 0) //surmix
{
setNextPrivateBit(1 + (3 & frame[pos + 6]>>>(skip > 0 ? 1 : 3)));
skip++;
}
if (getNextMode() == 2)
{
setNextModeExtension(getNextModeExtension() | (6 & mode>>>(10 - (2 * skip)))); //DS
skip++;
}
if (skip < 4)
{
setNextModeExtension(getNextModeExtension() | (1 & mode>>>(12 - (2 * skip)))); //lfe
setNextOriginal(0x1F & mode>>>(7 - (2 * skip))); //dialnorm
}
setNextChannel(ac3_channels[getNextMode()] + (1 & getNextModeExtension()));
setNextCopyright(0);
setNextFrameTimeLength(138240000.0 / getNextSamplingFrequency());
setNextSizeBase(ac3_size_table[3 & frame[pos + 4]>>>6][0x1F & frame[pos + 4]>>>1]);
setNextSize(getNextSamplingFrequency() == ac3_frequency_index[1] ? getNextSizeBase() + (getNextPaddingBit() * 2) : getNextSizeBase());
return 1;
}
/**
*
*/
private boolean hasAC3Syncword(byte[] frame, int offs)
{
if (frame[offs] != 0x0B || frame[offs + 1] != 0x77)
return false;
return true;
}
/**
*
*/
private int getAC3SamplingFrequency(byte[] frame, int offs)
{
return ac3_frequency_index[3 & frame[offs + 4]>>>6];
}
/**
*
*/
private int getAC3Bitrate(byte[] frame, int offs)
{
return ac3_bitrate_index[0x1F & frame[offs + 4]>>>1];
}
/**
*
*/
private int getAC3Bsmod(byte[] frame, int offs)
{
return (7 & frame[offs + 5]);
}
/**
*
*/
private int getAC3Mode(byte[] frame, int offs)
{
return (7 & frame[offs + 6]>>>5);
}
/**
* compare current & last ac3 header
*/
public int compareHeader()
{
if (getLastID() != getID())
return 0x1;
else if (getLastLayer() != getLayer())
return 0x2;
else if (getLastSamplingFrequency() != getSamplingFrequency())
return 0x4;
else if (getLastBitrate() != getBitrate())
return 0x8;
else if (getLastMode() != getMode())
return 0x10;
else if (getLastModeExtension() != getModeExtension())
return 0x20;
else if (getLastOriginal() != getOriginal())
return 0x40;
else if (getLastEmphasis() != getEmphasis())
return 0x80;
else if (getLastProtectionBit() != getProtectionBit())
return 0x100;
else
return 0;
}
/**
* display last ac3 header
*/
public String displayHeader()
{
return ("AC-3" + bsmod[getLastLayer()] +
", " +
acmod[getLastMode()] +
lfe[1][1 & getLastModeExtension()] +
"(" +
ac3_channels[getLastMode()] +
lfe[0][1 & getLastModeExtension()] +
")" +
", bsid " + getLastProtectionBit() +
", dn -" + getLastOriginal() + "dB" +
dsurmod[getLastModeExtension()>>>1] +
cmixlev[getLastEmphasis()] +
surmixlev[getLastPrivateBit()] +
", " +
getLastSamplingFrequency() + "Hz, " +
(getLastBitrate() / 1000) + "kbps");
}
/**
*
*/
public byte[] editFrame(byte[] frame, int mode)
{
switch (mode)
{
case 1: //patch only to 3/2
setChannelFlags(frame, 7);
// computeCRC(frame, framesize);
break;
case 2:
frame = setNewBitrate(frame);
break;
case 3:
frame = setSilence(frame);
break;
case 4:
frame = setBsid(frame);
break;
}
return frame;
}
/**
* fix to 3+2 channels, note the following bits will be dispointed and the frame is corrupted
*/
private void setChannelFlags(byte[] frame, int mode)
{
frame[6] = (byte)((0xF & frame[6]) | (mode<<5));
}
/**
* bitrate edit
*/
private byte[] setNewBitrate(byte[] frame)
{
int size_index_src = 0x1F & frame[4]>>>1;
int size_index = (int)(0x1FL & (CommonParsing.getAudioProcessingFlags()>>>4));
if (size_index_src == size_index)
return frame;
else if (size_index_src > size_index)
{
size_index = size_index_src;
if ((CommonParsing.getAudioProcessingFlags()>>>18) > 0) // not first frame
CommonParsing.setAudioProcessingFlags(CommonParsing.getAudioProcessingFlags() | 0xCL); //restart marker
}
CommonParsing.setAudioProcessingFlags((~0xFF0L & CommonParsing.getAudioProcessingFlags()) | size_index<<4); //common bitrate index
byte[] newframe = new byte[ac3_size_table[3 & frame[4]>>>6][size_index]];
System.arraycopy(frame, 0, newframe, 0, frame.length);
newframe[4] &= 0xC0; //keep samplerate
newframe[4] |= (size_index<<1); //set index
clearCRC(newframe, frame.length);
computeCRC(newframe, ac3_size_table[3 & newframe[4]>>>6][size_index]);
return newframe;
}
/**
* set silence
*/
private byte[] setSilence(byte[] frame)
{
byte[] newframe = new byte[frame.length];
System.arraycopy(frame, 0, newframe, 0, frame.length);
int bitpos = getBSI(newframe, 0);
if ((bitpos & 7) == 0) //byte aligned
Arrays.fill(newframe, bitpos>>>3, newframe.length, (byte) 0);
else
{
Arrays.fill(newframe, (bitpos + 1)>>>3, newframe.length, (byte) 0);
newframe[bitpos>>>3] &= (0xFF00>>>(bitpos & 7));
}
clearCRC(newframe, newframe.length);
computeCRC(newframe, ac3_size_table[3 & newframe[4]>>>6][0x1F & newframe[4]>>>1]);
return newframe;
}
/**
* set bsid
*/
private byte[] setBsid(byte[] frame)
{
byte[] newframe = new byte[frame.length];
System.arraycopy(frame, 0, newframe, 0, frame.length);
if (getLastProtectionBit() == (0x1F & newframe[5]>>3))
return newframe;
newframe[5] = (byte)(getLastProtectionBit()<<3 | (7 & newframe[5]));
clearCRC(newframe, newframe.length);
computeCRC(newframe, ac3_size_table[3 & newframe[4]>>>6][0x1F & newframe[4]>>>1]);
// net.sourceforge.dvb.projectx.common.Common.setMessage("bsid " + (0x1F & frame[5]>>3) + " /n " + (0x1F & newframe[5]>>3));
return newframe;
}
/**
* validate crc16 1 + 2
*/
public int validateCRC(byte[] frame, int offset, int frame_size)
{
// frame_size is BYTE
int words = frame_size>>>1; //to word
int frame_size_58 = 2 * ((words>>>1) + (words>>>3)); //frame_size_58
int crc = -1;
//crc1
if ((crc = determineCRC(frame, 2, frame_size_58, 0)) != 0)
return 1;
//crc2
if ((crc = determineCRC(frame, frame_size_58, frame_size, crc)) != 0)
return 2;
return 0;
}
/**
* clear crc
*/
private void clearCRC(byte[] frame, int size)
{
frame[2] = (byte) 0;
frame[3] = (byte) 0;
frame[size - 2] = (byte) 0;
frame[size - 1] = (byte) 0;
}
/**
* compute crc16 1 + 2
*/
private void computeCRC(byte[] frame, int frame_size)
{
// frame_size is BYTE
int words = frame_size>>>1; //to word
int frame_size_58 = 2 * ((words>>>1) + (words>>>3)); //frame_size_58
int crc1 = -1;
int crc2 = -1;
int crc_inv = -1;
crc1 = determineCRC(frame, 4, frame_size_58, 0);
crc_inv = pow_poly((CRC16_POLY >>> 1), (frame_size_58<<3) - 16, CRC16_POLY);
//crc1
crc1 = mul_poly(crc_inv, crc1, CRC16_POLY);
frame[2] = (byte)(0xFF & (crc1 >> 8));
frame[3] = (byte)(0xFF & crc1);
//crc2
crc2 = determineCRC(frame, frame_size_58, (words<<1) - 2, 0);
frame[(2* words) - 2] = (byte)(0xFF & (crc2 >> 8));
frame[(2* words) - 1] = (byte)(0xFF & crc2);
}
/**
* ac3 crc init table
*/
private void initCRCTable()
{
for (int n = 0, c, k; n < 256; n++)
{
c = n << 8;
for (k = 0; k < 8; k++)
{
if ((c & (1 << 15)) != 0)
c = ((c << 1) & 0xFFFF) ^ (CRC16_POLY & 0xFFFF);
else
c = c << 1;
}
crc_table[n] = c;
}
}
/**
* ac3 crc
*/
private int determineCRC(byte[] data, int offs, int len, int crc)
{
for (int i = offs; i < len; i++)
crc = (crc_table[(0xFF & data[i]) ^ (crc >> 8)] ^ (crc << 8)) & 0xFFFF;
return crc;
}
/**
* crc poly
*/
private int mul_poly(int a, int b, int poly)
{
int c = 0;
while (a > 0)
{
if ((a & 1) > 0)
c ^= b;
a = a >>> 1;
b = b << 1;
if ((b & (1 << 16)) > 0)
b ^= poly;
}
return c;
}
/**
* crc poly
*/
private int pow_poly(int a, int n, int poly)
{
int r = 1;
while (n > 0)
{
if ((n & 1) > 0)
r = mul_poly(r, a, poly);
a = mul_poly(a, a, poly);
n >>>= 1;
}
return r;
}
/**
* bsi , taken from Doc A/52
*/
private int getBSI(byte[] frame, int pos)
{
//start at frame[5]
int[] BitPos = { pos<<3 };
int acmod = 0;
int val = 0;
getBits(frame, BitPos, 16); //sync
getBits(frame, BitPos, 16); //crc1
getBits(frame, BitPos, 2); //freq
getBits(frame, BitPos, 6); //size
getBits(frame, BitPos, 5); //bsi
getBits(frame, BitPos, 3); //bsmod
acmod = getBits(frame, BitPos, 3); //acmod
if ((acmod & 1) > 0 && acmod != 1)
getBits(frame, BitPos, 2); //cmixlev // if 3 front channels
if ((acmod & 4) > 0)
getBits(frame, BitPos, 2); //surmixlev // if a surround channel exists
if (acmod == 2)
getBits(frame, BitPos, 2); //dsurmod // if in 2/0 mode
getBits(frame, BitPos, 1); //lfeon
getBits(frame, BitPos, 5); //dialnorm
if (getBits(frame, BitPos, 1) == 1) //compre
getBits(frame, BitPos, 8); //compr
if (getBits(frame, BitPos, 1) == 1) //langcode
getBits(frame, BitPos, 8); //langcod
if (getBits(frame, BitPos, 1) == 1) //audprodie
{
getBits(frame, BitPos, 5); //mixlevel
getBits(frame, BitPos, 2); //roomtyp
}
if (acmod == 0) // if 1+1 mode (dual mono, so some items need a second value)
{
getBits(frame, BitPos, 5); //dialnorm2
if (getBits(frame, BitPos, 1) == 1) //compr2e
getBits(frame, BitPos, 8); //compr2
if (getBits(frame, BitPos, 1) == 1) //langcod2e
getBits(frame, BitPos, 8); //langcod2
if (getBits(frame, BitPos, 1) == 1) //audprodi2e
{
getBits(frame, BitPos, 5); //mixlevel2
getBits(frame, BitPos, 2); //roomtyp2
}
}
getBits(frame, BitPos, 1); //copyrightb
getBits(frame, BitPos, 1); //origbs
if (getBits(frame, BitPos, 1) == 1) //timecod1e
getBits(frame, BitPos, 14); //timecod1
if (getBits(frame, BitPos, 1) == 1) //timecod2e
getBits(frame, BitPos, 14); //timecod2
if (getBits(frame, BitPos, 1) == 1) //addbsie
{
val = getBits(frame, BitPos, 6); //addbsil
getBits(frame, BitPos, (val + 1) * 8); //addbsi
}
return BitPos[0];
}
/**
* ac3 riff header stuff
*/
// 1536s / 44.1 -> 34.8299ms -> 3134.691
// 1536s / 48 -> 32ms -> 2880
// 1536s / 32 -> 48ms -> 4320
private final int[] armode = { 0, 1, 2, 3, 3, 4, 4, 5 };
private final int[] arsample = { 48000, 44100, 32000, 0 };
private final int[] arbitrate = {
0, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000,
224000, 256000, 320000, 384000, 448000, 512000, 576000, 640000, 0, 0
};
/**
* ac3 bitrate constants
*/
/* 96k,112k,128k,160k,192k,224k,256k,320k,384k,448k,512k,576k,640k
* 0=48khz,1=44.1khz,2=32khz 32ms,36ms,48ms 44.1khz padding +2 bytes
*/
private final int[][] ac3const = {
{ 288000000,160,192,224,256,320,384,448,512,640,768,896,1024,1280,1536,1792,2080,2304,2560 },
{ 313469388,174,208,242,278,348,416,486,556,696,834,974,1114,1392,1670,1950,2228,2506,2786 },
{ 432000000,240,288,336,384,480,576,672,768,960,1152,1344,1536,1920,2304,2688,3120,3456,3840 }
};
/**
* riffdata from ac3 audio
* awaiting a frame byte array, only the header is used
*/
public void parseRiffData(byte[] frame, int channel)
{
int[] riffdata = new int[10];
// nSamplesPerSec
riffdata[2] = arsample[(0xC0 & frame[4])>>>6];
// nChannels
riffdata[4] = armode[(0xE0 & frame[6])>>>5];
// dwHeadBitrate
riffdata[6] = arbitrate[(0x3F & frame[4])>>>1];
// nBlockAlign
riffdata[8] = ac3const[(0xC0 & frame[4])>>>6][(0x3E & frame[4])>>>1] + (((1 & frame[4])!=0) ? 2 : 0);
setExtraWaveData(riffdata, channel);
}
/**
* part for RIFF wave header data processing
*/
private WaveHeader WaveHeader_Ch1;
/**
*
*/
public void initExtraWaveHeader(boolean bool_ACM, boolean bool_BWF, boolean bool_AC3)
{
WaveHeader_Ch1 = new WaveHeader(bool_AC3);
}
/**
*
*/
public byte[] getExtraWaveHeader(int channel, boolean placeholder)
{
if (channel == 1)
return (placeholder ? WaveHeader_Ch1.getPlaceHolder() : WaveHeader_Ch1.getHeader());
return (new byte[0]);
}
/**
*
*/
public void setExtraWaveData(int[] array, int channel)
{
if (channel == 1)
WaveHeader_Ch1.setWaveData(array);
}
/**
*
*/
public void setExtraWaveLength(long filelength, long timelength, int channel)
{
if (channel == 1)
WaveHeader_Ch1.setWaveLength(filelength, timelength);
}
/**
*
*/
private class WaveHeader {
private byte[] riffac3 = {
82, 73, 70, 70, 0, 0, 0, 0, 87, 65, 86, 69,102,109,116, 32,
18, 0, 0, 0, 0, 32, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 18, 0,100, 97,116, 97, 0, 0, 0, 0,
};
private long Samples = 0;
private long SampleCount = 0;
private final int HeaderLength_AC3 = 46;
private final int AC3_WaveFormat = 1;
private int WaveFormat;
//init
public WaveHeader(boolean bool_AC3)
{
WaveFormat = bool_AC3 ? AC3_WaveFormat : 0;
}
/**
* get place holder
*/
public byte[] getPlaceHolder()
{
if (WaveFormat == AC3_WaveFormat)
return (new byte[HeaderLength_AC3]);
return (new byte[0]);
}
/**
* get updated header
*/
public byte[] getHeader()
{
if (WaveFormat == AC3_WaveFormat)
return riffac3;
return (new byte[0]);
}
/**
* set wave data
*/
public void setWaveData(int[] riffdata)
{
Samples += riffdata[2];
SampleCount++;
int nSamplesPerSec = getValue(riffac3, 24, 4, true);
int nBlockAlign = getValue(riffac3, 32, 2, true);
//nBlockAlign
if (nBlockAlign == 0)
setValue(riffac3, 32, 2, true, riffdata[8]);
else if (nBlockAlign != 1 && nBlockAlign != riffdata[8])
setValue(riffac3, 32, 2, true, 1);
//nSamplesPerSec
if (nSamplesPerSec == 1)
setValue(riffac3, 24, 4, true, riffdata[2]);
else if (nSamplesPerSec != 0 && nSamplesPerSec != riffdata[2])
setValue(riffac3, 24, 4, true, 0);
// nChannels
if ((0xFF & riffac3[22]) < riffdata[4])
riffac3[22] = (byte) riffdata[4];
}
/**
*
*/
public void setWaveLength(long filelength, long timelength)
{
int lengthAC3 = (int)filelength - HeaderLength_AC3;
for (int i = 0; i < 4; i++)
{
riffac3[4 + i] = (byte)(0xFF & (lengthAC3 + 38)>>>(i * 8));
riffac3[42 + i] = (byte)(0xFF & lengthAC3>>>(i * 8));
}
if (filelength <= 100)
return;
int time = (int)timelength;
int nAvgBytePerSecAC3 = (int)(1000L * lengthAC3 / time);
setValue(riffac3, 28, 4, true, nAvgBytePerSecAC3);
}
}
}