/* * Copyright (c) 2024 Lynne * * 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 = 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); }