From: Maxim Poliakovski <[email protected]> JPEG part decoding and minor improvements for ePIC decoder by Kostya Shishkov.
Signed-off-by: Diego Biurrun <[email protected]> --- Changelog | 1 + doc/general.texi | 2 + libavcodec/Makefile | 2 +- libavcodec/elsdec.c | 414 +++++++++++++++++++++++++++++ libavcodec/elsdec.h | 65 +++++ libavcodec/g2meet.c | 705 +++++++++++++++++++++++++++++++++++++++++++++++++- libavcodec/version.h | 4 +- 7 files changed, 1177 insertions(+), 16 deletions(-) create mode 100644 libavcodec/elsdec.c create mode 100644 libavcodec/elsdec.h diff --git a/Changelog b/Changelog index 279c0d8..3373509 100644 --- a/Changelog +++ b/Changelog @@ -4,6 +4,7 @@ releases are sorted from youngest to oldest. version <next>: - compand audio filter - shuffleplanes filter +- Go2Meeting decoder version 10: diff --git a/doc/general.texi b/doc/general.texi index 6bc7fda..4603b33 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -536,6 +536,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 bd93a6f..ef8268b 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -178,7 +178,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 mjpeg.o +OBJS-$(CONFIG_G2M_DECODER) += g2meet.o elsdec.o mjpeg.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..a2da0db --- /dev/null +++ b/libavcodec/elsdec.c @@ -0,0 +1,414 @@ +/* + * 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 + */ + +#include <math.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 { + short AMps; + short ALps; + unsigned char next0; + unsigned char 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[145]; +static const int *pAllowable = &els_exp_tab[108]; + +av_cold void ff_els_generate_exp_table(void) +{ + int i; + float jot_size; + + 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 + 72] = floor(pow(2.0f, (i + 36) * jot_size)); + els_exp_tab[i + 36] = els_exp_tab[i + 72] >> 8; + els_exp_tab[i + 108] = els_exp_tab[i + 72] << 8; + } + + els_exp_tab[144] = ELS_MAX; +} + +void ff_els_decoder_init(ElsDecCtx *ctx, const uint8_t *in, unsigned 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 = ELS_NOERR; + + ctx->j = ELS_JOTS_PER_BYTE; + + ctx->t = ELS_MAX; + ctx->diff = FFMIN(ELS_MAX - ctx->x, 0x248C00); +} + +int ff_els_decode_bit(ElsDecCtx *ctx, unsigned char *rung) +{ + int z, bit; + + if (ctx->err != ELS_NOERR) + 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. */ + if (!ctx->data_size) { + ctx->err = ELS_NODATA; + return -1; + } + ctx->x = ctx->x << 8 | *ctx->in_buf++; + ctx->data_size--; + ctx->j += ELS_JOTS_PER_BYTE; + ctx->t <<= 8; + } + + ctx->diff = FFMIN(ctx->t - ctx->x, ctx->t - pAllowable[ctx->j - 1]); + + 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; + if (!ctx->data_size) { + ctx->err = ELS_NODATA; + return -1; + } + ctx->x = ctx->x << 8 | *ctx->in_buf++; + ctx->data_size--; + ctx->j += ELS_JOTS_PER_BYTE; + ctx->t <<= 8; + if (ctx->j <= 0) { + /* LPS: import second byte from bytestream. */ + z <<= 8; + if (!ctx->data_size) { + ctx->err = ELS_NODATA; + return -1; + } + ctx->x = ctx->x << 8 | *ctx->in_buf++; + ctx->data_size--; + ctx->j += ELS_JOTS_PER_BYTE; + ctx->t <<= 8; + while (pAllowable[ctx->j - 1] >= z) + ctx->j--; + } + } + + ctx->diff = FFMIN(z - ctx->x, z - pAllowable[ctx->j - 1]); + + bit = !(*rung & 1); + + *rung = Ladder[*rung].next1; + } + + return bit; +} + +unsigned int ff_els_decode_unsigned(ElsDecCtx *ctx, ElsUnsignedRung *ur) +{ + int i, n, r, bit, pos; + ElsRungNode *rung_node; + + if (ctx->err != ELS_NOERR) + return 0; + + /* decode unary prefix */ + for (n = 0; n < ELS_EXPGOLOMB_LEN + 1 && !ff_els_decode_bit(ctx, &ur->prefix_rung[n]); n++) + ; + + /* handle the error/overflow case */ + if (ctx->err || n >= ELS_EXPGOLOMB_LEN) { + ctx->err = ELS_OVERFLOW; + return 0; + } + + /* handle the zero case */ + if (!n) + return 0; + + /* initialize probability tree */ + if (!ur->rem_rung_list) { + ur->rem_rung_list = av_mallocz(64 * sizeof(ElsRungNode)); + if (!ur->rem_rung_list) { + ctx->err = ELS_NOMEM; // Probability tree initialization failed + return 0; + } + ur->rung_list_size = 64 * sizeof(ElsRungNode); + 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 + pos = rung_node - ur->rem_rung_list; + ur->rem_rung_list = av_realloc(ur->rem_rung_list, + ur->rung_list_size + + 64 * sizeof(ElsRungNode)); + if (!ur->rem_rung_list) { + ctx->err = ELS_NOMEM; // Probability tree resize failed + return 0; + } + memset(((char *) ur->rem_rung_list) + ur->rung_list_size, + 0, 64 * sizeof(ElsRungNode)); + ur->rung_list_size += 64 * sizeof(ElsRungNode); + // 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 != ELS_NOERR) + return -1; + + 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..d3ce1be --- /dev/null +++ b/libavcodec/elsdec.h @@ -0,0 +1,65 @@ +/* + * 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> + +#define ELS_EXPGOLOMB_LEN 10 + +enum ElsErrors { + ELS_NOERR, ///< no error + ELS_NODATA, ///< attempt to read past end of data + ELS_OVERFLOW, ///< overflow in the unary prefix + ELS_NOMEM ///< could not allocate memory +}; + +typedef struct ElsDecCtx { + const uint8_t *in_buf; + unsigned int x, 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; + int 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, unsigned data_size); +int ff_els_decode_bit(ElsDecCtx *ctx, unsigned char *rung); +unsigned int ff_els_decode_unsigned(ElsDecCtx *ctx, ElsUnsignedRung *ur); + +#endif /* AVCODEC_ELSDEC_H */ diff --git a/libavcodec/g2meet.c b/libavcodec/g2meet.c index 28bed42..c11db66 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. * @@ -33,6 +34,7 @@ #include "get_bits.h" #include "internal.h" #include "mjpeg.h" +#include "elsdec.h" enum ChunkType { DISPLAY_INFO = 0xC8, @@ -70,6 +72,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[1121]; + ePICPixHash hash; +} ePICContext; + typedef struct JPGContext { DSPContext dsp; ScanTable scantable; @@ -82,7 +120,9 @@ typedef struct JPGContext { } JPGContext; typedef struct G2MContext { - JPGContext jc; + ePICContext ec; + JPGContext jc; + int version; int compression; @@ -95,8 +135,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; @@ -309,6 +350,635 @@ 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(ePICPixHash *hash, uint32_t key) +{ + int i, idx; + ePICPixHashElem *bucket; + + idx = djb2_hash(key); + bucket = hash->bucket[idx]; + for (i = 0; i < hash->bucket_fill[idx]; i++) + if (bucket[i].pix_id == key) + return &bucket[i]; + return 0; +} + +static ePICPixHashElem *epic_hash_add(ePICPixHash *hash, uint32_t key) +{ + int idx; + ePICPixHashElem *bucket, *ret; + int new_size; + + idx = djb2_hash(key); + if (hash->bucket_fill[idx] < hash->bucket_size[idx]) { + ret = &hash->bucket[idx][hash->bucket_fill[idx]++]; + memset(ret, 0, sizeof(*ret)); + ret->pix_id = key; + return ret; + } + if (hash->bucket_size[idx] > INT_MAX / sizeof(**hash->bucket)) + return 0; + new_size = hash->bucket_size[idx] + 16; + bucket = av_realloc(hash->bucket[idx], new_size * sizeof(**hash->bucket)); + if (!bucket) + return 0; + 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) +{ + ePICPixHashElem *hash_elem; + ePICPixListElem *new_elem; + + 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(ePICPixHash *hash, uint32_t pix) +{ + ePICPixHashElem *hash_elem = epic_hash_find(hash, pix); + + if (hash_elem != NULL && hash_elem->list != NULL) + return 1; + else + return 0; +} + +static void epic_free_pixel_cache(ePICPixHash *hash) +{ + ePICPixListElem *list_elem, *tmp; + int i, j; + + for (i = 0; i < EPIC_HASH_SIZE; i++) { + for (j = 0; j < hash->bucket_fill[i]; j++) { + list_elem = hash->bucket[i][j].list; + while (list_elem) { + 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(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) +{ + int delta; + + 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, + uint32_t *curr_row, uint32_t *above_row) +{ + uint32_t N, W, NW, pred, 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_handle_edges(ePICContext *dc, int x, int y, uint32_t *curr_row, + 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 (!ff_els_decode_bit(&dc->els_ctx, &dc->W_flag_rung)) { + *pPix = pix; + return 1; + } else + dc->stack[dc->stack_pos++] = pix; + } + + if (y) { /* then try to predict from N */ + pix = above_row[x]; + if (!dc->stack_pos || dc->stack[0] != pix) { + if (!ff_els_decode_bit(&dc->els_ctx, &dc->N_flag_rung)) { + *pPix = pix; + return 1; + } else + dc->stack[dc->stack_pos++] = pix; + } + } + + return 0; +} + +static int epic_decode_run_length(ePICContext *dc, int x, int y, + int tile_width, uint32_t *curr_row, + uint32_t *above_row, uint32_t *above2_row, + uint32_t *pPix, int *pRun) +{ + int idx, run, rle, got_pixel, WWneW, old_WWneW, NWneW; + int start_pos, pos, flag; + uint32_t pix, W, WW, N, NN, NW, NE, NWW, NNW, NNE; + + *pRun = 0; + old_WWneW = 0; + got_pixel = 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++] = W; + else { + *pPix = W; + got_pixel = 1; + } + + do { + 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: + av_log(NULL, AV_LOG_ERROR, "Haltepunkt 301, x_pos=%d, y_pos=%d\n", x, y); + break; + 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; + } + } + /* FALLTHROUGH */ + default: + NWneW = 1; + old_WWneW = WWneW; + if (!is_pixel_on_stack(dc, N)) + dc->stack[dc->stack_pos++] = N; + } + } + + (*pRun)++; + if (x + *pRun >= tile_width - 1) + break; + + UPDATE_NEIGHBOURS(x + *pRun); + + if (!NWneW && NW == N && N == NE) { + start_pos = x + *pRun; + + /* scan for a run of pix in the line above */ + pix = above_row[start_pos + 1]; + for (pos = start_pos + 2; + pos < tile_width && above_row[pos] == pix; pos++) ; + 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 { + /* 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_from_NW_NE(ePICContext *dc, int x, int y, int run, + int tile_width, + uint32_t *curr_row, uint32_t *above_row, + uint32_t *pPix) +{ + int pos; + uint32_t NW, NE; + + /* try to reuse the NW pixel first */ + if (x && y) { + NW = above_row[x - 1]; + if (NW != curr_row[x - 1] && NW != above_row[x] && !is_pixel_on_stack(dc, NW)) { + if (ff_els_decode_bit(&dc->els_ctx, &dc->nw_pred_rung[NW & 0xFF])) { + *pPix = NW; + return 1; + } else + dc->stack[dc->stack_pos++] = NW; + } + } + + /* try to reuse the NE[x+run,y] pixel */ + pos = x + run - 1; + if (pos < tile_width - 1 && y) { + NE = above_row[pos + 1]; + if (NE != above_row[pos] && !is_pixel_on_stack(dc, NE)) { + if (ff_els_decode_bit(&dc->els_ctx, &dc->ne_pred_rung[NE & 0xFF])) { + *pPix = NE; + return 1; + } else + dc->stack[dc->stack_pos++] = NE; + } + } + + return 0; +} + +static int epic_decode_from_cache(ePICContext *dc, uint32_t W, uint32_t *pPix) +{ + ePICPixHashElem *hash_elem; + ePICPixListElem *list, *prev; + + hash_elem = epic_hash_find(&dc->hash, W); + if (!hash_elem || !hash_elem->list) + return 0; + + list = hash_elem->list; + prev = 0; + 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; + } + } + 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, run, got_pixel, ret; + uint32_t pix, *curr_row, *above_row, *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 != ELS_NOERR) { + av_log(NULL, AV_LOG_ERROR, "Haltepunkt 602, x_pos=%d, y_pos=%d\n", x, y); + 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 { + 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)) { + if (!x || !epic_decode_from_cache(dc, curr_row[x - 1], &pix)) { + pix = epic_decode_pixel_pred(dc, x, y, curr_row, above_row); + if (x) { + ret = epic_add_pixel_to_cache(&dc->hash, curr_row[x - 1], 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, int src_size, + AVCodecContext *avctx) +{ + uint8_t prefix, mask, tr_r, tr_g, tr_b, tr; + int extrabytes, ret, tile_width, tile_height, i, j, k; + unsigned int els_dsize; + uint8_t *buf, *dst, *out, *jpg; + uint32_t *in; + + 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 %d, got %d\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); + + if (els_dsize) { + /* ELS decoder initializations */ + memset(&c->ec, 0, sizeof(ePICContext)); + 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 != ELS_NOERR) { + 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++) { + 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) { + int bstride = FFALIGN(tile_width, 8) >> 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); + + 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 * tile_height); + jpg_decode_data(&c->jc, tile_width, tile_height, 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, @@ -462,14 +1132,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 @@ -478,6 +1151,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; @@ -685,11 +1364,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; @@ -788,9 +1463,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), @@ -867,6 +1543,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); @@ -884,6 +1562,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 cdd5a61..a813fc9 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -29,8 +29,8 @@ #include "libavutil/version.h" #define LIBAVCODEC_VERSION_MAJOR 55 -#define LIBAVCODEC_VERSION_MINOR 34 -#define LIBAVCODEC_VERSION_MICRO 1 +#define LIBAVCODEC_VERSION_MINOR 35 +#define LIBAVCODEC_VERSION_MICRO 0 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ LIBAVCODEC_VERSION_MINOR, \ -- 1.7.9.5 _______________________________________________ libav-devel mailing list [email protected] https://lists.libav.org/mailman/listinfo/libav-devel
