Microsoft Screen Codec: Difference between revisions

From MultimediaWiki
Jump to navigation Jump to search
(may it be less undiscovered codec)
Line 13: Line 13:
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.
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.


=== Extradata format ===
=== 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)
(for some reason, data in .wmv is stored in big-endian order)


Line 30: Line 34:
  52-55  nFreeColors
  52-55  nFreeColors
  56-... palette (256 RGB triplets)
  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 [http://www.stanford.edu/class/ee398a/handouts/papers/WittenACM87ArithmCoding.pdf | 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;
      }
  }


[[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:00, 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;
     }
 }