TM2X: Difference between revisions

From MultimediaWiki
Jump to navigation Jump to search
No edit summary
(update information)
 
(15 intermediate revisions by the same user not shown)
Line 4: Line 4:
* Sample: http://samples.mplayerhq.hu/V-codecs/TM2x.avi
* Sample: http://samples.mplayerhq.hu/V-codecs/TM2x.avi


Duck TrueMotion 2X is believed to be related to [[Duck TrueMotion 2]].
Duck TrueMotion 2X is related to both [[Duck TrueMotion 1]] and [[Duck TrueMotion 2]]. This codec stored images in YUV444 format.


== Frame structure ==
== Coding principles ==
 
Truemotion 2X is a mix of technologies from both [[Duck TrueMotion 1]] and [[Duck Truemotion 2]]. From the former it takes codebook approach related to Tunstall codes (i.e. when codes are all fixed size but corresponding output sequence length may vary), from the latter it takes splitting frames into chunks for separate data sources.


Each frame consists of chunks with the following structure:
Each frame consists of chunks with the following structure:
Line 16: Line 18:


Analyzed frames have chunks in the following order:
Analyzed frames have chunks in the following order:
* <code>0x06</code> (usually takes more than a half of coded frame)
* <code>0x06</code>- coded deltas
* <code>0x15</code>- small, variable size
* <code>0x15</code>- frame decoding parameters
* <code>0x09</code>- 3 bytes long, seems to be some initialisation data
* <code>0x09</code>- 3 bytes long, initialisation data
* <code>0x02</code>- two chunks of variable size
* <code>0x02</code>- two chunks for delta values
* <code>0x0B</code>- there are always 16 of them with size=4. Maybe for some Huffman tables?
* <code>0x0B</code>- there are always 16 of them with size=4. They define coding parameters for different block modes.
* <code>0x0A</code>- variable size
* <code>0x0A</code>- codebook for decoding first chunk


In order to ease reverse-engineering Duck seemed to used pseudo-encryption on data. Pseudo-encryption means XORing some chunks with parts of LFSR which may be updated before some chunks. Register data is stored as big-endian number and looks like first 4 bytes of <code>0x06</code> chunk are used to initialize it (it also seems to be that chunk size minus four bytes).
In order to ease reverse-engineering Duck seemed to used pseudo-encryption on data. Pseudo-encryption means XORing some chunks with parts of LFSR which may be updated before some chunks. Register data is stored as big-endian number and looks like first 4 bytes of <code>0x06</code> chunk are used to initialize it (it also seems to be that chunk size minus four bytes).
Line 30: Line 32:
   shift register contents left by one bit and store new sum in LSB
   shift register contents left by one bit and store new sum in LSB
   repeat 4 times
   repeat 4 times
== Known chunks ==
Each chunk starts with 32-bit identifier and 32-bit chunk size, both big-endian. Usually frame is composed of chunks for main data, configuration parameters and the last one is inverse Huffman list chunk.


=== 0xA0000102 ===
=== 0xA0000102 ===
This chunk is obfuscated. It containc delta tables to translate decoded token values for luma and chroma.


There should be up to two chunks.
There should be up to two chunks.
Line 37: Line 45:
First byte gives the chunk number (0 or 1).
First byte gives the chunk number (0 or 1).


Second byte tells how many 16-bit words of actual dat this chunk has (up to 128).
Second byte tells how many 16-bit words of actual data this chunk has (up to 128).


The rest of chunk is 16-bit words.
The rest of chunk is 16-bit words.
Line 43: Line 51:
=== 0xA0000103 ===
=== 0xA0000103 ===


First byte - ID?
This chunk is obfuscated.


Seems to be similar to <code>0xA000010B</code>
  byte  0    --- chunk ID
  bytes 1-2  --- ???
 
Chunk ID is used instead of offset provided in <code>0xA000010B</code>.
 
=== 0xA0000105 ===
 
