Title: Decoding & Encoding Dark Omen Videos Post by: olly on November 17, 2014, 10:00:43 PM DMJC kindly pointed out that his fellow Wing Commander modders created a Decompressor for the Privateer 2 - TGV Videos, that should work for Dark Omen Movies. We already have other players but hopefully one day the following code could be reversed to encode videos, so we can add new movies into Dark Omen.
<DMJC> I've seen it done for other games, like Wing Commander Prophecy <DMJC> Mario "HCL" Brito might be worth contacting <DMJC> hcl.solsector.net <DMJC> he's done tons of hex/code injection game editing <Olly> cool <DMJC> the movie player he wrote actually plays dark omen videos. Turns out they're identical to Privateer 2: The Darkening's format <DMJC> mplayer/ffmpeg can also decode them <Olly> can anything encode them so i can have new custom vids for DO? as we have lots of movie players ( i think the need for speed ones play them as well) <DMJC> do you want DO to play the same format, or would you rather it play a better quality format? <DMJC> he's hacked Wing Commander Prophecy to play DVD VOB files that were developer-only <DMJC> might be possible to do the same to Dark Omen <Olly> i see would be cool <DMJC> http://hcl.solsector.net/information/video_p2.cpp (http://hcl.solsector.net/information/video_p2.cpp) video decompression code for Dark Omen <DMJC> I think if you reverse the code <DMJC> it'll encode Dark Omen format videos <Olly> would be great // Privateer 2 - TGV Video Decompressor // code reconstruction by Mario Brito (mbrito@dei.uc.pt) void bytecopy(BYTE * dest, BYTE * src, int count) { for (int i = 0; i < count; i ++) dest = src; } // generic compression algorithm: used here to decompress keyframes, but also has other // uses, both in Privateer 2 and StarLancer, to compress generic files. void unpack (unsigned char * in, unsigned char * out) { if ( (in[0] & 1) == 0) in += 2; else in += 5; int size = (in[0] << 16) + (in[1] << 8) + in[2]; in += 3; int counter = 0; while ( size > 0 ) { if ( in[0] & 0x80 ) { // 1 if (in[0] & 0x40 ) { // 11 if ( in[0] & 0x20 ) { // 111 // no compression, just copy. if ( in[0] >= 0xFC ) { counter = (in[0] & 3); // number of bytes to copy in ++; memcpy(out, in, counter); in += counter; out += counter; size = 0; } else { counter = (((in[0] & 31) + 1) << 2); // number of dwords to copy in ++; memcpy(out, in, counter); size -= counter; in += counter; out += counter; } } else { // 110 int size1 = (in[0] & 3); int position = -(((in[0] & 0x10) << 12) + (in[1] << 8) + in[2]) - 1; int size2 = ((in[0] & 0xC) << 6) + in[3] + 5; in += 4; memcpy(out, in, size1); size -= size1; in += size1; out += size1; bytecopy(out, out + position, size2); size -= size2; out += size2; } } else { // 10 int size1 = ( ( in[1] & 0xC0) >> 6 ); int position = -(((in[1] & 0x3f) << 8) + in[2]) - 1; int size2 = (in[0] & 0x3f) + 4; in += 3; memcpy (out, in, size1); size -= size1; in += size1; out += size1; bytecopy (out, out + position, size2); size -= size2; out += size2; } } else { // 0 int size1 = (in[0] & 3); int position = -( ((in[0] & 0x60) << 3) + in[1] ) - 1; int size2 = ((in[0] & 0x1c) >> 2) + 3; in += 2; memcpy (out, in, size1); size -= size1; in += size1; out += size1; bytecopy (out, out + position, size2); size -= size2; out += size2; } } } void do_frame(short val[], int dimx, int dimy, char src[], char dest[]) { int ebp_4 = dimx >> 2; int ebp_14 = (val[0] << 4); char * ebp_8 = table_23c0030 - ebp_14; // this is correct int edx = dimx; int ecx = edx * 3; int * esi = table_20d3048; char * edi = dest; int ebp_24; int eax; char * ebx; int disp = 0; int ebp_28 = dimy >> 2; while (ebp_28 > 0) { ebp_24 = ebp_4; while (ebp_24 > 0) { //__asm int 3 eax = *esi; esi ++; if (eax < (ebp_14>>4)) { //__asm int 3 ebx = src + disp + table_de0038[eax]; memcpy (edi, ebx, 4); memcpy (edi+dimx, ebx+dimx, 4); memcpy (edi+2*dimx, ebx+2*dimx, 4); memcpy (edi+3*dimx, ebx+3*dimx, 4); } else { //__asm int 3 ebx = ebp_8 + eax*16; memcpy (edi, ebx, 4); memcpy (edi+dimx, ebx+4, 4); memcpy (edi+2*dimx, ebx+8, 4); memcpy (edi+3*dimx, ebx+0xc, 4); } edi += 4; disp +=4; ebp_24 --; } edi += ecx; disp +=ecx; ebp_28 --; } } void build_table_20d3048(short val[], int dimx, int dimy, int in[], int out[]) { int ebx = 0; int ecx = val[3]; int esp = val[3]; int edx = ((dimx * dimy) >> 4) - 4; int eax = 1 << ecx; int ebp = eax - 1; int write = 0; while (edx >= 0) { unsigned int c; eax = ecx = ebx; eax >>= 3; ecx &= 7; //eax = in[eax]; // not dword alligned memcpy (&c, ((char *)in) + eax, 4); eax = c >> ecx; ecx = eax; ecx &= ebp; out[write] = ecx; ecx = esp; eax >>= ecx; eax &= ebp; out[write+1] = eax; eax = (ecx * 2 + ebx); ecx = eax; eax >>=3; ecx &= 7; //eax = in[eax]; // not dword alligned memcpy (&c, ((char *)in) + eax, 4); eax = c >> ecx; ecx = eax; ecx &= ebp; out[write+2] = ecx; ecx = esp; eax >>= ecx; eax &= ebp; out[write+3] = eax; write += 4; edx -= 4; ebx += ecx*4; } offset += (ebx/8); } void build_table_23c0030_pt2(short val[], int in[], char out[]) { int src = 0; int dest = 0; for (int i = 0; i < val[2]; i ++) { int ebp_8 = in[src+1]; for (int j = 15; j >= 0; j--) { out[dest+j] = ((char*)in)[(ebp_8 & 3)+src*4]; ebp_8 >>= 2; } src += 2; dest += 16; } } void build_table_de0038(short val[], int dimx, int dimy, int in[], int out[]) { for (int i = 0; i < val[0]; i ++) out = in[i*2 + 1] * dimx + in[i*2]; } void build_table_23b0030(short val[], int in[], int out[]) { int ebp_20 = val[0] * 2; int ebp_1c = 10; int ebp_14 = (ebp_20 - 1) * ebp_1c; int * ebp_4 = ebp_20 + out; int ebp_10 = (1 << (ebp_1c - 1)); int ebp_8 = ( -1 << ebp_1c ); int ebp_18; for (ebp_18 = 0; ebp_18 < ebp_20; ebp_18 ++) { int c; memcpy(&c, ((char *) in) + (ebp_14 >> 3), 4); int val = ( c >> (ebp_14 & 7) ) & ( (1 << ebp_1c) - 1 ); ebp_14 -= ebp_1c; if (val & ebp_10) val |= ebp_8; ebp_4 --; *ebp_4 = val; } } void uncompress_frame(int dimx, int dimy, int image[] /* in */, short ** frame0 /* out */ ) { int dim, i; memcpy(&dim, image, 4); if (dim == ((dimy << 16) | dimx)) { // kVGT for (i = 0; i < 256; i ++) memcpy (pal[0].color+i, ((char *)image) + 12 + 3*i, 3); SDL_SetColors(back, pal[0].color, 0,256); unpack ( ((unsigned char *)image) + 12 + 768 , (unsigned char*)buffer1); // update frame if (interlaced) do_interlace((char*)*frame0, buffer1, dimx, dimy); else memcpy (*frame0, buffer1, dimx*dimy); //printf ("Key frame\n"); } else { // fVGT short val[4]; offset = (((char *)image) + 0xc); // get the 4 short values from memory memcpy (val, image, 4*sizeof(short)); // step A build_table_23b0030(val, (int *)(offset), table_23b0030); // step B build_table_de0038(val, dimx, dimy, table_23b0030, table_de0038); // memcpy step offset += (((val[0] * 20 + 0x1f) & 0xffffffe0) >> 3); memcpy(table_23c0030, offset, val[1] << 4); // step C offset += val[1] << 4; build_table_23c0030_pt2(val, (int *)(offset), table_23c0030 + (val[1] << 4) ); offset += val[2] * 8; // step D build_table_20d3048(val, dimx, dimy, (int *)(offset), table_20d3048); // step E //do_frame(val, dimx, dimy, buffer1, (char *)(*frame0)); //memcpy (buffer1, *frame0, dimx*dimy); //printf ("offset = %p\n", offset - ((char *)image)); memset(buffer2, 0, dimx*dimy); do_frame(val, dimx, dimy, buffer1, buffer2); memcpy (buffer1, buffer2, dimx*dimy); if (interlaced) do_interlace((char*)*frame0, buffer2, dimx, dimy); else memcpy (*frame0, buffer2, dimx*dimy); } } |