private byte[] ParseVOP(byte[] data, bool modify) {
BitStream bits, bitsOut;
VOLInfo vol = _vol;
VOPInfo vop = new VOPInfo();
bits = new BitStream(data);
if (modify) {
bitsOut = new BitStream(data.Length);
bits.CopyDest = bitsOut;
}
else {
bitsOut = null;
}
bits.Copy(32);
vop.coding_type = bits.Copy(2);
while (bits.Copy(1) == 1) {
vop.modulo_time_base++;
}
bits.Copy(1);
vop.time_inc = bits.Copy(vol.time_inc_bits);
bits.Copy(1);
vop.coded = ToBool(bits.Copy(1));
vop.vop_type = vop.coded ? (VOPType)vop.coding_type : VOPType.N_VOP;
vop.is_reference_vop = vop.coded && (vop.vop_type != VOPType.B_VOP);
if (vop.coded) {
if (vol.newpred_enable) {
int vop_id_bits = Math.Min(vol.time_inc_bits + 3, 15);
bits.Copy(vop_id_bits);
if (bits.Copy(1) == 1) {
bits.Copy(vop_id_bits);
}
bits.Copy(1);
}
if ( (vol.shape != (uint)VOLShape.BinaryOnly) &&
( (vop.coding_type == (uint)VOPType.P_VOP) ||
( (vop.coding_type == (uint)VOPType.S_VOP) && (vol.sprite_enable == (uint)Sprite.GMC) ) ) )
{
bits.Copy(1);
}
if ( vol.reduced_resolution_enable &&
(vol.shape == (uint)VOLShape.Rectangular) &&
( (vop.coding_type == (uint)VOPType.P_VOP) || (vop.coding_type == (uint)VOPType.I_VOP) ) )
{
bits.Copy(1);
}
if (vol.shape != (uint)VOLShape.Rectangular) {
if ( !( (vol.sprite_enable == (uint)Sprite.Static) &&
(vop.coding_type == (uint)VOPType.I_VOP) ) )
{
// 56 bits
bits.Copy(32);
bits.Copy(24);
}
bits.Copy(1);
if (bits.Copy(1) == 1) {
bits.Copy(8);
}
}
if (vol.shape != (uint)VOLShape.BinaryOnly) {
bits.Copy(3);
if (vol.interlaced) {
vop.top_field_first = ToBool(bits.Read(1));
if (modify) {
bitsOut.Write( (_tff ? 1U : 0U) , 1);
}
bits.Copy(1);
}
}
if ( (vol.sprite_enable != (uint)Sprite.None) &&
(vop.coding_type == (uint)VOPType.S_VOP) )
{
vop.warping_points_used = 0;
for (int i = 1; i <= vol.sprite_warping_points; i++) {
bool x_used = CopyWarpingCode(bits);
bool y_used = CopyWarpingCode(bits);
if (x_used || y_used) {
vop.warping_points_used = (uint)i;
}
}
}
}
if (modify) {
while (bits.Remaining > 0) {
bits.Copy(Math.Min(bits.Remaining, 32));
}
}
_vop = vop;
return modify ? bitsOut.GetBytes(bitsOut.Position / 8) : null;
}
private byte[] ParseVOL(byte[] data, bool modify) {
BitStream bits, bitsOut;
VOLInfo vol = new VOLInfo();
bits = new BitStream(data);
if (modify) {
bitsOut = new BitStream(data.Length + 16);
bits.CopyDest = bitsOut;
}
else {
bitsOut = null;
}
bits.Copy(32);
bits.Copy(9);
if (bits.Copy(1) == 1) {
vol.ver_id = bits.Copy(4);
bits.Copy(3);
}
else {
vol.ver_id = 1;
}
// Read PAR info
vol.aspect_ratio = bits.Read(4);
if (vol.aspect_ratio == (uint)PARType.Custom) {
vol.par_width = bits.Read(8);
vol.par_height = bits.Read(8);
}
// Write new PAR info
if (modify) {
bitsOut.Write((uint)_parInfo.Type, 4);
if (_parInfo.Type == PARType.Custom) {
bitsOut.Write(_parInfo.Width, 8);
bitsOut.Write(_parInfo.Height, 8);
}
}
if (bits.Copy(1) == 1) {
bits.Copy(3);
if (bits.Copy(1) == 1) {
// 79 bits
bits.Copy(32);
bits.Copy(32);
bits.Copy(15);
}
}
vol.shape = bits.Copy(2);
if ((vol.ver_id != 1) && (vol.shape == (uint)VOLShape.Grayscale)) {
bits.Copy(4);
}
bits.Copy(1);
vol.time_inc_res = bits.Copy(16);
vol.time_inc_bits = Math.Max(BitsUsed(vol.time_inc_res - 1), 1);
bits.Copy(1);
if (bits.Copy(1) == 1) {
bits.Copy(vol.time_inc_bits);
}
if (vol.shape != (uint)VOLShape.BinaryOnly) {
if (vol.shape == (uint)VOLShape.Rectangular) {
bits.Copy(29);
}
vol.interlaced = ToBool(bits.Copy(1));
bits.Copy(1);
vol.sprite_enable = bits.Copy( vol.ver_id == 1 ? 1 : 2 );
if (vol.sprite_enable != (uint)Sprite.None) {
if (vol.sprite_enable == (uint)Sprite.Static) {
// 56 bits
bits.Copy(32);
bits.Copy(24);
}
vol.sprite_warping_points = bits.Copy(6);
if (vol.sprite_warping_points > 4) {
throw new Exception("Invalid VOL (too many warping points)");
}
bits.Copy(3);
if (vol.sprite_enable == (uint)Sprite.Static) {
bits.Copy(1);
}
}
if ((vol.ver_id != 1) && (vol.shape != (uint)VOLShape.Rectangular)) {
bits.Copy(1);
}
if (bits.Copy(1) == 1) {
bits.Copy(8);
}
if (vol.shape == (uint)VOLShape.Grayscale) {
bits.Copy(3);
}
vol.mpeg_quant = ToBool(bits.Copy(1));
if (vol.mpeg_quant) {
vol.load_intra_quant_mat = ToBool(bits.Copy(1));
if (vol.load_intra_quant_mat) {
vol.intra_quant_mat = CopyQuantMatrix(bits);
}
vol.load_inter_quant_mat = ToBool(bits.Copy(1));
if (vol.load_inter_quant_mat) {
vol.inter_quant_mat = CopyQuantMatrix(bits);
}
if (vol.shape == (uint)VOLShape.Grayscale) {
throw new Exception("Grayscale matrix isn't supported");
}
}
if (vol.ver_id != 1) {
vol.quarterpel = ToBool(bits.Copy(1));
}
if (bits.Copy(1) == 0) {
throw new Exception("Complexity estimation isn't supported");
}
bits.Copy(1);
if (bits.Copy(1) == 1) {
bits.Copy(1);
}
if (vol.ver_id != 1) {
vol.newpred_enable = ToBool(bits.Copy(1));
if (vol.newpred_enable) {
bits.Copy(3);
}
vol.reduced_resolution_enable = ToBool(bits.Copy(1));
}
if (bits.Copy(1) == 1) {
throw new Exception("Scalability isn't supported");
}
}
else {
if (vol.ver_id != 1) {
if (bits.Copy(1) == 1) {
throw new Exception("Scalability isn't supported");
}
}
bits.Copy(1);
}
// Check padding (padding should be present even if the data already ends on
// a byte boundary, but if there's no padding we will just ignore it)
if ((bits.Remaining < 0) || (bits.Remaining > 8)) {
throw new Exception("Invalid VOL");
}
bits.Copy(bits.Remaining);
_vol = vol;
return modify ? bitsOut.GetBytes(bitsOut.Position / 8) : null;
}