diff options
author | Vittorio Giovara <vittorio.giovara@gmail.com> | 2015-04-18 17:25:20 +0100 |
---|---|---|
committer | Vittorio Giovara <vittorio.giovara@gmail.com> | 2015-05-06 14:27:34 +0100 |
commit | 34efb8a169e4551326e069be47125c6c2cb7ab90 (patch) | |
tree | 3a25833512250c82670bf8dc772a7cd51ac68df4 /libavcodec/qdrw.c | |
parent | bb2cb0a66d86ec4ad9f43a488e8b6ab894c22d2f (diff) | |
download | ffmpeg-34efb8a169e4551326e069be47125c6c2cb7ab90.tar.gz |
quickdraw: Support direct pixel blocks
Data is stored in separated components so rework decode_rle() to support
stepping and offsets.
Diffstat (limited to 'libavcodec/qdrw.c')
-rw-r--r-- | libavcodec/qdrw.c | 88 |
1 files changed, 81 insertions, 7 deletions
diff --git a/libavcodec/qdrw.c b/libavcodec/qdrw.c index a70449d779..1eb2a76691 100644 --- a/libavcodec/qdrw.c +++ b/libavcodec/qdrw.c @@ -35,6 +35,8 @@ enum QuickdrawOpcodes { PACKBITSRECT = 0x0098, PACKBITSRGN, + DIRECTBITSRECT, + DIRECTBITSRGN, EOP = 0x00FF, }; @@ -64,14 +66,17 @@ static int parse_palette(AVCodecContext *avctx, GetByteContext *gbc, return 0; } -static int decode_rle(AVCodecContext *avctx, AVFrame *p, GetByteContext *gbc) +static int decode_rle(AVCodecContext *avctx, AVFrame *p, GetByteContext *gbc, + int step) { - int i; + int i, j; + int offset = avctx->width * step; uint8_t *outdata = p->data[0]; for (i = 0; i < avctx->height; i++) { int size, left, code, pix; uint8_t *out = outdata; + int pos = 0; /* size of packed line */ size = left = bytestream2_get_be16(gbc); @@ -83,12 +88,24 @@ static int decode_rle(AVCodecContext *avctx, AVFrame *p, GetByteContext *gbc) code = bytestream2_get_byte(gbc); if (code & 0x80 ) { /* run */ pix = bytestream2_get_byte(gbc); - memset(out, pix, 257 - code); - out += 257 - code; + for (j = 0; j < 257 - code; j++) { + out[pos] = pix; + pos += step; + if (pos >= offset) { + pos -= offset; + pos++; + } + } left -= 2; } else { /* copy */ - bytestream2_get_buffer(gbc, out, code + 1); - out += code + 1; + for (j = 0; j < code + 1; j++) { + out[pos] = bytestream2_get_byte(gbc); + pos += step; + if (pos >= offset) { + pos -= offset; + pos++; + } + } left -= 2 + code; } } @@ -134,6 +151,7 @@ static int decode_frame(AVCodecContext *avctx, while (bytestream2_get_bytes_left(&gbc) >= 4) { int bppcnt, bpp; + int rowbytes, pack_type; int opcode = bytestream2_get_be16(&gbc); switch(opcode) { @@ -185,7 +203,63 @@ static int decode_frame(AVCodecContext *avctx, avpriv_report_missing_feature(avctx, "Packbit mask region"); } - ret = decode_rle(avctx, p, &gbc); + ret = decode_rle(avctx, p, &gbc, bppcnt); + if (ret < 0) + return ret; + *got_frame = 1; + break; + case DIRECTBITSRECT: + case DIRECTBITSRGN: + av_log(avctx, AV_LOG_DEBUG, "Parsing Directbit opcode\n"); + + bytestream2_skip(&gbc, 4); + rowbytes = bytestream2_get_be16(&gbc) & 0x3FFF; + if (rowbytes <= 250) { + avpriv_report_missing_feature(avctx, "Short rowbytes"); + return AVERROR_PATCHWELCOME; + } + + bytestream2_skip(&gbc, 10); + pack_type = bytestream2_get_be16(&gbc); + + bytestream2_skip(&gbc, 16); + bppcnt = bytestream2_get_be16(&gbc); /* cmpCount */ + bpp = bytestream2_get_be16(&gbc); /* cmpSize */ + + av_log(avctx, AV_LOG_DEBUG, "bppcount %d bpp %d\n", bppcnt, bpp); + if (bppcnt == 3 && bpp == 8) { + avctx->pix_fmt = AV_PIX_FMT_RGB24; + } else if (bppcnt == 4 && bpp == 8) { + avctx->pix_fmt = AV_PIX_FMT_ARGB; + } else { + av_log(avctx, AV_LOG_ERROR, + "Invalid pixel format (bppcnt %d bpp %d) in Directbit\n", + bppcnt, bpp); + return AVERROR_INVALIDDATA; + } + + /* set packing when default is selected */ + if (pack_type == 0) + pack_type = bppcnt; + + if (pack_type != 3 && pack_type != 4) { + avpriv_request_sample(avctx, "Pack type %d", pack_type); + return AVERROR_PATCHWELCOME; + } + if ((ret = ff_get_buffer(avctx, p, 0)) < 0) { + av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); + return ret; + } + + /* jump to data */ + bytestream2_skip(&gbc, 30); + + if (opcode == DIRECTBITSRGN) { + bytestream2_skip(&gbc, 2 + 8); /* size + rect */ + avpriv_report_missing_feature(avctx, "DirectBit mask region"); + } + + ret = decode_rle(avctx, p, &gbc, bppcnt); if (ret < 0) return ret; *got_frame = 1; |