diff options
author | Paul B Mahol <onemda@gmail.com> | 2017-06-28 19:24:29 +0200 |
---|---|---|
committer | Paul B Mahol <onemda@gmail.com> | 2017-06-29 15:54:20 +0200 |
commit | 4d681269e0966446b21a324c15c5e5e6cef7c378 (patch) | |
tree | 0d755bfeda94ab30604ca5ba394d68b069e7335b /libavcodec | |
parent | 45dbb40cd1b350fd421233da3e13e969f7c1df81 (diff) | |
download | ffmpeg-4d681269e0966446b21a324c15c5e5e6cef7c378.tar.gz |
avcodec/gdv: add decompression for 2 and 5 method
Signed-off-by: Paul B Mahol <onemda@gmail.com>
Diffstat (limited to 'libavcodec')
-rw-r--r-- | libavcodec/gdv.c | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/libavcodec/gdv.c b/libavcodec/gdv.c index 275af9a351..b324e4f26e 100644 --- a/libavcodec/gdv.c +++ b/libavcodec/gdv.c @@ -38,6 +38,11 @@ typedef struct GDVContext { unsigned scale_h, scale_v; } GDVContext; +typedef struct Bits8 { + uint8_t queue; + uint8_t fill; +} Bits8; + typedef struct Bits32 { uint32_t queue; uint8_t fill; @@ -124,6 +129,21 @@ static void rescale(GDVContext *gdv, uint8_t *dst, int w, int h, int scale_v, in gdv->scale_h = scale_h; } +static int read_bits2(Bits8 *bits, GetByteContext *gb) +{ + int res; + + if (bits->fill == 0) { + bits->queue |= bytestream2_get_byte(gb); + bits->fill = 8; + } + res = bits->queue >> 6; + bits->queue <<= 2; + bits->fill -= 2; + + return res; +} + static void fill_bits32(Bits32 *bits, GetByteContext *gb) { bits->queue = bytestream2_get_le32(gb); @@ -173,6 +193,87 @@ static void lz_copy(PutByteContext *pb, GetByteContext *g2, int offset, unsigned } } +static int decompress_2(AVCodecContext *avctx) +{ + GDVContext *gdv = avctx->priv_data; + GetByteContext *gb = &gdv->gb; + GetByteContext *g2 = &gdv->g2; + PutByteContext *pb = &gdv->pb; + Bits8 bits = { 0 }; + int c, i; + + bytestream2_init(g2, gdv->frame, gdv->frame_size); + bytestream2_skip_p(pb, PREAMBLE_SIZE); + + for (c = 0; c < 256; c++) { + for (i = 0; i < 16; i++) { + gdv->frame[c * 16 + i] = c; + } + } + + while (bytestream2_get_bytes_left_p(pb) > 0 && bytestream2_get_bytes_left(gb) > 0) { + int tag = read_bits2(&bits, gb); + if (tag == 0) { + bytestream2_put_byte(pb, bytestream2_get_byte(gb)); + } else if (tag == 1) { + int b = bytestream2_get_byte(gb); + int len = (b & 0xF) + 3; + int top = (b >> 4) & 0xF; + int off = (bytestream2_get_byte(gb) << 4) + top - 4096; + lz_copy(pb, g2, off, len); + } else if (tag == 2) { + int len = (bytestream2_get_byte(gb)) + 2; + bytestream2_skip_p(pb, len); + } else { + break; + } + } + return 0; +} + +static int decompress_5(AVCodecContext *avctx, unsigned skip) +{ + GDVContext *gdv = avctx->priv_data; + GetByteContext *gb = &gdv->gb; + GetByteContext *g2 = &gdv->g2; + PutByteContext *pb = &gdv->pb; + Bits8 bits = { 0 }; + + bytestream2_init(g2, gdv->frame, gdv->frame_size); + bytestream2_skip_p(pb, skip + PREAMBLE_SIZE); + + while (bytestream2_get_bytes_left_p(pb) > 0 && bytestream2_get_bytes_left(gb) > 0) { + int tag = read_bits2(&bits, gb); + if (tag == 0) { + bytestream2_put_byte(pb, bytestream2_get_byte(gb)); + } else if (tag == 1) { + int b = bytestream2_get_byte(gb); + int len = (b & 0xF) + 3; + int top = b >> 4; + int off = (bytestream2_get_byte(gb) << 4) + top - 4096; + lz_copy(pb, g2, off, len); + } else if (tag == 2) { + int len; + int b = bytestream2_get_byte(gb); + if (b == 0) { + break; + } + if (b != 0xFF) { + len = b; + } else { + len = bytestream2_get_le16(gb); + } + bytestream2_skip_p(pb, len + 1); + } else { + int b = bytestream2_get_byte(gb); + int len = (b & 0x3) + 2; + int off = -(b >> 2) - 1; + lz_copy(pb, g2, off, len); + } + } + return 0; +} + static int decompress_68(AVCodecContext *avctx, unsigned skip, unsigned use8) { GDVContext *gdv = avctx->priv_data; @@ -333,8 +434,14 @@ static int gdv_decode_frame(AVCodecContext *avctx, void *data, gdv->pal[i] = 0xFFU << 24 | r << 18 | g << 10 | b << 2; } break; + case 2: + ret = decompress_2(avctx); + break; case 3: break; + case 5: + ret = decompress_5(avctx, flags >> 8); + break; case 6: ret = decompress_68(avctx, flags >> 8, 0); break; |