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;
}