Warhammer Dark Omen Forum

Modifications => Tools => Topic started by: olly on November 17, 2014, 10:00:43 PM



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);
   }

}