1 /*
2 * Vidvox Hap decoder
3 * Copyright (C) 2015 Vittorio Giovara <vittorio.giovara@gmail.com>
4 * Copyright (C) 2015 Tom Butterworth <bangnoise@gmail.com>
5 *
6 * HapQA and HAPAlphaOnly added by Jokyo Images
7 *
8 * This file is part of FFmpeg.
9 *
10 * FFmpeg is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * FFmpeg is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with FFmpeg; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 /**
26 * @file
27 * Hap decoder
28 *
29 * Fourcc: Hap1, Hap5, HapY, HapA, HapM
30 *
31 * https://github.com/Vidvox/hap/blob/master/documentation/HapVideoDRAFT.md
32 */
33
34 #include <stdint.h>
35
37
45
47 {
49 int section_size;
51 int is_first_table = 1, had_offsets = 0, had_compressors = 0, had_sizes = 0;
53
59
61
62 switch (section_type) {
67 for (
i = 0;
i < section_size;
i++) {
68 ctx->chunks[
i].compressor = bytestream2_get_byte(gbc) << 4;
69 }
70 had_compressors = 1;
71 is_first_table = 0;
72 break;
77 for (
i = 0;
i < section_size / 4;
i++) {
78 ctx->chunks[
i].compressed_size = bytestream2_get_le32(gbc);
79 }
80 had_sizes = 1;
81 is_first_table = 0;
82 break;
87 for (
i = 0;
i < section_size / 4;
i++) {
88 ctx->chunks[
i].compressed_offset = bytestream2_get_le32(gbc);
89 }
90 had_offsets = 1;
91 is_first_table = 0;
92 break;
93 default:
94 break;
95 }
97 }
98
99 if (!had_sizes || !had_compressors)
101
102 /* The offsets table is optional. If not present than calculate offsets by
103 * summing the sizes of preceding chunks. */
104 if (!had_offsets) {
105 size_t running_size = 0;
106 for (
i = 0;
i <
ctx->chunk_count;
i++) {
107 ctx->chunks[
i].compressed_offset = running_size;
108 if (
ctx->chunks[
i].compressed_size > UINT32_MAX - running_size)
110 running_size +=
ctx->chunks[
i].compressed_size;
111 }
112 }
113
114 return 0;
115 }
116
118 {
120 size_t running_offset = 0;
121 for (
i = 0;
i <
ctx->chunk_count;
i++) {
122 if (
ctx->chunks[
i].compressed_offset != running_offset
124 return 0;
125 running_offset +=
ctx->chunks[
i].compressed_size;
126 }
127 return 1;
128 }
129
131 {
134 int section_size;
136 const char *compressorstr;
138
142
150 "Invalid texture format %#04x.\n", section_type & 0x0F);
152 }
153
154 switch (section_type & 0xF0) {
159 ctx->chunks[0].compressor = section_type & 0xF0;
160 ctx->chunks[0].compressed_offset = 0;
161 ctx->chunks[0].compressed_size =
ctx->texture_section_size;
162 }
164 compressorstr = "none";
165 } else {
166 compressorstr = "snappy";
167 }
168 break;
175 compressorstr = "complex";
176 break;
177 default:
179 break;
180 }
181
184
185 /* Check the frame is valid and read the uncompressed chunk sizes */
187 for (
i = 0;
i <
ctx->chunk_count;
i++) {
189
190 /* Check the compressed buffer is valid */
193
194 /* Chunks are unpacked sequentially, ctx->tex_size is the uncompressed
195 * size thus far */
197
198 /* Fill out uncompressed size */
201 int64_t uncompressed_size;
205 if (uncompressed_size < 0) {
206 return uncompressed_size;
207 }
211 } else {
213 }
215 }
216
218
220 }
221
223 int chunk_nb, int thread_nb)
224 {
226
230
232
235 int64_t uncompressed_size =
ctx->tex_size;
236
237 /* Uncompress the frame */
242 }
245 }
246
247 return 0;
248 }
249
251 int slice, int thread_nb, int texture_num)
252 {
255 const uint8_t *
d =
ctx->tex_data;
258 int x, y;
259 int start_slice, end_slice;
260 int base_blocks_per_slice = h_block /
ctx->slice_count;
261 int remainder_blocks = h_block %
ctx->slice_count;
262
263 /* When the frame height (in blocks) doesn't divide evenly between the
264 * number of slices, spread the remaining blocks evenly between the first
265 * operations */
266 start_slice = slice * base_blocks_per_slice;
267 /* Add any extra blocks (one per slice) that have been added before this slice */
268 start_slice +=
FFMIN(slice, remainder_blocks);
269
270 end_slice = start_slice + base_blocks_per_slice;
271 /* Add an extra block if there are still remainder blocks to be accounted for */
272 if (slice < remainder_blocks)
273 end_slice++;
274
275 for (y = start_slice; y < end_slice; y++) {
277 int off = y * w_block;
278 for (x = 0; x < w_block; x++) {
279 if (texture_num == 0) {
280 ctx->tex_fun(p + x * 4 *
ctx->uncompress_pix_size,
frame->linesize[0],
281 d + (off + x) *
ctx->tex_rat);
282 } else {
283 ctx->tex_fun2(p + x * 4 *
ctx->uncompress_pix_size,
frame->linesize[0],
284 d + (off + x) *
ctx->tex_rat2);
285 }
286 }
287 }
288
289 return 0;
290 }
291
293 int slice, int thread_nb)
294 {
296 }
297
299 int slice, int thread_nb)
300 {
302 }
303
306 {
310 int section_size;
312 int start_texture_section = 0;
313 int tex_rat[2] = {0, 0};
314
316
317 tex_rat[0] =
ctx->tex_rat;
318
319 /* check for multi texture header */
320 if (
ctx->texture_count == 2) {
324 if ((section_type & 0x0F) != 0x0D) {
325 av_log(avctx,
AV_LOG_ERROR,
"Invalid section type in 2 textures mode %#04x.\n", section_type);
327 }
328 start_texture_section = 4;
329 tex_rat[1] =
ctx->tex_rat2;
330 }
331
332 /* Get the output frame ready to receive data */
337
338 for (t = 0; t <
ctx->texture_count; t++) {
340
341 /* Check for section header */
345
348 *tex_rat[t]) {
351 }
352
353 start_texture_section +=
ctx->texture_section_size + 4;
354
357
358 /* Unpack the DXT texture */
360 int tex_size;
361 /* Only DXTC texture compression in a contiguous block */
362 ctx->tex_data =
ctx->gbc.buffer;
366 *tex_rat[t]) {
369 }
370 } else {
371 /* Perform the second-stage decompression */
375
377 ctx->chunk_results,
ctx->chunk_count);
378
379 for (
i = 0;
i <
ctx->chunk_count;
i++) {
380 if (
ctx->chunk_results[
i] < 0)
381 return ctx->chunk_results[
i];
382 }
383
384 ctx->tex_data =
ctx->tex_buf;
385 }
386
387 /* Use the decompress function on the texture, one block per thread */
388 if (t == 0){
390 } else{
393 }
394 }
395
396 /* Frame is ready to be output */
399 *got_frame = 1;
400
402 }
403
405 {
407 const char *texture_name;
409
414 }
415
416 /* Since codec is based on 4x4 blocks, size is aligned to 4 */
419
421
422 ctx->texture_count = 1;
423 ctx->uncompress_pix_size = 4;
424
426 case MKTAG(
'H',
'a',
'p',
'1'):
427 texture_name = "DXT1";
429 ctx->tex_fun =
ctx->dxtc.dxt1_block;
431 break;
432 case MKTAG(
'H',
'a',
'p',
'5'):
433 texture_name = "DXT5";
435 ctx->tex_fun =
ctx->dxtc.dxt5_block;
437 break;
438 case MKTAG(
'H',
'a',
'p',
'Y'):
439 texture_name = "DXT5-YCoCg-scaled";
441 ctx->tex_fun =
ctx->dxtc.dxt5ys_block;
443 break;
444 case MKTAG(
'H',
'a',
'p',
'A'):
445 texture_name = "RGTC1";
447 ctx->tex_fun =
ctx->dxtc.rgtc1u_gray_block;
449 ctx->uncompress_pix_size = 1;
450 break;
451 case MKTAG(
'H',
'a',
'p',
'M'):
452 texture_name = "DXT5-YCoCg-scaled / RGTC1";
455 ctx->tex_fun =
ctx->dxtc.dxt5ys_block;
456 ctx->tex_fun2 =
ctx->dxtc.rgtc1u_alpha_block;
458 ctx->texture_count = 2;
459 break;
460 default:
462 }
463
465
468
469 return 0;
470 }
471
473 {
475
477
478 return 0;
479 }
480
494 .codec_tags = (const uint32_t []){
495 MKTAG(
'H',
'a',
'p',
'1'),
496 MKTAG(
'H',
'a',
'p',
'5'),
497 MKTAG(
'H',
'a',
'p',
'Y'),
498 MKTAG(
'H',
'a',
'p',
'A'),
499 MKTAG(
'H',
'a',
'p',
'M'),
501 },
502 };