FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/photocd.c
Date: 2021-09-24 20:55:06
Exec Total Coverage
Lines: 0 234 0.0%
Branches: 0 94 0.0%

Line Branch Exec Source
1 /*
2 * Kodak PhotoCD (a.k.a. ImagePac) image decoder
3 *
4 * Copyright (c) 1996-2002 Gerd Knorr
5 * Copyright (c) 2010 Kenneth Vermeirsch
6 * Copyright (c) 2020 Paul B Mahol
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 * Kodak PhotoCD (a.k.a. ImagePac) image decoder
28 *
29 * Supports resolutions up to 3072x2048.
30 */
31
32 #define CACHED_BITSTREAM_READER !ARCH_X86_32
33
34 #include "libavutil/intreadwrite.h"
35 #include "libavutil/opt.h"
36 #include "avcodec.h"
37 #include "bytestream.h"
38 #include "get_bits.h"
39 #include "internal.h"
40 #include "thread.h"
41
42 typedef struct PhotoCDContext {
43 AVClass *class;
44 int lowres;
45
46 GetByteContext gb;
47 int thumbnails; //* number of thumbnails; 0 for normal image */
48 int resolution;
49 int orientation;
50
51 int streampos;
52
53 uint8_t bits[256];
54 uint16_t codes[256];
55 uint8_t syms[256];
56
57 VLC vlc[3];
58 } PhotoCDContext;
59
60 typedef struct ImageInfo {
61 uint32_t start;
62 uint16_t width, height;
63 } ImageInfo;
64
65 static const ImageInfo img_info[6] = {
66 {8192, 192, 128},
67 {47104, 384, 256},
68 {196608, 768, 512},
69 {0, 1536, 1024},
70 {0, 3072, 2048},
71 {0, 6144, 4096},
72 };
73
74 static av_noinline void interp_lowres(PhotoCDContext *s, AVFrame *picture,
75 int width, int height)
76 {
77 GetByteContext *gb = &s->gb;
78 int start = s->streampos + img_info[2].start;
79 uint8_t *ptr, *ptr1, *ptr2;
80 uint8_t *dst;
81 int fill;
82
83 ptr = picture->data[0];
84 ptr1 = picture->data[1];
85 ptr2 = picture->data[2];
86
87 bytestream2_seek(gb, start, SEEK_SET);
88
89 for (int y = 0; y < height; y += 2) {
90 dst = ptr;
91 for (int x = 0; x < width - 1; x++) {
92 fill = bytestream2_get_byte(gb);
93 *(dst++) = fill;
94 *(dst++) = (fill + bytestream2_peek_byte(gb) + 1) >> 1;
95 }
96 fill = bytestream2_get_byte(gb);
97 *(dst++) = fill;
98 *(dst++) = fill;
99
100 ptr += picture->linesize[0] << 1;
101
102 dst = ptr;
103 for (int x = 0; x < width - 1; x++) {
104 fill = bytestream2_get_byte(gb);
105 *(dst++) = fill;
106 *(dst++) = (fill + bytestream2_peek_byte(gb) + 1) >> 1;
107 }
108 fill = bytestream2_get_byte(gb);
109 *(dst++) = fill;
110 *(dst++) = fill;
111
112 ptr += picture->linesize[0] << 1;
113
114 dst = ptr1;
115 for (int x = 0; x < (width >> 1) - 1; x++) {
116 fill = bytestream2_get_byte(gb);
117 *(dst++) = fill;
118 *(dst++) = (fill + bytestream2_peek_byte(gb) + 1) >> 1;
119 }
120 fill = bytestream2_get_byte(gb);
121 *(dst++) = fill;
122 *(dst++) = fill;
123
124 ptr1 += picture->linesize[1] << 1;
125
126 dst = ptr2;
127 for (int x = 0; x < (width >> 1) - 1; x++) {
128 fill = bytestream2_get_byte(gb);
129 *(dst++) = fill;
130 *(dst++) = (fill + bytestream2_peek_byte(gb) + 1) >> 1;
131 }
132 fill = bytestream2_get_byte(gb);
133 *(dst++) = fill;
134 *(dst++) = fill;
135
136 ptr2 += picture->linesize[2] << 1;
137 }
138
139 s->streampos += bytestream2_tell(gb) - start;
140 }
141
142 static av_noinline void interp_lines(uint8_t *ptr, int linesize,
143 int width, int height)
144 {
145 const uint8_t *src1;
146 uint8_t *dst;
147 int x;
148
149 for (int y = 0; y < height - 2; y += 2) {
150 const uint8_t *src1 = ptr;
151 uint8_t *dst = ptr + linesize;
152 const uint8_t *src2 = dst + linesize;
153 for (x = 0; x < width - 2; x += 2) {
154 dst[x] = (src1[x] + src2[x] + 1) >> 1;
155 dst[x + 1] = (src1[x] + src2[x] + src1[x + 2] + src2[x + 2] + 2) >> 2;
156 }
157 dst[x] = dst[x + 1] = (src1[x] + src2[x] + 1) >> 1;
158
159 ptr += linesize << 1;
160 }
161
162 src1 = ptr;
163 dst = ptr + linesize;
164 for (x = 0; x < width - 2; x += 2) {
165 dst[x] = src1[x];
166 dst[x + 1] = (src1[x] + src1[x + 2] + 1) >> 1;
167 }
168 dst[x] = dst[x + 1] = src1[x];
169 }
170
171 static av_noinline void interp_pixels(uint8_t *ptr, int linesize,
172 int width, int height)
173 {
174 for (int y = height - 2; y >= 0; y -= 2) {
175 const uint8_t *src = ptr + (y >> 1) * linesize;
176 uint8_t *dst = ptr + y * linesize;
177
178 dst[width - 2] = dst[width - 1] = src[(width >> 1) - 1];
179 for (int x = width - 4; x >= 0; x -= 2) {
180 dst[x] = src[x >> 1];
181 dst[x + 1] = (src[x >> 1] + src[(x >> 1) + 1] + 1) >> 1;
182 }
183 }
184 }
185
186 static av_noinline int read_hufftable(AVCodecContext *avctx, VLC *vlc)
187 {
188 PhotoCDContext *s = avctx->priv_data;
189 GetByteContext *gb = &s->gb;
190 int start = s->streampos;
191 int count, ret;
192
193 bytestream2_seek(gb, start, SEEK_SET);
194
195 count = bytestream2_get_byte(gb) + 1;
196 if (bytestream2_get_bytes_left(gb) < count * 4)
197 return AVERROR_INVALIDDATA;
198
199 for (int j = 0; j < count; j++) {
200 const int bit = bytestream2_get_byteu(gb) + 1;
201 const int code = bytestream2_get_be16u(gb);
202 const int sym = bytestream2_get_byteu(gb);
203
204 if (bit > 16)
205 return AVERROR_INVALIDDATA;
206
207 s->bits[j] = bit;
208 s->codes[j] = code >> (16 - bit);
209 s->syms[j] = sym;
210 }
211
212 ff_free_vlc(vlc);
213 ret = ff_init_vlc_sparse(vlc, 12, count,
214 s->bits, sizeof(*s->bits), sizeof(*s->bits),
215 s->codes, sizeof(*s->codes), sizeof(*s->codes),
216 s->syms, sizeof(*s->syms), sizeof(*s->syms), 0);
217
218 s->streampos = bytestream2_tell(gb);
219
220 return ret;
221 }
222
223 static av_noinline int decode_huff(AVCodecContext *avctx, AVFrame *frame,
224 int target_res, int curr_res)
225 {
226 PhotoCDContext *s = avctx->priv_data;
227 GetBitContext g;
228 GetByteContext *gb = &s->gb;
229 int ret, y = 0, type, height;
230 int start = s->streampos;
231 unsigned shiftreg;
232 const int scaling = target_res - curr_res;
233 const uint8_t type2idx[] = { 0, 0xff, 1, 2 };
234
235 bytestream2_seek(gb, start, SEEK_SET);
236 ret = init_get_bits8(&g, gb->buffer, bytestream2_get_bytes_left(gb));
237 if (ret < 0)
238 return ret;
239
240 height = img_info[curr_res].height;
241
242 while (y < height) {
243 uint8_t *data;
244 int x2, idx;
245
246 for (; get_bits_left(&g) > 0;) {
247 if (show_bits(&g, 12) == 0xfff)
248 break;
249 skip_bits(&g, 8);
250 }
251
252 shiftreg = show_bits(&g, 24);
253 while (shiftreg != 0xfffffe) {
254 if (get_bits_left(&g) <= 0)
255 return AVERROR_INVALIDDATA;
256 skip_bits(&g, 1);
257 shiftreg = show_bits(&g, 24);
258 }
259 skip_bits(&g, 24);
260 y = show_bits(&g, 15) & 0x1fff;
261 if (y >= height)
262 break;
263 type = get_bits(&g, 2);
264 skip_bits(&g, 14);
265
266 if (type == 1)
267 return AVERROR_INVALIDDATA;
268 idx = type2idx[type];
269
270 data = frame->data[idx] + (y >> !!idx) * frame->linesize[idx];
271
272 x2 = avctx->width >> (scaling + !!idx);
273 for (int x = 0; x < x2; x++) {
274 int m;
275
276 if (get_bits_left(&g) <= 0)
277 return AVERROR_INVALIDDATA;
278 m = get_vlc2(&g, s->vlc[idx].table, s->vlc[idx].bits, 2);
279 if (m < 0)
280 return AVERROR_INVALIDDATA;
281 m = sign_extend(m, 8);
282 data[x] = av_clip_uint8(data[x] + m);
283 }
284 }
285
286 s->streampos += (get_bits_count(&g) + 7) >> 3;
287 s->streampos = (s->streampos + 0x6000 + 2047) & ~0x7ff;
288
289 return 0;
290 }
291
292 static int photocd_decode_frame(AVCodecContext *avctx, void *data,
293 int *got_frame, AVPacket *avpkt)
294 {
295 PhotoCDContext *s = avctx->priv_data;
296 ThreadFrame frame = { .f = data };
297 const uint8_t *buf = avpkt->data;
298 GetByteContext *gb = &s->gb;
299 AVFrame *p = data;
300 uint8_t *ptr, *ptr1, *ptr2;
301 int ret;
302
303 if (avpkt->size < img_info[0].start)
304 return AVERROR_INVALIDDATA;
305
306 if (!memcmp("PCD_OPA", buf, 7)) {
307 s->thumbnails = AV_RL16(buf + 10);
308 av_log(avctx, AV_LOG_WARNING, "this is a thumbnails file, "
309 "reading first thumbnail only\n");
310 } else if (avpkt->size < 786432) {
311 return AVERROR_INVALIDDATA;
312 } else if (memcmp("PCD_IPI", buf + 0x800, 7)) {
313 return AVERROR_INVALIDDATA;
314 }
315
316 s->orientation = s->thumbnails ? buf[12] & 3 : buf[0x48] & 3;
317
318 if (s->thumbnails)
319 s->resolution = 0;
320 else if (avpkt->size <= 788480)
321 s->resolution = 2;
322 else
323 s->resolution = av_clip(4 - s->lowres, 0, 4);
324
325 ret = ff_set_dimensions(avctx, img_info[s->resolution].width, img_info[s->resolution].height);
326 if (ret < 0)
327 return ret;
328
329 if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0)
330 return ret;
331
332 p->pict_type = AV_PICTURE_TYPE_I;
333 p->key_frame = 1;
334
335 bytestream2_init(gb, avpkt->data, avpkt->size);
336
337 if (s->resolution < 3) {
338 ptr = p->data[0];
339 ptr1 = p->data[1];
340 ptr2 = p->data[2];
341
342 if (s->thumbnails)
343 bytestream2_seek(gb, 10240, SEEK_SET);
344 else
345 bytestream2_seek(gb, img_info[s->resolution].start, SEEK_SET);
346
347 for (int y = 0; y < avctx->height; y += 2) {
348 bytestream2_get_buffer(gb, ptr, avctx->width);
349 ptr += p->linesize[0];
350
351 bytestream2_get_buffer(gb, ptr, avctx->width);
352 ptr += p->linesize[0];
353
354 bytestream2_get_buffer(gb, ptr1, avctx->width >> 1);
355 ptr1 += p->linesize[1];
356
357 bytestream2_get_buffer(gb, ptr2, avctx->width >> 1);
358 ptr2 += p->linesize[2];
359 }
360 } else {
361 s->streampos = 0;
362 ptr = p->data[0];
363 ptr1 = p->data[1];
364 ptr2 = p->data[2];
365
366 interp_lowres(s, p, img_info[2].width, img_info[2].height);
367
368 interp_lines(ptr1, p->linesize[1], img_info[2].width, img_info[2].height);
369 interp_lines(ptr2, p->linesize[2], img_info[2].width, img_info[2].height);
370
371 if (s->resolution == 4) {
372 interp_pixels(ptr1, p->linesize[1], img_info[3].width, img_info[3].height);
373 interp_lines (ptr1, p->linesize[1], img_info[3].width, img_info[3].height);
374 interp_pixels(ptr2, p->linesize[2], img_info[3].width, img_info[3].height);
375 interp_lines (ptr2, p->linesize[2], img_info[3].width, img_info[3].height);
376 }
377
378 interp_lines(ptr, p->linesize[0], img_info[3].width, img_info[3].height);
379
380 s->streampos = 0xc2000;
381 for (int n = 0; n < 3; n++) {
382 if ((ret = read_hufftable(avctx, &s->vlc[n])) < 0)
383 return ret;
384 }
385 s->streampos = (s->streampos + 2047) & ~0x3ff;
386 if (decode_huff(avctx, p, s->resolution, 3) < 0)
387 return AVERROR_INVALIDDATA;
388
389 if (s->resolution == 4) {
390 interp_pixels(ptr, p->linesize[0], img_info[4].width, img_info[4].height);
391 interp_lines (ptr, p->linesize[0], img_info[4].width, img_info[4].height);
392
393 for (int n = 0; n < 3; n++) {
394 if ((ret = read_hufftable(avctx, &s->vlc[n])) < 0)
395 return ret;
396 }
397 s->streampos = (s->streampos + 2047) & ~0x3ff;
398 if (decode_huff(avctx, p, 4, 4) < 0)
399 return AVERROR_INVALIDDATA;
400 }
401 }
402
403 {
404 ptr1 = p->data[1];
405 ptr2 = p->data[2];
406
407 for (int y = 0; y < avctx->height >> 1; y++) {
408 for (int x = 0; x < avctx->width >> 1; x++) {
409 ptr1[x] = av_clip_uint8(ptr1[x] - 28);
410 ptr2[x] = av_clip_uint8(ptr2[x] - 9);
411 }
412
413 ptr1 += p->linesize[1];
414 ptr2 += p->linesize[2];
415 }
416 }
417
418 *got_frame = 1;
419
420 return 0;
421 }
422
423 static av_cold int photocd_decode_init(AVCodecContext *avctx)
424 {
425 avctx->pix_fmt = AV_PIX_FMT_YUV420P;
426 avctx->colorspace = AVCOL_SPC_BT709;
427 avctx->color_primaries = AVCOL_PRI_BT709;
428 avctx->color_trc = AVCOL_TRC_IEC61966_2_1;
429 avctx->color_range = AVCOL_RANGE_JPEG;
430
431 return 0;
432 }
433
434 static av_cold int photocd_decode_close(AVCodecContext *avctx)
435 {
436 PhotoCDContext *s = avctx->priv_data;
437
438 for (int i = 0; i < 3; i++)
439 ff_free_vlc(&s->vlc[i]);
440
441 return 0;
442 }
443
444 #define OFFSET(x) offsetof(PhotoCDContext, x)
445 #define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
446
447 static const AVOption options[] = {
448 { "lowres", "Lower the decoding resolution by a power of two",
449 OFFSET(lowres), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 4, VD },
450 { NULL },
451 };
452
453 static const AVClass photocd_class = {
454 .class_name = "photocd",
455 .item_name = av_default_item_name,
456 .option = options,
457 .version = LIBAVUTIL_VERSION_INT,
458 };
459
460 const AVCodec ff_photocd_decoder = {
461 .name = "photocd",
462 .type = AVMEDIA_TYPE_VIDEO,
463 .id = AV_CODEC_ID_PHOTOCD,
464 .priv_data_size = sizeof(PhotoCDContext),
465 .priv_class = &photocd_class,
466 .init = photocd_decode_init,
467 .close = photocd_decode_close,
468 .decode = photocd_decode_frame,
469 .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS,
470 .long_name = NULL_IF_CONFIG_SMALL("Kodak Photo CD"),
471 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
472 };
473