/* * 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 */ #pragma shader_stage(compute) #extension GL_GOOGLE_include_directive : require #define GET_BITS_SMEM 4 #include "common.glsl" layout (constant_id = 0) const bool interlaced = false; layout (set = 0, binding = 0) readonly buffer slice_offsets_buf { uint32_t slice_offsets[]; }; layout (set = 0, binding = 1) writeonly buffer quant_idx_buf { uint8_t quant_idx[]; }; layout (set = 0, binding = 2) uniform writeonly uimage2D dst[]; layout (push_constant, scalar) uniform pushConstants { u8buf slice_data; uint bitstream_size; uint16_t width; uint16_t height; uint16_t mb_width; uint16_t mb_height; uint16_t slice_width; uint16_t slice_height; uint8_t log2_slice_width; uint8_t log2_chroma_w; uint8_t depth; uint8_t alpha_info; uint8_t bottom_field; }; /** * Table 9, encoded as (last_rice_q << 0) | (krice or kexp << 4) | ((kexp or kexp + 1) << 8) * According to the SMPTE document, abs(prev_dc_diff) should be used * to index the table, duplicating the entries removes the abs operation. */ const uint16_t k_dc_codebook[] = { U16(0x100), U16(0x210), U16(0x210), U16(0x321), U16(0x321), U16(0x430), U16(0x430), }; /* Table 10 */ const uint16_t k_ac_run_codebook [] = { U16(0x102), U16(0x102), U16(0x101), U16(0x101), U16(0x100), U16(0x211), U16(0x211), U16(0x211), U16(0x211), U16(0x210), U16(0x210), U16(0x210), U16(0x210), U16(0x210), U16(0x210), U16(0x320), }; /* Table 11 */ const uint16_t k_ac_level_codebook[] = { U16(0x202), U16(0x101), U16(0x102), U16(0x100), U16(0x210), U16(0x210), U16(0x210), U16(0x210), U16(0x320) }; /* Figure 4, encoded as (x << 0) | (y << 4) */ const uint8_t k_scan_tbl[] = { U8(0x00), U8(0x01), U8(0x10), U8(0x11), U8(0x02), U8(0x03), U8(0x12), U8(0x13), U8(0x20), U8(0x21), U8(0x30), U8(0x31), U8(0x22), U8(0x23), U8(0x32), U8(0x33), U8(0x04), U8(0x05), U8(0x14), U8(0x24), U8(0x15), U8(0x06), U8(0x07), U8(0x16), U8(0x25), U8(0x34), U8(0x35), U8(0x26), U8(0x17), U8(0x27), U8(0x36), U8(0x37), U8(0x40), U8(0x41), U8(0x50), U8(0x60), U8(0x51), U8(0x42), U8(0x43), U8(0x52), U8(0x61), U8(0x70), U8(0x71), U8(0x62), U8(0x53), U8(0x44), U8(0x45), U8(0x54), U8(0x63), U8(0x72), U8(0x73), U8(0x64), U8(0x55), U8(0x46), U8(0x47), U8(0x56), U8(0x65), U8(0x74), U8(0x75), U8(0x66), U8(0x57), U8(0x67), U8(0x76), U8(0x77), }; /* Figure 5 */ const uint8_t k_scan_tbl_interlaced[] = { U8(0x00), U8(0x10), U8(0x01), U8(0x11), U8(0x20), U8(0x30), U8(0x21), U8(0x31), U8(0x02), U8(0x12), U8(0x03), U8(0x13), U8(0x22), U8(0x32), U8(0x23), U8(0x33), U8(0x40), U8(0x50), U8(0x41), U8(0x42), U8(0x51), U8(0x60), U8(0x70), U8(0x61), U8(0x52), U8(0x43), U8(0x53), U8(0x62), U8(0x71), U8(0x72), U8(0x63), U8(0x73), U8(0x04), U8(0x14), U8(0x05), U8(0x06), U8(0x15), U8(0x24), U8(0x34), U8(0x25), U8(0x16), U8(0x07), U8(0x17), U8(0x26), U8(0x35), U8(0x44), U8(0x54), U8(0x45), U8(0x36), U8(0x27), U8(0x37), U8(0x46), U8(0x55), U8(0x64), U8(0x74), U8(0x65), U8(0x56), U8(0x47), U8(0x57), U8(0x66), U8(0x75), U8(0x76), U8(0x67), U8(0x77), }; shared uint16_t dc_codebook [k_dc_codebook .length()], ac_run_codebook [k_ac_run_codebook .length()], ac_level_codebook[k_ac_level_codebook.length()]; shared uint8_t scan_tbl[k_scan_tbl.length()]; void put_px(uint tex_idx, ivec2 pos, uint v) { if (interlaced) pos = ivec2(pos.x, (pos.y << 1) + bottom_field); imageStore(dst[nonuniformEXT(tex_idx)], pos, uvec4(uint16_t(v))); } /* 7.5.3 Pixel Arrangement */ ivec2 pos_to_block(uint pos, uint luma) { return ivec2((pos & -luma - 2) + luma >> 1, pos >> luma & 1) << 3; } /* 7.1.1.2 Signed Golomb Combination Codes */ uint to_signed(uint x) { return (x >> 1) ^ -(x & 1); } /* 7.1.1.1 Golomb Combination Codes */ uint decode_codeword(inout GetBitContext gb, int codebook) { int last_rice_q = bitfieldExtract(codebook, 0, 4), krice = bitfieldExtract(codebook, 4, 4), kexp = bitfieldExtract(codebook, 8, 4); int q = 31 - findMSB(show_bits(gb, 32)); if (q <= last_rice_q) { /* Golomb-Rice encoding */ return (get_bits(gb, krice + q + 1) & ~(1 << krice)) + (q << krice); } else { /* exp-Golomb encoding */ return get_bits(gb, (q << 1) + kexp - last_rice_q) - (1 << kexp) + ((last_rice_q + 1) << krice); } } void decode_comp(in GetBitContext gb, uvec2 mb_pos, uint mb_count) { uvec3 gid = gl_GlobalInvocationID; uint is_luma = uint(gid.z == 0); uint chroma_shift = bool(is_luma) ? 0 : log2_chroma_w; uint num_blocks = mb_count << (2 - chroma_shift); ivec2 base_pos = ivec2(mb_pos.x << (4 - chroma_shift), mb_pos.y << 4); /* 7.1.1.3 DC Coefficients */ { /* First coeff */ uint c = to_signed(decode_codeword(gb, 0x650)); put_px(gid.z, base_pos, c); uint cw = 5, prev_dc_diff = 0; for (int i = 1; i < num_blocks; ++i) { cw = decode_codeword(gb, dc_codebook[min(cw, 6)]); int s = int(prev_dc_diff) >> 31; c += prev_dc_diff = (to_signed(cw) ^ s) - s; put_px(gid.z, base_pos + pos_to_block(i, is_luma), c); } } /* 7.1.1.4 AC Coefficients */ { uint block_mask = num_blocks - 1; uint block_shift = findLSB(num_blocks); uint pos = num_blocks - 1, run = 4, level = 1, s; while (pos < num_blocks << 6) { int left = left_bits(gb); if (left <= 0 || (left < 32 && show_bits(gb, left) == 0)) break; run = decode_codeword(gb, ac_run_codebook [min(run, 15)]); level = decode_codeword(gb, ac_level_codebook[min(level, 8 )]); s = get_bits(gb, 1); pos += run + 1; uint bidx = pos & block_mask, scan = scan_tbl[pos >> block_shift]; ivec2 spos = pos_to_block(bidx, is_luma); ivec2 bpos = ivec2(scan & 0xf, scan >> 4); uint c = ((level + 1) ^ -s) + s; put_px(gid.z, base_pos + spos + bpos, c); } } } /* 7.1.2 Scanned Alpha */ void decode_alpha(in GetBitContext gb, uvec2 mb_pos, uint mb_count) { uvec3 gid = gl_GlobalInvocationID; ivec2 base_pos = ivec2(mb_pos) << 4; uint block_shift = findMSB(mb_count) + 4, block_mask = (1 << block_shift) - 1; uint mask = (1 << (4 << alpha_info)) - 1; uint num_values = (mb_count << 4) * min(height - (gid.y << 4), 16); int num_cw_bits = alpha_info == 1 ? 5 : 8, num_flc_bits = alpha_info == 1 ? 9 : 17; uint alpha_rescale_lshift = alpha_info == 1 ? depth - 8 : 16, alpha_rescale_rshift = 16 - depth; uint alpha = -1; for (uint pos = 0; pos < num_values;) { uint diff, run; /* Decode run value */ { uint bits = show_bits(gb, num_cw_bits), q = num_cw_bits - 1 - findMSB(bits); /* Tables 13/14 */ if (q != 0) { uint m = (bits >> 1) + 1, s = bits & 1; diff = (m ^ -s) + s; skip_bits(gb, num_cw_bits); } else { diff = get_bits(gb, num_flc_bits); } alpha = alpha + diff & mask; } /* Decode run length */ { uint bits = show_bits(gb, 5), q = 4 - findMSB(bits); /* Table 12 */ if (q == 0) { run = 1; skip_bits(gb, 1); } else if (q <= 4) { run = bits + 1; skip_bits(gb, 5); } else { run = get_bits(gb, 16) + 1; } run = min(run, num_values - pos); } /** * FFmpeg doesn't support color and alpha with different precision, * so we need to rescale to the color range. */ uint val = (alpha << alpha_rescale_lshift) | (alpha >> alpha_rescale_rshift); for (uint end = pos + run; pos < end; ++pos) put_px(3, base_pos + ivec2(pos & block_mask, pos >> block_shift), val); } } void main(void) { uvec3 gid = gl_GlobalInvocationID; if (gid.x >= slice_width || gid.y >= slice_height) return; uint slice_idx = gid.y * slice_width + gid.x; uint slice_off = slice_offsets[slice_idx], slice_size = slice_offsets[slice_idx + 1] - slice_off; u8buf bs = u8buf(slice_data + slice_off); /* Decode slice header */ uint hdr_size, qidx, y_size, u_size, v_size, a_size; hdr_size = bs[0].v >> 3, qidx = clamp(bs[1].v, 1, 224); y_size = (uint(bs[2].v) << 8) | bs[3].v; u_size = (uint(bs[4].v) << 8) | bs[5].v; /** * The alpha_info field can be 0 even when an alpha plane is present, * if skip_alpha is enabled, so use the header size instead. */ if (hdr_size > 6) v_size = (uint(bs[6].v) << 8) | bs[7].v; else v_size = slice_size - hdr_size - y_size - u_size; a_size = slice_size - hdr_size - y_size - u_size - v_size; bs += hdr_size; int bs_size = 0; switch (gid.z) { case 0: bs_size = int(y_size); break; case 1: bs_size = int(u_size), bs += y_size; break; case 2: bs_size = int(v_size), bs += y_size + u_size; break; case 3: bs_size = int(a_size), bs += y_size + u_size + v_size; break; } GetBitContext gb; init_get_bits(gb, bs, bs_size); /** * Support for the grayscale "extension" in the prores_aw encoder. * According to the spec, entropy coded data should never be empty, * and instead contain at least the DC coefficients. * This avoids undefined behavior. */ if (left_bits(gb) == 0) return; /* Copy constant tables to local memory */ dc_codebook = k_dc_codebook; ac_run_codebook = k_ac_run_codebook; ac_level_codebook = k_ac_level_codebook; if (!interlaced) scan_tbl = k_scan_tbl; else scan_tbl = k_scan_tbl_interlaced; /** * 4 ProRes Frame Structure * ProRes tiles pictures into a grid of slices, whose size is determined * by the log2_slice_width parameter (height is always 1 MB). * Each slice has a width of (1 << log2_slice_width) MBs, until the picture * cannot accommodate a full one. At this point, the remaining space * is recursively completed using the first smaller power of two that fits * (see Figure 1). * The maximum number of extra slices is 3, when log2_slice_width is 3, * with sizes 4, 2 and 1 MBs. * The mb_width parameter therefore also represents the number of full slices, * when interpreted as a fixed-point number with log2_slice_width fractional bits. */ uint frac = bitfieldExtract(uint(mb_width), 0, log2_slice_width), num_extra = bitCount(frac); uint diff = slice_width - gid.x - 1, off = max(int(diff - num_extra + 1) << 2, 0); uint log2_width = min(findLSB(frac - diff >> diff) + diff + off, log2_slice_width); uint mb_x = (min(gid.x, slice_width - num_extra) << log2_slice_width) + (frac & (0xf << log2_width + 1)), mb_y = gid.y; uint mb_count = 1 << log2_width; if (gid.z < 3) { /* Color entropy decoding, inverse scanning */ decode_comp(gb, uvec2(mb_x, mb_y), mb_count); } else { /* Alpha entropy decoding */ decode_alpha(gb, uvec2(mb_x, mb_y), mb_count); } /* Forward the quantization index to the IDCT shader */ if (gid.z == 0) { uint base = mb_y * mb_width + mb_x; for (uint i = 0; i < mb_count; ++i) quant_idx[base + i] = uint8_t(qidx); } }