Real Lossless Codec

From MultimediaWiki
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

This is RealNetworks lossless audio codec.

Audio header in rm files is different from other Real audio codecs; the interface of the binary decoder is also different.


Extradata format

Numbers are stored big-endian.

bytes  0- 3 - codec FOURCC, always "LSD:"
bytes  4- 5 - version
bytes  8- 9 - number of channels
bytes 10-11 - bits per sample
bytes 12-15 - sampling rate
bytes 16-19 - block size in samples?
bytes 20-23 - ignored?

Known decoder support only 1/2 channel 16-bit audio with sampling rate up to 96 kHz.

Frame format

Data is read MSB.

 block header
 channel data 1
 if (stereo)
   channel data 2
 Each channel is then restored by applying filter and in stereo case channels are recombined.

Block header

 get frame length code
 if (stereo)
   decoding_mode = get_bits(2) + 1;
 else
   decoding_mode = 0;

Frame length code:

   64 - 111110
  128 - 111111
  256 - 11110
  512 - 1110
 1024 - 110
 2048 - 10
 4096 - 0

Decoding mode specifies table sets, bits and channel recombining:

Mode tableset1 bits1 tableset2 bits2 Channel decoupling
0 0 16 n/a n/a mono
1 0 16 0 16 L, R
2 0 16 2 17 L+R, R
3 1 16 2 17 L, R-L
4 2 17 2 17 (L+R)/2, (L-R)/2

Block data

Variable-length codes

RALF uses hybrid coding scheme for signed integers: coded value in range 1..N-1 maps to -N/2+1..N/2-1 and values 0 and N are used as escape values. In case an escape value is occurred, an additional Elias Gamma code (aka exp-Golomb) is read and added to or subtracted from the result. Also some low bits can be read explicitly.

 extend_code(code, range, add_bits)
 {
   if (code == 0) {
     len = get_unary(); // 000...001
     code = -range + 1 - get_bits(len + 1);
   } else if (code == range*2) {
     len = get_unary(); // 000...001
     code = range - 1 + get_bits(len + 1);
   } else {
     code -= range;
   }
   if (add_bits > 0)
     code = (code << add_bits) | get_bits(add_bits);
   return code;
 }

Channel data

Channel data is organised that way:

 filter_parameter = get_vlc(filter_parameter_table);
 if (filter_parameter == 642) {
     bias_val = 0;
     all samples are coded raw
 }
 bias_val = get_vlc(bias_table);
 bias_val = extend_code(bias_val, 127, 4); // input is 0..254, make it signed, read escape values if needed and low 4 bits
 if (filter_parameter == 0) {
     all samples are zero
     return
 }
 if (filter_parameter > 1) {
     filter_bits = (filter_parameter - 2) >> 6; // range 0..9
     filter_len  = filter_parameter - 1 - (filter_bits << 6); // range 1..64
     coeff = 0;
     coeff_mode = 0;
     for (i = 0; i < filter_len; i++) {
         t = get_vlc(filt_coef_table[filter_bits][coeff_mode + 5]);
         t = extend_code(t, 21, filter_bits);
         if (coeff_mode == 0)
             coeff -= 12 << filter_bits;
         coeff = t - coeff;
         filter[i] = coeff;
         coeff_mode = coeff >> filter_bits;
         if (coeff_mode < 0)
             coeff_mode = max(-5, -1 - log2(-coeff_mode));
         else if (coeff_mode > 0)
             coeff_mode = min(5, 1 + log2(coeff_mode));
     }
 }
 coding_mode = get_vlc(coding_mode_tree);
 if (coding_mode >= 15) { // big codes
     bits = (coding_mode / 5 - 3) / 2;
     if (bits > 9) {
         bits = 9;
         if ((coding_mode % 5) == 2)
             bits++;
     }
     for (i = 0; i < num_samples; i += 2) {
         t = get_vlc(long_codes_trees[coding_mode - 15]);
         val1 = t / 21;
         val2 = t - val1 * 21;
         val1 = extend_code(val1, 10, 0);
         val2 = extend_code(val2, 10, 0);
         if (bits == 0) {
             dst[i]     = val1;
             dst[i + 1] = val2;
         } else {
             dst[i]     = (val1 << bits) | get_bits(bits);
             dst[i + 1] = (val2 << bits) | get_bits(bits);
         }
     }
 } else {
     for (i = 0; i < num_samples; i += 2) {
         t = get_vlc(short_codes_trees[coding_mode]);
         val1 = t / 13;
         val2 = t - val1 * 13;
         val1 = extend_code(val1, 6, 0);
         val2 = extend_code(val2, 6, 0);
         dst[i]     = val1;
         dst[i + 1] = val2;
     }
 }

Restoring channel data

  • apply LPC filter
  • add bias value to all samples
  • re-correlate stereo channels if needed

LPC filter

 filter_bits = ((filter_parameter - 2) >> 6) + 3;
 range_bits  = bits_in_channel; // i.e. 16 or 17
 bias        = 1 << (filter_bits - 1);
 pos_clip    = (1 << range_bits) - 1;
 neg_clip    = ~pos_clip;
 
 for (i = 0; i < num_samples; i++) {
     acc = 0;
     for (j = 0; j < min(i, filter_length); j++)
         acc += filter[j] * src[i - j - 1];
     if (acc < 0)
         val = (acc + bias - 1) >> filter_bits;
     else
         val = (acc + bias) >> filter_bits;
     val = clip(val, neg_clip, pos_clip);
     src[i] += val;
 }