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
252 {
255 int section_size;
257 int start_texture_section = 0;
258
260
261 /* check for multi texture header */
262 if (
ctx->texture_count == 2) {
266 if ((section_type & 0x0F) != 0x0D) {
267 av_log(avctx,
AV_LOG_ERROR,
"Invalid section type in 2 textures mode %#04x.\n", section_type);
269 }
270 start_texture_section = 4;
271 }
272
273 /* Get the output frame ready to receive data */
277
278 for (t = 0; t <
ctx->texture_count; t++) {
280
281 /* Check for section header */
285
288 *
ctx->dec[t].tex_ratio) {
291 }
292
293 start_texture_section +=
ctx->texture_section_size + 4;
294
295 /* Unpack the DXT texture */
297 int tex_size;
298 /* Only DXTC texture compression in a contiguous block */
299 ctx->dec[t].tex_data.in =
ctx->gbc.buffer;
303 *
ctx->dec[t].tex_ratio) {
306 }
307 } else {
308 /* Perform the second-stage decompression */
312
314 ctx->chunk_results,
ctx->chunk_count);
315
316 for (
i = 0;
i <
ctx->chunk_count;
i++) {
317 if (
ctx->chunk_results[
i] < 0)
318 return ctx->chunk_results[
i];
319 }
320
321 ctx->dec[t].tex_data.in =
ctx->tex_buf;
322 }
323
324 ctx->dec[t].frame_data.out =
frame->data[0];
325 ctx->dec[t].stride =
frame->linesize[0];
327 }
328
329 /* Frame is ready to be output */
331 frame->key_frame = 1;
332 *got_frame = 1;
333
335 }
336
338 {
340 const char *texture_name;
342
347 }
348
349 /* Since codec is based on 4x4 blocks, size is aligned to 4 */
352
354
355 ctx->texture_count = 1;
356 ctx->dec[0].raw_ratio = 16;
359
361 case MKTAG(
'H',
'a',
'p',
'1'):
362 texture_name = "DXT1";
363 ctx->dec[0].tex_ratio = 8;
364 ctx->dec[0].tex_funct =
ctx->dxtc.dxt1_block;
366 break;
367 case MKTAG(
'H',
'a',
'p',
'5'):
368 texture_name = "DXT5";
369 ctx->dec[0].tex_ratio = 16;
370 ctx->dec[0].tex_funct =
ctx->dxtc.dxt5_block;
372 break;
373 case MKTAG(
'H',
'a',
'p',
'Y'):
374 texture_name = "DXT5-YCoCg-scaled";
375 ctx->dec[0].tex_ratio = 16;
376 ctx->dec[0].tex_funct =
ctx->dxtc.dxt5ys_block;
378 break;
379 case MKTAG(
'H',
'a',
'p',
'A'):
380 texture_name = "RGTC1";
381 ctx->dec[0].tex_ratio = 8;
382 ctx->dec[0].tex_funct =
ctx->dxtc.rgtc1u_gray_block;
383 ctx->dec[0].raw_ratio = 4;
385 break;
386 case MKTAG(
'H',
'a',
'p',
'M'):
387 texture_name = "DXT5-YCoCg-scaled / RGTC1";
388 ctx->dec[0].tex_ratio = 16;
389 ctx->dec[1].tex_ratio = 8;
390 ctx->dec[0].tex_funct =
ctx->dxtc.dxt5ys_block;
391 ctx->dec[1].tex_funct =
ctx->dxtc.rgtc1u_alpha_block;
392 ctx->dec[1].raw_ratio = 16;
393 ctx->dec[1].slice_count =
ctx->dec[0].slice_count;
395 ctx->texture_count = 2;
396 break;
397 default:
399 }
400
402
403 return 0;
404 }
405
407 {
409
411
412 return 0;
413 }
414
427 .codec_tags = (const uint32_t []){
428 MKTAG(
'H',
'a',
'p',
'1'),
429 MKTAG(
'H',
'a',
'p',
'5'),
430 MKTAG(
'H',
'a',
'p',
'Y'),
431 MKTAG(
'H',
'a',
'p',
'A'),
432 MKTAG(
'H',
'a',
'p',
'M'),
434 },
435 };