Ticket #5923: photocd.diff

File photocd.diff, 15.6 KB (added by Carl Eugen Hoyos, 10 years ago)

PhotoCD image decoder: Patch by Kenneth Vermeirsch

  • Changelog

     
    4949- Auravision Aura 1 and 2 decoders
    5050- Deluxe Paint Animation playback system
    5151- SIPR decoding for modes 8k5, 6k5 and 5k0
     52- Kodak PhotoCD image decoder
    5253
    5354
    5455
  • libavcodec/allcodecs.c

     
    144144    REGISTER_ENCDEC  (PCX, pcx);
    145145    REGISTER_ENCDEC  (PGM, pgm);
    146146    REGISTER_ENCDEC  (PGMYUV, pgmyuv);
     147    REGISTER_DECODER (PHOTOCD, photocd);
    147148    REGISTER_ENCDEC  (PNG, png);
    148149    REGISTER_ENCDEC  (PPM, ppm);
    149150    REGISTER_DECODER (PTX, ptx);
  • libavcodec/photocd.c

     
     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 *
     7 * This file is part of FFmpeg.
     8 *
     9 * FFmpeg is free software; you can redistribute it and/or
     10 * modify it under the terms of the GNU Lesser General Public
     11 * License as published by the Free Software Foundation; either
     12 * version 2.1 of the License, or (at your option) any later version.
     13 *
     14 * FFmpeg is distributed in the hope that it will be useful,
     15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     17 * Lesser General Public License for more details.
     18 *
     19 * You should have received a copy of the GNU Lesser General Public
     20 * License along with FFmpeg; if not, write to the Free Software
     21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     22 */
     23
     24/**
     25 * @file libavcodec/photocd.c
     26 * Kodak PhotoCD (a.k.a. ImagePac) image decoder
     27 *
     28 * Supports resolutions up to 3072x2048.
     29 */
     30#include "avcodec.h"
     31
     32typedef struct
     33{
     34    AVFrame  picture;
     35
     36    int      thumbnails;  //* number of thumbnails; 0 for normal image */
     37    int      resolution;
     38    int      orientation;
     39
     40    const uint8_t *stream;
     41    int      streampos;
     42
     43    uint8_t *seq [3]; //* huffman tables */
     44    uint8_t *bits[3];
     45} PhotoCDContext;
     46
     47static const int   img_start [] = { 0 /*dummy */ , 8192, 47104, 196608 };
     48static const short def_width [] = { 0 /*dummy */ , 192, 384, 768, 1536, 3072, 6144 };
     49static const short def_height[] = { 0 /*dummy */ , 128, 256, 512, 1024, 2048, 4096 };
     50
     51#define HTABLE_SIZE 0x10000
     52
     53#define SETSHIFT       { shiftreg=(((stream[0]<<16) | (stream[1]<<8 ) | \
     54                                    (stream[2])) >> (8-bit)) & 0xffff; }
     55#define LEFTSHIFT      { shiftreg=((shiftreg<<1) & 0xffff) | \
     56    ((stream[2]>>(7-bit++))&1); stream += bit>>3; bit &= 7; }
     57
     58static av_always_inline void interp_lowres(PhotoCDContext *ctx, AVFrame *picture,
     59                                           int width, int height)
     60{
     61    register uint8_t *dest;
     62    uint8_t *ptr, *ptr1, *ptr2;
     63    register int x;
     64    int y;
     65    const uint8_t *const start = ctx->stream + ctx->streampos + img_start[3];
     66    const register uint8_t *src = start;
     67
     68    ptr  = picture->data[0];
     69    ptr1 = picture->data[1];
     70    ptr2 = picture->data[2];
     71
     72    for (y = 0; y < height; y += 2) {
     73        for (dest = ptr, x = 0; x < width - 1; x++) {
     74            *(dest++) =  src[x];
     75            *(dest++) = (src[x] + src[x + 1] + 1) >> 1;
     76        }
     77        *(dest++) = src[x];
     78        *(dest++) = src[x];
     79
     80        src += def_width[3];
     81        ptr += picture->linesize[0] << 1;
     82
     83        for (dest = ptr, x = 0; x < width - 1; x++) {
     84            *(dest++) =  src[x];
     85            *(dest++) = (src[x] + src[x + 1] + 1) >> 1;
     86        }
     87        *(dest++) = src[x];
     88        *(dest++) = src[x];
     89
     90        src += def_width[3];
     91        ptr += picture->linesize[0] << 1;
     92
     93        for (dest = ptr1, x = 0; x < (width >> 1) - 1; x++) {
     94            *(dest++) =  src[x];
     95            *(dest++) = (src[x] + src[x + 1] + 1) >> 1;
     96        }
     97        *(dest++) = src[x];
     98        *(dest++) = src[x];
     99
     100        src  += def_width[3] >> 1;
     101        ptr1 += picture->linesize[1] << 1;
     102
     103        for (dest = ptr2, x = 0; x < (width >> 1) - 1; x++) {
     104            *(dest++) =  src[x];
     105            *(dest++) = (src[x] + src[x + 1] + 1) >> 1;
     106        }
     107        *(dest++) = src[x];
     108        *(dest++) = src[x];
     109
     110        src  += def_width[3] >> 1;
     111        ptr2 += picture->linesize[2] << 1;
     112    }
     113
     114    ctx->streampos += src - start;
     115}
     116
     117static void interp_lines(uint8_t *ptr, int linesize, int width, int height)
     118{
     119    register uint8_t *src1, *src2, *dest;
     120    register int x;
     121    int y;
     122
     123    for (y = 0; y < height - 2; y += 2) {
     124        src1 = ptr;
     125        dest = src1 + linesize;
     126        src2 = dest + linesize;
     127        for (x = 0; x < width - 2; x += 2) {
     128            dest[x]     = (src1[x] + src2[x] + 1) >> 1;
     129            dest[x + 1] = (src1[x] + src2[x] + src1[x + 2] + src2[x + 2] + 2) >> 2;
     130        }
     131        dest[x] = dest[x + 1] = (src1[x] + src2[x] + 1) >> 1;
     132
     133        ptr += linesize << 1;
     134    }
     135
     136    src1 = ptr;
     137    dest = ptr + linesize;
     138    for (x = 0; x < width - 2; x += 2) {
     139        dest[x]     = src1[x];
     140        dest[x + 1] = (src1[x] + src1[x + 2] + 1) >> 1;
     141    }
     142    dest[x] = dest[x + 1] = src1[x];
     143}
     144
     145static void interp_pixels(uint8_t *ptr, int linesize, int width, int height)
     146{
     147    register uint8_t *src, *dest;
     148    register int x;
     149    int y;
     150
     151    for (y = height - 2; y >= 0; y -= 2) {
     152        src  = ptr + (y >> 1) * linesize;
     153        dest = ptr +  y       * linesize;
     154
     155        dest[width - 2] = dest[width - 1] = src[(width >> 1) - 1];
     156        for (x = width - 4; x >= 0; x -= 2) {
     157            dest[x]     =  src[x >> 1];
     158            dest[x + 1] = (src[x >> 1] + src[(x >> 1) + 1] + 1) >> 1;
     159        }
     160    }
     161}
     162
     163static int read_hufftable(AVCodecContext *avctx, uint8_t ** aseq, uint8_t ** abits)
     164{
     165    PhotoCDContext *const ctx = avctx->priv_data;
     166    const uint8_t *src = ctx->stream + ctx->streampos;
     167    const int tablen = *src;
     168    int len = tablen, i, j;
     169
     170    if (!*aseq)
     171      *aseq  = av_malloc(HTABLE_SIZE * sizeof (char));
     172    if (!*abits)
     173      *abits = av_malloc(HTABLE_SIZE * sizeof (char));
     174
     175    memset(*aseq,  0, HTABLE_SIZE * sizeof (char));
     176    memset(*abits, 0, HTABLE_SIZE * sizeof (char));
     177
     178    for (i = 1; len >= 0; i += 4, len--) {
     179        const int bits = src[i] + 1;
     180        const int seq  = (int) src[i + 1] << 8 | (int) src[i + 2];
     181        const int seq2 = seq + (0x10000 >> bits);
     182        for (j = seq; j < seq2; j++) {
     183            if ((*abits)[j]) {
     184                av_log(avctx, AV_LOG_ERROR, "invalid huffmann code table #%x\n", j);
     185                return -1;
     186            }
     187            (*aseq )[j] = src[i + 3];
     188            (*abits)[j] = bits;
     189        }
     190    }
     191
     192    ctx->streampos += i << 2;
     193    return 0;
     194}
     195
     196static int decode_huff(AVCodecContext *avctx, AVFrame *frame,
     197                       int target_res, int curr_res)
     198{
     199    PhotoCDContext *const ctx = avctx->priv_data;
     200    const uint8_t *const start = ctx->stream + ctx->streampos;
     201    const uint8_t *stream = start;
     202    int y = 0, type, height, y2;
     203    register int shiftreg, bit;
     204    const int scaling = target_res - curr_res;
     205    const uint8_t type2idx[] = { 0, 0xff, 1, 2 };
     206
     207    height = def_height[curr_res];
     208    y2 = avctx->height >> scaling;
     209
     210    while (y < height) {
     211        register uint8_t *data;
     212        register int x;
     213        uint8_t *seq;
     214        uint8_t *bits;
     215        int x2, idx;
     216
     217        bit = 0;
     218        for (;;) {
     219            stream = memchr(stream, 0xff, 10240);
     220            if (stream[1] == 0xff)
     221                break;
     222            stream++;
     223        }
     224
     225        SETSHIFT;
     226        while (shiftreg != 0xfffe)
     227            LEFTSHIFT;
     228        stream += 2;
     229        SETSHIFT;
     230        y = (shiftreg >> 1) & 0x1fff;
     231        type = (shiftreg >> 14);
     232        stream += 2;
     233        SETSHIFT;
     234
     235        assert(type == 0 || type == 2 || type == 3);
     236        if (y > height) {
     237            av_log(avctx, AV_LOG_ERROR, "row out of range: %d\n", y);
     238            return -1;
     239        }
     240
     241        /* decode line */
     242        idx  = type2idx[type];
     243        seq  = ctx->seq [idx];
     244        bits = ctx->bits[idx];
     245        data = frame->data[idx] + (y >> !!type) * frame->linesize[idx];
     246
     247        x2 = avctx->width >> (scaling + !!type);
     248        for (x = 0; x < x2; x++) {
     249            data[x] = av_clip_uint8((int) data[x] + (signed char) seq[shiftreg]);
     250            bit += bits[shiftreg];
     251            stream += bit >> 3;
     252            bit &= 7;
     253            SETSHIFT;
     254        }
     255    }
     256
     257    ctx->streampos += (int) (stream - start);
     258    ctx->streampos  = (ctx->streampos + 0x6000 + 2047) & ~0x7ff;
     259    return 0;
     260}
     261
     262static int photocd_decode_frame(AVCodecContext *avctx, void *data,
     263                                int *data_size, AVPacket *avpkt)
     264{
     265    const uint8_t *const buf = avpkt->data;
     266    PhotoCDContext *const ctx = avctx->priv_data;
     267    AVFrame *picture = data;
     268    AVFrame *const p = (AVFrame *) &ctx->picture;
     269    int ptr_incr, size_read, n;
     270    uint8_t *ptr, *ptr1, *ptr2;
     271
     272    if (avpkt->size < 7) {
     273        av_log(avctx, AV_LOG_WARNING, "invalid file\n");
     274        return -1;
     275    }
     276
     277    if (!strncmp("PCD_OPA", buf, 7)) {
     278        ctx->thumbnails = (int) buf[10] << 8 | (int) buf[11];
     279        av_log(avctx, AV_LOG_WARNING, "this is a thumbnails file, "
     280                                      "reading first thumbnail only\n");
     281    } else if (avpkt->size < 786432) {
     282        av_log(avctx, AV_LOG_ERROR, "probably not a PhotoCD image: too small\n");
     283        return -1;
     284    }
     285
     286    ctx->orientation = ctx->thumbnails ? buf[12] & 3 : buf[0x48] & 3;
     287
     288    if (ctx->thumbnails)
     289        ctx->resolution = 1;
     290    else if (avpkt->size == 786432)
     291        ctx->resolution = 3;
     292    else
     293        ctx->resolution = av_clip(5 - avctx->lowres, 1, 5);
     294
     295    avctx->width  = def_width [ctx->resolution];
     296    avctx->height = def_height[ctx->resolution];
     297
     298    if (p->data[0])
     299        avctx->release_buffer(avctx, p);
     300    if (avctx->get_buffer(avctx, p) < 0) {
     301        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
     302        return -1;
     303    }
     304
     305    if (ctx->resolution < 4) {
     306        int y;
     307        const uint8_t *bufptr;
     308
     309        ptr  = p->data[0];
     310        ptr1 = p->data[1];
     311        ptr2 = p->data[2];
     312
     313        if (ctx->thumbnails) {
     314            bufptr = buf + 10240;
     315        } else {
     316            bufptr = buf + img_start[ctx->resolution];
     317        }
     318
     319        ptr_incr = avctx->width >> 1;
     320
     321        for (y = 0; y < avctx->height; y += 2) {
     322            n = avctx->width;
     323
     324            memcpy(ptr, bufptr, n);
     325            ptr += p->linesize[0];
     326            bufptr += ptr_incr + ptr_incr;
     327
     328            memcpy(ptr, bufptr, n);
     329            ptr += p->linesize[0];
     330            bufptr += ptr_incr + ptr_incr;
     331
     332            n >>= 1;
     333
     334            memcpy(ptr1, bufptr, n);
     335            ptr1 += p->linesize[1];
     336            bufptr += ptr_incr;
     337
     338            memcpy(ptr2, bufptr, n);
     339            ptr2 += p->linesize[2];
     340            bufptr += ptr_incr;
     341        }
     342        size_read = bufptr - buf;
     343    } else {
     344        ctx->stream = buf;
     345        ctx->streampos = 0;
     346        ptr  = p->data[0];
     347        ptr1 = p->data[1];
     348        ptr2 = p->data[2];
     349
     350        interp_lowres(ctx, p, def_width[3], def_height[3]);
     351
     352        interp_lines(ptr1, p->linesize[1], def_width[3], def_height[3]);
     353        interp_lines(ptr2, p->linesize[2], def_width[3], def_height[3]);
     354
     355        if (ctx->resolution == 5) {
     356            interp_pixels(ptr1, p->linesize[1], def_width[4], def_height[4]);
     357            interp_lines (ptr1, p->linesize[1], def_width[4], def_height[4]);
     358            interp_pixels(ptr2, p->linesize[2], def_width[4], def_height[4]);
     359            interp_lines (ptr2, p->linesize[2], def_width[4], def_height[4]);
     360        }
     361
     362        interp_lines(ptr, p->linesize[0], def_width[4], def_height[4]);
     363
     364        ctx->streampos = 0xc2000;
     365        if (read_hufftable(avctx, &ctx->seq[0], &ctx->bits[0]) < 0)
     366            return -1;
     367        ctx->streampos = (ctx->streampos + 2047) & ~0x3ff;
     368        if (decode_huff(avctx, p, ctx->resolution, 4) < 0)
     369            return -1;
     370
     371        if (ctx->resolution == 5) {
     372            interp_pixels(ptr, p->linesize[0], def_width[5], def_height[5]);
     373            interp_lines (ptr, p->linesize[0], def_width[5], def_height[5]);
     374
     375            for (n = 0; n < 3; n++) {
     376              if (read_hufftable(avctx, &ctx->seq[n], &ctx->bits[n]) < 0)
     377                  return -1;
     378            }
     379            ctx->streampos = (ctx->streampos + 2047) & ~0x3ff;
     380            if (decode_huff(avctx, p, 5, 5) < 0)
     381                return -1;
     382        }
     383
     384        size_read = ctx->streampos;
     385    }
     386
     387    *picture   = *(AVFrame *) &ctx->picture;
     388    *data_size = sizeof (AVPicture);
     389
     390    return size_read;
     391}
     392
     393static av_cold int photocd_decode_init(AVCodecContext *avctx)
     394{
     395    PhotoCDContext *const ctx = avctx->priv_data;
     396
     397    memset(ctx, 0, sizeof (PhotoCDContext));
     398
     399    /* how to get the colorspace right? */
     400    //avctx->pix_fmt    = PIX_FMT_YUV420P;
     401    //avctx->colorspace = AVCOL_SPC_BT470BG;
     402    //avctx->color_trc  = AVCOL_TRC_BT709;
     403    //avctx->color_primaries = AVCOL_PRI_BT470BG;
     404    //avctx->color_primaries = AVCOL_PRI_BT709;
     405
     406    avcodec_get_frame_defaults((AVFrame *) &ctx->picture);
     407    avctx->coded_frame = (AVFrame *) &ctx->picture;
     408
     409    return 0;
     410}
     411
     412static av_cold int photocd_decode_close(AVCodecContext *avctx)
     413{
     414    PhotoCDContext *const ctx = avctx->priv_data;
     415
     416    if (ctx->picture.data[0])
     417        avctx->release_buffer(avctx, &ctx->picture);
     418
     419    av_free(ctx->seq [0]);
     420    av_free(ctx->bits[0]);
     421    av_free(ctx->seq [1]);
     422    av_free(ctx->bits[1]);
     423    av_free(ctx->seq [2]);
     424    av_free(ctx->bits[2]);
     425
     426    return 0;
     427}
     428
     429AVCodec photocd_decoder =
     430{
     431    .name           = "photocd",
     432    .type           = CODEC_TYPE_VIDEO,
     433    .id             = CODEC_ID_PHOTOCD,
     434    .priv_data_size = sizeof (PhotoCDContext),
     435    .init           = photocd_decode_init,
     436    .close          = photocd_decode_close,
     437    .decode         = photocd_decode_frame,
     438    .capabilities   = CODEC_CAP_DR1,
     439    .pix_fmts       = (const enum PixelFormat[]) { PIX_FMT_YUV420P, PIX_FMT_NONE },
     440    .long_name      = NULL_IF_CONFIG_SMALL("Kodak Photo CD (a.k.a. ImagePac) image"),
     441};
  • libavcodec/avcodec.h

     
    203203    CODEC_ID_CDGRAPHICS,
    204204    CODEC_ID_R210,
    205205    CODEC_ID_ANM,
     206    CODEC_ID_PHOTOCD,
    206207
    207208    /* various PCM "codecs" */
    208209    CODEC_ID_PCM_S16LE= 0x10000,
  • libavcodec/Makefile

     
    224224OBJS-$(CONFIG_PGMYUV_DECODER)          += pnmdec.o pnm.o
    225225OBJS-$(CONFIG_PGMYUV_ENCODER)          += pnmenc.o pnm.o
    226226OBJS-$(CONFIG_PGSSUB_DECODER)          += pgssubdec.o
     227OBJS-$(CONFIG_PHOTOCD_DECODER)         += photocd.o
    227228OBJS-$(CONFIG_PNG_DECODER)             += png.o pngdec.o
    228229OBJS-$(CONFIG_PNG_ENCODER)             += png.o pngenc.o
    229230OBJS-$(CONFIG_PPM_DECODER)             += pnmdec.o pnm.o
  • libavformat/img2.c

     
    7373    { CODEC_ID_SUNRAST   , "sunras"},
    7474    { CODEC_ID_JPEG2000  , "jp2"},
    7575    { CODEC_ID_DPX       , "dpx"},
     76    { CODEC_ID_PHOTOCD   , "pcd"},
    7677    { CODEC_ID_NONE      , NULL}
    7778};
    7879