QPEG

From MultimediaWiki
Jump to navigation Jump to search

This page is based on the document 'Description of the QPEG Video Codec' by Mike Melanson and Konstantin Shishkov found at http://multimedia.cx/qpeg-format.txt.

QPEG is a video codec developed by Q-Team. Apparently a play on the common multimedia acronyms JPEG and MPEG, QPEG is a palettized 8-bit video codec that uses run length encoding (RLE), interframe differencing and motion compensation to achieve compression.

Algorithm Basics

Decoding a QPEG frame is a bottom-to-top operation. Multi-byte numbers are big-endian.

The palette data for the frame is carried in the container format that holds the QPEG data. This is typically an AVI file.

An encoded QPEG data frame has the following layout:

 bytes 0-3:    size of encoded frame (including this size field)
 bytes 4-131:  frame data table
 byte 132:     unknown, always seems to be 0xE0
 byte 133:     frame type

The frame data table is a special 128-byte table used in decoding interframes.

A frame type of 0x10 indicates that this is an intraframe (keyframe). A 0x00 indicates an interframe that does not use motion compensation. Any other value for frame type indicates an interframe with motion compensation.

Intraframe Decoding

The encoded data for an intraframe begins at byte 134 of the encoded frame (just after byte 133 which contains 0x10 indicating this frame is an intraframe). The algorithm for decoding intraframe data is a basic RLE algorithm that operates as follows:

 while (there are still bytes remaining in encoded frame)
   code = next byte in encoded frame

   if (code is 0xFC)
     frame decode is complete

   if (frame is 0xF8..0xFF, but not 0xFC)
     output very long run to the decoded frame
     code2 = next byte in encoded frame
     code3 = next byte in encoded frame
     run = ((code & 7) << 16) + (code2 << 8) + (code3) + 2
     output next byte in encoded frame to decoded frame (run) times

   if (code is 0xF0..0xF7)
     output long run to the decoded frame
     code2 = next byte in encoded frame
     run = ((code & 0xF) << 8) + (code2) + 2
     output next byte in encoded frame to decoded frame (run) times

   if (code is 0xE0..0xEF)
     output short run to the decoded frame
     run = (code & 0x1F) + 2
     output next byte in encoded frame to decoded frame (run) times

   if (code is 0xC0..0xDF)
     copy very long run from the encoded frame to the decoded frame
     code2 = next byte in encoded frame
     code3 = next byte in encoded frame
     copy = ((code & 0x3F) << 16) + (code2 << 8) + (code3) + 1
     copy (copy) bytes from encoded frame to decoded frame

   if (code is 0x80..0xBF)
     copy long run from the encoded frame to the decoded frame
     code2 = next byte in encoded frame
     copy = ((code & 0x7F) << 8) + (code2 << 8) + 1
     copy (copy) bytes from encoded frame to decoded frame

   if (code is 0x00..0x7F)
     copy short run from the encoded frame to the decoded frame
     copy = code + 1
     copy (copy) bytes from encoded frame to decoded frame

Interframe Decoding

An interframe has codes to allow RLE, pixel skipping, and motion compensation (if the frame type is non-zero). The interframe decoding algorithm operates as follows:

 while (there are still bytes remaining in encoded frame)
   code = next byte in encoded frame

   if (frame type is non-zero)
     while (code & 0xF0 == 0xF0)
       if (frame type is 1)
         do motion compensation
       code = next byte in encoded frame

   if (code is 0xE0)
     frame decode is complete

   if (code > 0xE0)
     note that code can range from 0xE1..0xFF or 0xE1..0xEF depending 
       on whether this interframe uses motion compensation
     output short run to the decoded frame
     run = (code & 0x1F)
     output next byte in encoded frame to decoded frame (run) times

   if (code is 0xC0..0xDF)
     copy short run from the encoded frame to the decoded frame
     copy = (code & 0x1F)
     copy (copy) bytes from encoded frame to decoded frame

   if (code is 0x82..0xBF)
     general skip code
     skip the next (code & 0x3F) pixels in the output frame (unchanged 
       from the previous frame)

   if (code is 0x81)
     special skip code
     code2 = next byte in encoded frame
     skip next (code2 + 320) pixels in the output frame (unchanged from 
       the previous frame)

   if (code is 0x80)
     special skip code
     code2 = next byte in encoded frame
     skip next (code2 + 64) pixels in the output frame (unchanged from 
       the previous frame)

   if (code is 0x01..0x7F)
     special fill code
     next pixel in output frame = frame data table[code]

   if (code is 0x00)
     one-pixel skip
     skip the next pixel in the output frame (unchanged from the
       previous frame)

Regarding "do motion compensation", the QPEG algorithm allows for copying blocks of pixels from the previous frame to the position referenced by the current pixel accounting. Blocks can be variable-sized with dimensions of 4, 8, 16, 24, and 32. The motion vectors have a range of -8..7.

For each iteration through "do motion compensation", the block dimensions are specified by the lower 4 bits of the code variable. The 4 bits (range 0..15) comprise an index into this dimension table:

 0:  0 x 0
 1: 32 x 32
 2: 24 x 32
 3:  8 x 32
 4: 24 x 24
 5: 16 x 16
 6: 32 x 16
 7: 16 x 32
 8:  8 x 16
 9: 16 x 8
10: 32 x 24
11: 32 x 8
12:  8 x 8
13: 16 x 24
14: 24 x 16
15:  4 x 4

The next byte is fetched from the encoded frame. The upper 4 bits of this byte comprise the horizontal component of the motion vector. The lower 4 bits comprise the vertical component. Both components are treated as signed, 2's-complement integers.

The motion block specified by the dimension index and the motion vector is copied into the current decode coordinates in the decoded frame. Note that after this copy takes place, the decoder should not update its output coordinate accounting variables. The algorithm updates these with subsequent skip codes.