[FFmpeg-devel] [PATCH] PhotoCD image decoder
Kenneth Vermeirsch
kavermei
Mon Jan 11 18:17:06 CET 2010
pross at xvid.org wrote:
> On Mon, Jan 11, 2010 at 02:09:39PM +0100, Kenneth Vermeirsch wrote:
>
>> Hi all,
>>
>> this is a port of the libpcd PhotoCD image decoder
>>
>
> comments below
>
>
Thanks for reviewing.
>> Index: Changelog
>> ===================================================================
>> --- Changelog (revision 21136)
>> +++ Changelog (working copy)
>> @@ -49,6 +49,7 @@
>> - Auravision Aura 1 and 2 decoders
>> - Deluxe Paint Animation playback system
>> - SIPR decoding for modes 8k5, 6k5 and 5k0
>> +- Kodak PhotoCD image decoder
>>
>
> consistency... everywhere else you've called it '... (a.k.a ImagePac)'.
> also i would remove the a.k.a, and just call it 'Kodak PhotoCD/ImagePac image'
>
>
done locally.
>> +
>> +typedef struct
>> +{
>>
>
> compact to one line: typedef struct {
>
>
done locally.
>> + AVFrame picture;
>> +
>> + int thumbnails; //* number of thumbnails; 0 for normal image */
>> + int resolution;
>> + int orientation;
>> +
>> + const uint8_t *stream;
>> + int streampos;
>> +
>> + uint8_t *seq [3]; //* huffman tables */
>> + uint8_t *bits[3];
>> +} PhotoCDContext;
>> +
>> +static const int img_start [] = { 0 /*dummy */ , 8192, 47104, 196608 };
>> +static const short def_width [] = { 0 /*dummy */ , 192, 384, 768, 1536, 3072, 6144 };
>> +static const short def_height[] = { 0 /*dummy */ , 128, 256, 512, 1024, 2048, 4096 };
>>
>
> def_height[] seems uneeded. you can caclulate the height using 2^(index+6)
> there are common divisors for the other arrays
>
>
replaced it by a macro.
>> +
>> +#define HTABLE_SIZE 0x10000
>> +
>> +#define SETSHIFT { shiftreg=(((stream[0]<<16) | (stream[1]<<8 ) | \
>> + (stream[2])) >> (8-bit)) & 0xffff; }
>> +#define LEFTSHIFT { shiftreg=((shiftreg<<1) & 0xffff) | \
>> + ((stream[2]>>(7-bit++))&1); stream += bit>>3; bit &= 7; }
>>
>
> comments describing the purpose of these macros do would be useful
>
>
added.
>> +static av_always_inline void interp_lowres(PhotoCDContext *ctx, AVFrame *picture,
>> + int width, int height)
>> +{
>> + register uint8_t *dest;
>> + uint8_t *ptr, *ptr1, *ptr2;
>> + register int x;
>> + int y;
>> + const uint8_t *const start = ctx->stream + ctx->streampos + img_start[3];
>> + const register uint8_t *src = start;
>> +
>> + ptr = picture->data[0];
>> + ptr1 = picture->data[1];
>> + ptr2 = picture->data[2];
>> +
>> + for (y = 0; y < height; y += 2) {
>> + for (dest = ptr, x = 0; x < width - 1; x++) {
>> + *(dest++) = src[x];
>> + *(dest++) = (src[x] + src[x + 1] + 1) >> 1;
>> + }
>> + *(dest++) = src[x];
>> + *(dest++) = src[x];
>>
>
> could be packed on one line e.g.
> dst[0] = dst[1] = src[x];
>
> elsewhere you have used an index variable to derefence dest (e.g. dest[x] = blah),
> rather then inline pointer arith. this makes it more readable imho
>
>
>> +static int read_hufftable(AVCodecContext *avctx, uint8_t ** aseq, uint8_t ** abits)
>> +{
>> + PhotoCDContext *const ctx = avctx->priv_data;
>> + const uint8_t *src = ctx->stream + ctx->streampos;
>> + const int tablen = *src;
>> + int len = tablen, i, j;
>> +
>> + if (!*aseq)
>> + *aseq = av_malloc(HTABLE_SIZE * sizeof (char));
>> + if (!*abits)
>> + *abits = av_malloc(HTABLE_SIZE * sizeof (char));
>>
>
> what happens if av_malloc fails?
>
>
I added a check.
>> +
>> + memset(*aseq, 0, HTABLE_SIZE * sizeof (char));
>> + memset(*abits, 0, HTABLE_SIZE * sizeof (char));
>>
>
> there is a variant of av_malloc that zeroises the buffer for you
>
>
I need the buffer zeroed every time the function is called, that's why I
used av_malloc+memset.
>> +
>> + for (i = 1; len >= 0; i += 4, len--) {
>> + const int bits = src[i] + 1;
>> + const int seq = (int) src[i + 1] << 8 | (int) src[i + 2];
>> + const int seq2 = seq + (0x10000 >> bits);
>> + for (j = seq; j < seq2; j++) {
>> + if ((*abits)[j]) {
>> + av_log(avctx, AV_LOG_ERROR, "invalid huffmann code table #%x\n", j);
>> + return -1;
>>
>
> return AVERROR_INVALIDDATA
>
>
done.
>> + const uint8_t type2idx[] = { 0, 0xff, 1, 2 };
>>
>
> preferred style is to capitalise hexadecimal values
>
>
didn't know, changed here and elsewhere.
>> + while (y < height) {
>> + register uint8_t *data;
>> + register int x;
>> + uint8_t *seq;
>> + uint8_t *bits;
>> + int x2, idx;
>> +
>> + bit = 0;
>> + for (;;) {
>> + stream = memchr(stream, 0xff, 10240);
>>
>
> what is this magic 10240 value?
>
>
>> + if (stream[1] == 0xff)
>> + break;
>> + stream++;
>> + }
>>
>
> indent
>
>
>> +static int photocd_decode_frame(AVCodecContext *avctx, void *data,
>> + int *data_size, AVPacket *avpkt)
>> +{
>> + const uint8_t *const buf = avpkt->data;
>> + PhotoCDContext *const ctx = avctx->priv_data;
>> + AVFrame *picture = data;
>> + AVFrame *const p = (AVFrame *) &ctx->picture;
>> + int ptr_incr, size_read, n;
>> + uint8_t *ptr, *ptr1, *ptr2;
>> +
>> + if (avpkt->size < 7) {
>> + av_log(avctx, AV_LOG_WARNING, "invalid file\n");
>> + return -1;
>>
>
> the av_log text should be consistent with that below. e.g.
> ''insufficient file size for this to be a PhotoCD image''
> and return AVERROR_INVALIDDATA;
>
>
fixed.
>> + }
>> +
>> + if (!strncmp("PCD_OPA", buf, 7)) {
>> + ctx->thumbnails = (int) buf[10] << 8 | (int) buf[11];
>> + av_log(avctx, AV_LOG_WARNING, "this is a thumbnails file, "
>> + "reading first thumbnail only\n");
>> + } else if (avpkt->size < 786432) {
>>
>
> how did you derive this magic number ^^ ?
>
>
this is the minimum size a valid file (with the exception of thumbnail
files) can be since it must contain at least resolution levels 1, 2 and
3 and these are stored uncompressed.
>> + av_log(avctx, AV_LOG_ERROR, "probably not a PhotoCD image: too small\n");
>> + return -1;
>>
>
> AVERROR_INVALIDDATA
>
>
>> +static av_cold int photocd_decode_init(AVCodecContext *avctx)
>> +{
>> + PhotoCDContext *const ctx = avctx->priv_data;
>> +
>> + memset(ctx, 0, sizeof (PhotoCDContext));
>>
>
> libavcodec already zeroises the struct for you
>
removed
> and why the space immiediately after sizeof??
>
>
same as for "if (", "for (", "while (" i think -- sizeof being an
operator rather than a function
>> +static av_cold int photocd_decode_close(AVCodecContext *avctx)
>> +{
>> + PhotoCDContext *const ctx = avctx->priv_data;
>> +
>> + if (ctx->picture.data[0])
>> + avctx->release_buffer(avctx, &ctx->picture);
>> +
>> + av_free(ctx->seq [0]);
>> + av_free(ctx->bits[0]);
>> + av_free(ctx->seq [1]);
>> + av_free(ctx->bits[1]);
>> + av_free(ctx->seq [2]);
>> + av_free(ctx->bits[2]);
>>
>
> for(i=0; i<3; i++) { av_free(foo[i]); } would simplify this
>
>
done.
I will send an updated patch one I get the colorspace thing working.
Best,
Kenneth
More information about the ffmpeg-devel
mailing list