package wrapper;
/**
* This class generates the (Audio/Video) Header Specific Info sent by RTMP Client .
*
*/
public class DecoderSpecificInfo {
public static final int NALU_START_CODE = 4;
/**
* Function Check for the Start Code of the NALU 0 0 0 1
*
* @param aBuffer - Stream Header Buffer
* @param aIndex - Present Index
* @return Flag if the Start Code is there
*/
public static boolean checkStartCode (final byte[] aBuffer,
final int aIndex)
{
return ((aBuffer[aIndex] == 0x0) &&
(aBuffer[aIndex + 1] == 0x0)&&
(aBuffer[aIndex + 2] == 0x0)&&
(aBuffer[aIndex + 3] == 0x1));
}
/**
* Function to get the Next NALU in the stream
*
* @param aBuffer - Stream Header Buffer
* @param aIndex - Present Index
* @param aLength - Buffer Length
* @return size of the NALU
*/
public static int getNextNALU (final byte[] aBuffer,
final int aIndex,
final int aLength)
{
int index = aIndex+1;
{
for(;index < aLength;index ++)
{
if (checkStartCode(aBuffer,index))
break;
}
}
return (index - aIndex - NALU_START_CODE);
}
/**
* Function to get the number of PPS(Picture Parameter Set) in the Stream
*
* @param aBuffer - Stream Header Buffer
* @param aIndex - Present Index
* @param aLength - Buffer Length
* @return Number of PPS
*/
public static int getPPSNumber (final byte[] aBuffer,
final int aIndex,
final int aLength)
{
int ppsnum = 0;
int index = aIndex;
while(index < aLength)
{
int lSize = getNextNALU(aBuffer,index,aLength);
index += (lSize + NALU_START_CODE);
ppsnum++;
}
return ppsnum;
}
/**
* Function to Realign the Data as required by the RTMP
* [Size of SPS in 2 bytes][SPS Data][Number of PPS in 1 byte][Size of PPS in 2 bytes][PPS Data]......
* SPS Sequence Parameter Set PPS Picture Parameter Set
* @param decspecinfo - Video Header Info
* @param decSpecInfoSize - Header Size
* @return VideoHeader Buffer
*/
public static byte[] VideoConstructorInfo(final byte[] decspecinfo,
final int decSpecInfoSize)
{
int i = 0;
byte[] aBuffer = new byte[128];
// SPS
int lSize = getNextNALU(decspecinfo,i,decSpecInfoSize);
aBuffer[0] = (byte) ((lSize >> 8) & 0xFF);
aBuffer[1] = (byte) ((lSize) & 0xFF);
System.arraycopy(decspecinfo, NALU_START_CODE, aBuffer, 2, lSize);
int lIndex = 2 + lSize;
i += (lSize + NALU_START_CODE);
// PPS
int lppsnumber = getPPSNumber(decspecinfo,i,decSpecInfoSize);
aBuffer[lIndex++] = (byte)lppsnumber;
while(lppsnumber > 0)
{
lSize = getNextNALU(decspecinfo,i,decSpecInfoSize);
aBuffer[lIndex] = (byte) ((lSize >> 8) & 0xFF);
aBuffer[lIndex + 1] = (byte) ((lSize) & 0xFF);
System.arraycopy(decspecinfo, i + NALU_START_CODE, aBuffer, lIndex + 2,lSize);
lIndex += (2 + lSize);
i += (lSize + NALU_START_CODE);
lppsnumber --;
}
byte[] videoHeaderBuffer = new byte[lIndex];
System.arraycopy(aBuffer, 0, videoHeaderBuffer, 0, lIndex);
return videoHeaderBuffer;
}
/**
* Function to create the Audio Header Data as required by the RTMP
*
*
* @param aObjectType - Audio Object Type ( 2 for AAC)
* @param aSampleFreq - Sampling Frequency
* @param aChannelCount - Number of Channels
* @return AudioHeader Buffer
*/
public static byte[] AudioConstructorInfo(final int aObjectType,
final int aSampleFreq,
final int aChannelCount)
{
int lSampFreqIdx = 4;
switch(aSampleFreq){
case 96000:
lSampFreqIdx = 0;
break;
case 88200:
lSampFreqIdx = 1;
break;
case 64000:
lSampFreqIdx = 2;
break;
case 48000:
lSampFreqIdx = 3;
break;
case 44100:
lSampFreqIdx = 4;
break;
case 32000:
lSampFreqIdx = 5;
break;
case 24000:
lSampFreqIdx = 6;
break;
case 22050:
lSampFreqIdx = 7;
break;
case 16000:
lSampFreqIdx = 8;
break;
case 12000:
lSampFreqIdx = 9;
break;
case 11025:
lSampFreqIdx = 10;
break;
case 8000:
lSampFreqIdx = 11;
break;
case 7350:
lSampFreqIdx = 12;
break;
default:
lSampFreqIdx = 4;
}
byte[] aBuffer = new byte[2];
aBuffer[0] = (byte) (((aObjectType << 3) | (lSampFreqIdx >> 1)) & 0xff);
aBuffer[1] = (byte) ((((lSampFreqIdx & 1) << 7) | (aChannelCount << 3)) & 0xff);
return aBuffer;
}
}