EveryFileExplorer/LegoPirates/FMV.cs
Gericom 381ef84ce5 Added Lego Pirates of the Carribean FMV format
Also, added an error when trying to open a dll from external sources
(instead of an exception).
Auto creates Plugins directory, and copies the libraries.
2014-11-04 17:36:37 +01:00

1257 lines
36 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using LibEveryFileExplorer.Files;
using LibEveryFileExplorer.IO;
using System.Drawing;
namespace LegoPirates
{
public class FMV : FileFormat<FMV.FMVIdentifier>, IViewable
{
private readonly static byte[] QuantizationGenerationTable1 = {
0x10, 0x10, 0x10, 0x10, 0x11, 0x12, 0x15, 0x18, 0x10, 0x10, 0x10, 0x10,
0x11, 0x13, 0x16, 0x19, 0x10, 0x10, 0x11, 0x12, 0x14, 0x16, 0x19, 0x1D,
0x10, 0x10, 0x12, 0x15, 0x18, 0x1B, 0x1F, 0x24, 0x11, 0x11, 0x14, 0x18,
0x1E, 0x23, 0x29, 0x2F, 0x12, 0x13, 0x16, 0x1B, 0x23, 0x2C, 0x36, 0x41,
0x15, 0x16, 0x19, 0x1F, 0x29, 0x36, 0x46, 0x58, 0x18, 0x19, 0x1D, 0x24,
0x2F, 0x41, 0x58, 0x73, 0x11, 0x12, 0x18, 0x2F, 0x63, 0x63, 0x63, 0x63,
0x12, 0x15, 0x1A, 0x42, 0x63, 0x63, 0x63, 0x63, 0x18, 0x1A, 0x38, 0x63,
0x63, 0x63, 0x63, 0x63, 0x2F, 0x42, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63
};
private readonly static byte[] QuantizationGenerationTable2 = {
0x10, 0x0B, 0x0A, 0x10, 0x18, 0x28, 0x33, 0x3D, 0x0C, 0x0C, 0x0E, 0x13,
0x1A, 0x3A, 0x3C, 0x37, 0x0E, 0x0D, 0x10, 0x18, 0x28, 0x39, 0x45, 0x38,
0x0E, 0x11, 0x16, 0x1D, 0x33, 0x57, 0x50, 0x3E, 0x12, 0x16, 0x25, 0x38,
0x44, 0x6D, 0x67, 0x4D, 0x18, 0x23, 0x37, 0x40, 0x51, 0x68, 0x71, 0x5C,
0x31, 0x40, 0x4E, 0x57, 0x67, 0x79, 0x78, 0x65, 0x48, 0x5C, 0x5F, 0x62,
0x70, 0x64, 0x67, 0x63, 0x11, 0x12, 0x18, 0x2F, 0x63, 0x63, 0x63, 0x63,
0x12, 0x15, 0x1A, 0x42, 0x63, 0x63, 0x63, 0x63, 0x18, 0x1A, 0x38, 0x63,
0x63, 0x63, 0x63, 0x63, 0x2F, 0x42, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63
};
private readonly static uint[] AnotherQuantizationGenerationTable = {
0x10000,
0x16315,
0x14E7B,
0x12D06,
0x10000,
0xC923,
0x8A8C,
0x46A1
};
private readonly static byte[] ZigZagTable = {
0x00, 0x08, 0x01, 0x02, 0x09, 0x10, 0x18, 0x11, 0x0A, 0x03, 0x04, 0x0B,
0x12, 0x19, 0x20, 0x28, 0x21, 0x1A, 0x13, 0x0C, 0x05, 0x06, 0x0D, 0x14,
0x1B, 0x22, 0x29, 0x30, 0x38, 0x31, 0x2A, 0x23, 0x1C, 0x15, 0x0E, 0x07,
0x0F, 0x16, 0x1D, 0x24, 0x2B, 0x32, 0x39, 0x3A, 0x33, 0x2C, 0x25, 0x1E,
0x17, 0x1F, 0x26, 0x2D, 0x34, 0x3B, 0x3C, 0x35, 0x2E, 0x27, 0x2F, 0x36,
0x3D, 0x3E, 0x37, 0x3F
};
private FMVInfo Info;
public FMV(byte[] Data)
{
EndianBinaryReader er = new EndianBinaryReader(new MemoryStream(Data), Endianness.LittleEndian);
try
{
Header = new FMVHeader(er);
Info = new FMVInfo(this, er);
}
catch
{
er.Close();
}
}
public System.Windows.Forms.Form GetDialog()
{
return new UI.FMVViewer(this);
}
public FMVHeader Header;
public class FMVHeader
{
public FMVHeader(EndianBinaryReader er)
{
Signature = er.ReadString(Encoding.ASCII, 4);
if (Signature != "FMV!") throw new SignatureNotCorrectException(Signature, "FMV!", er.BaseStream.Position - 4);
Version = er.ReadUInt16();
HeaderLength = er.ReadUInt16();
Width = er.ReadUInt16();
Height = er.ReadUInt16();
NrBlocks = er.ReadUInt32();
Unknown1 = er.ReadUInt32();
FrameRate = er.ReadUInt16();
Flags = er.ReadUInt32();
Unknown2 = er.ReadUInt32();
if ((Flags & 4) == 4)
{
Unknown3 = er.ReadUInt16();
AudioRate = er.ReadUInt32();
Unknown4 = er.ReadByte();
Unknown5 = er.ReadByte();
Unknown6 = er.ReadByte();
Unknown7 = er.ReadByte();
}
}
public String Signature;
public UInt16 Version;
public UInt16 HeaderLength;
public UInt16 Width;
public UInt16 Height;
public UInt32 NrBlocks;
public UInt32 Unknown1;
public UInt16 FrameRate;
public UInt32 Flags;
public UInt32 Unknown2;
//If Flags & 4, means audio
public UInt16 Unknown3;
public UInt32 AudioRate;
public Byte Unknown4;
public Byte Unknown5;
public Byte Unknown6;
public Byte Unknown7;
}
private class FMVk
{
public FMVk(FMVInfo Info, bool Tables)
{
Signature = Info.er.ReadString(Encoding.ASCII, 4);
if (Signature != "FMVk") throw new SignatureNotCorrectException(Signature, "FMVk", Info.er.BaseStream.Position - 4);
SectionSize = Info.er.ReadUInt32();
FrameBlockDataSize = Info.er.ReadUInt16();
FrameBlockData = DecompressRLE(Info.er.ReadBytes(FrameBlockDataSize), 0, FrameBlockDataSize);
Quality = Info.er.ReadByte();
int total = 0;
if (Tables)
{
TableInfo1a = Info.er.ReadBytes(16);
int q = 0;
foreach (byte b in TableInfo1a) q += b;
Table1a = Info.er.ReadBytes(q);
total += q + 16;
TableInfo2a = Info.er.ReadBytes(16);
q = 0;
foreach (byte b in TableInfo2a) q += b;
Table2a = Info.er.ReadBytes(q);
total += q + 16;
TableInfo1b = Info.er.ReadBytes(16);
q = 0;
foreach (byte b in TableInfo1b) q += b;
Table1b = Info.er.ReadBytes(q);
total += q + 16;
TableInfo2b = Info.er.ReadBytes(16);
q = 0;
foreach (byte b in TableInfo2b) q += b;
Table2b = Info.er.ReadBytes(q);
total += q + 16;
ReadTable(Info, TableInfo1a, Table1a, 0, 0);
ReadTable(Info, TableInfo2a, Table2a, 1, 0);
ReadTable(Info, TableInfo1b, Table1b, 0, 1);
ReadTable(Info, TableInfo2b, Table2b, 1, 1);
}
FrameData = Info.er.ReadBytes((int)SectionSize - 3 - FrameBlockDataSize - total);//(Tables ? 0x19C : 0));
}
public String Signature;
public UInt32 SectionSize;
public UInt16 FrameBlockDataSize;
public byte[] FrameBlockData;
public byte Quality;
public byte[] TableInfo1a;
public byte[] Table1a;
public byte[] TableInfo2a;
public byte[] Table2a;
public byte[] TableInfo1b;
public byte[] Table1b;
public byte[] TableInfo2b;
public byte[] Table2b;
public byte[] FrameData;
private void ReadTable(FMVInfo Info, byte[] TableInfo, byte[] Table, int r1, int r2)
{
if (r1 == 1)
{
CreateTables(ref Info.field_1200[r2], ref Info.field_1600[r2], ref Info.field_1900[r2], ref Info.field_1A04[r2], ref Info.field_1A4C[r2], TableInfo);
Info.field_1800[r2] = new byte[Table.Length];
Array.Copy(Table, Info.field_1800[r2], Table.Length);
}
else
{
CreateTables(ref Info.field_0[r2], ref Info.field_400[r2], ref Info.field_700[r2], ref Info.field_804[r2], ref Info.field_84C[r2], TableInfo);
Info.field_600[r2] = new byte[Table.Length];
Array.Copy(Table, Info.field_600[r2], Table.Length);
}
}
private void CreateTables(ref byte[] Table0x0, ref ushort[] Table0x400, ref byte[] Table0x700, ref uint[] Table0x804, ref uint[] Table0x84C, byte[] TableInfo)
{
List<byte> data = new List<byte>();
for (int i = 0; i < 16; i++)
{
for (int j = 0; j < TableInfo[i]; j++)
{
data.Add((byte)((i + 1) & 0xFF));
}
}
data.Add(0);
Table0x700 = data.ToArray();
Table0x804 = new uint[18];
Table0x84C = new uint[18];
List<ushort> table0x400 = new List<ushort>();
uint v7 = 0;
int v8 = 0;
int v9 = 1;
do
{
for (Table0x84C[v9] = (uint)(v8 - v7); v9 == Table0x700[v8]; table0x400.Add((ushort)v7++), v8++) ;
uint v10 = v7 << (16 - v9);
Table0x804[v9++] = v10;
v7 *= 2;
}
while (v9 <= 16);
Table0x804[v9] = 0xFFFFFFFF;
Table0x400 = table0x400.ToArray();
Table0x0 = new byte[0x400];
//This just fills with 0xFF
//ushort[] _data = new ushort[0x200];
//sub_213474C(ref _data, 0xFF, 0x400);
for (int i = 0; i < 0x400; i++)
{
Table0x0[i] = 0xFF;
}
for (int i = 0; i < v8; i++)
{
int v13 = Table0x700[i];
if (v13 <= 10)
{
int v14 = 10 - v13;
int v15 = 1 << v14;
int v16 = 0;
int v17 = Table0x400[i];
if (1 << v14 > 0)
{
do
{
Table0x0[(v17 << v14) + v16++] = (byte)i;
}
while (v16 < v15);
}
}
}
}
}
private class FMVd
{
public FMVd(FMVInfo Info)
{
Signature = Info.er.ReadString(Encoding.ASCII, 4);
if (Signature != "FMVd") throw new SignatureNotCorrectException(Signature, "FMVd", Info.er.BaseStream.Position - 4);
SectionSize = Info.er.ReadUInt32();
FrameBlockDataSize = Info.er.ReadUInt16();
FrameBlockData = DecompressRLE(Info.er.ReadBytes(FrameBlockDataSize), 0, FrameBlockDataSize);
Marker = Info.er.ReadByte();
FrameData = Info.er.ReadBytes((int)SectionSize - 3 - FrameBlockDataSize);
}
public String Signature;
public UInt32 SectionSize;
public UInt16 FrameBlockDataSize;
public byte[] FrameBlockData;
public byte Marker;//?
public byte[] FrameData;
}
public Bitmap GetNextFrame(out byte[] Audio)
{
if (Info.er != null && Info.er.BaseStream.Position >= Info.er.BaseStream.Length)
{
Info.er.Close();
Info.er = null;
Audio = null;
return null;
}
Audio = null;
String s = Info.er.ReadString(Encoding.ASCII, 4);
Info.er.BaseStream.Position -= 4;
switch (s)
{
case "FMVk":
{
var v = new FMVk(Info, Info.FirstKeyFrame);
Info.FirstKeyFrame = false;
GenerateQuantizationTables(Info, v.Quality);
Info.LastFrame = ToBitmap(Info, v.FrameBlockData, v.FrameData);
return Info.LastFrame;
}
case "FMVd":
{
var v = new FMVd(Info);
GenerateQuantizationTables(Info, v.Marker);
Info.LastFrame = ToBitmap(Info, v.FrameBlockData, v.FrameData);
return Info.LastFrame;
}
case "FMVn":
Info.er.BaseStream.Position += 8;
return Info.LastFrame;
case "FMA\0":
Info.er.BaseStream.Position += 4;
int length = (int)Info.er.ReadUInt32();
Audio = Info.er.ReadBytes(length);
return null;
default:
return null;
}
}
public void Close()
{
if (Info.er != null)
{
Info.er.Close();
Info.er = null;
}
}
private static void GenerateQuantizationTables(FMVInfo Info, uint Quality)
{
uint r0;
uint r1 = Quality;
uint r2;
uint r3;
uint r4;
uint r6;
uint r7;
uint r8;
uint r11;
uint r12;
uint lr;
byte[] QuantizationGenerationTable = QuantizationGenerationTable1;//If 16 bit at offset 4 in header == 0x113
Info.QuantizationTables[0] = new uint[64];
Info.QuantizationTables[1] = new uint[64];
if (r1 <= 0) r1 = 1;
if (r1 > 100) r1 = 100;
if (r1 >= 50)
{
r0 = r1 << 1;
r0 = 0xC8 - r0;
}
else
{
r0 = 0x1388 / r1;
//r0 = 0;
}
r7 = 0;
while (true)
{
r6 = 0;
r1 = 0x51EB851F;
r11 = 1;
while (true)
{
r2 = QuantizationGenerationTable[64 * r7 + r6];
r4 = (uint)((int)r6 >> 3);
r12 = r6 & 7;
r2 = r0 * r2;
r3 = r2 + 0x32;
ulong tmpl = (ulong)(((long)(int)r1) * ((long)(int)r3));
r2 = (uint)(tmpl & 0xFFFFFFFF);
r8 = (uint)((tmpl >> 32) & 0xFFFFFFFF);
r2 = r3 >> 31;
r3 = AnotherQuantizationGenerationTable[r12];
lr = AnotherQuantizationGenerationTable[r4];
r8 = r2 + (uint)((int)r8 >> 5);
tmpl = (ulong)(((long)(int)lr) * ((long)(int)r3));
r12 = (uint)(tmpl & 0xFFFFFFFF);
r3 = (uint)((tmpl >> 32) & 0xFFFFFFFF);
if (r8 <= 0) r8 = r11;
r12 >>= 16;
if (r8 > 255) r8 = 255;
r12 |= r3 << 16;
tmpl = (ulong)(((long)(int)r8) * ((long)(int)r12));
r3 = (uint)(tmpl & 0xFFFFFFFF);
r12 = (uint)((tmpl >> 32) & 0xFFFFFFFF);
r12 = r6 << 29;
r6++;
r4 += r12 >> 26;
Info.QuantizationTables[r7][r4] = r3;
if (r6 >= 0x40) break;
}
r7++;
if (r7 >= 2) break;
}
}
private static Bitmap ToBitmap(FMVInfo Info, byte[] FrameBlockData, byte[] FrameData)
{
Info.BitReg = 0;
Info.BitRegNrBits = 0;
Info.PhaseInfos[0].Field10 = 0;
Info.PhaseInfos[1].Field10 = 0;
Info.PhaseInfos[2].Field10 = 0;
int offset = 0;
for (int y = 0; y < Info.NrTilesY; y++)
{
for (int x = 0; x < Info.NrTilesX; x++)
{
int type = FrameBlockData[y * Info.NrTilesX + x];
switch (type)
{
case 0:
{
}
break;
case 1:
{
if (Info.BitRegNrBits < 5) FillBits(FrameData, ref Info.BitReg, ref Info.BitRegNrBits, ref offset);
Info.BitRegNrBits -= 5;
int a = (int)(Info.BitReg >> Info.BitRegNrBits) & 0x1F;
if (a > 15) a -= 32;
if (Info.BitRegNrBits < 5) FillBits(FrameData, ref Info.BitReg, ref Info.BitRegNrBits, ref offset);
Info.BitRegNrBits -= 5;
int b = (int)(Info.BitReg >> Info.BitRegNrBits) & 0x1F;
if (b > 15) b -= 32;
for (int _y = 0; _y < 16; _y++)
{
for (int _x = 0; _x < 16; _x++)
{
Info.PhaseInfos[0].PhaseData[((y * 16) + _y) * Info.PhaseInfos[0].PhaseDataWidth + ((x * 16) + _x)] = Info.PhaseInfos[0].PhaseDataOld[(((y * 16) + _y) - b) * Info.PhaseInfos[0].PhaseDataWidth + ((x * 16) + _x) - a];
}
}
for (int _y = 0; _y < 8; _y++)
{
for (int _x = 0; _x < 8; _x++)
{
Info.PhaseInfos[1].PhaseData[((y * 8) + _y) * Info.PhaseInfos[1].PhaseDataWidth + ((x * 8) + _x)] = Info.PhaseInfos[1].PhaseDataOld[(((y * 8) + _y) - b / 2) * Info.PhaseInfos[1].PhaseDataWidth + ((x * 8) + _x) - a / 2];
}
}
for (int _y = 0; _y < 8; _y++)
{
for (int _x = 0; _x < 8; _x++)
{
Info.PhaseInfos[2].PhaseData[((y * 8) + _y) * Info.PhaseInfos[2].PhaseDataWidth + ((x * 8) + _x)] = Info.PhaseInfos[2].PhaseDataOld[(((y * 8) + _y) - b / 2) * Info.PhaseInfos[2].PhaseDataWidth + ((x * 8) + _x) - a / 2];
}
}
}
break;
case 2:
{
if (Info.BitRegNrBits < 8) FillBits(FrameData, ref Info.BitReg, ref Info.BitRegNrBits, ref offset);
Info.BitRegNrBits -= 8;
int a = (int)(Info.BitReg >> Info.BitRegNrBits) & 0xFF;
if (Info.BitRegNrBits < 8) FillBits(FrameData, ref Info.BitReg, ref Info.BitRegNrBits, ref offset);
Info.BitRegNrBits -= 8;
int b = (int)(Info.BitReg >> Info.BitRegNrBits) & 0xFF;
if (Info.BitRegNrBits < 8) FillBits(FrameData, ref Info.BitReg, ref Info.BitRegNrBits, ref offset);
Info.BitRegNrBits -= 8;
int c = (int)(Info.BitReg >> Info.BitRegNrBits) & 0xFF;
for (int _y = 0; _y < 16; _y++)
{
for (int _x = 0; _x < 16; _x++)
{
Info.PhaseInfos[0].PhaseData[((y * 16) + _y) * Info.PhaseInfos[0].PhaseDataWidth + ((x * 16) + _x)] = (byte)a;
}
}
for (int _y = 0; _y < 8; _y++)
{
for (int _x = 0; _x < 8; _x++)
{
Info.PhaseInfos[1].PhaseData[((y * 8) + _y) * Info.PhaseInfos[1].PhaseDataWidth + ((x * 8) + _x)] = (byte)b;
}
}
for (int _y = 0; _y < 8; _y++)
{
for (int _x = 0; _x < 8; _x++)
{
Info.PhaseInfos[2].PhaseData[((y * 8) + _y) * Info.PhaseInfos[2].PhaseDataWidth + ((x * 8) + _x)] = (byte)c;
}
}
}
break;
case 255:
{
for (int i = 0; i < Info.NrPhases; i++)
{
for (int j = 0; j < Info.PhaseInfos[i].NrBlocksX * Info.PhaseInfos[i].NrBlocksY; j++)
{
ushort[] r7 = new ushort[0x40];
if (Info.BitRegNrBits < 16) FillBits(FrameData, ref Info.BitReg, ref Info.BitRegNrBits, ref offset);
int a = (int)(Info.BitReg >> (Info.BitRegNrBits - 10)) & 0x3FF;
int q = Info.field_0[Info.PhaseInfos[i].Table1Idx][a];
int r10;
if (q >= 255)
{
uint v12;
if (Info.BitRegNrBits >= 16) v12 = Info.BitReg >> (Info.BitRegNrBits - 16);
else v12 = Info.BitReg << (16 - Info.BitRegNrBits);
v12 &= 0xFFFF;
int qq = 0xB;
while (true)
{
if (v12 >= Info.field_804[Info.PhaseInfos[i].Table1Idx][qq]) qq++;
else break;
}
int v16 = (int)(((1 << qq) - 1) & (Info.BitReg >> (Info.BitRegNrBits - qq))) + (int)Info.field_84C[Info.PhaseInfos[i].Table1Idx][qq];//*(v15 + 531);
Info.BitRegNrBits -= qq;
r10 = Info.field_600[Info.PhaseInfos[i].Table1Idx][v16];
}
else
{
int q2 = Info.field_700[Info.PhaseInfos[i].Table1Idx][q];
Info.BitRegNrBits -= q2;
r10 = Info.field_600[Info.PhaseInfos[i].Table1Idx][q];
}
uint _r5 = 0;
sub_213474C(ref r7, 0, 0x80);
if (r10 != 0)
{
if (Info.BitRegNrBits < r10) FillBits(FrameData, ref Info.BitReg, ref Info.BitRegNrBits, ref offset);
Info.BitRegNrBits -= r10;
int mask = (1 << r10) - 1;
_r5 = (uint)((int)(Info.BitReg >> Info.BitRegNrBits) & mask);
if (_r5 < (1 << (r10 - 1)))
{
uint _r0 = 0xFFFFFFFF;
_r0 = _r5 + (_r0 << r10);
_r5 = (uint)(((int)_r0) + 1);
}
}
Info.PhaseInfos[i].Field10 += (int)_r5;
r7[0] = (ushort)Info.PhaseInfos[i].Field10;
int counter = 1;
while (true)
{
if (Info.BitRegNrBits < 16) FillBits(FrameData, ref Info.BitReg, ref Info.BitRegNrBits, ref offset);
int c = (int)(Info.BitReg >> (Info.BitRegNrBits - 10)) & 0x3FF;
int qc = Info.field_1200[Info.PhaseInfos[i].Table2Idx][c];
int r1;
if (qc >= 255)
{
uint r0;
if (Info.BitRegNrBits < 16)
{
r0 = 16 - (uint)Info.BitRegNrBits;
r0 = (uint)(Info.BitReg << (int)r0);
}
else
{
r0 = (uint)Info.BitRegNrBits - 16;
r0 = (uint)(Info.BitReg >> (int)r0);
}
r0 <<= 16;
uint r9 = r0 >> 16;
int r3 = 0xB;
while (true)
{
if (r9 >= Info.field_1A04[Info.PhaseInfos[i].Table2Idx][r3]) r3++;
else break;
}
uint r5 = (uint)1 << r3;
r9 = r5 - 1;
r5 = (uint)(Info.BitRegNrBits - r3);
r5 = r9 & (Info.BitReg >> (int)r5);
int r2 = (int)Info.field_1A4C[Info.PhaseInfos[i].Table2Idx][r3];
Info.BitRegNrBits -= r3;
r1 = Info.field_1800[Info.PhaseInfos[i].Table2Idx][r5 + r2];
}
else
{
int q2c = Info.field_1900[Info.PhaseInfos[i].Table2Idx][qc];
Info.BitRegNrBits -= q2c;
r1 = Info.field_1800[Info.PhaseInfos[i].Table2Idx][qc];
}
r10 = r1 & 0xF;
if (r10 != 0)
{
counter += r1 >> 4;
if (Info.BitRegNrBits < r10) FillBits(FrameData, ref Info.BitReg, ref Info.BitRegNrBits, ref offset);
Info.BitRegNrBits -= r10;
int mask = (1 << r10) - 1;
uint d = (uint)((Info.BitReg >> Info.BitRegNrBits) & mask);
uint r0;
if (d < (1 << (r10 - 1)))
{
r0 = 0xFFFFFFFF;
r0 = (uint)(d + (r0 << r10));
d = r0 + 1;
}
r0 = ZigZagTable[counter];
counter++;
r7[r0] = (ushort)d;
}
else if (r1 != 0xF0) break;
else counter += 16;
if (counter >= 0x40) goto con;
continue;
}
con:
byte[] data = sub_20A66B0(r7, Info.QuantizationTables[Info.PhaseInfos[i].QTIdx]);
if (i == 0)
{
for (int qq = 0; qq < 64; qq++)
{
int _x = (qq % 8) + x * 16 + (j % 2 * 8);
int _y = (qq / 8) + y * 16 + (j / 2 * 8);
Info.PhaseInfos[i].PhaseData[_y * Info.PhaseInfos[i].PhaseDataWidth + _x] = data[qq];
}
}
else if (i == 1)
{
for (int qq = 0; qq < 64; qq++)
{
int _x = (qq % 8) + x * 8;
int _y = (qq / 8) + y * 8;
Info.PhaseInfos[i].PhaseData[_y * Info.PhaseInfos[i].PhaseDataWidth + _x] = data[qq];
}
}
else
{
for (int qq = 0; qq < 64; qq++)
{
int _x = (qq % 8) + x * 8;
int _y = (qq / 8) + y * 8;
Info.PhaseInfos[i].PhaseData[_y * Info.PhaseInfos[i].PhaseDataWidth + _x] = data[qq];
}
}
continue;
}
}
}
break;
}
}
}
Bitmap bb4 = new Bitmap(Info.Width, Info.Height);
for (int y = 0; y < Info.Height; y++)
{
for (int x = 0; x < Info.Width; x++)
{
float Y = Info.PhaseInfos[0].PhaseData[y * Info.PhaseInfos[0].PhaseDataWidth + x] / 256f;
float U = Info.PhaseInfos[1].PhaseData[y / 2 * Info.PhaseInfos[1].PhaseDataWidth + x / 2] / 256f - 0.5f;
float V = Info.PhaseInfos[2].PhaseData[y / 2 * Info.PhaseInfos[2].PhaseDataWidth + x / 2] / 256f - 0.5f;
float R = Y + V * 1.13983f;
float G = Y - U * 0.39465f - V * 0.58060f;
float B = Y + U * 2.03211f;
if (R < 0) R = 0;
if (R > 1) R = 1;
if (G < 0) G = 0;
if (G > 1) G = 1;
if (B < 0) B = 0;
if (B > 1) B = 1;
bb4.SetPixel(x, y, Color.FromArgb((int)(R * 255), (int)(G * 255), (int)(B * 255)));
}
}
Array.Copy(Info.PhaseInfos[0].PhaseData, Info.PhaseInfos[0].PhaseDataOld, Info.PhaseInfos[0].PhaseData.Length);
Array.Copy(Info.PhaseInfos[1].PhaseData, Info.PhaseInfos[1].PhaseDataOld, Info.PhaseInfos[1].PhaseData.Length);
Array.Copy(Info.PhaseInfos[2].PhaseData, Info.PhaseInfos[2].PhaseDataOld, Info.PhaseInfos[2].PhaseData.Length);
return bb4;
}
private static void FillBits(byte[] FrameData, ref uint bitreg, ref int nrbits, ref int offset)
{
while (nrbits <= 24)
{
byte a;
if (offset + 1 < FrameData.Length) a = FrameData[offset++];
else a = 0;
bitreg = bitreg << 8 | a;
nrbits += 8;
}
}
private static void sub_213474C(ref ushort[] r0, uint r1, uint r2)
{
byte[] data = new byte[r0.Length * 2];
for (int i = 0; i < r0.Length; i++)
{
data[i * 2] = (byte)(r0[i] & 0xFF);
data[i * 2 + 1] = (byte)((r0[i] >> 8) & 0xFF);
}
int Offset = 0;
uint r3 = r1 & 0xFF;
if (r2 >= 0x20)
{
if (r3 != 0)
{
r1 = r3 << 16;
r1 |= r3 << 24;
r1 |= r3 << 8;
r3 |= r1;
}
r1 = r2 >> 5;
while (r1 != 0)
{
//0
data[Offset++] = (byte)(r3 & 0xFF);
data[Offset++] = (byte)((r3 >> 8) & 0xFF);
data[Offset++] = (byte)((r3 >> 16) & 0xFF);
data[Offset++] = (byte)((r3 >> 24) & 0xFF);
//4
data[Offset++] = (byte)(r3 & 0xFF);
data[Offset++] = (byte)((r3 >> 8) & 0xFF);
data[Offset++] = (byte)((r3 >> 16) & 0xFF);
data[Offset++] = (byte)((r3 >> 24) & 0xFF);
//8
data[Offset++] = (byte)(r3 & 0xFF);
data[Offset++] = (byte)((r3 >> 8) & 0xFF);
data[Offset++] = (byte)((r3 >> 16) & 0xFF);
data[Offset++] = (byte)((r3 >> 24) & 0xFF);
//12
data[Offset++] = (byte)(r3 & 0xFF);
data[Offset++] = (byte)((r3 >> 8) & 0xFF);
data[Offset++] = (byte)((r3 >> 16) & 0xFF);
data[Offset++] = (byte)((r3 >> 24) & 0xFF);
//16
data[Offset++] = (byte)(r3 & 0xFF);
data[Offset++] = (byte)((r3 >> 8) & 0xFF);
data[Offset++] = (byte)((r3 >> 16) & 0xFF);
data[Offset++] = (byte)((r3 >> 24) & 0xFF);
//20
data[Offset++] = (byte)(r3 & 0xFF);
data[Offset++] = (byte)((r3 >> 8) & 0xFF);
data[Offset++] = (byte)((r3 >> 16) & 0xFF);
data[Offset++] = (byte)((r3 >> 24) & 0xFF);
//24
data[Offset++] = (byte)(r3 & 0xFF);
data[Offset++] = (byte)((r3 >> 8) & 0xFF);
data[Offset++] = (byte)((r3 >> 16) & 0xFF);
data[Offset++] = (byte)((r3 >> 24) & 0xFF);
//28
data[Offset++] = (byte)(r3 & 0xFF);
data[Offset++] = (byte)((r3 >> 8) & 0xFF);
data[Offset++] = (byte)((r3 >> 16) & 0xFF);
data[Offset++] = (byte)((r3 >> 24) & 0xFF);
r1--;
}
r1 = r2 & 0x1F;
r1 >>= 2;
while (r1 != 0)
{
data[Offset++] = (byte)(r3 & 0xFF);
data[Offset++] = (byte)((r3 >> 8) & 0xFF);
data[Offset++] = (byte)((r3 >> 16) & 0xFF);
data[Offset++] = (byte)((r3 >> 24) & 0xFF);
r1--;
}
r2 &= 3;
}
if (r2 == 0) goto ret;
r1 = r3 & 0xFF;
while (true)
{
data[Offset++] = (byte)r1;
r2--;
if (r2 == 0) break;
}
ret:
for (int i = 0; i < r0.Length; i++)
{
r0[i] = (ushort)(data[i * 2] | (data[i * 2 + 1] << 8));
}
}
private static byte[] sub_20A66B0(ushort[] indata, uint[] QuantizationTable)
{
byte[] data = new byte[indata.Length * 2];
for (int i = 0; i < indata.Length; i++)
{
data[i * 2] = (byte)(indata[i] & 0xFF);
data[i * 2 + 1] = (byte)((indata[i] >> 8) & 0xFF);
}
int DOffset = 0;
int QTOffset = 0;
int R0Offset = 0;
int R5Offset = 0;
int Counter = 0;
byte[] r0data = new byte[64];
uint[] r5data = new uint[64];
uint r2;
uint r3;
uint r4;
uint r5;
uint r6;
uint r7;
uint r8;
uint r9;
uint r10;
uint r11;
uint r12;
uint lr;
uint SP_660_var_644;
uint SP_660_var_648;
uint SP_660_var_64C;
uint SP_660_var_650;
uint SP_660_var_654;
uint SP_660_var_658;
while (true)
{
bool tmp;
r8 = (uint)(int)IOUtil.ReadS16LE(data, DOffset + 2);
if (tmp = r8 == 0)
{
r4 = IOUtil.ReadU32LE(data, DOffset + 4);
if (tmp = r4 == 0)
{
r4 = IOUtil.ReadU32LE(data, DOffset + 8);
if (tmp = r4 == 0)
{
r4 = IOUtil.ReadU32LE(data, DOffset + 12);
tmp = r4 == 0;
}
}
}
if (tmp)
{
r6 = (uint)(int)IOUtil.ReadS16LE(data, DOffset + 0);
r4 = QuantizationTable[QTOffset + 0];
r4 = r6 * r4;
r5data[R5Offset + 0] = r4;
r5data[R5Offset + 8] = r4;
r5data[R5Offset + 16] = r4;
r5data[R5Offset + 24] = r4;
r5data[R5Offset + 32] = r4;
r5data[R5Offset + 40] = r4;
r5data[R5Offset + 48] = r4;
r5data[R5Offset + 56] = r4;
goto loc_20A687C;
}
r7 = QuantizationTable[QTOffset + 1];
r6 = (uint)(int)IOUtil.ReadS16LE(data, DOffset + 6);
lr = r8 * r7;
r4 = QuantizationTable[QTOffset + 3];
r8 = (uint)(int)IOUtil.ReadS16LE(data, DOffset + 10);
r7 = r6 * r4;
r6 = QuantizationTable[QTOffset + 5];
r4 = (uint)(int)IOUtil.ReadS16LE(data, DOffset + 0);
r9 = QuantizationTable[QTOffset + 0];
r6 = r8 * r6;
r12 = r4 * r9;
r8 = (uint)(int)IOUtil.ReadS16LE(data, DOffset + 4);
r4 = QuantizationTable[QTOffset + 2];
r10 = (uint)(int)IOUtil.ReadS16LE(data, DOffset + 8);
r4 = r8 * r4;
r9 = QuantizationTable[QTOffset + 4];
r8 = (uint)(int)IOUtil.ReadS16LE(data, DOffset + 12);
r11 = QuantizationTable[QTOffset + 6];
r9 = r10 * r9;
r11 = r8 * r11;
r10 = r12 + r9;
r9 = r12 - r9;
r8 = r4 + r11;
r12 = r4 - r11;
r4 = 0x16A0A;
ulong tmpl = (ulong)(((long)(int)r12) * ((long)(int)r4));
r11 = (uint)(tmpl & 0xFFFFFFFF);
r4 = (uint)((tmpl >> 32) & 0xFFFFFFFF);
r11 >>= 16;
r11 |= r4 << 16;
r4 = r11 - r8;
r11 = r10 + r8;
r8 = r10 - r8;
r10 = r9 + r4;
r4 = r9 - r4;
SP_660_var_658 = r4;
SP_660_var_648 = r10;
r10 = r6 + r7;
r9 = (uint)(int)IOUtil.ReadS16LE(data, DOffset + 14);
r4 = QuantizationTable[QTOffset + 7];
r6 = r6 - r7;
r4 = r9 * r4;
r7 = lr + r4;
SP_660_var_64C = r11;
r9 = lr - r4;
r4 = r7 + r10;
r11 = r7 - r10;
r7 = 0x16A0A;
tmpl = (ulong)(((long)(int)r11) * ((long)(int)r7));
r10 = (uint)(tmpl & 0xFFFFFFFF);
r7 = (uint)((tmpl >> 32) & 0xFFFFFFFF);
r11 = r10 >> 16;
r11 |= r7 << 16;
r10 = 0x1D907;
r7 = r6 + r9;
tmpl = (ulong)(((long)(int)r7) * ((long)(int)r10));
r12 = (uint)(tmpl & 0xFFFFFFFF);
r10 = (uint)((tmpl >> 32) & 0xFFFFFFFF);
r7 = r12 >> 16;
SP_660_var_654 = r10;
r7 |= r10 << 16;
r10 = 0x11518;
tmpl = (ulong)(((long)(int)r10) * ((long)(int)r9));
r12 = (uint)(tmpl & 0xFFFFFFFF);
r9 = (uint)((tmpl >> 32) & 0xFFFFFFFF);
r10 = r12 >> 16;
r10 |= r9 << 16;
r9 = 0xFFFD630B;
r10 = r10 - r7;
tmpl = (ulong)(((long)(int)r9) * ((long)(int)r6));
r12 = (uint)(tmpl & 0xFFFFFFFF);
r6 = (uint)((tmpl >> 32) & 0xFFFFFFFF);
r9 = r12 >> 16;
r9 |= r6 << 16;
r6 = r9 + r7;
r9 = r6 - r4;
r7 = r11 - r9;
r6 = r10 + r7;
r10 = SP_660_var_64C;
r11 = r10 + r4;
r4 = r10 - r4;
r5data[R5Offset + 0] = r11;
r5data[R5Offset + 56] = r4;
r4 = SP_660_var_648;
r10 = r4 + r9;
r4 = r4 - r9;
r5data[R5Offset + 8] = r10;
r5data[R5Offset + 48] = r4;
r4 = SP_660_var_658;
r9 = r4 + r7;
r4 = r4 - r7;
r5data[R5Offset + 16] = r9;
r5data[R5Offset + 40] = r4;
r7 = r8 + r6;
r4 = r8 - r6;
r5data[R5Offset + 32] = r7;
r5data[R5Offset + 24] = r4;
loc_20A687C:
DOffset += 16;
Counter++;
QTOffset += 8;
R5Offset++;
if (Counter >= 8) break;
}
Counter = 0;
R5Offset = 0;
r4 = 0xFF;
while (true)
{
r5 = r5data[R5Offset + 4];
r2 = r5data[R5Offset + 0];
r8 = r5data[R5Offset + 6];
r7 = r5data[R5Offset + 2];
r3 = r2 + r5;
r6 = r2 - r5;
r2 = r7 + r8;
r9 = r7 - r8;
r7 = 0x16A0A;
r12 = r3 + r2;
ulong tmpl = (ulong)(((long)(int)r9) * ((long)(int)r7));
r8 = (uint)(tmpl & 0xFFFFFFFF);
r7 = (uint)((tmpl >> 32) & 0xFFFFFFFF);
r8 >>= 16;
r8 |= r7 << 16;
r7 = r8 - r2;
r3 = r3 - r2;
r5 = r5data[R5Offset + 3];
r8 = r5data[R5Offset + 5];
r2 = r6 + r7;
r11 = r6 - r7;
r6 = r8 + r5;
r9 = r8 - r5;
r5 = 0xFFFD630B;
SP_660_var_644 = r6;
tmpl = (ulong)(((long)(int)r5) * ((long)(int)r9));
r10 = (uint)(tmpl & 0xFFFFFFFF);
r8 = (uint)((tmpl >> 32) & 0xFFFFFFFF);
r5 = r10 >> 16;
r7 = r5data[R5Offset + 7];
r6 = r5data[R5Offset + 1];
r5 |= r8 << 16;
r8 = r6 + r7;
r7 = r6 - r7;
r6 = 0x1D907;
r10 = r9 + r7;
tmpl = (ulong)(((long)(int)r10) * ((long)(int)r6));
r9 = (uint)(tmpl & 0xFFFFFFFF);
r6 = (uint)((tmpl >> 32) & 0xFFFFFFFF);
SP_660_var_650 = r6;
r6 = r9 >> 16;
r9 = SP_660_var_650;
R5Offset += 8;
r6 |= r9 << 16;
r9 = 0x11518;
r5 = r5 + r6;
tmpl = (ulong)(((long)(int)r9) * ((long)(int)r7));
r10 = (uint)(tmpl & 0xFFFFFFFF);
r7 = (uint)((tmpl >> 32) & 0xFFFFFFFF);
r9 = r10 >> 16;
r9 |= r7 << 16;
r9 = r9 - r6;
r6 = SP_660_var_644;
r7 = r8 + r6;
r6 = r8 - r6;
r8 = 0x16A0A;
r5 = r5 - r7;
tmpl = (ulong)(((long)(int)r6) * ((long)(int)r8));
r10 = (uint)(tmpl & 0xFFFFFFFF);
r8 = (uint)((tmpl >> 32) & 0xFFFFFFFF);
r6 = r10 >> 16;
r6 |= r8 << 16;
r8 = r6 - r5;
r6 = r9 + r8;
r9 = r12 + r7;
r9 = (uint)((int)r9 >> 19);
r9 += 0x80;
r7 = r12 - r7;
if (((int)r9) < 0) r9 = 0;
if (r9 > 255) r9 = r4;
r7 = (uint)((int)r7 >> 19);
r7 += 0x80;
if (((int)r7) < 0) r7 = 0;
r0data[R0Offset + 0] = (byte)r9;
if (r7 > 255) r7 = r4;
r0data[R0Offset + 7] = (byte)r7;
r7 = r2 + r5;
r7 = (uint)((int)r7 >> 19);
r7 += 0x80;
r2 = r2 - r5;
if (((int)r7) < 0) r7 = 0;
if (r7 > 255) r7 = r4;
r2 = (uint)((int)r2 >> 19);
r2 += 0x80;
if (((int)r2) < 0) r2 = 0;
r0data[R0Offset + 1] = (byte)r7;
if (r2 > 255) r2 = r4;
r0data[R0Offset + 6] = (byte)r2;
r2 = r11 + r8;
r2 = (uint)((int)r2 >> 19);
r5 = r2 + 0x80;
r2 = r11 - r8;
if (((int)r5) < 0) r5 = 0;
if (r5 > 255) r5 = r4;
r2 = (uint)((int)r2 >> 19);
r2 += 0x80;
if (((int)r2) < 0) r2 = 0;
r0data[R0Offset + 2] = (byte)r5;
if (r2 > 255) r2 = r4;
r0data[R0Offset + 5] = (byte)r2;
r2 = r3 + r6;
r2 = (uint)((int)r2 >> 19);
r5 = r2 + 0x80;
r2 = r3 - r6;
if (((int)r5) < 0) r5 = 0;
if (r5 > 255) r5 = r4;
r2 = (uint)((int)r2 >> 19);
r2 += 0x80;
if (((int)r2) < 0) r2 = 0;
r0data[R0Offset + 4] = (byte)r5;
if (r2 > 255) r2 = r4;
r0data[R0Offset + 3] = (byte)r2;
R0Offset += 8;
Counter++;
if (Counter >= 8) break;
}
return r0data;
}
private static byte[] DecompressRLE(byte[] Data, int DataOffset, int Length)
{
List<byte> OutputData = new List<byte>();
int Offset = DataOffset;
int R5 = Data[Offset++];
int R12;
int LR;
while (true)
{
R12 = Data[Offset++];
if (R12 == R5)
{
LR = Data[Offset++];
if (LR <= 2)
{
R12 = 0;
while (true)
{
R12++;
OutputData.Add((byte)R5);
if (R12 > LR) break;
}
goto loc_20A5AA0;
}
if ((LR & 0x80) != 0)
{
R12 = Data[Offset++];
LR <<= 25;
LR = R12 + (LR >> 17);
}
R12 = Data[Offset++];
int R8 = 0;
while (true)
{
R8++;
OutputData.Add((byte)R12);
if (R8 > LR) break;
}
goto loc_20A5AA0;
}
OutputData.Add((byte)R12);
loc_20A5AA0:
if (Offset >= (Length + DataOffset)) break;
}
return OutputData.ToArray();
}
private class FMVInfo
{
public FMVInfo(FMV f, EndianBinaryReader er)
{
this.er = er;
Width = f.Header.Width;
Height = f.Header.Height;
NrTilesX = Width / 16;
NrTilesY = Height / 16;
PhaseInfos[0] = new PhaseInfo(this, 2, 2, 0, 0, 0);
PhaseInfos[1] = new PhaseInfo(this, 1, 1, 1, 1, 1);
PhaseInfos[2] = new PhaseInfo(this, 1, 1, 1, 1, 1);
}
public EndianBinaryReader er;
public byte[][] field_0 = new byte[2][];
public ushort[][] field_400 = new ushort[2][];
public byte[][] field_600 = new byte[2][];
public byte[][] field_700 = new byte[2][];
public uint[][] field_804 = new uint[2][];
public uint[][] field_84C = new uint[2][];
public byte[][] field_1200 = new byte[2][];
public ushort[][] field_1600 = new ushort[2][];
public byte[][] field_1800 = new byte[2][];
public byte[][] field_1900 = new byte[2][];
public uint[][] field_1A04 = new uint[2][];
public uint[][] field_1A4C = new uint[2][];
public bool FirstKeyFrame = true;
public int Width;
public int Height;
public int NrPhases = 3;
public int Quality = 0;
public uint[][] QuantizationTables = new uint[2][];
public int NrTilesX;
public int NrTilesY;
public uint BitReg = 0;
public int BitRegNrBits = 0;
public PhaseInfo[] PhaseInfos = new PhaseInfo[3];
public Bitmap LastFrame;
public class PhaseInfo
{
public PhaseInfo(FMVInfo Info, int NrBlocksX, int NrBlocksY, int QTIdx, int Table1Idx, int Table2Idx)
{
this.NrBlocksX = NrBlocksX;
this.NrBlocksY = NrBlocksY;
this.QTIdx = QTIdx;
this.Table1Idx = Table1Idx;
this.Table2Idx = Table2Idx;
Field10 = 0;
PhaseDataWidth = 8 * Info.NrTilesX * NrBlocksX;
PhaseDataHeight = 8 * Info.NrTilesY * NrBlocksY;
PhaseData = new byte[PhaseDataWidth * PhaseDataHeight];
PhaseDataOld = new byte[PhaseDataWidth * PhaseDataHeight];
}
public int NrBlocksX;
public int NrBlocksY;
public int QTIdx;
public int Table1Idx;
public int Table2Idx;
public int Field10;
public int PhaseDataWidth;
public int PhaseDataHeight;
public byte[] PhaseData;
public byte[] PhaseDataOld;
}
}
public class FMVIdentifier : FileFormatIdentifier
{
public override string GetCategory()
{
return Category_Videos;
}
public override string GetFileDescription()
{
return "Lego Pirates of the Carribean Cutscenes (FMV)";
}
public override string GetFileFilter()
{
return "Lego Pirates of the Carribean Cutscenes (*.fmv)|*.fmv";
}
public override Bitmap GetIcon()
{
return null;
}
public override FormatMatch IsFormat(EFEFile File)
{
if (File.Data.Length > 4 && File.Data[0] == 'F' && File.Data[1] == 'M' && File.Data[2] == 'V' && File.Data[3] == '!') return FormatMatch.Content;
return FormatMatch.No;
}
}
}
}