Codebook data.
 
  bytes 0-1  --- list size
  bytes 2-3  --- list length (usually 256)
  byte  4    --- list depth (should be 8)
  byte  5-... --- list data


=== 0xA0000106 ===
=== 0xA0000106 ===


First 32-bit word is used to initialise LSFR key.
First 32-bit word is used to initialise LSFR key.
For version 5 there's motion vector data:
  npasses = get_bits(3);
  maxd = max(width, height) rounded up to the power of two;
  for (i = 0; i < npasses; i++) {
    mvbits = get_bits(5);
    get_mv_recursive(0, 0, maxd, maxd, mvbits);
  }
 
  nblocks = get_bits(16);
  for (i = 0; i < nblocks; i++) {
    idx = get_bits(16);
    mb[idx]->mv_x = get_sbits(8) << 1;
    mb[idx]->mv_y = get_sbits(8) << 1;
  }
 
  idx = 0;
  do {
    type = get_bits(2);
    if (type == 3) {
      run  = get_bits(8);
      type = get_bits(2);
    } else {
      run = 1;
    }
    for (i = 0; i < run; i++)
      mb[idx++].type = type;
  } while (idx < num_mb_blocks);
 
  mv_bits = get_bits(4);
  for (i = 0; i < num_mb_blocks; i++) {
    if (mb[i].type == 2) {
      mb[i].mv_x += get_sbits(mv_bits);
      mb[i].mv_y += get_sbits(mv_bits);
    }
  }
  get_mv_recursive(int off_w, int off_h, int w, int h, int mvbits)
  {
    if (get_bit()) {
      w >>= 1;
      h >>= 1;
      get_mv_recursive(off_w,    off_h,    w, h, mvbits);
      get_mv_recursive(off_w + w, off_h,    w, h, mvbits);
      get_mv_recursive(off_w,    off_h + h, w, h, mvbits);
      off_w += w;
      off_h += h;
    }
    for (all MBs in this subdivision) {
      mb->mv_x += get_sbits(mvbits);
      mb->mv_y += get_sbits(mvbits);
    }
  }
The rest of the chunk data is coded block data.
=== 0xA0000108 ===
Initialisation chunk for version 0.


=== 0xA0000109 ===
=== 0xA0000109 ===


Byte 0 - ?
This chunk is obfuscated. It contains decoder configuration data.
Byte 1 - ?
 
Byte 2 - ?
  byte 0 --- some length parameter or block size
  byte 1  --- ???
  byte 2  --- also block size?
 
=== 0xA000010A ===
 
Codebook data.
 
  byte  0    --- escape value
  bytes 1-2   --- ???
  bytes 3-4  --- list size
  bytes 5-6  --- list length (usually 256)
  byte  7    --- list depth (should be 8)
  byte  8-... --- list data


=== 0xA000010B ===
=== 0xA000010B ===


First byte - chunk ID.
This chunk is obfuscated. It contains coding parameters for the different block types.
 
  byte 0    --- chunk ID  
  bytes 1-2  --- ???
  byte  3    --- block type ID
 
The following codebook is used for nonzero chunk IDs, it seems to affect which block decoding functions are selected:
 
  0, 0, 0, 0,
  0, 1, 1, 1,
  0, 1, 1, 2,
  0, 1, 2, 4
  1, 1, 2, 4,
  0, 2, 2, 4,
  1, 2, 2, 4,
  2, 2, 2, 4
  1, 4, 2, 4,
  2, 4, 2, 4,
  2, 8, 3, 8,
  3, 4, 3, 8
  3, 8, 3, 8,
  0, 1, 1, 4,
  0, 1, 2, 2,
  0, 2, 1, 4
  1, 1, 2, 2,
  1, 4, 2, 8,
  2, 2, 3, 4,
  2, 4, 3, 8
  0, 1, 3, 8,
  1, 2, 3, 8,
  2, 4, 2, 4,
  2, 4, 3, 8
  3, 8, 3, 8
 
