Expression Encoder Screen Capture Codec

From MultimediaWiki
Jump to navigation Jump to search

This is fast codec used primarily as an intermediate between screen capture and encoding for delivery with Microsoft Expression Encoder. It was originally part of MSR's "Project Titanium". It is most commonly seen in ASF files with the .xesc extension.

Frame format

Every frame seems to start with this header (all numbers are big-endian):

 0-1 width
 2-3 height
 4   2 - intra, 3 - inter)
 5   should be always zero
 6   should be in range 0-100
 7   should be in range 0-2, maybe frame type too? (0 - intra, 1 - inter and 2 - skip frames)

Frame consists of macroblocks in YUV 4:2:0 format. Static VLCs are employed for coding block data.


 for (mb_y = 0; mb_y < mb_width; mb_y++) {
     for (mb_x = 0; mb_x < mb_height; mb_x++) {
         mb_type = get_vlc();
         if (mb_type == 2)
             decode_dct_mb();
         else if (mb_type == 1)
             decode_vq_mb();
     }
 }

Block type VLC:

 0  - 0 (skip)
 10 - 2 (DCT)
 11 - 1 VQ)

Decoding long coefficients

 val = get_vlc();
 if (val > 0) {
     len = val;
     val = get_bits(len);
     if (val < (1 << (len - 1)))
         val -= (1 << len) - 1;
 }

DCT coding

In general DCT coding is the same as in MS ATC Screen codec except for bitstream format.

DC coefficient is coded as long coefficient with prediction from its neighbours.

AC coefficients use codebook with entries like (skip << 4) | coef_len. coef_len = 0 means end of block.

Decoding AC is similar to decoding long coefficient:

 val = get_bits(coef_len);
 if (val < (1 << (coef_len - 1)))
     val -= (1 << coef_len) - 1;

There are four VLCs ­— for luma and chroma blocks DC and for luma and chroma block coded AC information.

VQ coding

Decoding macroblock properties:

 vec_len[0] = get_vlc(luma_block_vlc); // in 1-4 range
 for (i = 0; i < vec_len[0]; i++)
     vec[0][i] = get_long_coef(luma_entry_vlc);
 vec_len[1] = get_vlc(chroma_block_vlc); // in 1-4 range
 for (i = 0; i < vec_len[1]; i++)
     vec[1][i] = get_long_coef(chroma_entry_vlc);
 vec_len[2] = get_vlc(chroma_block_vlc); // in 1-4 range
 for (i = 0; i < vec_len[2]; i++)
     vec[2][i] = get_long_coef(chroma_entry_vlc);
 for (i = 0; i < 3; i++) {
     flags[i] = vec_len[i] > 0;
     blens[i] = vec_len[i] > 2 ? vec_len[i] - 2 : 0;
 }

Decoding macroblock coefficients:

TODO