From: Kostya Shishkov <[email protected]> ELS and ePIC decoder courtesy of Maxim Poliakovski Cleanup and integration by Diego Biurrun.
Signed-off-by: Diego Biurrun <[email protected]> --- - Rebased on top of current master. - Fixed all Coverity warnings. - minor cosmetic cleanups Changelog | 1 + doc/general.texi | 2 + libavcodec/Makefile | 2 +- libavcodec/elsdec.c | 411 +++++++++++++++++++++++++++ libavcodec/elsdec.h | 60 ++++ libavcodec/g2meet.c | 753 ++++++++++++++++++++++++++++++++++++++++++++++++-- libavcodec/version.h | 2 +- tests/fate/screen.mak | 12 + tests/ref/fate/g2m2 | 161 +++++++++++ tests/ref/fate/g2m3 | 42 +++ tests/ref/fate/g2m4 | 29 ++ 11 files changed, 1451 insertions(+), 24 deletions(-) create mode 100644 libavcodec/elsdec.c create mode 100644 libavcodec/elsdec.h create mode 100644 tests/ref/fate/g2m2 create mode 100644 tests/ref/fate/g2m3 create mode 100644 tests/ref/fate/g2m4 diff --git a/Changelog b/Changelog index 4542e32..97a9b7f 100644 --- a/Changelog +++ b/Changelog @@ -27,6 +27,7 @@ version <next>: - Intel QSV-accelerated H.264 encoding - MMAL-accelerated H.264 decoding - DTS decoding through libdcadec +- Go2Meeting decoding support version 11: diff --git a/doc/general.texi b/doc/general.texi index 3fa4377..65c489c 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -603,6 +603,8 @@ following image formats are supported: @tab Sorenson H.263 used in Flash @item Forward Uncompressed @tab @tab X @item Fraps @tab @tab X +@item Go2Meeting @tab @tab X + @tab fourcc: G2M2, G2M3 @item Go2Webinar @tab @tab X @tab fourcc: G2M4 @item H.261 @tab X @tab X diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 8dd10c3..1b4fa94 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -207,7 +207,7 @@ OBJS-$(CONFIG_FLIC_DECODER) += flicvideo.o OBJS-$(CONFIG_FOURXM_DECODER) += 4xm.o OBJS-$(CONFIG_FRAPS_DECODER) += fraps.o OBJS-$(CONFIG_FRWU_DECODER) += frwu.o -OBJS-$(CONFIG_G2M_DECODER) += g2meet.o +OBJS-$(CONFIG_G2M_DECODER) += g2meet.o elsdec.o OBJS-$(CONFIG_G723_1_DECODER) += g723_1.o acelp_vectors.o \ celp_filters.o OBJS-$(CONFIG_GIF_DECODER) += gifdec.o lzw.o diff --git a/libavcodec/elsdec.c b/libavcodec/elsdec.c new file mode 100644 index 0000000..951918a --- /dev/null +++ b/libavcodec/elsdec.c @@ -0,0 +1,411 @@ +/* + * ELS (Entropy Logarithmic-Scale) decoder + * + * Copyright (c) 2013 Maxim Poliakovski + * + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Entropy Logarithmic-Scale binary arithmetic decoder + */ + +#include <math.h> +#include <stdint.h> + +#include "libavutil/common.h" +#include "libavutil/intreadwrite.h" + +#include "avcodec.h" +#include "elsdec.h" + +/* ELS coder constants and structures. */ +#define ELS_JOTS_PER_BYTE 36 +#define ELS_MAX (1 << 24) + +/* ELS coder tables. */ +static const struct Ladder { + int8_t AMps; + int8_t ALps; + uint8_t next0; + uint8_t next1; +} Ladder[174] = { + { -6, -5, 2, 1 }, + { -2, -12, 3, 6 }, + { -2, -12, 4, 6 }, + { -1, -16, 7, 5 }, + { -1, -16, 8, 10 }, + { -5, -6, 11, 9 }, + { -6, -5, 10, 5 }, + { -1, -18, 13, 11 }, + { -1, -18, 12, 14 }, + { -6, -5, 15, 18 }, + { -5, -6, 14, 9 }, + { -3, -8, 17, 15 }, + { -1, -20, 20, 16 }, + { -1, -20, 23, 17 }, + { -3, -8, 16, 18 }, + { -5, -6, 19, 26 }, + { -3, -9, 22, 24 }, + { -3, -9, 21, 19 }, + { -5, -6, 24, 26 }, + { -4, -7, 27, 25 }, + { -1, -22, 34, 28 }, + { -2, -11, 29, 27 }, + { -2, -11, 28, 30 }, + { -1, -22, 39, 29 }, + { -4, -7, 30, 32 }, + { -6, -5, 33, 31 }, + { -6, -5, 32, 25 }, + { -3, -8, 35, 33 }, + { -2, -12, 36, 38 }, + { -2, -12, 37, 35 }, + { -3, -8, 38, 40 }, + { -6, -5, 41, 48 }, + { -6, -5, 40, 31 }, + { -5, -6, 43, 41 }, + { -1, -24, 94, 42 }, + { -3, -8, 45, 43 }, + { -2, -12, 42, 44 }, + { -2, -12, 47, 45 }, + { -3, -8, 44, 46 }, + { -1, -24, 125, 47 }, + { -5, -6, 46, 48 }, + { -6, -5, 49, 49 }, + { -2, -13, 152, 164 }, + { -4, -7, 51, 49 }, + { -3, -9, 164, 168 }, + { -3, -9, 55, 51 }, + { -4, -7, 168, 170 }, + { -2, -13, 67, 55 }, + { -6, -5, 170, 49 }, + { -6, -5, 51, 170 }, + { -1, -72, 50, 74 }, + { -4, -7, 53, 49 }, + { -1, -61, 50, 74 }, + { -3, -8, 55, 49 }, + { -1, -51, 52, 76 }, + { -3, -9, 57, 51 }, + { -1, -46, 54, 76 }, + { -2, -10, 59, 53 }, + { -1, -43, 56, 78 }, + { -2, -11, 61, 53 }, + { -1, -41, 58, 80 }, + { -2, -12, 63, 55 }, + { -1, -39, 60, 82 }, + { -2, -12, 65, 55 }, + { -1, -37, 62, 84 }, + { -2, -13, 67, 57 }, + { -1, -36, 64, 86 }, + { -1, -14, 69, 59 }, + { -1, -35, 66, 88 }, + { -1, -14, 71, 59 }, + { -1, -34, 68, 90 }, + { -1, -15, 73, 61 }, + { -1, -33, 70, 92 }, + { -1, -15, 75, 61 }, + { -1, -32, 72, 94 }, + { -1, -15, 77, 63 }, + { -1, -31, 74, 96 }, + { -1, -16, 79, 65 }, + { -1, -31, 76, 98 }, + { -1, -16, 81, 67 }, + { -1, -30, 78, 100 }, + { -1, -17, 83, 67 }, + { -1, -29, 80, 102 }, + { -1, -17, 85, 69 }, + { -1, -29, 82, 104 }, + { -1, -18, 87, 71 }, + { -1, -28, 84, 104 }, + { -1, -18, 89, 73 }, + { -1, -28, 86, 108 }, + { -1, -18, 91, 73 }, + { -1, -27, 88, 108 }, + { -1, -19, 93, 75 }, + { -1, -27, 90, 112 }, + { -1, -19, 95, 77 }, + { -1, -26, 92, 112 }, + { -1, -20, 97, 79 }, + { -1, -26, 94, 114 }, + { -1, -20, 99, 81 }, + { -1, -25, 96, 116 }, + { -1, -20, 101, 83 }, + { -1, -25, 98, 118 }, + { -1, -21, 103, 83 }, + { -1, -24, 100, 120 }, + { -1, -21, 105, 85 }, + { -1, -24, 102, 122 }, + { -1, -22, 107, 87 }, + { -1, -23, 104, 124 }, + { -1, -22, 109, 89 }, + { -1, -23, 106, 126 }, + { -1, -22, 111, 91 }, + { -1, -22, 108, 128 }, + { -1, -23, 113, 93 }, + { -1, -22, 110, 130 }, + { -1, -23, 115, 95 }, + { -1, -22, 112, 132 }, + { -1, -24, 117, 97 }, + { -1, -21, 114, 134 }, + { -1, -24, 119, 99 }, + { -1, -21, 116, 136 }, + { -1, -25, 121, 101 }, + { -1, -20, 118, 136 }, + { -1, -25, 123, 103 }, + { -1, -20, 120, 138 }, + { -1, -26, 125, 105 }, + { -1, -20, 122, 140 }, + { -1, -26, 127, 107 }, + { -1, -19, 124, 142 }, + { -1, -27, 129, 107 }, + { -1, -19, 126, 144 }, + { -1, -27, 131, 111 }, + { -1, -18, 128, 146 }, + { -1, -28, 133, 111 }, + { -1, -18, 130, 146 }, + { -1, -28, 135, 115 }, + { -1, -18, 132, 148 }, + { -1, -29, 137, 115 }, + { -1, -17, 134, 150 }, + { -1, -29, 139, 117 }, + { -1, -17, 136, 152 }, + { -1, -30, 141, 119 }, + { -1, -16, 138, 152 }, + { -1, -31, 143, 121 }, + { -1, -16, 140, 154 }, + { -1, -31, 145, 123 }, + { -1, -15, 142, 156 }, + { -1, -32, 147, 125 }, + { -1, -15, 144, 158 }, + { -1, -33, 149, 127 }, + { -1, -15, 146, 158 }, + { -1, -34, 151, 129 }, + { -1, -14, 148, 160 }, + { -1, -35, 153, 131 }, + { -1, -14, 150, 160 }, + { -1, -36, 155, 133 }, + { -2, -13, 152, 162 }, + { -1, -37, 157, 135 }, + { -2, -12, 154, 164 }, + { -1, -39, 159, 137 }, + { -2, -12, 156, 164 }, + { -1, -41, 161, 139 }, + { -2, -11, 158, 166 }, + { -1, -43, 163, 141 }, + { -2, -10, 160, 166 }, + { -1, -46, 165, 143 }, + { -3, -9, 162, 168 }, + { -1, -51, 167, 143 }, + { -3, -8, 164, 170 }, + { -1, -61, 169, 145 }, + { -4, -7, 166, 170 }, + { -1, -72, 169, 145 }, + { -6, -5, 168, 49 }, + { 0, -108, 171, 171 }, + { 0, -108, 172, 172 }, + { -6, -5, 173, 173 } +}; + +static int els_exp_tab[ELS_JOTS_PER_BYTE * 4 + 1]; +static const int *pAllowable = &els_exp_tab[ELS_JOTS_PER_BYTE * 3]; + +av_cold void ff_els_generate_exp_table(void) +{ + int i; + float jot_size = 8.0f / ELS_JOTS_PER_BYTE; + + for (i = 0; i < ELS_JOTS_PER_BYTE; i++) { + els_exp_tab[i] = 0; + els_exp_tab[i + ELS_JOTS_PER_BYTE * 2] = floor(pow(2.0f, (i + ELS_JOTS_PER_BYTE) * jot_size)); + els_exp_tab[i + ELS_JOTS_PER_BYTE] = els_exp_tab[i + ELS_JOTS_PER_BYTE * 2] >> 8; + els_exp_tab[i + ELS_JOTS_PER_BYTE * 3] = els_exp_tab[i + ELS_JOTS_PER_BYTE * 2] << 8; + } + + els_exp_tab[ELS_JOTS_PER_BYTE * 4] = ELS_MAX; +} + +void ff_els_decoder_init(ElsDecCtx *ctx, const uint8_t *in, size_t data_size) +{ + int nbytes; + + /* consume up to 3 bytes from the input data */ + if (data_size >= 3) { + ctx->x = AV_RB24(in); + nbytes = 3; + } else if (data_size == 2) { + ctx->x = AV_RB16(in); + nbytes = 2; + } else { + ctx->x = *in; + nbytes = 1; + } + + ctx->in_buf = in + nbytes; + ctx->data_size = data_size - nbytes; + ctx->err = 0; + ctx->j = ELS_JOTS_PER_BYTE; + ctx->t = ELS_MAX; + ctx->diff = FFMIN(ELS_MAX - ctx->x, + ELS_MAX - els_exp_tab[ELS_JOTS_PER_BYTE * 4 - 1]); +} + +static int els_import_byte(ElsDecCtx *ctx) +{ + if (!ctx->data_size) { + ctx->err = AVERROR_EOF; + return AVERROR_EOF; + } + ctx->x = (ctx->x << 8) | *ctx->in_buf++; + ctx->data_size--; + ctx->j += ELS_JOTS_PER_BYTE; + ctx->t <<= 8; + + return 0; +} + +int ff_els_decode_bit(ElsDecCtx *ctx, uint8_t *rung) +{ + int z, bit, ret; + + if (ctx->err) + return 0; + + z = pAllowable[ctx->j + Ladder[*rung].ALps]; + ctx->t -= z; + ctx->diff -= z; + if (ctx->diff > 0) + return *rung & 1; /* shortcut for x < t > pAllowable[j - 1] */ + + if (ctx->t > ctx->x) { /* decode most probable symbol (MPS) */ + ctx->j += Ladder[*rung].AMps; + while (ctx->t > pAllowable[ctx->j]) + ctx->j++; + + if (ctx->j <= 0) { /* MPS: import one byte from bytestream. */ + ret = els_import_byte(ctx); + if (ret < 0) + return ret; + } + + z = ctx->t; + bit = *rung & 1; + *rung = Ladder[*rung].next0; + } else { /* decode less probable symbol (LPS) */ + ctx->x -= ctx->t; + ctx->t = z; + + ctx->j += Ladder[*rung].ALps; + if (ctx->j <= 0) { + /* LPS: import one byte from bytestream. */ + z <<= 8; + ret = els_import_byte(ctx); + if (ret < 0) + return ret; + if (ctx->j <= 0) { + /* LPS: import second byte from bytestream. */ + z <<= 8; + ret = els_import_byte(ctx); + if (ret < 0) + return ret; + while (pAllowable[ctx->j - 1] >= z) + ctx->j--; + } + } + + bit = !(*rung & 1); + *rung = Ladder[*rung].next1; + } + + ctx->diff = FFMIN(z - ctx->x, z - pAllowable[ctx->j - 1]); + + return bit; +} + +#define RUNG_SPACE (64 * sizeof(ElsRungNode)) + +unsigned ff_els_decode_unsigned(ElsDecCtx *ctx, ElsUnsignedRung *ur) +{ + int i, n, r, bit; + ElsRungNode *rung_node; + + if (ctx->err) + return 0; + + /* decode unary prefix */ + for (n = 0; n < ELS_EXPGOLOMB_LEN + 1; n++) + if (ff_els_decode_bit(ctx, &ur->prefix_rung[n])) + break; + + /* handle the error/overflow case */ + if (ctx->err || n >= ELS_EXPGOLOMB_LEN) { + ctx->err = AVERROR(EOVERFLOW); + return 0; + } + + /* handle the zero case */ + if (!n) + return 0; + + /* initialize probability tree */ + if (!ur->rem_rung_list) { + ur->rem_rung_list = av_mallocz(RUNG_SPACE); + if (!ur->rem_rung_list) { + ctx->err = AVERROR(ENOMEM); // Probability tree initialization failed + return 0; + } + ur->rung_list_size = RUNG_SPACE; + ur->avail_index = ELS_EXPGOLOMB_LEN; + } + + /* decode the remainder */ + for (i = 0, r = 0, bit = 0; i < n; i++) { + if (!i) + rung_node = &ur->rem_rung_list[n]; + else { + if (!rung_node->next_index) { + if (ur->rung_list_size <= (ur->avail_index + 2) * sizeof(ElsRungNode)) { + // remember rung_node position + ptrdiff_t pos = rung_node - ur->rem_rung_list; + ur->rem_rung_list = av_realloc(ur->rem_rung_list, + ur->rung_list_size + + RUNG_SPACE); + if (!ur->rem_rung_list) { + ctx->err = AVERROR(ENOMEM); // Probability tree resize failed + return 0; + } + memset((uint8_t *) ur->rem_rung_list + ur->rung_list_size, 0, + RUNG_SPACE); + ur->rung_list_size += RUNG_SPACE; + // restore rung_node position in the new list + rung_node = &ur->rem_rung_list[pos]; + } + rung_node->next_index = ur->avail_index; + ur->avail_index += 2; + } + rung_node = &ur->rem_rung_list[rung_node->next_index + bit]; + } + + bit = ff_els_decode_bit(ctx, &rung_node->rung); + if (ctx->err) + return bit; + + r = (r << 1) + bit; + } + + return (1 << n) - 1 + r; /* make value from exp golomb code */ +} diff --git a/libavcodec/elsdec.h b/libavcodec/elsdec.h new file mode 100644 index 0000000..a74fe1e --- /dev/null +++ b/libavcodec/elsdec.h @@ -0,0 +1,60 @@ +/* + * ELS (Entropy Logarithmic-Scale) decoder + * + * Copyright (c) 2013 Maxim Poliakovski + * + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Entropy Logarithmic-Scale binary arithmetic coder + */ + +#ifndef AVCODEC_ELSDEC_H +#define AVCODEC_ELSDEC_H + +#include <stdint.h> +#include <sys/types.h> + +#define ELS_EXPGOLOMB_LEN 10 + +typedef struct ElsDecCtx { + const uint8_t *in_buf; + unsigned x; + size_t data_size; + int j, t, diff, err; +} ElsDecCtx; + +typedef struct ElsRungNode { + uint8_t rung; + uint16_t next_index; +} ElsRungNode; + +typedef struct ElsUnsignedRung { + uint8_t prefix_rung[ELS_EXPGOLOMB_LEN + 1]; + ElsRungNode *rem_rung_list; + size_t rung_list_size; + uint16_t avail_index; +} ElsUnsignedRung; + +void ff_els_generate_exp_table(void); +void ff_els_decoder_init(ElsDecCtx *ctx, const uint8_t *in, size_t data_size); +int ff_els_decode_bit(ElsDecCtx *ctx, unsigned char *rung); +unsigned ff_els_decode_unsigned(ElsDecCtx *ctx, ElsUnsignedRung *ur); + +#endif /* AVCODEC_ELSDEC_H */ diff --git a/libavcodec/g2meet.c b/libavcodec/g2meet.c index a995724..98dc57f 100644 --- a/libavcodec/g2meet.c +++ b/libavcodec/g2meet.c @@ -1,6 +1,7 @@ /* * Go2Webinar decoder * Copyright (c) 2012 Konstantin Shishkov + * Copyright (c) 2013 Maxim Poliakovski * * This file is part of Libav. * @@ -32,12 +33,16 @@ #include "avcodec.h" #include "blockdsp.h" #include "bytestream.h" +#include "elsdec.h" #include "get_bits.h" #include "idctdsp.h" #include "internal.h" #include "jpegtables.h" #include "mjpeg.h" +#define EPIC_PIX_STACK_SIZE 1024 +#define EPIC_PIX_STACK_MAX (EPIC_PIX_STACK_SIZE - 1) + enum ChunkType { DISPLAY_INFO = 0xC8, TILE_DATA, @@ -74,6 +79,42 @@ static const uint8_t chroma_quant[64] = { 50, 50, 50, 50, 50, 50, 50, 50, }; +typedef struct ePICPixListElem { + struct ePICPixListElem *next; + uint32_t pixel; + uint8_t rung; +} ePICPixListElem; + +typedef struct ePICPixHashElem { + uint32_t pix_id; + struct ePICPixListElem *list; +} ePICPixHashElem; + +#define EPIC_HASH_SIZE 256 +typedef struct ePICPixHash { + ePICPixHashElem *bucket[EPIC_HASH_SIZE]; + int bucket_size[EPIC_HASH_SIZE]; + int bucket_fill[EPIC_HASH_SIZE]; +} ePICPixHash; + +typedef struct ePICContext { + ElsDecCtx els_ctx; + int next_run_pos; + ElsUnsignedRung unsigned_rung; + uint8_t W_flag_rung; + uint8_t N_flag_rung; + uint8_t W_ctx_rung[256]; + uint8_t N_ctx_rung[512]; + uint8_t nw_pred_rung[256]; + uint8_t ne_pred_rung[256]; + uint8_t prev_row_rung[14]; + uint8_t runlen_zeroes[14]; + uint8_t runlen_one; + int stack_pos; + uint32_t stack[EPIC_PIX_STACK_SIZE]; + ePICPixHash hash; +} ePICContext; + typedef struct JPGContext { BlockDSPContext bdsp; IDCTDSPContext idsp; @@ -87,7 +128,9 @@ typedef struct JPGContext { } JPGContext; typedef struct G2MContext { - JPGContext jc; + ePICContext ec; + JPGContext jc; + int version; int compression; @@ -101,8 +144,9 @@ typedef struct G2MContext { uint8_t *framebuf; int framebuf_stride, old_width, old_height; - uint8_t *synth_tile, *jpeg_tile; - int tile_stride, old_tile_w, old_tile_h; + uint8_t *synth_tile, *jpeg_tile, *epic_buf, *epic_buf_base; + int tile_stride, epic_buf_stride, old_tile_w, old_tile_h; + int swapuv; uint8_t *kempf_buf, *kempf_flags; @@ -179,7 +223,7 @@ static void jpg_unescape(const uint8_t *src, int src_size, uint8_t *dst, int *dst_size) { const uint8_t *src_end = src + src_size; - uint8_t *dst_start = dst; + uint8_t *dst_start = dst; while (src < src_end) { uint8_t x = *src++; @@ -229,11 +273,11 @@ static int jpg_decode_block(JPGContext *c, GetBitContext *gb, return 0; } -static inline void yuv2rgb(uint8_t *out, int Y, int U, int V) +static inline void yuv2rgb(uint8_t *out, int ridx, int Y, int U, int V) { - out[0] = av_clip_uint8(Y + ( 91881 * V + 32768 >> 16)); - out[1] = av_clip_uint8(Y + (-22554 * U - 46802 * V + 32768 >> 16)); - out[2] = av_clip_uint8(Y + (116130 * U + 32768 >> 16)); + out[ridx] = av_clip_uint8(Y + (91881 * V + 32768 >> 16)); + out[1] = av_clip_uint8(Y + (-22554 * U - 46802 * V + 32768 >> 16)); + out[2 - ridx] = av_clip_uint8(Y + (116130 * U + 32768 >> 16)); } static int jpg_decode_data(JPGContext *c, int width, int height, @@ -247,6 +291,7 @@ static int jpg_decode_data(JPGContext *c, int width, int height, int bx, by; int unesc_size; int ret; + const int ridx = swapuv ? 2 : 0; if ((ret = av_reallocp(&c->buf, src_size + FF_INPUT_BUFFER_PADDING_SIZE)) < 0) @@ -298,9 +343,9 @@ static int jpg_decode_data(JPGContext *c, int width, int height, int Y, U, V; Y = c->block[(j >> 3) * 2 + (i >> 3)][(i & 7) + (j & 7) * 8]; - U = c->block[4 ^ swapuv][(i >> 1) + (j >> 1) * 8] - 128; - V = c->block[5 ^ swapuv][(i >> 1) + (j >> 1) * 8] - 128; - yuv2rgb(out + i * 3, Y, U, V); + U = c->block[4][(i >> 1) + (j >> 1) * 8] - 128; + V = c->block[5][(i >> 1) + (j >> 1) * 8] - 128; + yuv2rgb(out + i * 3, ridx, Y, U, V); } } @@ -317,6 +362,659 @@ static int jpg_decode_data(JPGContext *c, int width, int height, return 0; } +#define LOAD_NEIGHBOURS(x) \ + W = curr_row[(x) - 1]; \ + N = above_row[(x)]; \ + WW = curr_row[(x) - 2]; \ + NW = above_row[(x) - 1]; \ + NE = above_row[(x) + 1]; \ + NN = above2_row[(x)]; \ + NNW = above2_row[(x) - 1]; \ + NWW = above_row[(x) - 2]; \ + NNE = above2_row[(x) + 1] + +#define UPDATE_NEIGHBOURS(x) \ + NNW = NN; \ + NN = NNE; \ + NWW = NW; \ + NW = N; \ + N = NE; \ + NE = above_row[(x) + 1]; \ + NNE = above2_row[(x) + 1] + +#define R_shift 16 +#define G_shift 8 +#define B_shift 0 + +static inline int log2_ceil(uint32_t x) +{ + int c = 0; + + for (--x; x > 0; x >>= 1, c++) + ; + + return c; +} + +/* improved djb2 hash from http://www.cse.yorku.ca/~oz/hash.html */ +static int djb2_hash(uint32_t key) +{ + int h = 5381; + + h = (h * 33) ^ ((key >> 24) & 0xFF); // xxx: probably not needed at all + h = (h * 33) ^ ((key >> 16) & 0xFF); + h = (h * 33) ^ ((key >> 8) & 0xFF); + h = (h * 33) ^ ( key & 0xFF); + + return h & (EPIC_HASH_SIZE - 1); +} + +static void epic_hash_init(ePICPixHash *hash) +{ + memset(hash, 0, sizeof(*hash)); +} + +static ePICPixHashElem *epic_hash_find(const ePICPixHash *hash, uint32_t key) +{ + int i, idx = djb2_hash(key); + ePICPixHashElem *bucket = hash->bucket[idx]; + + for (i = 0; i < hash->bucket_fill[idx]; i++) + if (bucket[i].pix_id == key) + return &bucket[i]; + + return NULL; +} + +static ePICPixHashElem *epic_hash_add(ePICPixHash *hash, uint32_t key) +{ + ePICPixHashElem *bucket, *ret; + int idx = djb2_hash(key); + + if (hash->bucket_size[idx] > INT_MAX / sizeof(**hash->bucket)) + return NULL; + + if (!(hash->bucket_fill[idx] < hash->bucket_size[idx])) { + int new_size = hash->bucket_size[idx] + 16; + bucket = av_realloc(hash->bucket[idx], new_size * sizeof(*bucket)); + if (!bucket) + return NULL; + hash->bucket[idx] = bucket; + hash->bucket_size[idx] = new_size; + } + + ret = &hash->bucket[idx][hash->bucket_fill[idx]++]; + memset(ret, 0, sizeof(*ret)); + ret->pix_id = key; + return ret; +} + +static int epic_add_pixel_to_cache(ePICPixHash *hash, uint32_t key, uint32_t pix) +{ + ePICPixListElem *new_elem; + ePICPixHashElem *hash_elem = epic_hash_find(hash, key); + + if (!hash_elem) { + if (!(hash_elem = epic_hash_add(hash, key))) + return AVERROR(ENOMEM); + } + + new_elem = av_mallocz(sizeof(*new_elem)); + if (!new_elem) + return AVERROR(ENOMEM); + + new_elem->pixel = pix; + new_elem->next = hash_elem->list; + hash_elem->list = new_elem; + + return 0; +} + +static inline int epic_cache_entries_for_pixel(const ePICPixHash *hash, + uint32_t pix) +{ + ePICPixHashElem *hash_elem = epic_hash_find(hash, pix); + + if (hash_elem != NULL && hash_elem->list != NULL) + return 1; + + return 0; +} + +static void epic_free_pixel_cache(ePICPixHash *hash) +{ + int i, j; + + for (i = 0; i < EPIC_HASH_SIZE; i++) { + for (j = 0; j < hash->bucket_fill[i]; j++) { + ePICPixListElem *list_elem = hash->bucket[i][j].list; + while (list_elem) { + ePICPixListElem *tmp = list_elem->next; + av_free(list_elem); + list_elem = tmp; + } + } + av_freep(&hash->bucket[i]); + hash->bucket_size[i] = + hash->bucket_fill[i] = 0; + } +} + +static inline int is_pixel_on_stack(const ePICContext *dc, uint32_t pix) +{ + int i; + + for (i = 0; i < dc->stack_pos; i++) + if (dc->stack[i] == pix) + break; + + return i != dc->stack_pos; +} + +#define TOSIGNED(val) (((val) >> 1) ^ -((val) & 1)) + +static inline int epic_decode_component_pred(ePICContext *dc, + int N, int W, int NW) +{ + unsigned delta = ff_els_decode_unsigned(&dc->els_ctx, &dc->unsigned_rung); + return mid_pred(N, N + W - NW, W) - TOSIGNED(delta); +} + +static uint32_t epic_decode_pixel_pred(ePICContext *dc, int x, int y, + const uint32_t *curr_row, + const uint32_t *above_row) +{ + uint32_t N, W, NW, pred; + unsigned delta; + int GN, GW, GNW, R, G, B; + + if (x && y) { + W = curr_row[x - 1]; + N = above_row[x]; + NW = above_row[x - 1]; + + GN = (N >> G_shift) & 0xFF; + GW = (W >> G_shift) & 0xFF; + GNW = (NW >> G_shift) & 0xFF; + + G = epic_decode_component_pred(dc, GN, GW, GNW); + + R = G + epic_decode_component_pred(dc, + ((N >> R_shift) & 0xFF) - GN, + ((W >> R_shift) & 0xFF) - GW, + ((NW >> R_shift) & 0xFF) - GNW); + + B = G + epic_decode_component_pred(dc, + ((N >> B_shift) & 0xFF) - GN, + ((W >> B_shift) & 0xFF) - GW, + ((NW >> B_shift) & 0xFF) - GNW); + } else { + if (x) + pred = curr_row[x - 1]; + else + pred = above_row[x]; + + delta = ff_els_decode_unsigned(&dc->els_ctx, &dc->unsigned_rung); + R = ((pred >> R_shift) & 0xFF) - TOSIGNED(delta); + + delta = ff_els_decode_unsigned(&dc->els_ctx, &dc->unsigned_rung); + G = ((pred >> G_shift) & 0xFF) - TOSIGNED(delta); + + delta = ff_els_decode_unsigned(&dc->els_ctx, &dc->unsigned_rung); + B = ((pred >> B_shift) & 0xFF) - TOSIGNED(delta); + } + + return (R << R_shift) | (G << G_shift) | (B << B_shift); +} + +static int epic_predict_pixel(ePICContext *dc, uint8_t *rung, + uint32_t *pPix, uint32_t pix) +{ + if (!ff_els_decode_bit(&dc->els_ctx, rung)) { + *pPix = pix; + return 1; + } + dc->stack[dc->stack_pos++ & EPIC_PIX_STACK_MAX] = pix; + return 0; +} + +static int epic_handle_edges(ePICContext *dc, int x, int y, + const uint32_t *curr_row, + const uint32_t *above_row, uint32_t *pPix) +{ + uint32_t pix; + + if (!x && !y) { /* special case: top-left pixel */ + /* the top-left pixel is coded independently with 3 unsigned numbers */ + *pPix = (ff_els_decode_unsigned(&dc->els_ctx, &dc->unsigned_rung) << R_shift) | + (ff_els_decode_unsigned(&dc->els_ctx, &dc->unsigned_rung) << G_shift) | + (ff_els_decode_unsigned(&dc->els_ctx, &dc->unsigned_rung) << B_shift); + return 1; + } + + if (x) { /* predict from W first */ + pix = curr_row[x - 1]; + if (epic_predict_pixel(dc, &dc->W_flag_rung, pPix, pix)) + return 1; + } + + if (y) { /* then try to predict from N */ + pix = above_row[x]; + if (!dc->stack_pos || dc->stack[0] != pix) { + if (epic_predict_pixel(dc, &dc->N_flag_rung, pPix, pix)) + return 1; + } + } + + return 0; +} + +static int epic_decode_run_length(ePICContext *dc, int x, int y, int tile_width, + const uint32_t *curr_row, + const uint32_t *above_row, + const uint32_t *above2_row, + uint32_t *pPix, int *pRun) +{ + int idx, got_pixel = 0, WWneW, old_WWneW = 0; + uint32_t W, WW, N, NN, NW, NE, NWW, NNW, NNE; + + *pRun = 0; + + LOAD_NEIGHBOURS(x); + + if (dc->next_run_pos == x) { + /* can't reuse W for the new pixel in this case */ + WWneW = 1; + } else { + idx = (WW != W) << 7 | + (NW != W) << 6 | + (N != NE) << 5 | + (NW != N) << 4 | + (NWW != NW) << 3 | + (NNE != NE) << 2 | + (NN != N) << 1 | + (NNW != NW); + WWneW = ff_els_decode_bit(&dc->els_ctx, &dc->W_ctx_rung[idx]); + } + + if (WWneW) + dc->stack[dc->stack_pos++ & EPIC_PIX_STACK_MAX] = W; + else { + *pPix = W; + got_pixel = 1; + } + + do { + int NWneW = 1; + if (got_pixel) // pixel value already known (derived from either W or N) + NWneW = *pPix != N; + else { // pixel value is unknown and will be decoded later + NWneW = *pRun ? NWneW : NW != W; + + /* TODO: RFC this mess! */ + switch (((NW != N) << 2) | (NWneW << 1) | WWneW) { + case 0: + break; // do nothing here + case 3: + case 5: + case 6: + case 7: + if (!is_pixel_on_stack(dc, N)) { + idx = WWneW << 8 | + (*pRun ? old_WWneW : WW != W) << 7 | + NWneW << 6 | + (N != NE) << 5 | + (NW != N) << 4 | + (NWW != NW) << 3 | + (NNE != NE) << 2 | + (NN != N) << 1 | + (NNW != NW); + if (!ff_els_decode_bit(&dc->els_ctx, &dc->N_ctx_rung[idx])) { + NWneW = 0; + *pPix = N; + got_pixel = 1; + break; + } + } + /* fall through */ + default: + NWneW = 1; + old_WWneW = WWneW; + if (!is_pixel_on_stack(dc, N)) + dc->stack[dc->stack_pos++ & EPIC_PIX_STACK_MAX] = N; + } + } + + (*pRun)++; + if (x + *pRun >= tile_width - 1) + break; + + UPDATE_NEIGHBOURS(x + *pRun); + + if (!NWneW && NW == N && N == NE) { + int pos, run, rle; + int start_pos = x + *pRun; + + /* scan for a run of pix in the line above */ + uint32_t pix = above_row[start_pos + 1]; + for (pos = start_pos + 2; pos < tile_width; pos++) + if (!(above_row[pos] == pix)) + break; + run = pos - start_pos - 1; + idx = log2_ceil(run); + if (ff_els_decode_bit(&dc->els_ctx, &dc->prev_row_rung[idx])) + *pRun += run; + else { + int flag; + /* run-length is coded as plain binary number of idx - 1 bits */ + for (pos = idx - 1, rle = 0, flag = 0; pos >= 0; pos--) { + if ((1 << pos) + rle < run && + ff_els_decode_bit(&dc->els_ctx, + flag ? &dc->runlen_one + : &dc->runlen_zeroes[pos])) { + flag = 1; + rle |= 1 << pos; + } + } + *pRun += rle; + break; // return immediately + } + if (x + *pRun >= tile_width - 1) + break; + + LOAD_NEIGHBOURS(x + *pRun); + WWneW = 0; + NWneW = 0; + } + + idx = WWneW << 7 | + NWneW << 6 | + (N != NE) << 5 | + (NW != N) << 4 | + (NWW != NW) << 3 | + (NNE != NE) << 2 | + (NN != N) << 1 | + (NNW != NW); + WWneW = ff_els_decode_bit(&dc->els_ctx, &dc->W_ctx_rung[idx]); + } while (!WWneW); + + dc->next_run_pos = x + *pRun; + return got_pixel; +} + +static int epic_predict_pixel2(ePICContext *dc, uint8_t *rung, + uint32_t *pPix, uint32_t pix) +{ + if (ff_els_decode_bit(&dc->els_ctx, rung)) { + *pPix = pix; + return 1; + } + dc->stack[dc->stack_pos++ & EPIC_PIX_STACK_MAX] = pix; + return 0; +} + +static int epic_predict_from_NW_NE(ePICContext *dc, int x, int y, int run, + int tile_width, const uint32_t *curr_row, + const uint32_t *above_row, uint32_t *pPix) +{ + int pos; + + /* try to reuse the NW pixel first */ + if (x && y) { + uint32_t NW = above_row[x - 1]; + if (NW != curr_row[x - 1] && NW != above_row[x] && !is_pixel_on_stack(dc, NW)) { + if (epic_predict_pixel2(dc, &dc->nw_pred_rung[NW & 0xFF], pPix, NW)) + return 1; + } + } + + /* try to reuse the NE[x + run, y] pixel */ + pos = x + run - 1; + if (pos < tile_width - 1 && y) { + uint32_t NE = above_row[pos + 1]; + if (NE != above_row[pos] && !is_pixel_on_stack(dc, NE)) { + if (epic_predict_pixel2(dc, &dc->ne_pred_rung[NE & 0xFF], pPix, NE)) + return 1; + } + } + + return 0; +} + +static int epic_decode_from_cache(ePICContext *dc, uint32_t W, uint32_t *pPix) +{ + ePICPixListElem *list, *prev = NULL; + ePICPixHashElem *hash_elem = epic_hash_find(&dc->hash, W); + + if (!hash_elem || !hash_elem->list) + return 0; + + list = hash_elem->list; + while (list) { + if (!is_pixel_on_stack(dc, list->pixel)) { + if (ff_els_decode_bit(&dc->els_ctx, &list->rung)) { + *pPix = list->pixel; + if (list != hash_elem->list) { + prev->next = list->next; + list->next = hash_elem->list; + hash_elem->list = list; + } + return 1; + } + dc->stack[dc->stack_pos++ & EPIC_PIX_STACK_MAX] = list->pixel; + } + prev = list; + list = list->next; + } + + return 0; +} + +static int epic_decode_tile(ePICContext *dc, uint8_t *out, int tile_height, + int tile_width, int stride) +{ + int x, y; + uint32_t pix; + uint32_t *curr_row = NULL, *above_row = NULL, *above2_row; + + for (y = 0; y < tile_height; y++, out += stride) { + above2_row = above_row; + above_row = curr_row; + curr_row = (uint32_t *) out; + + for (x = 0, dc->next_run_pos = 0; x < tile_width;) { + if (dc->els_ctx.err) + return AVERROR_INVALIDDATA; // bail out in the case of ELS overflow + + pix = curr_row[x - 1]; // get W pixel + + if (y >= 1 && x >= 2 && + pix != curr_row[x - 2] && pix != above_row[x - 1] && + pix != above_row[x - 2] && pix != above_row[x] && + !epic_cache_entries_for_pixel(&dc->hash, pix)) { + curr_row[x] = epic_decode_pixel_pred(dc, x, y, curr_row, above_row); + x++; + } else { + int got_pixel, run; + dc->stack_pos = 0; // empty stack + + if (y < 2 || x < 2 || x == tile_width - 1) { + run = 1; + got_pixel = epic_handle_edges(dc, x, y, curr_row, above_row, &pix); + } else + got_pixel = epic_decode_run_length(dc, x, y, tile_width, + curr_row, above_row, + above2_row, &pix, &run); + + if (!got_pixel && !epic_predict_from_NW_NE(dc, x, y, run, + tile_width, curr_row, + above_row, &pix)) { + uint32_t ref_pix = curr_row[x - 1]; + if (!x || !epic_decode_from_cache(dc, ref_pix, &pix)) { + pix = epic_decode_pixel_pred(dc, x, y, curr_row, above_row); + if (x) { + int ret = epic_add_pixel_to_cache(&dc->hash, + ref_pix, + pix); + if (ret) + return ret; + } + } + } + for (; run > 0; x++, run--) + curr_row[x] = pix; + } + } + } + + return 0; +} + +static int epic_jb_decode_tile(G2MContext *c, int tile_x, int tile_y, + const uint8_t *src, size_t src_size, + AVCodecContext *avctx) +{ + uint8_t prefix, mask; + int extrabytes, tile_width, tile_height, awidth, aheight; + size_t els_dsize; + uint8_t *dst; + + if (!src_size) + return 0; + + /* get data size of the ELS partition as unsigned variable-length integer */ + prefix = *src++; + for (extrabytes = 0, mask = 0x80; (prefix & mask) && (extrabytes < 7); + mask >>= 1, extrabytes++) + ; + if (extrabytes > 3 || --src_size < extrabytes) { + av_log(avctx, AV_LOG_ERROR, "ePIC: invalid data size VLI\n"); + return AVERROR_INVALIDDATA; + } + + els_dsize = prefix & ((0x80 >> extrabytes) - 1); // mask out the length prefix + while (extrabytes-- > 0) { + els_dsize = (els_dsize << 8) | *src++; + src_size--; + } + + if (src_size < els_dsize) { + av_log(avctx, AV_LOG_ERROR, "ePIC: data too short, needed %zu, got %zu\n", + els_dsize, src_size); + return AVERROR_INVALIDDATA; + } + + tile_width = FFMIN(c->width - tile_x * c->tile_width, c->tile_width); + tile_height = FFMIN(c->height - tile_y * c->tile_height, c->tile_height); + awidth = FFALIGN(tile_width, 16); + aheight = FFALIGN(tile_height, 16); + + if (els_dsize) { + int ret, i, j, k; + uint8_t tr_r, tr_g, tr_b, *buf; + uint32_t *in; + /* ELS decoder initializations */ + memset(&c->ec, 0, sizeof(c->ec)); + ff_els_decoder_init(&c->ec.els_ctx, src, els_dsize); + epic_hash_init(&c->ec.hash); + + /* decode transparent pixel value */ + tr_r = ff_els_decode_unsigned(&c->ec.els_ctx, &c->ec.unsigned_rung); + tr_g = ff_els_decode_unsigned(&c->ec.els_ctx, &c->ec.unsigned_rung); + tr_b = ff_els_decode_unsigned(&c->ec.els_ctx, &c->ec.unsigned_rung); + if (c->ec.els_ctx.err != 0) { + av_log(avctx, AV_LOG_ERROR, + "ePIC: couldn't decode transparency pixel!\n"); + return AVERROR_INVALIDDATA; + } + + ret = epic_decode_tile(&c->ec, c->epic_buf, tile_height, tile_width, + c->epic_buf_stride); + + epic_free_pixel_cache(&c->ec.hash); + av_free(c->ec.unsigned_rung.rem_rung_list); + + if (ret) { + av_log(avctx, AV_LOG_ERROR, + "ePIC: tile decoding failed, frame=%d, tile_x=%d, tile_y=%d\n", + avctx->frame_number, tile_x, tile_y); + return AVERROR_INVALIDDATA; + } + + buf = c->epic_buf; + dst = c->framebuf + tile_x * c->tile_width * 3 + + tile_y * c->tile_height * c->framebuf_stride; + + for (j = 0; j < tile_height; j++) { + uint8_t *out = dst; + in = (uint32_t *) buf; + for (i = 0; i < tile_width; i++) { + out[0] = (in[i] >> R_shift) & 0xFF; + out[1] = (in[i] >> G_shift) & 0xFF; + out[2] = (in[i] >> B_shift) & 0xFF; + out += 3; + } + buf += c->epic_buf_stride; + dst += c->framebuf_stride; + } + + if (src_size > els_dsize) { + uint8_t *jpg, tr; + int bstride = FFALIGN(tile_width, 16) >> 3; + int nblocks = 0; + int estride = c->epic_buf_stride >> 2; + + src += els_dsize; + src_size -= els_dsize; + + in = (uint32_t *) c->epic_buf; + tr = (tr_r << R_shift) | (tr_g << G_shift) | (tr_b << B_shift); + + memset(c->kempf_flags, + 0, + (aheight >> 3) * bstride * sizeof(*c->kempf_flags)); + for (j = 0; j < tile_height; j += 8) { + for (i = 0; i < tile_width; i += 8) { + c->kempf_flags[(i >> 3) + (j >> 3) * bstride] = 0; + for (k = 0; k < 8 * 8; k++) { + if (in[i + (k & 7) + (k >> 3) * estride] == tr) { + c->kempf_flags[(i >> 3) + (j >> 3) * bstride] = 1; + nblocks++; + break; + } + } + } + in += 8 * estride; + } + + memset(c->jpeg_tile, 0, c->tile_stride * aheight); + jpg_decode_data(&c->jc, awidth, aheight, src, src_size, + c->jpeg_tile, c->tile_stride, + c->kempf_flags, bstride, nblocks, c->swapuv); + + in = (uint32_t *) c->epic_buf; + dst = c->framebuf + tile_x * c->tile_width * 3 + + tile_y * c->tile_height * c->framebuf_stride; + jpg = c->jpeg_tile; + for (j = 0; j < tile_height; j++) { + for (i = 0; i < tile_width; i++) + if (in[i] == tr) + memcpy(dst + i * 3, jpg + i * 3, 3); + in += c->epic_buf_stride >> 2; + dst += c->framebuf_stride; + jpg += c->tile_stride; + } + } + } else { + dst = c->framebuf + tile_x * c->tile_width * 3 + + tile_y * c->tile_height * c->framebuf_stride; + return jpg_decode_data(&c->jc, tile_width, tile_height, src, src_size, + dst, c->framebuf_stride, NULL, 0, 0, c->swapuv); + } + + return 0; +} + static void kempf_restore_buf(const uint8_t *src, int len, uint8_t *dst, int stride, const uint8_t *jpeg_tile, int tile_stride, @@ -325,6 +1023,7 @@ static void kempf_restore_buf(const uint8_t *src, int len, { GetBitContext gb; int i, j, nb, col; + int align_width = FFALIGN(width, 16); init_get_bits(&gb, src, len * 8); @@ -347,6 +1046,7 @@ static void kempf_restore_buf(const uint8_t *src, int len, else memcpy(dst + i * 3, jpeg_tile + i * 3, 3); } + skip_bits_long(&gb, nb * (align_width - width)); } } @@ -470,14 +1170,17 @@ static int g2m_init_buffers(G2MContext *c) return AVERROR(ENOMEM); } if (!c->synth_tile || !c->jpeg_tile || + (c->compression == 2 && !c->epic_buf_base) || c->old_tile_w < c->tile_width || c->old_tile_h < c->tile_height) { - c->tile_stride = FFALIGN(c->tile_width * 3, 16); - aligned_height = FFALIGN(c->tile_height, 16); + c->tile_stride = FFALIGN(c->tile_width * 3, 16); + c->epic_buf_stride = FFALIGN(c->tile_width * 4, 16); + aligned_height = FFALIGN(c->tile_height, 16); av_free(c->synth_tile); av_free(c->jpeg_tile); av_free(c->kempf_buf); av_free(c->kempf_flags); + av_free(c->epic_buf_base); c->synth_tile = av_mallocz(c->tile_stride * aligned_height); c->jpeg_tile = av_mallocz(c->tile_stride * aligned_height); c->kempf_buf = av_mallocz((c->tile_width + 1) * aligned_height @@ -486,6 +1189,12 @@ static int g2m_init_buffers(G2MContext *c) if (!c->synth_tile || !c->jpeg_tile || !c->kempf_buf || !c->kempf_flags) return AVERROR(ENOMEM); + if (c->compression == 2) { + c->epic_buf_base = av_mallocz(c->epic_buf_stride * aligned_height + 4); + if (!c->epic_buf_base) + return AVERROR(ENOMEM); + c->epic_buf = c->epic_buf_base + 4; + } } return 0; @@ -667,7 +1376,7 @@ static int g2m_decode_frame(AVCodecContext *avctx, void *data, int *got_picture_ptr, AVPacket *avpkt) { const uint8_t *buf = avpkt->data; - int buf_size = avpkt->size; + int buf_size = avpkt->size; G2MContext *c = avctx->priv_data; AVFrame *pic = data; GetByteContext bc, tbc; @@ -693,11 +1402,7 @@ static int g2m_decode_frame(AVCodecContext *avctx, void *data, av_log(avctx, AV_LOG_ERROR, "Wrong magic %08X\n", magic); return AVERROR_INVALIDDATA; } - - if ((magic & 0xF) != 4) { - av_log(avctx, AV_LOG_ERROR, "G2M2 and G2M3 are not yet supported\n"); - return AVERROR(ENOSYS); - } + c->swapuv = magic == MKBETAG('G', '2', 'M', '2'); while (bytestream2_get_bytes_left(&bc) > 5) { chunk_size = bytestream2_get_le32(&bc) - 1; @@ -799,9 +1504,10 @@ static int g2m_decode_frame(AVCodecContext *avctx, void *data, ret = 0; switch (c->compression) { case COMPR_EPIC_J_B: - av_log(avctx, AV_LOG_ERROR, - "ePIC j-b compression is not implemented yet\n"); - return AVERROR(ENOSYS); + ret = epic_jb_decode_tile(c, c->tile_x, c->tile_y, + buf + bytestream2_tell(&bc), + chunk_size - 2, avctx); + break; case COMPR_KEMPF_J_B: ret = kempf_decode_tile(c, c->tile_x, c->tile_y, buf + bytestream2_tell(&bc), @@ -878,6 +1584,8 @@ static av_cold int g2m_decode_init(AVCodecContext *avctx) G2MContext *const c = avctx->priv_data; int ret; + ff_els_generate_exp_table(); + if ((ret = jpg_init(avctx, &c->jc)) != 0) { av_log(avctx, AV_LOG_ERROR, "Cannot initialise VLCs\n"); jpg_free_context(&c->jc); @@ -899,6 +1607,7 @@ static av_cold int g2m_decode_end(AVCodecContext *avctx) jpg_free_context(&c->jc); + av_freep(&c->epic_buf_base); av_freep(&c->kempf_buf); av_freep(&c->kempf_flags); av_freep(&c->synth_tile); diff --git a/libavcodec/version.h b/libavcodec/version.h index f6a0b58..3f4e47c 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -29,7 +29,7 @@ #include "libavutil/version.h" #define LIBAVCODEC_VERSION_MAJOR 56 -#define LIBAVCODEC_VERSION_MINOR 22 +#define LIBAVCODEC_VERSION_MINOR 23 #define LIBAVCODEC_VERSION_MICRO 0 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ diff --git a/tests/fate/screen.mak b/tests/fate/screen.mak index f0667ae..d401edc 100644 --- a/tests/fate/screen.mak +++ b/tests/fate/screen.mak @@ -29,6 +29,18 @@ fate-fraps-v5: CMD = framecrc -i $(TARGET_SAMPLES)/fraps/fraps-v5-bouncing-balls FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, FRAPS) += $(FATE_FRAPS) fate-fraps: $(FATE_FRAPS) +FATE_G2M += fate-g2m2 +fate-g2m2: CMD = framecrc -i $(TARGET_SAMPLES)/g2m/g2m2.asf -an + +FATE_G2M += fate-g2m3 +fate-g2m3: CMD = framecrc -i $(TARGET_SAMPLES)/g2m/g2m3.asf + +FATE_G2M += fate-g2m4 +fate-g2m4: CMD = framecrc -i $(TARGET_SAMPLES)/g2m/g2m4.asf + +FATE_SAMPLES_AVCONV-$(call DEMDEC, ASF, G2M) += $(FATE_G2M) +fate-g2m: $(FATE_G2M) + FATE_SAMPLES_AVCONV-$(call DEMDEC, ASF, TDSC) += fate-tdsc fate-tdsc: CMD = framecrc -idct simple -i $(TARGET_SAMPLES)/tdsc/tdsc.asf -an -pix_fmt bgr24 diff --git a/tests/ref/fate/g2m2 b/tests/ref/fate/g2m2 new file mode 100644 index 0000000..f117b48 --- /dev/null +++ b/tests/ref/fate/g2m2 @@ -0,0 +1,161 @@ +#tb 0: 1/1000 +0, 47, 47, 0, 2359296, 0xb4434e4f +0, 62, 62, 0, 2359296, 0x59cb5027 +0, 78, 78, 0, 2359296, 0xe9bc578d +0, 109, 109, 0, 2359296, 0x5d17554f +0, 125, 125, 0, 2359296, 0x6d685457 +0, 437, 437, 0, 2359296, 0x13205420 +0, 438, 438, 0, 2359296, 0xb8e15116 +0, 453, 453, 0, 2359296, 0x2ca55195 +0, 469, 469, 0, 2359296, 0x767d1c45 +0, 484, 484, 0, 2359296, 0x0af42016 +0, 500, 500, 0, 2359296, 0xa2083e69 +0, 516, 516, 0, 2359296, 0xb68a1308 +0, 531, 531, 0, 2359296, 0x4f334c0e +0, 547, 547, 0, 2359296, 0x98b74e4f +0, 562, 562, 0, 2359296, 0xd9de4e4f +0, 578, 578, 0, 2359296, 0xa17c4e4f +0, 594, 594, 0, 2359296, 0xa49a665d +0, 609, 609, 0, 2359296, 0xf5f87360 +0, 781, 781, 0, 2359296, 0x75747360 +0, 797, 797, 0, 2359296, 0x745d7360 +0, 812, 812, 0, 2359296, 0x33047360 +0, 828, 828, 0, 2359296, 0xf19c7360 +0, 844, 844, 0, 2359296, 0xb0437360 +0, 859, 859, 0, 2359296, 0xaf2c7360 +0, 875, 875, 0, 2359296, 0x2ea87360 +0, 891, 891, 0, 2359296, 0xee577360 +0, 953, 953, 0, 2359296, 0x6dd37360 +0, 1078, 1078, 0, 2359296, 0xab327965 +0, 1094, 1094, 0, 2359296, 0x5f8677d0 +0, 1109, 1109, 0, 2359296, 0x02135eb4 +0, 1125, 1125, 0, 2359296, 0x09784e4f +0, 1141, 1141, 0, 2359296, 0xa140a62d +0, 1156, 1156, 0, 2359296, 0xa140a62d +0, 1484, 1484, 0, 2359296, 0xa140a62d +0, 1516, 1516, 0, 2359296, 0xa140a62d +0, 1547, 1547, 0, 2359296, 0xa140a62d +0, 1641, 1641, 0, 2359296, 0xa140a62d +0, 1642, 1642, 0, 2359296, 0xa140a62d +0, 1656, 1656, 0, 2359296, 0xa140a62d +0, 1657, 1657, 0, 2359296, 0xa140a62d +0, 1672, 1672, 0, 2359296, 0xa140a62d +0, 1673, 1673, 0, 2359296, 0x92024e4f +0, 1687, 1687, 0, 2359296, 0xb1754dbe +0, 1688, 1688, 0, 2359296, 0x15ee5eb4 +0, 1703, 1703, 0, 2359296, 0xb1d9746e +0, 1719, 1719, 0, 2359296, 0xabe77360 +0, 1734, 1734, 0, 2359296, 0xaad07360 +0, 1750, 1750, 0, 2359296, 0x2a4c7360 +0, 1766, 1766, 0, 2359296, 0x69777360 +0, 1781, 1781, 0, 2359296, 0xe8e47360 +0, 2328, 2328, 0, 2359296, 0x29357360 +0, 3031, 3031, 0, 2359296, 0x69777360 +0, 3078, 3078, 0, 2359296, 0xa9b97360 +0, 3109, 3109, 0, 2359296, 0xd2697707 +0, 3141, 3141, 0, 2359296, 0x22a07965 +0, 3156, 3156, 0, 2359296, 0xf9327aa7 +0, 3172, 3172, 0, 2359296, 0xa5d277d0 +0, 3203, 3203, 0, 2359296, 0x97b6746e +0, 3328, 3328, 0, 2359296, 0x80bb746e +0, 4562, 4562, 0, 2359296, 0x530b719a +0, 4672, 4672, 0, 2359296, 0x4827665d +0, 4703, 4703, 0, 2359296, 0xc48c5eb4 +0, 5391, 5391, 0, 2359296, 0xe6465eb4 +0, 5578, 5578, 0, 2359296, 0xece455ec +0, 5594, 5594, 0, 2359296, 0xb5344dbe +0, 5609, 5609, 0, 2359296, 0xa140a62d +0, 5625, 5625, 0, 2359296, 0xa140a62d +0, 5641, 5641, 0, 2359296, 0xa140a62d +0, 5642, 5642, 0, 2359296, 0xa140a62d +0, 5656, 5656, 0, 2359296, 0xa140a62d +0, 5672, 5672, 0, 2359296, 0xa140a62d +0, 5703, 5703, 0, 2359296, 0xa140a62d +0, 5750, 5750, 0, 2359296, 0xa140a62d +0, 5766, 5766, 0, 2359296, 0xa140a62d +0, 5781, 5781, 0, 2359296, 0xa140a62d +0, 5797, 5797, 0, 2359296, 0xa140a62d +0, 5812, 5812, 0, 2359296, 0xa140a62d +0, 5875, 5875, 0, 2359296, 0xa140a62d +0, 5922, 5922, 0, 2359296, 0xa140a62d +0, 5984, 5984, 0, 2359296, 0xa140a62d +0, 6031, 6031, 0, 2359296, 0xa140a62d +0, 6047, 6047, 0, 2359296, 0xa140a62d +0, 6062, 6062, 0, 2359296, 0xa140a62d +0, 6406, 6406, 0, 2359296, 0xa140a62d +0, 6453, 6453, 0, 2359296, 0xa140a62d +0, 6469, 6469, 0, 2359296, 0xa140a62d +0, 6484, 6484, 0, 2359296, 0xa140a62d +0, 6500, 6500, 0, 2359296, 0xa140a62d +0, 6516, 6516, 0, 2359296, 0xa140a62d +0, 6531, 6531, 0, 2359296, 0xa140a62d +0, 6547, 6547, 0, 2359296, 0xa140a62d +0, 6562, 6562, 0, 2359296, 0x5c2a4cd9 +0, 6578, 6578, 0, 2359296, 0x28f94e4f +0, 6594, 6594, 0, 2359296, 0x9acb4820 +0, 6609, 6609, 0, 2359296, 0x9ec716e1 +0, 6625, 6625, 0, 2359296, 0xaf5f3fa4 +0, 6641, 6641, 0, 2359296, 0x7d633218 +0, 6642, 6642, 0, 2359296, 0x34fb2016 +0, 6656, 6656, 0, 2359296, 0x61351665 +0, 6812, 6812, 0, 2359296, 0xb23c1039 +0, 6828, 6828, 0, 2359296, 0x59290d69 +0, 6844, 6844, 0, 2359296, 0x639c132d +0, 6859, 6859, 0, 2359296, 0x0b252237 +0, 6875, 6875, 0, 2359296, 0xe66f2fc5 +0, 6891, 6891, 0, 2359296, 0xa8b33761 +0, 6906, 6906, 0, 2359296, 0x81a63f8b +0, 6969, 6969, 0, 2359296, 0x18074843 +0, 6984, 6984, 0, 2359296, 0x434a5195 +0, 7000, 7000, 0, 2359296, 0x6da15116 +0, 7001, 7001, 0, 2359296, 0xca755420 +0, 7016, 7016, 0, 2359296, 0xe6fc5457 +0, 7017, 7017, 0, 2359296, 0x271d53fd +0, 7031, 7031, 0, 2359296, 0xa15b554f +0, 7281, 7281, 0, 2359296, 0x49f6578d +0, 7282, 7282, 0, 2359296, 0x2c0c4e4f +0, 7297, 7297, 0, 2359296, 0x7e924e4f +0, 7298, 7298, 0, 2359296, 0x32ff4e4f +0, 7312, 7312, 0, 2359296, 0x23ad4e4f +0, 7313, 7313, 0, 2359296, 0x7ddc4e4f +0, 7328, 7328, 0, 2359296, 0xd0624e4f +0, 7329, 7329, 0, 2359296, 0x22f74e4f +0, 7781, 7781, 0, 2359296, 0x49fa4e4f +0, 7797, 7797, 0, 2359296, 0x6a5a5027 +0, 7812, 7812, 0, 2359296, 0x9f935027 +0, 7828, 7828, 0, 2359296, 0xc5e55027 +0, 7844, 7844, 0, 2359296, 0xd4cc5027 +0, 8250, 8250, 0, 2359296, 0xd2ab5027 +0, 8266, 8266, 0, 2359296, 0x68f04e4f +0, 8281, 8281, 0, 2359296, 0xd0b44e4f +0, 8297, 8297, 0, 2359296, 0xfced4e4f +0, 8298, 8298, 0, 2359296, 0x8b0d4e4f +0, 8312, 8312, 0, 2359296, 0x09db4e4f +0, 8328, 8328, 0, 2359296, 0x4d0f4e4f +0, 8329, 8329, 0, 2359296, 0xad824dbe +0, 8344, 8344, 0, 2359296, 0x9aca4dbe +0, 8345, 8345, 0, 2359296, 0x755a4dbe +0, 8359, 8359, 0, 2359296, 0xc6824d2d +0, 8360, 8360, 0, 2359296, 0x7c344c0e +0, 8375, 8375, 0, 2359296, 0x50f04c0e +0, 8391, 8391, 0, 2359296, 0xfa594c0e +0, 8406, 8406, 0, 2359296, 0x4d494c0e +0, 8422, 8422, 0, 2359296, 0xf6b24c0e +0, 8437, 8437, 0, 2359296, 0xcb6e4c0e +0, 8453, 8453, 0, 2359296, 0xbd024c0e +0, 8516, 8516, 0, 2359296, 0x245b4dbe +0, 8531, 8531, 0, 2359296, 0x47874e4f +0, 8547, 8547, 0, 2359296, 0xdead4e4f +0, 8562, 8562, 0, 2359296, 0x847e4e4f +0, 9344, 9344, 0, 2359296, 0x614ce46d +0, 9345, 9345, 0, 2359296, 0x8dece312 +0, 9876, 9876, 0, 2359296, 0xbdf9e34e +0, 9922, 9922, 0, 2359296, 0x3e21e50a +0, 9938, 9938, 0, 2359296, 0xf348e4a4 +0, 9954, 9954, 0, 2359296, 0x8178e415 +0, 9955, 9955, 0, 2359296, 0xf0b5e199 +0, 9969, 9969, 0, 2359296, 0x5a33e00e +0, 9970, 9970, 0, 2359296, 0xaceddf05 +0, 9985, 9985, 0, 2359296, 0xca09e023 +0, 9986, 9986, 0, 2359296, 0xeb8be0c0 +0, 10001, 10001, 0, 2359296, 0x6a0fdf28 diff --git a/tests/ref/fate/g2m3 b/tests/ref/fate/g2m3 new file mode 100644 index 0000000..84e2a8e --- /dev/null +++ b/tests/ref/fate/g2m3 @@ -0,0 +1,42 @@ +#tb 0: 1/1000 +0, 0, 0, 0, 1536000, 0xf1765db3 +0, 1739, 1739, 0, 1536000, 0x343a602f +0, 1839, 1839, 0, 1536000, 0x70f16029 +0, 1939, 1939, 0, 1536000, 0xa1da62e1 +0, 1940, 1940, 0, 1536000, 0x16c36270 +0, 2039, 2039, 0, 1536000, 0x453965a5 +0, 2040, 2040, 0, 1536000, 0x907a65bd +0, 2139, 2139, 0, 1536000, 0xeee672c8 +0, 2239, 2239, 0, 1536000, 0x20c88b29 +0, 2240, 2240, 0, 1536000, 0x557089b9 +0, 2339, 2339, 0, 1536000, 0x70f67eef +0, 2639, 2639, 0, 1536000, 0xb5b77248 +0, 2739, 2739, 0, 1536000, 0x88cf7350 +0, 2740, 2740, 0, 1536000, 0x7be871df +0, 2839, 2839, 0, 1536000, 0xdbc67126 +0, 2840, 2840, 0, 1536000, 0xc12f7131 +0, 4339, 4339, 0, 1536000, 0xb2e270d8 +0, 4340, 4340, 0, 1536000, 0xc31e71d3 +0, 4439, 4439, 0, 1536000, 0xe39e6c58 +0, 4539, 4539, 0, 1536000, 0xf2027181 +0, 4540, 4540, 0, 1536000, 0x8c6a74ab +0, 4639, 4639, 0, 1536000, 0x9c1c81b6 +0, 4739, 4739, 0, 1536000, 0xc18c7f14 +0, 4838, 4838, 0, 1536000, 0x06895cc8 +0, 4839, 4839, 0, 1536000, 0xb72148a7 +0, 4840, 4840, 0, 1536000, 0x0fe9890e +0, 4841, 4841, 0, 1536000, 0x94e3897f +0, 6338, 6338, 0, 1536000, 0x71afd197 +0, 7038, 7038, 0, 1536000, 0xff4dd121 +0, 7039, 7039, 0, 1536000, 0xbe93111d +0, 7138, 7138, 0, 1536000, 0xebc6051e +0, 7238, 7238, 0, 1536000, 0x3ec6e73d +0, 7338, 7338, 0, 1536000, 0x6326e3c9 +0, 7438, 7438, 0, 1536000, 0xcc8fcee1 +0, 7439, 7439, 0, 1536000, 0x35abce72 +0, 7638, 7638, 0, 1536000, 0xc98b7b20 +0, 7738, 7738, 0, 1536000, 0xc5c06520 +0, 8038, 8038, 0, 1536000, 0xce0853d8 +0, 8228, 8228, 0, 1536000, 0xaf0ae816 +0, 9417, 9417, 0, 1536000, 0xa49eaf86 +0, 9807, 9807, 0, 1536000, 0xa707af86 diff --git a/tests/ref/fate/g2m4 b/tests/ref/fate/g2m4 new file mode 100644 index 0000000..2f2bd74 --- /dev/null +++ b/tests/ref/fate/g2m4 @@ -0,0 +1,29 @@ +#tb 0: 1/1000 +0, 0, 0, 0, 3932160, 0xafab48e8 +0, 29, 29, 0, 3932160, 0x47a47bf9 +0, 129, 129, 0, 3932160, 0x9ffb4d10 +0, 239, 239, 0, 3932160, 0x5eb6786b +0, 240, 240, 0, 3932160, 0x38b6ed92 +0, 339, 339, 0, 3932160, 0x3ef8eaa4 +0, 439, 439, 0, 3932160, 0x7ffa3289 +0, 440, 440, 0, 3932160, 0x7da7699a +0, 539, 539, 0, 3932160, 0x7b155d8a +0, 540, 540, 0, 3932160, 0xf26fcddd +0, 649, 649, 0, 3932160, 0xea566b0b +0, 739, 739, 0, 3932160, 0x6e7f92ab +0, 740, 740, 0, 3932160, 0xb8f23669 +0, 949, 949, 0, 3932160, 0x9738365d +0, 1439, 1439, 0, 3932160, 0x82051cc1 +0, 3049, 3049, 0, 3932160, 0xd9ff1cc1 +0, 3050, 3050, 0, 3932160, 0xb006d146 +0, 3149, 3149, 0, 3932160, 0x79381d19 +0, 3150, 3150, 0, 3932160, 0xefd735fc +0, 3449, 3449, 0, 3932160, 0x4c4983b4 +0, 3450, 3450, 0, 3932160, 0x44dc88b7 +0, 3549, 3549, 0, 3932160, 0xd6c86d49 +0, 3550, 3550, 0, 3932160, 0xe288e81f +0, 3749, 3749, 0, 3932160, 0x0b57c172 +0, 3849, 3849, 0, 3932160, 0x0b683895 +0, 3850, 3850, 0, 3932160, 0xdb1e21bb +0, 3949, 3949, 0, 3932160, 0x25440443 +0, 4049, 4049, 0, 3932160, 0xe07e071d -- 2.1.0 _______________________________________________ libav-devel mailing list [email protected] https://lists.libav.org/mailman/listinfo/libav-devel
