<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.multimedia.cx/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Nkd</id>
	<title>MultimediaWiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.multimedia.cx/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Nkd"/>
	<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php/Special:Contributions/Nkd"/>
	<updated>2026-06-13T11:41:42Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.5</generator>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=Microsoft_Screen_Codec&amp;diff=14066</id>
		<title>Microsoft Screen Codec</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=Microsoft_Screen_Codec&amp;diff=14066"/>
		<updated>2012-06-20T08:36:40Z</updated>

		<summary type="html">&lt;p&gt;Nkd: Add MSS2 spec&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Also known as Windows Media Screen Codec.&lt;br /&gt;
&lt;br /&gt;
* FourCCs: MSS1, MSS2, MSA1&lt;br /&gt;
* Samples:&lt;br /&gt;
** http://samples.mplayerhq.hu/V-codecs/MSS1/&lt;br /&gt;
** http://samples.mplayerhq.hu/V-codecs/MSS2/&lt;br /&gt;
&lt;br /&gt;
MSA1 is created by Live Meeting 2007&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Some details about format ==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== MSS1 details ===&lt;br /&gt;
&lt;br /&gt;
MSS1 (aka Windows Media Screen V7 codec) compresses only palettised images.&lt;br /&gt;
&lt;br /&gt;
==== Extradata format ====&lt;br /&gt;
(for some reason, data in .wmv is stored in big-endian order)&lt;br /&gt;
&lt;br /&gt;
  4- 7  header length&lt;br /&gt;
  8-11  major version (1 for MSS1, 2 for MSS2)&lt;br /&gt;
 12-15  minor version&lt;br /&gt;
 16-19  display width&lt;br /&gt;
 20-23  display height&lt;br /&gt;
 24-27  coded width&lt;br /&gt;
 28-31  coded height&lt;br /&gt;
 32-35  frames per second (float)&lt;br /&gt;
 36-39  bitrate&lt;br /&gt;
 40-43  max lead time (float)&lt;br /&gt;
 44-47  max lag time (float)&lt;br /&gt;
 48-51  max seek time (float)&lt;br /&gt;
 52-55  nFreeColors&lt;br /&gt;
 56-823 palette (256 RGB triplets)&lt;br /&gt;
Only for MSS2:&lt;br /&gt;
 824-827 threadingSplit (domain: -1, 0, 1..codedH)&lt;br /&gt;
 828-831 numSymbolsEscapeModel (domain: 0..256)&lt;br /&gt;
