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.
122 lines
2.8 KiB
122 lines
2.8 KiB
/* |
|
* 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); |
|
}
|
|
|