/***************************************
* ViPER-MPEG *
* The Video Processing *
* Evaluation Resource *
* MPEG-1 Decoder *
* Distributed under the LGPL license *
* Terms available at gnu.org. *
* *
* Copyright University of Maryland, *
* College Park. *
***************************************/
package edu.umd.cfar.lamp.mpeg1.video;
import java.io.*;
import java.util.*;
import edu.columbia.ee.flavor.*;
import edu.umd.cfar.lamp.mpeg1.*;
public class SequenceHeader implements Parsable
{
public static final int VARIABLE_BITRATE = 0x3FFFF;
private static final int default_intra_quantizer_matrix[][] =
{ { 8, 16, 19, 22, 26, 27, 29, 34},
{16, 16, 22, 24, 27, 29, 34, 37},
{19, 22, 26, 27, 29, 34, 34, 38},
{22, 22, 26, 27, 29, 34, 37, 40},
{22, 26, 27, 29, 32, 35, 40, 48},
{26, 27, 29, 32, 35, 40, 48, 58},
{26, 27, 29, 34, 38, 46, 56, 69},
{27, 29, 35, 38, 46, 56, 69, 83} };
private int horizontal_size = 0;
private int vertical_size = 0;
private int mb_width = 0;
private int mb_height = 0;
private PelAspectRatio pel_aspect_ratio = new PelAspectRatio(1);
private float picture_rate = 0.0f;
private int bit_rate = 0;
private int vbv_buffer_size = 0;
private boolean constrained_parameters_flag = false;
private int intra_quantizer_matrix[][] = new int[8][8];
private int non_intra_quantizer_matrix[][] = new int[8][8];
public void writeIndex(DataOutput out) throws IOException
{
out.writeInt(horizontal_size);
out.writeInt(vertical_size);
out.writeInt(pel_aspect_ratio.getValue());
out.writeFloat(picture_rate);
out.writeInt(bit_rate);
out.writeInt(vbv_buffer_size);
out.writeBoolean(constrained_parameters_flag);
boolean storeIntraQuantizerMatrix = false;
for (int row = 0; row < 8; row++)
{
if (!Arrays.equals(intra_quantizer_matrix[row], default_intra_quantizer_matrix[row]))
{
storeIntraQuantizerMatrix = true;
break;
}
}
out.writeBoolean(storeIntraQuantizerMatrix);
if (storeIntraQuantizerMatrix)
{
for (int row = 0; row < 8; row++)
{
for (int col = 0; col < 8; col++)
{
out.writeByte(intra_quantizer_matrix[row][col]);
}
}
}
boolean storeNonIntraQuantizerMatrix = false;
for (int row = 0; row < 8; row++)
{
for (int col = 0; col < 8; col++)
{
if (non_intra_quantizer_matrix[row][col] != 16)
{
storeNonIntraQuantizerMatrix = true;
break;
}
}
if (storeNonIntraQuantizerMatrix)
break;
}
out.writeBoolean(storeNonIntraQuantizerMatrix);
if (storeNonIntraQuantizerMatrix)
{
for (int row = 0; row < 8; row++)
{
for (int col = 0; col < 8; col++)
{
out.writeByte(non_intra_quantizer_matrix[row][col]);
}
}
}
}
public void readIndex(DataInput in, byte version) throws IOException, UnsupportedIndexVersionException
{
switch (version)
{
case 0x01:
horizontal_size = in.readInt();
vertical_size = in.readInt();
mb_width = (horizontal_size / 16) + ((horizontal_size % 16) > 0 ? 1 : 0);
mb_height = (vertical_size / 16) + ((vertical_size % 16) > 0 ? 1 : 0);
pel_aspect_ratio = new PelAspectRatio(in.readInt());
picture_rate = in.readFloat();
bit_rate = in.readInt();
vbv_buffer_size = in.readInt();
constrained_parameters_flag = in.readBoolean();
boolean loadIntraQuantizerMatrix = in.readBoolean();
if (loadIntraQuantizerMatrix)
{
for (int row = 0; row < 8; row++)
{
for (int col = 0; col < 8; col++)
{
intra_quantizer_matrix[row][col] = in.readUnsignedByte();
}
}
}
else
{
for (int row = 0; row < 8; row++)
{
System.arraycopy(default_intra_quantizer_matrix[row], 0, intra_quantizer_matrix[row], 0, 8);
}
}
boolean loadNonIntraQuantizerMatrix = in.readBoolean();
if (loadNonIntraQuantizerMatrix)
{
for (int row = 0; row < 8; row++)
{
for (int col = 0; col < 8; col++)
{
non_intra_quantizer_matrix[row][col] = in.readUnsignedByte();
}
}
}
else
{
for (int row = 0; row < 8; row++)
{
Arrays.fill(non_intra_quantizer_matrix[row], 16);
}
}
break;
default:
throw new UnsupportedIndexVersionException("version: " + Integer.toHexString(version));
}
}
public int getFrameWidth()
{
return horizontal_size;
}
public int getFrameHeight()
{
return vertical_size;
}
public int getMbWidth()
{
return mb_width;
}
public int getMbHeight()
{
return mb_height;
}
public PelAspectRatio getPixelAspectRatio()
{
return pel_aspect_ratio;
}
public float getFrameRate()
{
return picture_rate;
}
public int getBitRate()
{
return bit_rate;
}
public int[][] getIntraQuantizerMatrix()
{
return intra_quantizer_matrix;
}
public int[][] getNonIntraQuantizerMatrix()
{
return non_intra_quantizer_matrix;
}
public void parse(Bitstream bitstream) throws IOException
{
if (bitstream.getbits(32) != VideoStartCodes.SEQUENCE_HEADER_CODE)
throw new ParsingException("Expected sequence_header_code not found.");
horizontal_size = bitstream.getbits(12);
vertical_size = bitstream.getbits(12);
// mb_width is horizontal_size/16 with maybe one added if the horizontal_size is not a multiple of 16.
// Same with mb_height and vertical_size.
mb_width = (horizontal_size / 16) + ((horizontal_size % 16) > 0 ? 1 : 0);
mb_height = (vertical_size / 16) + ((vertical_size % 16) > 0 ? 1 : 0);
pel_aspect_ratio = new PelAspectRatio();
pel_aspect_ratio.parse(bitstream);
PictureRate pr = new PictureRate();
pr.parse(bitstream);
picture_rate = pr.getValue();
bit_rate = bitstream.getbits(18);
if (bitstream.getbits(1) != 1)
throw new ParsingException("Expected marker_bit not found.");
vbv_buffer_size = bitstream.getbits(10);
constrained_parameters_flag = (bitstream.getbits(1) == 1);
boolean load_intra_quantizer_matrix = (bitstream.getbits(1) == 1);
if (load_intra_quantizer_matrix)
{
for (int i = 0; i < 8; i++)
for (int j = 0; j < 8; j++)
intra_quantizer_matrix[i][j] = bitstream.getbits(8);
}
else // copy values from the default intra_quantizer_matrix
{
for (int i = 0; i < 8; i++)
System.arraycopy(default_intra_quantizer_matrix[i], 0, intra_quantizer_matrix[i], 0, 8);
}
boolean load_non_intra_quantizer_matrix = (bitstream.getbits(1) == 1);
if (load_non_intra_quantizer_matrix)
{
for (int i = 0; i < 8; i++)
for (int j = 0; j < 8; j++)
non_intra_quantizer_matrix[i][j] = bitstream.getbits(8);
}
else // fill with 16s (which is the default non_intra_quantizer_matrix)
{
for (int i = 0; i < 8; i++)
Arrays.fill(non_intra_quantizer_matrix[i], 16);
}
NextStartCode.parse(bitstream);
if (bitstream.nextbits(32) == VideoStartCodes.EXTENSION_START_CODE)
{
if (bitstream.getbits(32) != VideoStartCodes.EXTENSION_START_CODE)
throw new ParsingException("Expected extension_start_code not found.");
while (bitstream.nextbits(24) != 1)
{
int sequence_extension_data = bitstream.getbits(8);
}
NextStartCode.parse(bitstream);
}
if (bitstream.nextbits(32) == VideoStartCodes.USER_DATA_START_CODE)
{
if (bitstream.getbits(32) != VideoStartCodes.USER_DATA_START_CODE)
throw new ParsingException("Expected user_data_start_code not found.");
while (bitstream.nextbits(24) != 1)
{
int user_data = bitstream.getbits(8);
}
NextStartCode.parse(bitstream);
}
}
}