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