Real Lossless Codec
- FOURCCs: ralf
- Company: RealNetworks
- Samples: http://samples.libav.org/A-codecs/lossless/ (luckynight.rmvb)
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; }