/* * 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 */ layout(buffer_reference, buffer_reference_align = 1) buffer u8buf { uint8_t v;}; layout(buffer_reference, buffer_reference_align = 1) buffer u8vec2buf { u8vec2 v;}; layout(buffer_reference, buffer_reference_align = 1) buffer u8vec4buf { u8vec4 v;}; layout(buffer_reference, buffer_reference_align = 2) buffer u16buf { uint16_t v;}; layout(buffer_reference, buffer_reference_align = 4) buffer u32buf { uint32_t v;}; layout(buffer_reference, buffer_reference_align = 4) buffer u32vec2buf { u32vec2 v;}; layout(buffer_reference, buffer_reference_align = 8) buffer u64buf { uint64_t v;}; #define OFFBUF(type, b, l) \ type(uint64_t(b) + uint64_t(l)) #define zero_extend(a, p) \ ((a) & ((1 << (p)) - 1)) #define sign_extend(val, bits) \ bitfieldExtract(val, 0, bits) #define fold(diff, bits) \ sign_extend(diff, bits) #define mid_pred(a, b, c) \ max(min((a), (b)), min(max((a), (b)), (c))) /* TODO: optimize */uint align(uint src, uint a){ uint res = src % a; if (res == 0) return src; return src + a - res;} /* TODO: optimize */uint64_t align64(uint64_t src, uint64_t a){ uint64_t res = src % a; if (res == 0) return src; return src + a - res;} #define reverse4(src) \ (pack32(unpack8(uint32_t(src)).wzyx)) u32vec2 reverse8(uint64_t src){ u32vec2 tmp = unpack32(src); tmp.x = reverse4(tmp.x); tmp.y = reverse4(tmp.y); return tmp.yx;} #ifdef PB_32#define BIT_BUF_TYPE uint32_t#define BUF_TYPE u32buf#define BUF_REVERSE(src) reverse4(src)#define BUF_BITS uint8_t(32)#define BUF_BYTES uint8_t(4)#define BYTE_EXTRACT(src, byte_off) \ (uint8_t(bitfieldExtract((src), ((byte_off) << 3), 8)))#else#define BIT_BUF_TYPE uint64_t#define BUF_TYPE u32vec2buf#define BUF_REVERSE(src) reverse8(src)#define BUF_BITS uint8_t(64)#define BUF_BYTES uint8_t(8)#define BYTE_EXTRACT(src, byte_off) \ (uint8_t(((src) >> ((byte_off) << 3)) & 0xFF))#endif struct PutBitContext { uint64_t buf_start; uint64_t buf; BIT_BUF_TYPE bit_buf; uint8_t bit_left;}; void put_bits(inout PutBitContext pb, const uint32_t n, uint32_t value){ if (n < pb.bit_left) { pb.bit_buf = (pb.bit_buf << n) | value; pb.bit_left -= uint8_t(n); } else { pb.bit_buf <<= pb.bit_left; pb.bit_buf |= (value >> (n - pb.bit_left)); #ifdef PB_UNALIGNED u8buf bs = u8buf(pb.buf); [[unroll]] for (uint8_t i = uint8_t(0); i < BUF_BYTES; i++) bs[i].v = BYTE_EXTRACT(pb.bit_buf, BUF_BYTES - uint8_t(1) - i);#else#ifdef DEBUG if ((pb.buf % BUF_BYTES) != 0) debugPrintfEXT("put_bits buffer is not aligned!");#endif BUF_TYPE bs = BUF_TYPE(pb.buf); bs.v = BUF_REVERSE(pb.bit_buf);#endif pb.buf = uint64_t(bs) + BUF_BYTES; pb.bit_left += BUF_BITS - uint8_t(n); pb.bit_buf = value; }} uint32_t flush_put_bits(inout PutBitContext pb){ /* Align bits to MSBs */ if (pb.bit_left < BUF_BITS) pb.bit_buf <<= pb.bit_left; if (pb.bit_left < BUF_BITS) { uint to_write = ((BUF_BITS - pb.bit_left - 1) >> 3) + 1; u8buf bs = u8buf(pb.buf); for (int i = 0; i < to_write; i++) bs[i].v = BYTE_EXTRACT(pb.bit_buf, BUF_BYTES - uint8_t(1) - i); pb.buf = uint64_t(bs) + to_write; } pb.bit_left = BUF_BITS; pb.bit_buf = 0x0; return uint32_t(pb.buf - pb.buf_start);} void init_put_bits(out PutBitContext pb, u8buf data, uint64_t len){ pb.buf_start = uint64_t(data); pb.buf = uint64_t(data); pb.bit_buf = 0; pb.bit_left = BUF_BITS;} uint64_t put_bits_count(in PutBitContext pb){ return (pb.buf - pb.buf_start)*8 + BUF_BITS - pb.bit_left;} uint32_t put_bytes_count(in PutBitContext pb){ uint64_t num_bytes = (pb.buf - pb.buf_start) + ((BUF_BITS - pb.bit_left) >> 3); return uint32_t(num_bytes);} struct GetBitContext { uint64_t buf_start; uint64_t buf; uint64_t buf_end; uint64_t bits; uint bits_valid; uint size_in_bits;}; #define LOAD64() \ { \ u8vec4buf ptr = u8vec4buf(gb.buf); \ uint32_t rf1 = pack32((ptr[0].v).wzyx); \ uint32_t rf2 = pack32((ptr[1].v).wzyx); \ gb.buf += 8; \ gb.bits = uint64_t(rf1) << 32 | uint64_t(rf2); \ gb.bits_valid = 64; \ } #define RELOAD32() \ { \ u8vec4buf ptr = u8vec4buf(gb.buf); \ uint32_t rf = pack32((ptr[0].v).wzyx); \ gb.buf += 4; \ gb.bits = uint64_t(rf) << (32 - gb.bits_valid) | gb.bits; \ gb.bits_valid += 32; \ } void init_get_bits(inout GetBitContext gb, u8buf data, uint64_t len){ gb.buf = gb.buf_start = uint64_t(data); gb.buf_end = uint64_t(data) + len; gb.size_in_bits = uint(len) * 8; /* Preload */ LOAD64()} bool get_bit(inout GetBitContext gb){ if (gb.bits_valid == 0) LOAD64() bool val = bool(gb.bits >> (64 - 1)); gb.bits <<= 1; gb.bits_valid--; return val;} uint get_bits(inout GetBitContext gb, uint n){ if (n == 0) return 0; if (n > gb.bits_valid) RELOAD32() uint val = uint(gb.bits >> (64 - n)); gb.bits <<= n; gb.bits_valid -= n; return val;} uint show_bits(inout GetBitContext gb, uint n){ if (n > gb.bits_valid) RELOAD32() return uint(gb.bits >> (64 - n));} void skip_bits(inout GetBitContext gb, uint n){ if (n > gb.bits_valid) RELOAD32() gb.bits <<= n; gb.bits_valid -= n;} uint tell_bits(in GetBitContext gb){ return uint(gb.buf - gb.buf_start) * 8 - gb.bits_valid;} uint left_bits(in GetBitContext gb){ return gb.size_in_bits - uint(gb.buf - gb.buf_start) * 8 + gb.bits_valid;}
/*
* 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
*/
layout(buffer_reference, buffer_reference_align = 1) buffer u8buf {
uint8_t v;
};
layout(buffer_reference, buffer_reference_align = 1) buffer u8vec2buf {
u8vec2 v;
};
layout(buffer_reference, buffer_reference_align = 1) buffer u8vec4buf {
u8vec4 v;
};
layout(buffer_reference, buffer_reference_align = 2) buffer u16buf {
uint16_t v;
};
layout(buffer_reference, buffer_reference_align = 4) buffer u32buf {
uint32_t v;
};
layout(buffer_reference, buffer_reference_align = 4) buffer u32vec2buf {
u32vec2 v;
};
layout(buffer_reference, buffer_reference_align = 8) buffer u64buf {
uint64_t v;
};
#define OFFBUF(type, b, l) \
type(uint64_t(b) + uint64_t(l))
#define zero_extend(a, p) \
((a) & ((1 << (p)) - 1))
#define sign_extend(val, bits) \
bitfieldExtract(val, 0, bits)
#define fold(diff, bits) \
sign_extend(diff, bits)
#define mid_pred(a, b, c) \
max(min((a), (b)), min(max((a), (b)), (c)))
/* TODO: optimize */
uint align(uint src, uint a)
{
uint res = src % a;
if (res == 0)
return src;
return src + a - res;
}
/* TODO: optimize */
uint64_t align64(uint64_t src, uint64_t a)
{
uint64_t res = src % a;
if (res == 0)
return src;
return src + a - res;
}
#define reverse4(src) \
(pack32(unpack8(uint32_t(src)).wzyx))
u32vec2 reverse8(uint64_t src)
{
u32vec2 tmp = unpack32(src);
tmp.x = reverse4(tmp.x);
tmp.y = reverse4(tmp.y);
return tmp.yx;
}
#ifdef PB_32
#define BIT_BUF_TYPE uint32_t
#define BUF_TYPE u32buf
#define BUF_REVERSE(src) reverse4(src)
#define BUF_BITS uint8_t(32)
#define BUF_BYTES uint8_t(4)
#define BYTE_EXTRACT(src, byte_off) \
(uint8_t(bitfieldExtract((src), ((byte_off) << 3), 8)))
#else
#define BIT_BUF_TYPE uint64_t
#define BUF_TYPE u32vec2buf
#define BUF_REVERSE(src) reverse8(src)
#define BUF_BITS uint8_t(64)
#define BUF_BYTES uint8_t(8)
#define BYTE_EXTRACT(src, byte_off) \
(uint8_t(((src) >> ((byte_off) << 3)) & 0xFF))
#endif
struct PutBitContext {
uint64_t buf_start;
uint64_t buf;
BIT_BUF_TYPE bit_buf;
uint8_t bit_left;
};
void put_bits(inout PutBitContext pb, const uint32_t n, uint32_t value)
{
if (n < pb.bit_left) {
pb.bit_buf = (pb.bit_buf << n) | value;
pb.bit_left -= uint8_t(n);
} else {
pb.bit_buf <<= pb.bit_left;
pb.bit_buf |= (value >> (n - pb.bit_left));
#ifdef PB_UNALIGNED
u8buf bs = u8buf(pb.buf);
[[unroll]]
for (uint8_t i = uint8_t(0); i < BUF_BYTES; i++)
bs[i].v = BYTE_EXTRACT(pb.bit_buf, BUF_BYTES - uint8_t(1) - i);
#else
#ifdef DEBUG
if ((pb.buf % BUF_BYTES) != 0)
debugPrintfEXT("put_bits buffer is not aligned!");
#endif
BUF_TYPE bs = BUF_TYPE(pb.buf);
bs.v = BUF_REVERSE(pb.bit_buf);
#endif
pb.buf = uint64_t(bs) + BUF_BYTES;
pb.bit_left += BUF_BITS - uint8_t(n);
pb.bit_buf = value;
}
}
uint32_t flush_put_bits(inout PutBitContext pb)
{
/* Align bits to MSBs */
if (pb.bit_left < BUF_BITS)
pb.bit_buf <<= pb.bit_left;
if (pb.bit_left < BUF_BITS) {
uint to_write = ((BUF_BITS - pb.bit_left - 1) >> 3) + 1;
u8buf bs = u8buf(pb.buf);
for (int i = 0; i < to_write; i++)
bs[i].v = BYTE_EXTRACT(pb.bit_buf, BUF_BYTES - uint8_t(1) - i);
pb.buf = uint64_t(bs) + to_write;
}
pb.bit_left = BUF_BITS;
pb.bit_buf = 0x0;
return uint32_t(pb.buf - pb.buf_start);
}
void init_put_bits(out PutBitContext pb, u8buf data, uint64_t len)
{
pb.buf_start = uint64_t(data);
pb.buf = uint64_t(data);
pb.bit_buf = 0;
pb.bit_left = BUF_BITS;
}
uint64_t put_bits_count(in PutBitContext pb)
{
return (pb.buf - pb.buf_start)*8 + BUF_BITS - pb.bit_left;
}
uint32_t put_bytes_count(in PutBitContext pb)
{
uint64_t num_bytes = (pb.buf - pb.buf_start) + ((BUF_BITS - pb.bit_left) >> 3);
return uint32_t(num_bytes);
}
struct GetBitContext {
uint64_t buf_start;
uint64_t buf;
uint64_t buf_end;
uint64_t bits;
uint bits_valid;
uint size_in_bits;
};
#define LOAD64() \
{ \
u8vec4buf ptr = u8vec4buf(gb.buf); \
uint32_t rf1 = pack32((ptr[0].v).wzyx); \
uint32_t rf2 = pack32((ptr[1].v).wzyx); \
gb.buf += 8; \
gb.bits = uint64_t(rf1) << 32 | uint64_t(rf2); \
gb.bits_valid = 64; \
}
#define RELOAD32() \
{ \
u8vec4buf ptr = u8vec4buf(gb.buf); \
uint32_t rf = pack32((ptr[0].v).wzyx); \
gb.buf += 4; \
gb.bits = uint64_t(rf) << (32 - gb.bits_valid) | gb.bits; \
gb.bits_valid += 32; \
}
void init_get_bits(inout GetBitContext gb, u8buf data, uint64_t len)
{
gb.buf = gb.buf_start = uint64_t(data);
gb.buf_end = uint64_t(data) + len;
gb.size_in_bits = uint(len) * 8;
/* Preload */
LOAD64()
}
bool get_bit(inout GetBitContext gb)
{
if (gb.bits_valid == 0)
LOAD64()
bool val = bool(gb.bits >> (64 - 1));
gb.bits <<= 1;
gb.bits_valid--;
return val;
}
uint get_bits(inout GetBitContext gb, uint n)
{
if (n == 0)
return 0;
if (n > gb.bits_valid)
RELOAD32()
uint val = uint(gb.bits >> (64 - n));
gb.bits <<= n;
gb.bits_valid -= n;
return val;
}
uint show_bits(inout GetBitContext gb, uint n)
{
if (n > gb.bits_valid)
RELOAD32()
return uint(gb.bits >> (64 - n));
}
void skip_bits(inout GetBitContext gb, uint n)
{
if (n > gb.bits_valid)
RELOAD32()
gb.bits <<= n;
gb.bits_valid -= n;
}
uint tell_bits(in GetBitContext gb)
{
return uint(gb.buf - gb.buf_start) * 8 - gb.bits_valid;
}
uint left_bits(in GetBitContext gb)
{
return gb.size_in_bits - uint(gb.buf - gb.buf_start) * 8 + gb.bits_valid;
}