mirror of https://github.com/FFmpeg/FFmpeg.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
123 lines
2.8 KiB
123 lines
2.8 KiB
4 months ago
|
/*
|
||
|
* FFv1 codec
|
||
|
*
|
||
|
* Copyright (c) 2024 Lynne <dev@lynne.ee>
|
||
|
*
|
||
|
* This file is part of FFmpeg.
|
||
|
*
|
||
|
* FFmpeg is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU Lesser General Public
|
||
|
* License as published by the Free Software Foundation; either
|
||
|
* version 2.1 of the License, or (at your option) any later version.
|
||
|
*
|
||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
* Lesser General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Lesser General Public
|
||
|
* License along with FFmpeg; if not, write to the Free Software
|
||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
*/
|
||
|
|
||
|
#define VLC_STATE_SIZE 8
|
||
|
layout(buffer_reference, buffer_reference_align = VLC_STATE_SIZE) buffer VlcState {
|
||
|
uint32_t error_sum;
|
||
|
int16_t drift;
|
||
|
int8_t bias;
|
||
|
uint8_t count;
|
||
|
};
|
||
|
|
||
|
void update_vlc_state(inout VlcState state, const int v)
|
||
|
{
|
||
|
int drift = state.drift;
|
||
|
int count = state.count;
|
||
|
int bias = state.bias;
|
||
|
state.error_sum += uint16_t(abs(v));
|
||
|
drift += v;
|
||
|
|
||
|
if (count == 128) { // FIXME: variable
|
||
|
count >>= 1;
|
||
|
drift >>= 1;
|
||
|
state.error_sum >>= 1;
|
||
|
}
|
||
|
count++;
|
||
|
|
||
|
if (drift <= -count) {
|
||
|
bias = max(bias - 1, -128);
|
||
|
drift = max(drift + count, -count + 1);
|
||
|
} else if (drift > 0) {
|
||
|
bias = min(bias + 1, 127);
|
||
|
drift = min(drift - count, 0);
|
||
|
}
|
||
|
|
||
|
state.bias = int8_t(bias);
|
||
|
state.drift = int16_t(drift);
|
||
|
state.count = uint8_t(count);
|
||
|
}
|
||
|
|
||
|
struct Symbol {
|
||
|
uint32_t bits;
|
||
|
uint32_t val;
|
||
|
};
|
||
|
|
||
|
Symbol set_ur_golomb(int i, int k, int limit, int esc_len)
|
||
|
{
|
||
|
int e;
|
||
|
Symbol sym;
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
if (i < 0)
|
||
|
debugPrintfEXT("Error: i is zero!");
|
||
|
#endif
|
||
|
|
||
|
e = i >> k;
|
||
|
if (e < limit) {
|
||
|
sym.bits = e + k + 1;
|
||
|
sym.val = (1 << k) + zero_extend(i, k);
|
||
|
} else {
|
||
|
sym.bits = limit + esc_len;
|
||
|
sym.val = i - limit + 1;
|
||
|
}
|
||
|
|
||
|
return sym;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* write signed golomb rice code (ffv1).
|
||
|
*/
|
||
|
Symbol set_sr_golomb(int i, int k, int limit, int esc_len)
|
||
|
{
|
||
|
int v;
|
||
|
|
||
|
v = -2 * i - 1;
|
||
|
v ^= (v >> 31);
|
||
|
|
||
|
return set_ur_golomb(v, k, limit, esc_len);
|
||
|
}
|
||
|
|
||
|
Symbol get_vlc_symbol(inout VlcState state, int v, int bits)
|
||
|
{
|
||
|
int i, k, code;
|
||
|
Symbol sym;
|
||
|
v = fold(v - int(state.bias), bits);
|
||
|
|
||
|
i = state.count;
|
||
|
k = 0;
|
||
|
while (i < state.error_sum) { // FIXME: optimize
|
||
|
k++;
|
||
|
i += i;
|
||
|
}
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
if (k > 16)
|
||
|
debugPrintfEXT("Error: k > 16!");
|
||
|
#endif
|
||
|
|
||
|
code = v ^ ((2 * state.drift + state.count) >> 31);
|
||
|
|
||
|
update_vlc_state(state, v);
|
||
|
|
||
|
return set_sr_golomb(code, k, 12, bits);
|
||
|
}
|