&lt;br /&gt;
Both width and height must be in the range 1..4096.&lt;br /&gt;
&lt;br /&gt;
==== Frame format ====&lt;br /&gt;
&lt;br /&gt;
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].&lt;br /&gt;
&lt;br /&gt;
Codec uses delta compression and can change top palette entries with every intra frame:&lt;br /&gt;
&lt;br /&gt;
  is_inter = coder-&amp;gt;decode_bit();&lt;br /&gt;
  if (!is_inter) {&lt;br /&gt;
      if (nFreeColors) {&lt;br /&gt;
          num_entries = coder-&amp;gt;decode_number(nFreeColors + 1);&lt;br /&gt;
          for (i = 0; i &amp;lt; num_entries; i++) {&lt;br /&gt;
              pal[(256 - nFreeColors) + i].R = coder-&amp;gt;decode_bits(8);&lt;br /&gt;
              pal[(256 - nFreeColors) + i].G = coder-&amp;gt;decode_bits(8);&lt;br /&gt;
              pal[(256 - nFreeColors) + i].B = coder-&amp;gt;decode_bits(8);&lt;br /&gt;
          }&lt;br /&gt;
      }&lt;br /&gt;
      recursive_decode_intra(0, 0, width, height);&lt;br /&gt;
  } else {&lt;br /&gt;
      recursive_decode_inter(0, 0, width, height);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Frame coding is done by recursively partitioning picture horizontally or vertically and coding partitions in some way:&lt;br /&gt;
&lt;br /&gt;
  recursive_decode_intra(x, y, width, height) {&lt;br /&gt;
      mode = coder-&amp;gt;decode_model(split_mode_model);&lt;br /&gt;
      switch (mode) {&lt;br /&gt;
      case 0:&lt;br /&gt;
          pivot = decode_pivot(height);&lt;br /&gt;
          recursive_decode_intra(x, y, width, pivot);&lt;br /&gt;
          recursive_decode_intra(x, y + pivot, width, height - pivot);&lt;br /&gt;
          break;&lt;br /&gt;
      case 1:&lt;br /&gt;
          pivot = decode_pivot(width);&lt;br /&gt;
          recursive_decode_intra(x, y, pivot, height);&lt;br /&gt;
          recursive_decode_intra(x + pivot, y, width - pivot, height&lt;br /&gt;
          break;&lt;br /&gt;
      case 2:&lt;br /&gt;
          mode = coder-&amp;gt;decode_model(intra_decode_model);&lt;br /&gt;
          if (!mode) {&lt;br /&gt;
              pix = decode_pixel();&lt;br /&gt;
              fill_rect(x, y, width, height, pixel);&lt;br /&gt;
          } else {&lt;br /&gt;
              decode_area(x, y, width, height);&lt;br /&gt;
          }&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  recursive_decode_inter(x, y, width, height) {&lt;br /&gt;
      mode = coder-&amp;gt;decode_model(split_mode_model);&lt;br /&gt;
      switch (mode) {&lt;br /&gt;
      case 0:&lt;br /&gt;
          pivot = decode_pivot(height);&lt;br /&gt;
          recursive_decode_inter(x, y, width, pivot);&lt;br /&gt;
          recursive_decode_inter(x, y + pivot, width, height - pivot);&lt;br /&gt;
          break;&lt;br /&gt;
      case 1:&lt;br /&gt;
          pivot = decode_pivot(width);&lt;br /&gt;
          recursive_decode_inter(x, y, pivot, height);&lt;br /&gt;
          recursive_decode_inter(x + pivot, y, width - pivot, height&lt;br /&gt;
          break;&lt;br /&gt;
      case 2:&lt;br /&gt;
          mode = coder-&amp;gt;decode_model(inter_decode_model);&lt;br /&gt;
          if (!mode) {&lt;br /&gt;
              pix = decode_pixel();&lt;br /&gt;
              // same meaning as mask values, see below&lt;br /&gt;
              // for MSS2, pix == 4 means a motion compensated rectangle&lt;br /&gt;
              if (pix != 0xFF) {&lt;br /&gt;
                  copy_rect(x, y, width, height, pixel);&lt;br /&gt;
              } else {&lt;br /&gt;
                  mode = coder-&amp;gt;decode_model(intra_decode_model);&lt;br /&gt;
                  if (!mode) {&lt;br /&gt;
                      pix = decode_pixel();&lt;br /&gt;
                      fill_rect(x, y, width, height, pixel);&lt;br /&gt;
                  } else {&lt;br /&gt;
                      decode_area(x, y, width, height);&lt;br /&gt;
                  }&lt;br /&gt;
              }&lt;br /&gt;
          } else {&lt;br /&gt;
              // this decoded change mask first and then&lt;br /&gt;
              // checks - if mask value is 0xFF then decode pixel&lt;br /&gt;
              // otherwise copy if from the previous frame&lt;br /&gt;
              mask = decode_area(x, y, width, height);&lt;br /&gt;
              decode_area_masked(x, y, width, height);&lt;br /&gt;
          }&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Mask values:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Type !! Value in MSS1 !! Value in MSS2&lt;br /&gt;
|- &lt;br /&gt;
| copy from same location || 0x80 || 0x02&lt;br /&gt;
|- &lt;br /&gt;
| copy motion compensated || N/A || 0x04&lt;br /&gt;
|- &lt;br /&gt;
| decode new || 0xFF || 0x01&lt;br /&gt;
|- &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In decode_area_masked(), decode new pixels as described in &amp;quot;Context modeller&amp;quot; even if the neighboring pixels were copied.&lt;br /&gt;
&lt;br /&gt;
==== other decoding routines ====&lt;br /&gt;
&lt;br /&gt;
Decoding pivot point:&lt;br /&gt;
&lt;br /&gt;
  decode_pivot(ref_value) {&lt;br /&gt;
      edge  = coder-&amp;gt;decode_model(edge_model);&lt;br /&gt;
      coord = coder-&amp;gt;decode_model(pivot_model) + 1;&lt;br /&gt;
      if (coord &amp;gt; 2)&lt;br /&gt;
          coord = coder-&amp;gt;decode_number((ref_value + 1) / 2 - 2) + 3;&lt;br /&gt;
      if (edge)&lt;br /&gt;
          return ref_value - coord;&lt;br /&gt;
      else&lt;br /&gt;
          return coord;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Decoding pixels is not that trivial.&lt;br /&gt;
Codec uses neighbour pixels (left, top-left, top, top-right) to form a cache which is used&lt;br /&gt;
along with cached move-to-front queue and several models to restore pixel.&lt;br /&gt;
&lt;br /&gt;
==== Models ====&lt;br /&gt;
&lt;br /&gt;
Models are reinitialised at every intraframe. Initially all symbols have weigth = 1.&lt;br /&gt;
With every update weight is increased by one and when they're too large they get rescaled.&lt;br /&gt;
&lt;br /&gt;
Rescaling weights is performed when total cumulative probability is bigger than threshold, which can be static or adaptive.&lt;br /&gt;
Static threshold is calculated as &amp;lt;code&amp;gt;num_symbols * symbol_threshold&amp;lt;/code&amp;gt;, adaptive one is recalculated every time as&lt;br /&gt;
&amp;lt;code&amp;gt;min(0x3FFF, ((2 * weights[num_symbols] - 1) / 2 + 4 * cumulative_probability[0]) / (2 * weights[num_symbols] - 1))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Scaling weights is simply &amp;lt;code&amp;gt;weight' = (weight + 1) &amp;gt;&amp;gt; 1&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Main models:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Name !! Purpose !! Number of symbols !! Threshold per symbol&lt;br /&gt;
|- &lt;br /&gt;
| intra_decode_model || region decoding mode for intra (solid fill or not) || 2 || adaptive&lt;br /&gt;
|- &lt;br /&gt;
| inter_decode_model || region decoding mode for inter (full region decoder or masked) || 2 || adaptive&lt;br /&gt;
|- &lt;br /&gt;
| split_mode_model || region split mode (horizontal/vertical/none) || 3 || 50&lt;br /&gt;
|- &lt;br /&gt;
| edge_model || signals from which edge pivot point is decoded  || 2 || 50&lt;br /&gt;
|- &lt;br /&gt;
| pivot_model || rough coordinates for pivot point (1, 2, escape) || 3 || 15&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Context modeller ====&lt;br /&gt;
&lt;br /&gt;
Context modeller is used for modelling pixel context by using its neighbours and caching last decoded values.&lt;br /&gt;
There are two context modellers used by decoder — one for decoding picture data (in both kinds of frames),&lt;br /&gt;
another one is used solely for decoding mask in interframes.&lt;br /&gt;
&lt;br /&gt;
Modeller components (values in {brackets} are for MSS2):&lt;br /&gt;
&lt;br /&gt;
* last decoded pixels cache (8 for picture data, 2 {3} for mask), initially filled with 0, 1, 2... and reset to that every intraframe&lt;br /&gt;
* primary model for decoding pixel (&amp;lt;code&amp;gt;(cache_size + 1)&amp;lt;/code&amp;gt; symbols, &amp;lt;code&amp;gt;15&amp;lt;/code&amp;gt; symbol threshold)&lt;br /&gt;
* escape model for decoding pixel value not in cache (&amp;lt;code&amp;gt;256&amp;lt;/code&amp;gt; {&amp;lt;code&amp;gt;numSymbolsEscapeModel&amp;lt;/code&amp;gt;} symbols, &amp;lt;code&amp;gt;50&amp;lt;/code&amp;gt; symbol threshold)&lt;br /&gt;
* secondary models for context-modelled pixels, four layers of models for different combinations of non-equal neighbours:&lt;br /&gt;
** first layer - 1x4 models (&amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; symbols, adaptive symbol threshold)&lt;br /&gt;
** second layer - 7x4 models (&amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt; symbols, &amp;lt;code&amp;gt;15&amp;lt;/code&amp;gt; symbol threshold)&lt;br /&gt;
** third layer - 6x4 models (&amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt; symbols, &amp;lt;code&amp;gt;15&amp;lt;/code&amp;gt; symbol threshold)&lt;br /&gt;
** fourth layer - 1x4 models (&amp;lt;code&amp;gt;5&amp;lt;/code&amp;gt; symbols, &amp;lt;code&amp;gt;15&amp;lt;/code&amp;gt; symbol threshold)&lt;br /&gt;
&lt;br /&gt;
Decoding top left pixel (for it no neighbourhood is provided):&lt;br /&gt;
&lt;br /&gt;
  val = coder-&amp;gt;decode_model(modeller-&amp;gt;primary_model);&lt;br /&gt;
  if (val &amp;lt; modeller-&amp;gt;cache_size) {&lt;br /&gt;
      pix = modeller-&amp;gt;cache[pix];&lt;br /&gt;
      if pix is found in the provided neighbourhood, insert it to the first position in the cache&lt;br /&gt;
        (it doesn't matter if it's already in the cache)&lt;br /&gt;
      else move it to the first position shifting other values by one&lt;br /&gt;
  } else {&lt;br /&gt;
      pix = coder-&amp;gt;decode_model(modeller-&amp;gt;escape_model);&lt;br /&gt;
      if pix is found in cache, move it to the first position shifting other values by one&lt;br /&gt;
      else just insert it at the first position in cache&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Decoding other pixels:&lt;br /&gt;
&lt;br /&gt;
  get neighbourhood (left, top, top-right and top-left pixels)&lt;br /&gt;
  select secondary model depending on neighbourhood&lt;br /&gt;
  if decoded value is less than number of neighbours, pick corresponding neighbour&lt;br /&gt;
  else decode pixel like top left one but provide neighbourhood for the reference this time&lt;br /&gt;
&lt;br /&gt;
Determine neighborhood as:&lt;br /&gt;
 If top pixel isn't available (first row): top = top-right = top-left = left&lt;br /&gt;
     (left is available, as it was decoded above)&lt;br /&gt;
 &lt;br /&gt;
 If right pixel isn't available (last column): top-right = top&lt;br /&gt;
 &lt;br /&gt;
 If left pixel isn't available (first column): left = top-left = top&lt;br /&gt;
 &lt;br /&gt;
 If neither right nor left are available (single column):  top-right = top-left = left = top&lt;br /&gt;
 &lt;br /&gt;
 note: pixels outside the current area aren't considered available&lt;br /&gt;
&lt;br /&gt;
Determine secondary model as:&lt;br /&gt;
&lt;br /&gt;
 layer = number of different neighborhoods (1 if all equal, 4 if all different, 2 if ABBB or AABB&lt;br /&gt;
 or ABBA or any other such combination, 3 if ABCC or ABBC or ABCA or any other such combination)&lt;br /&gt;
 &lt;br /&gt;
 sublayer = identify which neighborhoods are equal to each other. For example:&lt;br /&gt;
 &lt;br /&gt;
 if layer == 1:    # all equal&lt;br /&gt;
     sublayer = 0&lt;br /&gt;
 &lt;br /&gt;
 if layer == 2:    # 2-2 or 3-1&lt;br /&gt;
     if top == topLeft:&lt;br /&gt;
         if topRight == topLeft:&lt;br /&gt;
             sublayer = 3&lt;br /&gt;
         elsif left == topLeft:&lt;br /&gt;
             sublayer = 2&lt;br /&gt;
         else:&lt;br /&gt;
             sublayer = 4&lt;br /&gt;
     elsif topRight == topLeft:&lt;br /&gt;
         if left == topLeft:&lt;br /&gt;
             sublayer = 1&lt;br /&gt;
         else:&lt;br /&gt;
             sublayer = 5&lt;br /&gt;
     else&lt;br /&gt;
         if left == topLeft:&lt;br /&gt;
             sublayer = 6&lt;br /&gt;
         else:&lt;br /&gt;
             sublayer = 0&lt;br /&gt;
 &lt;br /&gt;
 if layer == 3:    # 2-1-1&lt;br /&gt;
     if top == topLeft:&lt;br /&gt;
         sublayer = 0&lt;br /&gt;
     elsif topRight == topLeft:&lt;br /&gt;
         sublayer = 1&lt;br /&gt;
     elsif left == topLeft:&lt;br /&gt;
         sublayer = 2&lt;br /&gt;
     elsif topRight == top:&lt;br /&gt;
         sublayer = 3&lt;br /&gt;
     elsif left == top:&lt;br /&gt;
         sublayer = 4&lt;br /&gt;
     else&lt;br /&gt;
         sublayer = 5&lt;br /&gt;
 &lt;br /&gt;
 if layer == 4:    # all different&lt;br /&gt;
     sublayer = 0&lt;br /&gt;
 &lt;br /&gt;
 subsublayer = 0&lt;br /&gt;
 if left-left pixel is available (column &amp;gt;= 2) and its value is equal to the left pixel:&lt;br /&gt;
     subsublayer += 1&lt;br /&gt;
 if top-top pixel is available (row &amp;gt;= 2) and its value is equal to the top pixel:&lt;br /&gt;
     subsublayer += 2&lt;br /&gt;
&lt;br /&gt;
Last decoded pixels cache use:&lt;br /&gt;
&lt;br /&gt;
This cache internally has 4 more entries (12 total for picture data, 6 {7} for mask). The extra entries are to skip neighboring colors which we already know aren't the ones we're looking for.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
Get neiborhood pixels, in this order: topLeft = 140, top = 134, topRight = 140, left = 136&lt;br /&gt;
Remove duplicates: [140, 134, 136]&lt;br /&gt;
We have 3 unique colors, therefore we use the third layer in the secondary model.&lt;br /&gt;
Since topRight == topLeft, we use sublayer 1. The subsublayer doesn't mater for the sake of this example.&lt;br /&gt;
&lt;br /&gt;
Now we fetch a value x using the corresponding secondary model:&lt;br /&gt;
&lt;br /&gt;
if x == 0, output 140&lt;br /&gt;
&lt;br /&gt;
if x == 1, output 134&lt;br /&gt;
&lt;br /&gt;
if x == 2, output 136&lt;br /&gt;
&lt;br /&gt;
if x == 3, the secondary model can't code the color. Fall back to the primary model to try and decode it from the cache.&lt;br /&gt;
&lt;br /&gt;
Assume the cache contents are [25, 140, 136, 134, 50, 23, ...&lt;br /&gt;
&lt;br /&gt;
If the primary model returned 0, output 25&lt;br /&gt;
&lt;br /&gt;
If it returned 1, since we know the color isn't 134, 136, or 140, output 50&lt;br /&gt;
&lt;br /&gt;
If it returned 2, output 23, and so on, until 8 which means the color isn't in the cache either and we have to fall back to the escape model. In this example, the last cache entry was unreachable. For the top-left pixel, there are zero neighbors and the last 4 entries are unreachable.&lt;br /&gt;
&lt;br /&gt;
=== MSS2 (Windows Media Video 9 Screen codec) details ===&lt;br /&gt;
&lt;br /&gt;
In MSS2, the frame header, RLE modes, palette updates, motion vector coding&lt;br /&gt;
and WMV9 data are not arithmetic coded, whereas the rectangle info data and&lt;br /&gt;
paletted recursive subdivision modes are. Each block is byte-aligned and&lt;br /&gt;
consumes a integral number of bytes. The coders have to be re-initialized&lt;br /&gt;
between blocks, even if they are of the same type.&lt;br /&gt;
&lt;br /&gt;
 alignByteStream() {&lt;br /&gt;
    &amp;lt; Align to byte boundary discarding any partially read bytes.&lt;br /&gt;
      When using VLC decoding, use&lt;br /&gt;
    get_bits_count() + 7 &amp;gt;&amp;gt; 3;&lt;br /&gt;
      to determine the number of consumed bytes. For the AC&lt;br /&gt;
      portions, use&lt;br /&gt;
    ac2_get_consumed_byes(); &amp;gt;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 RLE555Decode(x, y, w, h) {&lt;br /&gt;
    //outputs RGB555&lt;br /&gt;
    &lt;br /&gt;
    if (!isIntra) {&lt;br /&gt;
        x = get_bits(12);&lt;br /&gt;
        w = x - get_bits(12) + 1;&lt;br /&gt;
        y = y + get_bits(12);&lt;br /&gt;
        h = y - get_bits(12) + 1;&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    for each pixel in the (x, y, w, h) rectangle:&lt;br /&gt;
    read a byte, and switch:&lt;br /&gt;
        0..127, 134..255:&lt;br /&gt;
            read another byte b and put the color (byte&amp;lt;&amp;lt;8 &amp;amp;&amp;amp; b)&lt;br /&gt;
            #note that if the byte was &amp;gt;133, this will generate colors &amp;gt;32767&lt;br /&gt;
        128: copy from prev line&lt;br /&gt;
        129: copy from prev frame (leave unchanged)&lt;br /&gt;
        130..133:&lt;br /&gt;
            r = 0&lt;br /&gt;
            repeat (value-130) times:&lt;br /&gt;
                r = (r &amp;lt;&amp;lt; 8) + (read another byte)&lt;br /&gt;
            r += 1&lt;br /&gt;
            repeat the previous decoded symbol r times&lt;br /&gt;
            #the previous symbol can be a color or a copy instruction&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 RLEDecode(x, y, w, h) {&lt;br /&gt;
    if (!isIntra) {&lt;br /&gt;
        x = get_bits(12);&lt;br /&gt;
        y = get_bits(12);&lt;br /&gt;
        w = get_bits(12) + 1;&lt;br /&gt;
        h = get_bits(12) + 1;&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    // This mode uses a single tree of VLC codes.&lt;br /&gt;
    // It is built using the code lengths, which are read as follows:&lt;br /&gt;
    usedCodes = 0&lt;br /&gt;
    currentCodeLength = 1&lt;br /&gt;
    loop:&lt;br /&gt;
        remainingCodes = (1 &amp;lt;&amp;lt; currentCodeLength) - usedCodes&lt;br /&gt;
        codesOfThisLength = get_bits(ceil_log2(remainingCodes + 1))&lt;br /&gt;
        if codesOfThisLength == remainingCodes:&lt;br /&gt;
            we're done, all of the remainign codes have the current length&lt;br /&gt;
        otherwise, for each codesOfThisLength:&lt;br /&gt;
            x = get 8 bits&lt;br /&gt;
            if x &amp;lt; 190:&lt;br /&gt;
                addcode(get_bits1() + (x &amp;lt;&amp;lt; 1) - 190, currentCodeLength)&lt;br /&gt;
            if x &amp;lt; 204 - isIntra:&lt;br /&gt;
                addcode(x, currentCodeLength)&lt;br /&gt;
            #if x &amp;gt;= 204:&lt;br /&gt;
            addcode(x + 14 - isIntra, currentCodeLength)&lt;br /&gt;
        usedCodes = (usedCodes + codesOfThisLength) &amp;lt;&amp;lt; 1&lt;br /&gt;
        currentCodeLength++&lt;br /&gt;
 &lt;br /&gt;
    // main decoding loop&lt;br /&gt;
    for each pixel in the (x, y, w, h) rectangle:&lt;br /&gt;
    read an VLC code using the tree generated above, and switch:&lt;br /&gt;
        0-255: put that color&lt;br /&gt;
        256-267:&lt;br /&gt;
            q = value - 256&lt;br /&gt;
            if q == 11:&lt;br /&gt;
                q = get_bits(4) + 10&lt;br /&gt;
            if !q: r=1&lt;br /&gt;
            else: r = get_bits(q) + 1&lt;br /&gt;
            while q--:&lt;br /&gt;
                r += 1 &amp;lt;&amp;lt; q&lt;br /&gt;
            repeat the previous symbol r times&lt;br /&gt;
        268: copy from prev line&lt;br /&gt;
        269: copy from prev frame (leave unchanged)&lt;br /&gt;
 &lt;br /&gt;
    alignByteStream();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 SubDivDecode(contextSet, x, y, w, h) {&lt;br /&gt;
    &amp;lt; load the corresponding contextSet, with includes&lt;br /&gt;
      all the 5 main models plus both color contexts    &amp;gt;&lt;br /&gt;
    if (isIntra) {&lt;br /&gt;
        reset_contextSet();&lt;br /&gt;
        recursive_decode_intra(x, y, w, h); // same as MSS1, with the differences outlined above&lt;br /&gt;
    } else&lt;br /&gt;
        recursive_decode_inter(x, y, w, h); // same as MSS1, with the differences outlined above&lt;br /&gt;
    alignByteStream();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The WMV9 rectangle coordinates are read like a tree, but&lt;br /&gt;
we're only interested on the list that will be placed on root_rect.children.&lt;br /&gt;
There shouldn't be any grandchildren. levelIsPal determines whether&lt;br /&gt;
the root rect is a paletted subdivision node and its children are WMV9 nodes&lt;br /&gt;
or viceversa. In practice it should always be 1. There's a limit of 20 WMV9&lt;br /&gt;
rectangles per frame.&lt;br /&gt;
&lt;br /&gt;
 WMV9RectRecursive(rect, offset, depth, levelIsPal, flagsRead) {&lt;br /&gt;
    int n = 0;&lt;br /&gt;
    while (ac2_get_bit()) {&lt;br /&gt;
        if (!n)&lt;br /&gt;
            new_rect.x = ac2_get_number(rect.w);&lt;br /&gt;
        else&lt;br /&gt;
            new_rect.x = ac2_get_number(rect.h - rect.children[n-1].x) +&lt;br /&gt;
                rect.children[n-1].x;&lt;br /&gt;
        new_rect.y = ac2_get_number(rect.h);&lt;br /&gt;
        new_rect.w = ac2_get_number(rect.w - new_rect.x);&lt;br /&gt;
        new_rect.h = ac2_get_number(rect.h - new_rect.y);&lt;br /&gt;
        new_rect.children = [];&lt;br /&gt;
        rect.children += new_rect; // append to list&lt;br /&gt;
        n++;&lt;br /&gt;
    }&lt;br /&gt;
    if (!levelIsPAL &amp;amp;&amp;amp; !flagsRead) {&lt;br /&gt;
        if (offset == 0) {&lt;br /&gt;
            if (maskWMV9 = ac2_get_bit())&lt;br /&gt;
                maskWMV9color = ac2_get_number(256);&lt;br /&gt;
        }&lt;br /&gt;
        WMV9RectIsCoded[offset] = ac2_get_number(2);&lt;br /&gt;
        flagsRead = 1;&lt;br /&gt;
    }&lt;br /&gt;
    n = 0;&lt;br /&gt;
    foreach crect in rect.children {&lt;br /&gt;
        WMV9RectRecursive(crect, n, depth + 1, !levelIsPal, flagsRead);&lt;br /&gt;
        n++;&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 WMV9RectInfoDecode() {&lt;br /&gt;
 &lt;br /&gt;
    topLevelIsPal = ac2_get_bit();&lt;br /&gt;
    &lt;br /&gt;
    root_rect.x = 0;&lt;br /&gt;
    root_rect.y = 0;&lt;br /&gt;
    root_rect.w = codedWidth;&lt;br /&gt;
    root_rect.h = Height;&lt;br /&gt;
    root_rect.children = [];&lt;br /&gt;
 &lt;br /&gt;
    WMV9RectRecursive(root_rect, 0, 0, topLevelIsPal, 0);&lt;br /&gt;
 &lt;br /&gt;
    alignByteStream();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 decodeWMV9Rect(rect) {&lt;br /&gt;
    &amp;lt; Initialize a WMV9 decoder. The sequence header, which is usually&lt;br /&gt;
    stored in the extradata for WM9 files, is implicit here, as follows:&lt;br /&gt;
 &lt;br /&gt;
    codec tag = MKTAG('W', 'M', 'V', '9')&lt;br /&gt;
    codedWidth/Height = rect.w/h (might be odd, round up if necessary)&lt;br /&gt;
    &lt;br /&gt;
    profile = PROFILE_MAIN&lt;br /&gt;
    res_y411 = 0&lt;br /&gt;
    res_sprite = 0&lt;br /&gt;
    frmrtq_postproc = 7&lt;br /&gt;
    bitrtq_postproc = 31&lt;br /&gt;
    s.loop_filter = 1&lt;br /&gt;
    res_x8 = 0&lt;br /&gt;
    multires = 0&lt;br /&gt;
    res_fasttx = 1&lt;br /&gt;
    fastuvmc = 0&lt;br /&gt;
    extended_mv = 0&lt;br /&gt;
    dquant = 1&lt;br /&gt;
    vstransform = 1&lt;br /&gt;
    res_transtab = 0&lt;br /&gt;
    overlap = 0&lt;br /&gt;
    s.resync_marker = 0&lt;br /&gt;
    rangered = 0&lt;br /&gt;
    s.max_b_frames = 0&lt;br /&gt;
    quantizer_mode = 0&lt;br /&gt;
    finterpflag = 0&lt;br /&gt;
    res_rtm_flag = 1&lt;br /&gt;
 &lt;br /&gt;
    Then read the frame header (ff_vc1_parse_frame_header()) and&lt;br /&gt;
    frame data (vc1_decode_i_blocks()).&lt;br /&gt;
    &lt;br /&gt;
    If maskWMV9 is set, blit the resulting picture only over the pixels&lt;br /&gt;
    that had maskWMV9color. &amp;gt;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
==== Main frame decoding ====&lt;br /&gt;
&lt;br /&gt;
===== Header =====&lt;br /&gt;
&lt;br /&gt;
    isIntra = get_bits1();&lt;br /&gt;
    if (isIntra)&lt;br /&gt;
        skip_bits(7);&lt;br /&gt;
    hasWMV9 = getBits1();&lt;br /&gt;
    hasMotionVector = isIntra ? 0 : getBits1();&lt;br /&gt;
    isRLE = getBits1();&lt;br /&gt;
    isRLE555 = isRLE &amp;amp;&amp;amp; getBits1();&lt;br /&gt;
    if (threadingSplit &amp;gt; 0)&lt;br /&gt;
        splitPosition = threadingSplit&lt;br /&gt;
    else if (threadingSplit == -1) {&lt;br /&gt;
        if (getBits1()) {&lt;br /&gt;
            if (getBits1()) {&lt;br /&gt;
                if (getBits1())&lt;br /&gt;
                    splitPosition = get_bits(16);&lt;br /&gt;
                else&lt;br /&gt;
                    splitPosition = get_bits(12);&lt;br /&gt;
            } else splitPosition = get_bits(8) &amp;lt;&amp;lt; 4;&lt;br /&gt;
            splitPosition = readSplit&lt;br /&gt;
        } else {&lt;br /&gt;
            splitPosition = isIntra ? codedHeight / 2 : oldSplitPosition;&lt;br /&gt;
        }&lt;br /&gt;
        oldSplitPosition = splitPosition;&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    if (threadingSplit) {&lt;br /&gt;
        rectangle1 = {0, 0, codedWidth, splitPosition};&lt;br /&gt;
        rectangle2 = {0, splitPosition, codedWidth, codedHeight - splitPosition};&lt;br /&gt;
    } else {&lt;br /&gt;
        rectangle1 = {0, 0, codedWidth, codedHeight};&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    alignByteStream();&lt;br /&gt;
&lt;br /&gt;
===== Frame =====&lt;br /&gt;
&lt;br /&gt;
    if (isRLE555) {&lt;br /&gt;
        RLE555Decode(rectangle1);&lt;br /&gt;
        if (threadingSplit)&lt;br /&gt;
            RLE555Decode(rectangle2);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    if (hasWMV9) WMV9RectInfoDecode();&lt;br /&gt;
    if (isIntra)&lt;br /&gt;
        getPalette(); /* similar to MSS1, but here both the number of&lt;br /&gt;
                         changed colors and the colors themselves are&lt;br /&gt;
                         directly read as bytes */&lt;br /&gt;
    else {&lt;br /&gt;
        if (hasMotionVector) {&lt;br /&gt;
            mvX = get_bits(16) - codedWidth;&lt;br /&gt;
            mvY = get_bits(16) - codedHeight;&lt;br /&gt;
        } else {&lt;br /&gt;
            mvX = mvY = 0;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    if (isRLE) {&lt;br /&gt;
        RLEDecode(rectangle1);&lt;br /&gt;
        if (threadingSplit)&lt;br /&gt;
            RLEDecode(rectangle2);&lt;br /&gt;
    } else {&lt;br /&gt;
        SubDivDecode(contextSet1, rectangle1);&lt;br /&gt;
        if (threadingSplit)&lt;br /&gt;
            SubDivDecode(contextSet2, rectangle2);&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    if (hasWMV9) {&lt;br /&gt;
        int i = 0;&lt;br /&gt;
        foreach rect in root_rect.children {&lt;br /&gt;
            if (WMV9RectIsCoded[i]) {&lt;br /&gt;
                WMV9codedFrameSize = get_le24();&lt;br /&gt;
                decodeWMV9Rect(rect);&lt;br /&gt;
            } else {&lt;br /&gt;
                fillGrey(rect); // fill with 128,128,128&lt;br /&gt;
            }&lt;br /&gt;
            i++;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==== V2 Arithmetic Coder ====&lt;br /&gt;
&lt;br /&gt;
 void ac2_init(AC2 *c, GetByteContext *gb)&lt;br /&gt;
 {&lt;br /&gt;
    c-&amp;gt;low   = 0;&lt;br /&gt;
    c-&amp;gt;high  = 0xFFFFFF;&lt;br /&gt;
    c-&amp;gt;value = bytestream2_get_be24(gb);&lt;br /&gt;
    c-&amp;gt;gb    = gb;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 void ac2_renorm(AC2 *c)&lt;br /&gt;
 {&lt;br /&gt;
    while ((c-&amp;gt;high &amp;gt;&amp;gt; 15) - (c-&amp;gt;low &amp;gt;&amp;gt; 15) &amp;lt; 2) {&lt;br /&gt;
        if ((c-&amp;gt;low ^ c-&amp;gt;high) &amp;amp; 0x10000) {&lt;br /&gt;
            c-&amp;gt;high  ^= 0x8000;&lt;br /&gt;
            c-&amp;gt;value ^= 0x8000;&lt;br /&gt;
            c-&amp;gt;low   ^= 0x8000;&lt;br /&gt;
        }&lt;br /&gt;
        c-&amp;gt;high  = c-&amp;gt;high  &amp;lt;&amp;lt; 8 &amp;amp; 0xFFFFFF | 0xFF;&lt;br /&gt;
        c-&amp;gt;value = c-&amp;gt;value &amp;lt;&amp;lt; 8 &amp;amp; 0xFFFFFF | bytestream2_get_byte(gb);&lt;br /&gt;
        c-&amp;gt;low   = c-&amp;gt;low   &amp;lt;&amp;lt; 8 &amp;amp; 0xFFFFFF;&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 int ac2_get_bit(AC2 *c);&lt;br /&gt;
 // Identical to its MSS1 counterpart, except it renormalizes using ac2_renorm()&lt;br /&gt;
&lt;br /&gt;
 /* decodes a number dividing the range into two linear pieces: one&lt;br /&gt;
    whose values have probability 1 and another whose values have&lt;br /&gt;
    probability 2, so that it maps to n values ( range/2 &amp;lt; n &amp;lt;= range ) */&lt;br /&gt;
 int ac2_get_scaled_value(int value, int n, int range) {&lt;br /&gt;
    split = (n &amp;lt;&amp;lt; 1) - range;&lt;br /&gt;
    if (value &amp;gt; split)&lt;br /&gt;
      return split + (value - split &amp;gt;&amp;gt; 1);&lt;br /&gt;
    else&lt;br /&gt;
      return value;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 /* rescales the interval considering the piecewise linear division */&lt;br /&gt;
 void ac2_rescale_interval(AC2 *c, int range,&lt;br /&gt;
                                int low, int high, int n) {&lt;br /&gt;
    split = (n &amp;lt;&amp;lt; 1) - range;&lt;br /&gt;
    &lt;br /&gt;
    if (high &amp;gt; split)&lt;br /&gt;
        c-&amp;gt;high = split + (high - split &amp;lt;&amp;lt; 1);&lt;br /&gt;
    else&lt;br /&gt;
        c-&amp;gt;high = high;&lt;br /&gt;
 &lt;br /&gt;
    c-&amp;gt;high += c-&amp;gt;low;&lt;br /&gt;
 &lt;br /&gt;
    if (low &amp;gt; split)&lt;br /&gt;
        c-&amp;gt;low += split + (low - split &amp;lt;&amp;lt; 1);&lt;br /&gt;
    else&lt;br /&gt;
        c-&amp;gt;low += low;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 int ac2_get_number(AC2 *c, int n)&lt;br /&gt;
 {&lt;br /&gt;
    int range = c-&amp;gt;high - c-&amp;gt;low + 1;&lt;br /&gt;
    int scale = av_log2(range) - av_log2(n);&lt;br /&gt;
    int val;&lt;br /&gt;
    &lt;br /&gt;
    if ( n &amp;lt;&amp;lt; scale &amp;gt; range )&lt;br /&gt;
        scale--;&lt;br /&gt;
    &lt;br /&gt;
    n &amp;lt;&amp;lt;= scale;&lt;br /&gt;
    &lt;br /&gt;
    val = ac2_get_scaled_value(c-&amp;gt;value - c-&amp;gt;low, n, range) &amp;gt;&amp;gt; scale;&lt;br /&gt;
    &lt;br /&gt;
    ac2_rescale_interval(c, range, val &amp;lt;&amp;lt; scale, (val + 1) &amp;lt;&amp;lt; scale, n);&lt;br /&gt;
    &lt;br /&gt;
    ac2_renorm(c);&lt;br /&gt;
 &lt;br /&gt;
    return val;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 int ac2_get_prob(AC2 *c, int *probs)&lt;br /&gt;
 {&lt;br /&gt;
    int range = c-&amp;gt;high - c-&amp;gt;low + 1, n = *probs;&lt;br /&gt;
    int scale = av_log2(range) - av_log2(n);&lt;br /&gt;
    int i = 0, val;&lt;br /&gt;
 &lt;br /&gt;
    if ( n &amp;lt;&amp;lt; scale &amp;gt; range )&lt;br /&gt;
        scale--;&lt;br /&gt;
 &lt;br /&gt;
    n &amp;lt;&amp;lt;= scale;&lt;br /&gt;
 &lt;br /&gt;
    val = ac2_get_scaled_value(c-&amp;gt;value - c-&amp;gt;low, n, range) &amp;gt;&amp;gt; scale;&lt;br /&gt;
    while (probs[++i] &amp;gt; val) ;&lt;br /&gt;
 &lt;br /&gt;
    ac2_rescale_interval(c, range, probs[i] &amp;lt;&amp;lt; scale, probs[i-1] &amp;lt;&amp;lt; scale, n);&lt;br /&gt;
 &lt;br /&gt;
    return i;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 int ac2_get_model_sym(AC2 *c, Model *m);&lt;br /&gt;
 // Identical to its MSS1 counterpart, except it gets the symbol index&lt;br /&gt;
 // using ac2_get_prob() and renormalizes using ac2_renorm()&lt;br /&gt;
&lt;br /&gt;
 int ac2_get_consumed_byes(AC2 *c)&lt;br /&gt;
 {&lt;br /&gt;
    int diff = (c-&amp;gt;high &amp;gt;&amp;gt; 16) - (c-&amp;gt;low &amp;gt;&amp;gt; 16);&lt;br /&gt;
    int bp   = bytestream2_tell(c-&amp;gt;gb) - 3 &amp;lt;&amp;lt; 3;&lt;br /&gt;
    int bits = 1;&lt;br /&gt;
 &lt;br /&gt;
    while (!(diff &amp;amp; 0x80)) {&lt;br /&gt;
        bits++;&lt;br /&gt;
        diff &amp;lt;&amp;lt;= 1;&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    return (bits + bp + 7 &amp;gt;&amp;gt; 3) + ((c-&amp;gt;low &amp;gt;&amp;gt; 16) + 1 == c-&amp;gt;high &amp;gt;&amp;gt; 16);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Video Codecs]]&lt;br /&gt;
[[Category:Screen Capture Video Codecs]]&lt;br /&gt;
[[Category:Undiscovered Video Codecs]]&lt;/div&gt;</summary>
		<author><name>Nkd</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=Microsoft_Screen_Codec&amp;diff=14063</id>
		<title>Microsoft Screen Codec</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=Microsoft_Screen_Codec&amp;diff=14063"/>
		<updated>2012-06-12T09:01:24Z</updated>

		<summary type="html">&lt;p&gt;Nkd: Add details about context and cache color decoding&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Also known as Windows Media Screen Codec.&lt;br /&gt;
&lt;br /&gt;
* FourCCs: MSS1, MSS2, MSA1&lt;br /&gt;
* Samples:&lt;br /&gt;
** http://samples.mplayerhq.hu/V-codecs/MSS1/&lt;br /&gt;
** http://samples.mplayerhq.hu/V-codecs/MSS2/&lt;br /&gt;
&lt;br /&gt;
MSA1 is created by Live Meeting 2007&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Some details about format ==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== MSS1 details ===&lt;br /&gt;
&lt;br /&gt;
MSS1 (aka Windows Media Screen V7 codec) compresses only palettised images.&lt;br /&gt;
&lt;br /&gt;
==== Extradata format ====&lt;br /&gt;
(for some reason, data in .wmv is stored in big-endian order)&lt;br /&gt;
&lt;br /&gt;
  4- 7  header length&lt;br /&gt;
  8-11  major version (1 for MSS1, 2 for MSS2)&lt;br /&gt;
 12-15  minor version&lt;br /&gt;
 16-19  display width&lt;br /&gt;
 20-23  display height&lt;br /&gt;
 24-27  coded width&lt;br /&gt;
 28-31  coded height&lt;br /&gt;
 32-35  frames per second (float)&lt;br /&gt;
 36-39  bitrate&lt;br /&gt;
 40-43  max lead time (float)&lt;br /&gt;
 44-47  max lag time (float)&lt;br /&gt;
 48-51  max seek time (float)&lt;br /&gt;
 52-55  nFreeColors&lt;br /&gt;
 56-823 palette (256 RGB triplets)&lt;br /&gt;
Only for MSS2:&lt;br /&gt;
 824-827 threadingSplit (domain: -1, 0, 1..codedH)&lt;br /&gt;
 828-831 numSymbolsEscapeModel (domain: 0..256)&lt;br /&gt;
&lt;br /&gt;
Both width and height must be in the range 1..4096.&lt;br /&gt;
&lt;br /&gt;
==== Frame format ====&lt;br /&gt;
&lt;br /&gt;
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].&lt;br /&gt;
&lt;br /&gt;
Codec uses delta compression and can change top palette entries with every intra frame:&lt;br /&gt;
&lt;br /&gt;
  is_inter = coder-&amp;gt;decode_bit();&lt;br /&gt;
  if (!is_inter) {&lt;br /&gt;
      if (nFreeColors) {&lt;br /&gt;
          num_entries = coder-&amp;gt;decode_number(nFreeColors + 1);&lt;br /&gt;
          for (i = 0; i &amp;lt; num_entries; i++) {&lt;br /&gt;
              pal[(256 - nFreeColors) + i].R = coder-&amp;gt;decode_bits(8);&lt;br /&gt;
              pal[(256 - nFreeColors) + i].G = coder-&amp;gt;decode_bits(8);&lt;br /&gt;
              pal[(256 - nFreeColors) + i].B = coder-&amp;gt;decode_bits(8);&lt;br /&gt;
          }&lt;br /&gt;
      }&lt;br /&gt;
      recursive_decode_intra(0, 0, width, height);&lt;br /&gt;
  } else {&lt;br /&gt;
      recursive_decode_inter(0, 0, width, height);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Frame coding is done by recursively partitioning picture horizontally or vertically and coding partitions in some way:&lt;br /&gt;
&lt;br /&gt;
  recursive_decode_intra(x, y, width, height) {&lt;br /&gt;
      mode = coder-&amp;gt;decode_model(split_mode_model);&lt;br /&gt;
      switch (mode) {&lt;br /&gt;
      case 0:&lt;br /&gt;
          pivot = decode_pivot(height);&lt;br /&gt;
          recursive_decode_intra(x, y, width, pivot);&lt;br /&gt;
          recursive_decode_intra(x, y + pivot, width, height - pivot);&lt;br /&gt;
          break;&lt;br /&gt;
      case 1:&lt;br /&gt;
          pivot = decode_pivot(width);&lt;br /&gt;
          recursive_decode_intra(x, y, pivot, height);&lt;br /&gt;
          recursive_decode_intra(x + pivot, y, width - pivot, height&lt;br /&gt;
          break;&lt;br /&gt;
      case 2:&lt;br /&gt;
          mode = coder-&amp;gt;decode_model(intra_decode_model);&lt;br /&gt;
          if (!mode) {&lt;br /&gt;
              pix = decode_pixel();&lt;br /&gt;
              fill_rect(x, y, width, height, pixel);&lt;br /&gt;
          } else {&lt;br /&gt;
              decode_area(x, y, width, height);&lt;br /&gt;
          }&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  recursive_decode_inter(x, y, width, height) {&lt;br /&gt;
      mode = coder-&amp;gt;decode_model(split_mode_model);&lt;br /&gt;
      switch (mode) {&lt;br /&gt;
      case 0:&lt;br /&gt;
          pivot = decode_pivot(height);&lt;br /&gt;
          recursive_decode_inter(x, y, width, pivot);&lt;br /&gt;
          recursive_decode_inter(x, y + pivot, width, height - pivot);&lt;br /&gt;
          break;&lt;br /&gt;
      case 1:&lt;br /&gt;
          pivot = decode_pivot(width);&lt;br /&gt;
          recursive_decode_inter(x, y, pivot, height);&lt;br /&gt;
          recursive_decode_inter(x + pivot, y, width - pivot, height&lt;br /&gt;
          break;&lt;br /&gt;
      case 2:&lt;br /&gt;
          mode = coder-&amp;gt;decode_model(inter_decode_model);&lt;br /&gt;
          if (!mode) {&lt;br /&gt;
              pix = decode_pixel();&lt;br /&gt;
              // same meaning as mask values, see below&lt;br /&gt;
              // for MSS2, pix == 4 means a motion compensated rectangle&lt;br /&gt;
              if (pix != 0xFF) {&lt;br /&gt;
                  copy_rect(x, y, width, height, pixel);&lt;br /&gt;
              } else {&lt;br /&gt;
                  mode = coder-&amp;gt;decode_model(intra_decode_model);&lt;br /&gt;
                  if (!mode) {&lt;br /&gt;
                      pix = decode_pixel();&lt;br /&gt;
                      fill_rect(x, y, width, height, pixel);&lt;br /&gt;
                  } else {&lt;br /&gt;
                      decode_area(x, y, width, height);&lt;br /&gt;
                  }&lt;br /&gt;
              }&lt;br /&gt;
          } else {&lt;br /&gt;
              // this decoded change mask first and then&lt;br /&gt;
              // checks - if mask value is 0xFF then decode pixel&lt;br /&gt;
              // otherwise copy if from the previous frame&lt;br /&gt;
              mask = decode_area(x, y, width, height);&lt;br /&gt;
              decode_area_masked(x, y, width, height);&lt;br /&gt;
          }&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Mask values:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Type !! Value in MSS1 !! Value in MSS2&lt;br /&gt;
|- &lt;br /&gt;
| copy from same location || 0x80 || 0x02&lt;br /&gt;
|- &lt;br /&gt;
| copy motion compensated || N/A || 0x04&lt;br /&gt;
|- &lt;br /&gt;
| decode new || 0xFF || 0x01&lt;br /&gt;
|- &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In decode_area_masked(), decode new pixels as described in &amp;quot;Context modeller&amp;quot; even if the neighboring pixels were copied.&lt;br /&gt;
&lt;br /&gt;
==== other decoding routines ====&lt;br /&gt;
&lt;br /&gt;
Decoding pivot point:&lt;br /&gt;
&lt;br /&gt;
  decode_pivot(ref_value) {&lt;br /&gt;
      edge  = coder-&amp;gt;decode_model(edge_model);&lt;br /&gt;
      coord = coder-&amp;gt;decode_model(pivot_model) + 1;&lt;br /&gt;
      if (coord &amp;gt; 2)&lt;br /&gt;
          coord = coder-&amp;gt;decode_number((ref_value + 1) / 2 - 2) + 3;&lt;br /&gt;
      if (edge)&lt;br /&gt;
          return ref_value - coord;&lt;br /&gt;
      else&lt;br /&gt;
          return coord;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Decoding pixels is not that trivial.&lt;br /&gt;
Codec uses neighbour pixels (left, top-left, top, top-right) to form a cache which is used&lt;br /&gt;
along with cached move-to-front queue and several models to restore pixel.&lt;br /&gt;
&lt;br /&gt;
==== Models ====&lt;br /&gt;
&lt;br /&gt;
Models are reinitialised at every intraframe. Initially all symbols have weigth = 1.&lt;br /&gt;
With every update weight is increased by one and when they're too large they get rescaled.&lt;br /&gt;
&lt;br /&gt;
Rescaling weights is performed when total cumulative probability is bigger than threshold, which can be static or adaptive.&lt;br /&gt;
Static threshold is calculated as &amp;lt;code&amp;gt;num_symbols * symbol_threshold&amp;lt;/code&amp;gt;, adaptive one is recalculated every time as&lt;br /&gt;
&amp;lt;code&amp;gt;min(0x3FFF, ((2 * weights[num_symbols] - 1) / 2 + 4 * cumulative_probability[0]) / (2 * weights[num_symbols] - 1))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Scaling weights is simply &amp;lt;code&amp;gt;weight' = (weight + 1) &amp;gt;&amp;gt; 1&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Main models:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Name !! Purpose !! Number of symbols !! Threshold per symbol&lt;br /&gt;
|- &lt;br /&gt;
| intra_decode_model || region decoding mode for intra (solid fill or not) || 2 || adaptive&lt;br /&gt;
|- &lt;br /&gt;
| inter_decode_model || region decoding mode for inter (full region decoder or masked) || 2 || adaptive&lt;br /&gt;
|- &lt;br /&gt;
| split_mode_model || region split mode (horizontal/vertical/none) || 3 || 50&lt;br /&gt;
|- &lt;br /&gt;
| edge_model || signals from which edge pivot point is decoded  || 2 || 50&lt;br /&gt;
|- &lt;br /&gt;
| pivot_model || rough coordinates for pivot point (1, 2, escape) || 3 || 15&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Context modeller ====&lt;br /&gt;
&lt;br /&gt;
Context modeller is used for modelling pixel context by using its neighbours and caching last decoded values.&lt;br /&gt;
There are two context modellers used by decoder — one for decoding picture data (in both kinds of frames),&lt;br /&gt;
another one is used solely for decoding mask in interframes.&lt;br /&gt;
&lt;br /&gt;
Modeller components (values in {brackets} are for MSS2):&lt;br /&gt;
&lt;br /&gt;
* last decoded pixels cache (8 for picture data, 2 {3} for mask), initially filled with 0, 1, 2... and reset to that every intraframe&lt;br /&gt;
* primary model for decoding pixel (&amp;lt;code&amp;gt;(cache_size + 1)&amp;lt;/code&amp;gt; symbols, &amp;lt;code&amp;gt;15&amp;lt;/code&amp;gt; symbol threshold)&lt;br /&gt;
* escape model for decoding pixel value not in cache (&amp;lt;code&amp;gt;256&amp;lt;/code&amp;gt; {&amp;lt;code&amp;gt;numSymbolsEscapeModel&amp;lt;/code&amp;gt;} symbols, &amp;lt;code&amp;gt;50&amp;lt;/code&amp;gt; symbol threshold)&lt;br /&gt;
* secondary models for context-modelled pixels, four layers of models for different combinations of non-equal neighbours:&lt;br /&gt;
** first layer - 1x4 models (&amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; symbols, adaptive symbol threshold)&lt;br /&gt;
** second layer - 7x4 models (&amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt; symbols, &amp;lt;code&amp;gt;15&amp;lt;/code&amp;gt; symbol threshold)&lt;br /&gt;
** third layer - 6x4 models (&amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt; symbols, &amp;lt;code&amp;gt;15&amp;lt;/code&amp;gt; symbol threshold)&lt;br /&gt;
** fourth layer - 1x4 models (&amp;lt;code&amp;gt;5&amp;lt;/code&amp;gt; symbols, &amp;lt;code&amp;gt;15&amp;lt;/code&amp;gt; symbol threshold)&lt;br /&gt;
&lt;br /&gt;
Decoding top left pixel (for it no neighbourhood is provided):&lt;br /&gt;
&lt;br /&gt;
  val = coder-&amp;gt;decode_model(modeller-&amp;gt;primary_model);&lt;br /&gt;
  if (val &amp;lt; modeller-&amp;gt;cache_size) {&lt;br /&gt;
      pix = modeller-&amp;gt;cache[pix];&lt;br /&gt;
      if pix is found in the provided neighbourhood, insert it to the first position in the cache&lt;br /&gt;
        (it doesn't matter if it's already in the cache)&lt;br /&gt;
      else move it to the first position shifting other values by one&lt;br /&gt;
  } else {&lt;br /&gt;
      pix = coder-&amp;gt;decode_model(modeller-&amp;gt;escape_model);&lt;br /&gt;
      if pix is found in cache, move it to the first position shifting other values by one&lt;br /&gt;
      else just insert it at the first position in cache&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Decoding other pixels:&lt;br /&gt;
&lt;br /&gt;
  get neighbourhood (left, top, top-right and top-left pixels)&lt;br /&gt;
  select secondary model depending on neighbourhood&lt;br /&gt;
  if decoded value is less than number of neighbours, pick corresponding neighbour&lt;br /&gt;
  else decode pixel like top left one but provide neighbourhood for the reference this time&lt;br /&gt;
&lt;br /&gt;
Determine neighborhood as:&lt;br /&gt;
 If top pixel isn't available (first row): top = top-right = top-left = left&lt;br /&gt;
     (left is available, as it was decoded above)&lt;br /&gt;
 &lt;br /&gt;
 If right pixel isn't available (last column): top-right = top&lt;br /&gt;
 &lt;br /&gt;
 If left pixel isn't available (first column): left = top-left = top&lt;br /&gt;
 &lt;br /&gt;
 If neither right nor left are available (single column):  top-right = top-left = left = top&lt;br /&gt;
 &lt;br /&gt;
 note: pixels outside the current area aren't considered available&lt;br /&gt;
&lt;br /&gt;
Determine secondary model as:&lt;br /&gt;
&lt;br /&gt;
 layer = number of different neighborhoods (1 if all equal, 4 if all different, 2 if ABBB or AABB&lt;br /&gt;
 or ABBA or any other such combination, 3 if ABCC or ABBC or ABCA or any other such combination)&lt;br /&gt;
 &lt;br /&gt;
 sublayer = identify which neighborhoods are equal to each other. For example:&lt;br /&gt;
 &lt;br /&gt;
 if layer == 1:    # all equal&lt;br /&gt;
     sublayer = 0&lt;br /&gt;
 &lt;br /&gt;
 if layer == 2:    # 2-2 or 3-1&lt;br /&gt;
     if top == topLeft:&lt;br /&gt;
         if topRight == topLeft:&lt;br /&gt;
             sublayer = 3&lt;br /&gt;
         elsif left == topLeft:&lt;br /&gt;
             sublayer = 2&lt;br /&gt;
         else:&lt;br /&gt;
             sublayer = 4&lt;br /&gt;
     elsif topRight == topLeft:&lt;br /&gt;
         if left == topLeft:&lt;br /&gt;
             sublayer = 1&lt;br /&gt;
         else:&lt;br /&gt;
             sublayer = 5&lt;br /&gt;
     else&lt;br /&gt;
         if left == topLeft:&lt;br /&gt;
             sublayer = 6&lt;br /&gt;
         else:&lt;br /&gt;
             sublayer = 0&lt;br /&gt;
 &lt;br /&gt;
 if layer == 3:    # 2-1-1&lt;br /&gt;
     if top == topLeft:&lt;br /&gt;
         sublayer = 0&lt;br /&gt;
     elsif topRight == topLeft:&lt;br /&gt;
         sublayer = 1&lt;br /&gt;
     elsif left == topLeft:&lt;br /&gt;
         sublayer = 2&lt;br /&gt;
     elsif topRight == top:&lt;br /&gt;
         sublayer = 3&lt;br /&gt;
     elsif left == top:&lt;br /&gt;
         sublayer = 4&lt;br /&gt;
     else&lt;br /&gt;
         sublayer = 5&lt;br /&gt;
 &lt;br /&gt;
 if layer == 4:    # all different&lt;br /&gt;
     sublayer = 0&lt;br /&gt;
 &lt;br /&gt;
 subsublayer = 0&lt;br /&gt;
 if left-left pixel is available (column &amp;gt;= 2) and its value is equal to the left pixel:&lt;br /&gt;
     subsublayer += 1&lt;br /&gt;
 if top-top pixel is available (row &amp;gt;= 2) and its value is equal to the top pixel:&lt;br /&gt;
     subsublayer += 2&lt;br /&gt;
&lt;br /&gt;
Last decoded pixels cache use:&lt;br /&gt;
&lt;br /&gt;
This cache internally has 4 more entries (12 total for picture data, 6 {7} for mask). The extra entries are to skip neighboring colors which we already know aren't the ones we're looking for.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
Get neiborhood pixels, in this order: topLeft = 140, top = 134, topRight = 140, left = 136&lt;br /&gt;
Remove duplicates: [140, 134, 136]&lt;br /&gt;
We have 3 unique colors, therefore we use the third layer in the secondary model.&lt;br /&gt;
Since topRight == topLeft, we use sublayer 1. The subsublayer doesn't mater for the sake of this example.&lt;br /&gt;
&lt;br /&gt;
Now we fetch a value x using the corresponding secondary model:&lt;br /&gt;
&lt;br /&gt;
if x == 0, output 140&lt;br /&gt;
&lt;br /&gt;
if x == 1, output 134&lt;br /&gt;
&lt;br /&gt;
if x == 2, output 136&lt;br /&gt;
&lt;br /&gt;
if x == 3, the secondary model can't code the color. Fall back to the primary model to try and decode it from the cache.&lt;br /&gt;
&lt;br /&gt;
Assume the cache contents are [25, 140, 136, 134, 50, 23, ...&lt;br /&gt;
&lt;br /&gt;
If the primary model returned 0, output 25&lt;br /&gt;
&lt;br /&gt;
If it returned 1, since we know the color isn't 134, 136, or 140, output 50&lt;br /&gt;
&lt;br /&gt;
If it returned 2, output 23, and so on, until 8 which means the color isn't in the cache either and we have to fall back to the escape model. In this example, the last cache entry was unreachable. For the top-left pixel, there are zero neighbors and the last 4 entries are unreachable.&lt;br /&gt;
&lt;br /&gt;
=== MSS2 details ===&lt;br /&gt;
&lt;br /&gt;
MSS2 (aka Windows Media Video 9 Screen codec) seems to be largely the same as MSS1 with such differences:&lt;br /&gt;
* RGB24 compression instead of palettised images (maybe)&lt;br /&gt;
* motion compensation in interframes&lt;br /&gt;
* different header format&lt;br /&gt;
&lt;br /&gt;
[[Category:Video Codecs]]&lt;br /&gt;
[[Category:Screen Capture Video Codecs]]&lt;br /&gt;
[[Category:Undiscovered Video Codecs]]&lt;/div&gt;</summary>
		<author><name>Nkd</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=Microsoft_Screen_Codec&amp;diff=14061</id>
		<title>Microsoft Screen Codec</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=Microsoft_Screen_Codec&amp;diff=14061"/>
		<updated>2012-06-11T17:56:13Z</updated>

		<summary type="html">&lt;p&gt;Nkd: Added MSS2 differences for the recursive decoder and model selection details&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Also known as Windows Media Screen Codec.&lt;br /&gt;
&lt;br /&gt;
* FourCCs: MSS1, MSS2, MSA1&lt;br /&gt;
* Samples:&lt;br /&gt;
** http://samples.mplayerhq.hu/V-codecs/MSS1/&lt;br /&gt;
** http://samples.mplayerhq.hu/V-codecs/MSS2/&lt;br /&gt;
&lt;br /&gt;
MSA1 is created by Live Meeting 2007&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Some details about format ==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== MSS1 details ===&lt;br /&gt;
&lt;br /&gt;
MSS1 (aka Windows Media Screen V9 codec) compresses only palettised images.&lt;br /&gt;
&lt;br /&gt;
==== Extradata format ====&lt;br /&gt;
(for some reason, data in .wmv is stored in big-endian order)&lt;br /&gt;
&lt;br /&gt;
  4- 7  header length&lt;br /&gt;
  8-11  major version (1 for MSS1, 2 for MSS2)&lt;br /&gt;
 12-15  minor version&lt;br /&gt;
 16-19  display width&lt;br /&gt;
 20-23  display height&lt;br /&gt;
 24-27  coded width&lt;br /&gt;
 28-31  coded height&lt;br /&gt;
 32-35  frames per second (float)&lt;br /&gt;
 36-39  bitrate&lt;br /&gt;
 40-43  max lead time (float)&lt;br /&gt;
 44-47  max lag time (float)&lt;br /&gt;
 48-51  max seek time (float)&lt;br /&gt;
 52-55  nFreeColors&lt;br /&gt;
 56-823 palette (256 RGB triplets)&lt;br /&gt;
Only for MSS2:&lt;br /&gt;
 824-827 threadingSplit (domain: -1, 0, 1..codedH)&lt;br /&gt;
 828-831 numSymbolsEscapeModel (domain: 0..256)&lt;br /&gt;
&lt;br /&gt;
Both width and height must be in the range 1..4096.&lt;br /&gt;
&lt;br /&gt;
==== Frame format ====&lt;br /&gt;
&lt;br /&gt;
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].&lt;br /&gt;
&lt;br /&gt;
Codec uses delta compression and can change top palette entries with every intra frame:&lt;br /&gt;
&lt;br /&gt;
  is_inter = coder-&amp;gt;decode_bit();&lt;br /&gt;
  if (!is_inter) {&lt;br /&gt;
      if (nFreeColors) {&lt;br /&gt;
          num_entries = coder-&amp;gt;decode_number(nFreeColors + 1);&lt;br /&gt;
          for (i = 0; i &amp;lt; num_entries; i++) {&lt;br /&gt;
              pal[(256 - nFreeColors) + i].R = coder-&amp;gt;decode_bits(8);&lt;br /&gt;
              pal[(256 - nFreeColors) + i].G = coder-&amp;gt;decode_bits(8);&lt;br /&gt;
              pal[(256 - nFreeColors) + i].B = coder-&amp;gt;decode_bits(8);&lt;br /&gt;
          }&lt;br /&gt;
      }&lt;br /&gt;
      recursive_decode_intra(0, 0, width, height);&lt;br /&gt;
  } else {&lt;br /&gt;
      recursive_decode_inter(0, 0, width, height);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Frame coding is done by recursively partitioning picture horizontally or vertically and coding partitions in some way:&lt;br /&gt;
&lt;br /&gt;
  recursive_decode_intra(x, y, width, height) {&lt;br /&gt;
      mode = coder-&amp;gt;decode_model(split_mode_model);&lt;br /&gt;
      switch (mode) {&lt;br /&gt;
      case 0:&lt;br /&gt;
          pivot = decode_pivot(height);&lt;br /&gt;
          recursive_decode_intra(x, y, width, pivot);&lt;br /&gt;
          recursive_decode_intra(x, y + pivot, width, height - pivot);&lt;br /&gt;
          break;&lt;br /&gt;
      case 1:&lt;br /&gt;
          pivot = decode_pivot(width);&lt;br /&gt;
          recursive_decode_intra(x, y, pivot, height);&lt;br /&gt;
          recursive_decode_intra(x + pivot, y, width - pivot, height&lt;br /&gt;
          break;&lt;br /&gt;
      case 2:&lt;br /&gt;
          mode = coder-&amp;gt;decode_model(intra_decode_model);&lt;br /&gt;
          if (!mode) {&lt;br /&gt;
              pix = decode_pixel();&lt;br /&gt;
              fill_rect(x, y, width, height, pixel);&lt;br /&gt;
          } else {&lt;br /&gt;
              decode_area(x, y, width, height);&lt;br /&gt;
          }&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  recursive_decode_inter(x, y, width, height) {&lt;br /&gt;
      mode = coder-&amp;gt;decode_model(split_mode_model);&lt;br /&gt;
      switch (mode) {&lt;br /&gt;
      case 0:&lt;br /&gt;
          pivot = decode_pivot(height);&lt;br /&gt;
          recursive_decode_inter(x, y, width, pivot);&lt;br /&gt;
          recursive_decode_inter(x, y + pivot, width, height - pivot);&lt;br /&gt;
          break;&lt;br /&gt;
      case 1:&lt;br /&gt;
          pivot = decode_pivot(width);&lt;br /&gt;
          recursive_decode_inter(x, y, pivot, height);&lt;br /&gt;
          recursive_decode_inter(x + pivot, y, width - pivot, height&lt;br /&gt;
          break;&lt;br /&gt;
      case 2:&lt;br /&gt;
          mode = coder-&amp;gt;decode_model(inter_decode_model);&lt;br /&gt;
          if (!mode) {&lt;br /&gt;
              pix = decode_pixel();&lt;br /&gt;
              // same meaning as mask values, see below&lt;br /&gt;
              // for MSS2, pix == 4 means a motion compensated rectangle&lt;br /&gt;
              if (pix != 0xFF) {&lt;br /&gt;
                  copy_rect(x, y, width, height, pixel);&lt;br /&gt;
              } else {&lt;br /&gt;
                  mode = coder-&amp;gt;decode_model(intra_decode_model);&lt;br /&gt;
                  if (!mode) {&lt;br /&gt;
                      pix = decode_pixel();&lt;br /&gt;
                      fill_rect(x, y, width, height, pixel);&lt;br /&gt;
                  } else {&lt;br /&gt;
                      decode_area(x, y, width, height);&lt;br /&gt;
                  }&lt;br /&gt;
              }&lt;br /&gt;
          } else {&lt;br /&gt;
              // this decoded change mask first and then&lt;br /&gt;
              // checks - if mask value is 0xFF then decode pixel&lt;br /&gt;
              // otherwise copy if from the previous frame&lt;br /&gt;
              mask = decode_area(x, y, width, height);&lt;br /&gt;
              decode_area_masked(x, y, width, height);&lt;br /&gt;
          }&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Mask values:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Type !! Value in MSS1 !! Value in MSS2&lt;br /&gt;
|- &lt;br /&gt;
| copy from same location || 0x80 || 0x02&lt;br /&gt;
|- &lt;br /&gt;
| copy motion compensated || N/A || 0x04&lt;br /&gt;
|- &lt;br /&gt;
| decode new || 0xFF || 0x01&lt;br /&gt;
|- &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In decode_area_masked(), decode new pixels as described in &amp;quot;Context modeller&amp;quot; even if the neighboring pixels were copied.&lt;br /&gt;
&lt;br /&gt;
==== other decoding routines ====&lt;br /&gt;
&lt;br /&gt;
Decoding pivot point:&lt;br /&gt;
&lt;br /&gt;
  decode_pivot(ref_value) {&lt;br /&gt;
      edge  = coder-&amp;gt;decode_model(edge_model);&lt;br /&gt;
      coord = coder-&amp;gt;decode_model(pivot_model) + 1;&lt;br /&gt;
      if (coord &amp;gt; 2)&lt;br /&gt;
          coord = coder-&amp;gt;decode_number((ref_value + 1) / 2 - 2) + 3;&lt;br /&gt;
      if (edge)&lt;br /&gt;
          return ref_value - coord;&lt;br /&gt;
      else&lt;br /&gt;
          return coord;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Decoding pixels is not that trivial.&lt;br /&gt;
Codec uses neighbour pixels (left, top-left, top, top-right) to form a cache which is used&lt;br /&gt;
along with cached move-to-front queue and several models to restore pixel.&lt;br /&gt;
&lt;br /&gt;
==== Models ====&lt;br /&gt;
&lt;br /&gt;
Models are reinitialised at every intraframe. Initially all symbols have weigth = 1.&lt;br /&gt;
With every update weight is increased by one and when they're too large they get rescaled.&lt;br /&gt;
&lt;br /&gt;
Rescaling weights is performed when total cumulative probability is bigger than threshold, which can be static or adaptive.&lt;br /&gt;
Static threshold is calculated as &amp;lt;code&amp;gt;num_symbols * symbol_threshold&amp;lt;/code&amp;gt;, adaptive one is recalculated every time as&lt;br /&gt;
&amp;lt;code&amp;gt;min(0x3FFF, ((2 * weights[num_symbols] - 1) / 2 + 4 * cumulative_probability[0]) / (2 * weights[num_symbols] - 1))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Scaling weights is simply &amp;lt;code&amp;gt;weight' = (weight + 1) &amp;gt;&amp;gt; 1&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Main models:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Name !! Purpose !! Number of symbols !! Threshold per symbol&lt;br /&gt;
|- &lt;br /&gt;
| intra_decode_model || region decoding mode for intra (solid fill or not) || 2 || adaptive&lt;br /&gt;
|- &lt;br /&gt;
| inter_decode_model || region decoding mode for inter (full region decoder or masked) || 2 || adaptive&lt;br /&gt;
|- &lt;br /&gt;
| split_mode_model || region split mode (horizontal/vertical/none) || 3 || 50&lt;br /&gt;
|- &lt;br /&gt;
| edge_model || signals from which edge pivot point is decoded  || 2 || 50&lt;br /&gt;
|- &lt;br /&gt;
| pivot_model || rough coordinates for pivot point (1, 2, escape) || 3 || 15&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Context modeller ====&lt;br /&gt;
&lt;br /&gt;
Context modeller is used for modelling pixel context by using its neighbours and caching last decoded values.&lt;br /&gt;
There are two context modellers used by decoder — one for decoding picture data (in both kinds of frames),&lt;br /&gt;
another one is used solely for decoding mask in interframes.&lt;br /&gt;
&lt;br /&gt;
Modeller components (values in {brackets} are for MSS2):&lt;br /&gt;
&lt;br /&gt;
* last decoded pixels cache (8 for picture data, 2 {3} for mask), initially filled with 0, 1, 2... and reset to that every intraframe&lt;br /&gt;
* primary model for decoding pixel (&amp;lt;code&amp;gt;(cache_size + 1)&amp;lt;/code&amp;gt; symbols, &amp;lt;code&amp;gt;15&amp;lt;/code&amp;gt; symbol threshold)&lt;br /&gt;
* escape model for decoding pixel value not in cache (&amp;lt;code&amp;gt;256&amp;lt;/code&amp;gt; {&amp;lt;code&amp;gt;numSymbolsEscapeModel&amp;lt;/code&amp;gt;} symbols, &amp;lt;code&amp;gt;50&amp;lt;/code&amp;gt; symbol threshold)&lt;br /&gt;
* secondary models for context-modelled pixels, four layers of models for different combinations of non-equal neighbours:&lt;br /&gt;
** first layer - 1x4 models (&amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; symbols, adaptive symbol threshold)&lt;br /&gt;
** second layer - 7x4 models (&amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt; symbols, &amp;lt;code&amp;gt;15&amp;lt;/code&amp;gt; symbol threshold)&lt;br /&gt;
** third layer - 6x4 models (&amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt; symbols, &amp;lt;code&amp;gt;15&amp;lt;/code&amp;gt; symbol threshold)&lt;br /&gt;
** fourth layer - 1x4 models (&amp;lt;code&amp;gt;5&amp;lt;/code&amp;gt; symbols, &amp;lt;code&amp;gt;15&amp;lt;/code&amp;gt; symbol threshold)&lt;br /&gt;
&lt;br /&gt;
Decoding top left pixel (for it no neighbourhood is provided):&lt;br /&gt;
&lt;br /&gt;
  val = coder-&amp;gt;decode_model(modeller-&amp;gt;primary_model);&lt;br /&gt;
  if (val &amp;lt; modeller-&amp;gt;cache_size) {&lt;br /&gt;
      pix = modeller-&amp;gt;cache[pix];&lt;br /&gt;
      if pix is found in the provided neighbourhood, insert it to the first position in the cache&lt;br /&gt;
        (it doesn't matter if it's already in the cache)&lt;br /&gt;
      else move it to the first position shifting other values by one&lt;br /&gt;
  } else {&lt;br /&gt;
      pix = coder-&amp;gt;decode_model(modeller-&amp;gt;escape_model);&lt;br /&gt;
      if pix is found in cache, move it to the first position shifting other values by one&lt;br /&gt;
      else just insert it at the first position in cache&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Decoding other pixels:&lt;br /&gt;
&lt;br /&gt;
  get neighbourhood (left, top, top-right and top-left pixels)&lt;br /&gt;
  select secondary model depending on neighbourhood&lt;br /&gt;
  if decoded value is less than number of neighbours, pick corresponding neighbour&lt;br /&gt;
  else decode pixel like top left one but provide neighbourhood for the reference this time&lt;br /&gt;
&lt;br /&gt;
Determine neighborhood as:&lt;br /&gt;
 If top pixel isn't available (first row): top = top-right = top-left = left&lt;br /&gt;
     (left is available, as it was decoded above)&lt;br /&gt;
 &lt;br /&gt;
 If right pixel isn't available (last column): top-right = top&lt;br /&gt;
 &lt;br /&gt;
 If left pixel isn't available (first column): left = top-left = top&lt;br /&gt;
 &lt;br /&gt;
 If neither right now left are available (single column):  top-right = top-left = left = top&lt;br /&gt;
 &lt;br /&gt;
 note: pixels outside the current area aren't considered available&lt;br /&gt;
&lt;br /&gt;
Determine secondary model as:&lt;br /&gt;
&lt;br /&gt;
 layer = number of different neighborhoods (1 if all equal, 4 if all different, 2 if ABBB or AABB&lt;br /&gt;
 or ABBA or any other such combination, 3 if ABCC or ABBC or ABCA or any other such combination)&lt;br /&gt;
 &lt;br /&gt;
 sublayer = identify which neighborhoods are equal to each other. For example:&lt;br /&gt;
 &lt;br /&gt;
 if layer == 1:    # all equal&lt;br /&gt;
     sublayer = 0&lt;br /&gt;
 &lt;br /&gt;
 if layer == 2:    # 2-2&lt;br /&gt;
     if top == topLeft:&lt;br /&gt;
         if topRight == topLeft:&lt;br /&gt;
             sublayer = 3&lt;br /&gt;
         elsif left == topLeft:&lt;br /&gt;
             sublayer = 2&lt;br /&gt;
         else:&lt;br /&gt;
             sublayer = 4&lt;br /&gt;
     elsif topRight == topLeft:&lt;br /&gt;
         if left == topLeft:&lt;br /&gt;
             sublayer = 1&lt;br /&gt;
         else:&lt;br /&gt;
             sublayer = 5&lt;br /&gt;
     else&lt;br /&gt;
         if left == topLeft:&lt;br /&gt;
             sublayer = 6&lt;br /&gt;
         else:&lt;br /&gt;
             sublayer = 0&lt;br /&gt;
 &lt;br /&gt;
 if layer == 3:    # 2-1-1&lt;br /&gt;
     if top == topLeft:&lt;br /&gt;
         sublayer = 0&lt;br /&gt;
     elsif topRight == topLeft:&lt;br /&gt;
         sublayer = 1&lt;br /&gt;
     elsif left == topLeft:&lt;br /&gt;
         sublayer = 2&lt;br /&gt;
     elsif topRight == top:&lt;br /&gt;
         sublayer = 3&lt;br /&gt;
     elsif left == top:&lt;br /&gt;
         sublayer = 4&lt;br /&gt;
     else&lt;br /&gt;
         sublayer = 5&lt;br /&gt;
 &lt;br /&gt;
 if layer == 4:    # all different&lt;br /&gt;
     sublayer = 0&lt;br /&gt;
 &lt;br /&gt;
 subsublayer = 0&lt;br /&gt;
 if left-left pixel is available (column &amp;gt;= 2) and its value is equal to the left pixel:&lt;br /&gt;
     subsublayer += 1&lt;br /&gt;
 if top-top pixel is available (row &amp;gt;= 2) and its value is equal to the top pixel:&lt;br /&gt;
     subsublayer += 2&lt;br /&gt;
&lt;br /&gt;
=== MSS2 details ===&lt;br /&gt;
&lt;br /&gt;
MSS2 (aka Windows Media Video 9 Screen codec) seems to be largely the same as MSS1 with such differences:&lt;br /&gt;
* RGB24 compression instead of palettised images (maybe)&lt;br /&gt;
* motion compensation in interframes&lt;br /&gt;
* different header format&lt;br /&gt;
&lt;br /&gt;
[[Category:Video Codecs]]&lt;br /&gt;
[[Category:Screen Capture Video Codecs]]&lt;br /&gt;
[[Category:Undiscovered Video Codecs]]&lt;/div&gt;</summary>
		<author><name>Nkd</name></author>
	</entry>
</feed>