=== 0xA000010C ===
 
Initialisation chunk for version 1.


=== 0xA000010E ===
=== 0xA000010E ===


Also seems to be related to <code>0xA000010B</code>
This chunk is obfuscated.
 
byte  0    --- chunk ID
bytes 1-2  --- ???
bytes 3-6  --- some parameters used instead of codebook in 0xA000010B (offset = chunk ID as for 0xA00000103)


First byte - chunk ID.
=== 0xA0000110 ===


Initialisation chunk for version 2.
=== 0xA0000111 ===
Initialisation chunk for version 3.


=== 0xA0000112 ===
=== 0xA0000112 ===


This represents some 2D array.
This chunk is obfuscated. It contains some 2D array.


First byte is number of elements per line.
First byte is number of elements per line.
Line 77: Line 215:


The rest of chunk is 16-bit words forming some 2D array.
The rest of chunk is 16-bit words forming some 2D array.
=== 0xA0000115 ===
Initialisation chunk for version 4.
=== 0xA0000116 ===
Initialisation chunk for version 5.
=== 0xA0000117 ===
Codebook data.
  byte  0    --- escape value
  bytes 1-2  --- ???
  bytes 3-4  --- ???
  bytes 5-6  --- ???
  byte  7    --- ???
  byte  8    --- list length - 1
  byte  9-... --- list data
=== 0xA0000118 ===
Codebook data.
  byte  0    --- escape value
  bytes 1-2  --- ???
  bytes 3-4  --- ???
  bytes 5-6  --- ???
  byte  7    --- list length - 1
  byte  8-... --- list data


=== 0xA0000119 ===
=== 0xA0000119 ===


Another extended form of <code>0xA000010B</code>?
This chunk is obfuscated.
 
byte  0    --- number of parameter blocks
bytes 1-... --- parameter IDs (used in the same way as chunk ID in 0xA0000103)
 
=== Initialisation data ===
 
This data is obfuscated with the usual key.
 
For version 5 there's some 32-bit value first.
 
  bytes 0-1    --- frame height?
  bytes 2-3    --- frame width?
 
For version 5 there's some additional 32-bit value here.
 
  byte  4      --- maximum quadtree depth?
  byte  5      --- ???
  bytes 6-7    --- ???
  byte  8      --- bits per motion vector?
 
For version 5 there are some additional fields:
 
  16-bit      --- some flags?
  byte        --- ???
  byte        --- ???
  byte        --- ???
  32-bit      --- ???
 
=== Codebook format ===
 
The list is stored in sparse form --- first you have a byte for length of the entry and then the tokens themselves (each takes a byte too). For example <code> 01 0A 02 2A 2A </code> expands to <code> { 0A }, { 2A, 2A } </code>.
 
== Frame decoding ==
After decoding the information from the various chunks it is used to reconstruct the frame.
 
First frame is split into tiles of the size provided in one of the chunks and then for each tile perform the following:
 
* for all 8x8 blocks in tile get codes for block type, MV flag and (if MV flag is true) motion vector
* for each line in tile get required deltas for this line depending on block mode and apply them (or perform motion compensation instead).
 


[[Category:Undiscovered Video Codecs]]
[[Category:Video Codecs]]
[[Category:Video Codecs]]
[[Category:Video FourCCs]]
[[Category:Video FourCCs]]

Latest revision as of 04:33, 1 January 2021

Duck TrueMotion 2X is related to both Duck TrueMotion 1 and Duck TrueMotion 2. This codec stored images in YUV444 format.

Coding principles

Truemotion 2X is a mix of technologies from both Duck TrueMotion 1 and Duck Truemotion 2. From the former it takes codebook approach related to Tunstall codes (i.e. when codes are all fixed size but corresponding output sequence length may vary), from the latter it takes splitting frames into chunks for separate data sources.

