Microsoft Screen Codec: Difference between revisions

From MultimediaWiki
Jump to navigation Jump to search
Line 121: Line 121:
       }
       }
   }
   }
==== other decoding routines ====
Decoding pivot point:
  decode_pivot(ref_value) {
      edge  = coder->decode_model(edge_model);
      coord = coder->decode_model(pivot_model) + 1;
      if (coord > 2)
          coord = coder->decode_number((ref_value + 1) / 2 - 2) + 3;
      if (edge)
          return ref_value - coord;
      else
          return coord;
  }
Decoding pixels is not that trivial.
Codec uses neighbour pixels (left, top-left, top, top-right) to form a cache which is used
along with cached move-to-front queue and several models to restore pixel.


[[Category:Video Codecs]]
[[Category:Video Codecs]]
[[Category:Screen Capture Video Codecs]]
[[Category:Screen Capture Video Codecs]]
[[Category:Undiscovered Video Codecs]]
[[Category:Undiscovered Video Codecs]]

Revision as of 08:14, 9 June 2012

Also known as Windows Media Screen Codec.

MSA1 is created by Live Meeting 2007


Some details about format

Both MSS1 and MSS2 are quite close (thus are decoded with single decoder). They employ arithmetic coding - real one, with probability coding. This coding is used with several adaptive models, which look a bit like PPM.

MSS1 details

MSS1 (aka Windows Media Screen codec) compresses only palletised images.

Extradata format

(for some reason, data in .wmv is stored in big-endian order)

 4- 7  header length
 8-11  major version
12-15  minor version
16-19  display width
20-23  display height
24-27  coded width
28-31  coded height
32-35  frames per second (float)
36-39  bitrate
40-43  max lead time (float)
44-47  max lag time
48-51  max seek time
52-55  nFreeColors
56-... palette (256 RGB triplets)

Frame format

Codec uses arithmetic decoders for all operations and adaptive models. All code for them is suspiciously similar to the one in | 1987 paper by Witten, Neal and Cleary.

Codec uses delta compression and can change top palette entries with every intra frame:

 is_inter = coder->decode_bit();
 if (!is_inter) {
     if (nFreeColors) {
         num_entries = coder->decode_number(nFreeColors + 1);
         for (i = 0; i < num_entries; i++) {
             pal[(256 - nFreeColors) + i].R = coder->decode_bits(8);
             pal[(256 - nFreeColors) + i].G = coder->decode_bits(8);
             pal[(256 - nFreeColors) + i].B = coder->decode_bits(8);
         }
     }
     recursive_decode_intra(0, 0, width, height);
 } else {
     recursive_decode_inter(0, 0, width, height);
 }

Frame coding is done by recursively partitioning picture horizontally or vertically and coding partitions in some way:

 recursive_decode_intra(x, y, width, height) {
     mode = coder->decode_model(split_mode_model);
     switch (mode) {
     case 0:
         pivot = decode_pivot(height);
         recursive_decode_intra(x, y, width, pivot);
         recursive_decode_intra(x, y + pivot, width, height - pivot);
         break;
     case 1:
         pivot = decode_pivot(width);
         recursive_decode_intra(x, y, pivot, height);
         recursive_decode_intra(x + pivot, y, width - pivot, height
         break;
     case 2:
         mode = coder->decode_model(intra_decode_model);
         if (!mode) {
             pix = decode_pixel();
             fill_rect(x, y, width, height, pixel);
         } else {
             decode_area(x, y, width, height);
         }
         break;
     }
 }
 
 recursive_decode_inter(x, y, width, height) {
     mode = coder->decode_model(split_mode_model);
     switch (mode) {
     case 0:
         pivot = decode_pivot(height);
         recursive_decode_inter(x, y, width, pivot);
         recursive_decode_inter(x, y + pivot, width, height - pivot);
         break;
     case 1:
         pivot = decode_pivot(width);
         recursive_decode_inter(x, y, pivot, height);
         recursive_decode_inter(x + pivot, y, width - pivot, height
         break;
     case 2:
         mode = coder->decode_model(inter_decode_model);
         if (!mode) {
             pix = decode_pixel();
             if (pix != 0xFF) {
                 copy_rect(x, y, width, height, pixel);
             } else {
                 mode = coder->decode_model(intra_decode_model);
                 if (!mode) {
                     pix = decode_pixel();
                     fill_rect(x, y, width, height, pixel);
                 } else {
                     decode_area(x, y, width, height);
                 }
             }
         } else {
             // this decoded change mask first and then
             // checks - if mask value is 0xFF then decode pixel
             // otherwise copy if from the previous frame
             mask = decode_area(x, y, width, height);
             decode_area_masked(x, y, width, height);
         }
         break;
     }
 }

other decoding routines

Decoding pivot point:

 decode_pivot(ref_value) {
     edge  = coder->decode_model(edge_model);
     coord = coder->decode_model(pivot_model) + 1;
     if (coord > 2)
         coord = coder->decode_number((ref_value + 1) / 2 - 2) + 3;
     if (edge)
         return ref_value - coord;
     else
         return coord;
 }

Decoding pixels is not that trivial. Codec uses neighbour pixels (left, top-left, top, top-right) to form a cache which is used along with cached move-to-front queue and several models to restore pixel.