Each frame consists of chunks with the following structure:

 0-2 always 0xA0 0x00 0x01
 3      chunk identifier
 4-7 chunk size (big-endian)
 8-... chunk payload

Analyzed frames have chunks in the following order:

  • 0x06- coded deltas
  • 0x15- frame decoding parameters
  • 0x09- 3 bytes long, initialisation data
  • 0x02- two chunks for delta values
  • 0x0B- there are always 16 of them with size=4. They define coding parameters for different block modes.
  • 0x0A- codebook for decoding first chunk

In order to ease reverse-engineering Duck seemed to used pseudo-encryption on data. Pseudo-encryption means XORing some chunks with parts of LFSR which may be updated before some chunks. Register data is stored as big-endian number and looks like first 4 bytes of 0x06 chunk are used to initialize it (it also seems to be that chunk size minus four bytes).

LSFR update algorithm:

 calculate sum by modulo 2 of bits 31, 21, 3 and inverted bit 0
 shift register contents left by one bit and store new sum in LSB
 repeat 4 times

Known chunks

Each chunk starts with 32-bit identifier and 32-bit chunk size, both big-endian. Usually frame is composed of chunks for main data, configuration parameters and the last one is inverse Huffman list chunk.

0xA0000102

This chunk is obfuscated. It containc delta tables to translate decoded token values for luma and chroma.

There should be up to two chunks.

First byte gives the chunk number (0 or 1).

Second byte tells how many 16-bit words of actual data this chunk has (up to 128).

The rest of chunk is 16-bit words.

0xA0000103

This chunk is obfuscated.

 byte  0     --- chunk ID 
 bytes 1-2   --- ???

Chunk ID is used instead of offset provided in 0xA000010B.

0xA0000105

Codebook data.

 bytes 0-1   --- list size
 bytes 2-3   --- list length (usually 256)
 byte  4     --- list depth (should be 8)
 byte  5-... --- list data

0xA0000106

First 32-bit word is used to initialise LSFR key.

For version 5 there's motion vector data:

 npasses = get_bits(3);
 maxd = max(width, height) rounded up to the power of two;
 for (i = 0; i < npasses; i++) {
   mvbits = get_bits(5);
   get_mv_recursive(0, 0, maxd, maxd, mvbits);
 }
 
 nblocks = get_bits(16);
 for (i = 0; i < nblocks; i++) {
   idx = get_bits(16);
   mb[idx]->mv_x = get_sbits(8) << 1;
   mb[idx]->mv_y = get_sbits(8) << 1;
 }
 
 idx = 0;
 do {
   type = get_bits(2);
   if (type == 3) {
     run  = get_bits(8);
     type = get_bits(2);
   } else {
     run = 1;
   }
   for (i = 0; i < run; i++)
     mb[idx++].type = type;
 } while (idx < num_mb_blocks);
 
 mv_bits = get_bits(4);
 for (i = 0; i < num_mb_blocks; i++) {
   if (mb[i].type == 2) {
     mb[i].mv_x += get_sbits(mv_bits);
     mb[i].mv_y += get_sbits(mv_bits);
   }
 }
 get_mv_recursive(int off_w, int off_h, int w, int h, int mvbits)
 {
   if (get_bit()) {
     w >>= 1;
     h >>= 1;
     get_mv_recursive(off_w,     off_h,     w, h, mvbits);
     get_mv_recursive(off_w + w, off_h,     w, h, mvbits);
     get_mv_recursive(off_w,     off_h + h, w, h, mvbits);
     off_w += w;
     off_h += h;
   }
   for (all MBs in this subdivision) {
     mb->mv_x += get_sbits(mvbits);
     mb->mv_y += get_sbits(mvbits);
   }
 }

The rest of the chunk data is coded block data.

0xA0000108

Initialisation chunk for version 0.

0xA0000109

This chunk is obfuscated. It contains decoder configuration data.

 byte 0  --- some length parameter or block size
 byte 1  --- ???
 byte 2  --- also block size?

0xA000010A

Codebook data.

 byte  0     --- escape value
 bytes 1-2   --- ???
 bytes 3-4   --- list size
 bytes 5-6   --- list length (usually 256)
 byte  7     --- list depth (should be 8)
 byte  8-... --- list data

0xA000010B

This chunk is obfuscated. It contains coding parameters for the different block types.

 byte  0     --- chunk ID 
 bytes 1-2   --- ???
 byte  3     --- block type ID

The following codebook is used for nonzero chunk IDs, it seems to affect which block decoding functions are selected:

 0, 0, 0, 0,
 0, 1, 1, 1,
 0, 1, 1, 2,
 0, 1, 2, 4
 1, 1, 2, 4,
 0, 2, 2, 4,
 1, 2, 2, 4,
 2, 2, 2, 4
 1, 4, 2, 4,
 2, 4, 2, 4,
 2, 8, 3, 8,
 3, 4, 3, 8
 3, 8, 3, 8,
 0, 1, 1, 4,
 0, 1, 2, 2,
 0, 2, 1, 4
 1, 1, 2, 2,
 1, 4, 2, 8,
 2, 2, 3, 4,
 2, 4, 3, 8
 0, 1, 3, 8,
 1, 2, 3, 8,
 2, 4, 2, 4,
 2, 4, 3, 8
 3, 8, 3, 8

0xA000010C

Initialisation chunk for version 1.

0xA000010E

This chunk is obfuscated.

byte  0     --- chunk ID 
bytes 1-2   --- ???
bytes 3-6   --- some parameters used instead of codebook in 0xA000010B (offset = chunk ID as for 0xA00000103)

0xA0000110

Initialisation chunk for version 2.

0xA0000111

Initialisation chunk for version 3.

0xA0000112

This chunk is obfuscated. It contains some 2D array.

First byte is number of elements per line. Second byte seems to be padding. Following 16-bit word is number of lines.

The rest of chunk is 16-bit words forming some 2D array.

0xA0000115

Initialisation chunk for version 4.

0xA0000116

Initialisation chunk for version 5.

0xA0000117

Codebook data.

 byte  0     --- escape value
 bytes 1-2   --- ???
 bytes 3-4   --- ???
 bytes 5-6   --- ???
 byte  7     --- ???
 byte  8     --- list length - 1
 byte  9-... --- list data

0xA0000118

Codebook data.

 byte  0     --- escape value
 bytes 1-2   --- ???
 bytes 3-4   --- ???
 bytes 5-6   --- ???
 byte  7     --- list length - 1
 byte  8-... --- list data

0xA0000119

This chunk is obfuscated.

byte  0     --- number of parameter blocks
bytes 1-... --- parameter IDs (used in the same way as chunk ID in 0xA0000103)

Initialisation data

This data is obfuscated with the usual key.

For version 5 there's some 32-bit value first.

 bytes 0-1    --- frame height?
 bytes 2-3    --- frame width?

For version 5 there's some additional 32-bit value here.

 byte  4      --- maximum quadtree depth?
 byte  5      --- ???
 bytes 6-7    --- ???
 byte  8      --- bits per motion vector?

For version 5 there are some additional fields:

 16-bit       --- some flags?
 byte         --- ???
 byte         --- ???
 byte         --- ???
 32-bit       --- ???

Codebook format

The list is stored in sparse form --- first you have a byte for length of the entry and then the tokens themselves (each takes a byte too). For example 01 0A 02 2A 2A expands to { 0A }, { 2A, 2A } .

Frame decoding

After decoding the information from the various chunks it is used to reconstruct the frame.

First frame is split into tiles of the size provided in one of the chunks and then for each tile perform the following:

  • for all 8x8 blocks in tile get codes for block type, MV flag and (if MV flag is true) motion vector
  • for each line in tile get required deltas for this line depending on block mode and apply them (or perform motion compensation instead).