summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKostya Shishkov <kostya.shishkov@gmail.com>2015-04-10 12:14:27 +0200
committerLuca Barbato <lu_zero@gentoo.org>2015-07-01 01:08:15 +0200
commit08c2d8f0aa679c2f060721d1d0d4f33d2ae32368 (patch)
treeb3e507b95f6135f4061fa812e55325608f61ef74
parente2bd03a14a4e3366df0b1ee8e284a97165be1f3c (diff)
Go2Meeting decoder
ELS and ePIC decoder courtesy of Maxim Poliakovski, cleanup and integration by Diego Biurrun. Signed-off-by: Diego Biurrun <diego@biurrun.de> Signed-off-by: Luca Barbato <lu_zero@gentoo.org>
-rw-r--r--Changelog1
-rw-r--r--doc/general.texi2
-rw-r--r--libavcodec/Makefile2
-rw-r--r--libavcodec/elsdec.c422
-rw-r--r--libavcodec/elsdec.h60
-rw-r--r--libavcodec/g2meet.c755
-rw-r--r--libavcodec/version.h4
7 files changed, 1220 insertions, 26 deletions
diff --git a/Changelog b/Changelog
index 46e5f7a292..7d4678314f 100644
--- a/Changelog
+++ b/Changelog
@@ -37,6 +37,7 @@ version <next>:
- Hap decoder and encoder
- DirectDraw Surface image/texture decoder
- rewritten ASF demuxer
+- Go2Meeting decoding support
version 11:
diff --git a/doc/general.texi b/doc/general.texi
index 0beffad370..ef9bc6a577 100644
--- a/doc/general.texi
+++ b/doc/general.texi
@@ -607,6 +607,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 dcdd428792..2b6d65b60f 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -214,7 +214,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 0000000000..5e89045864
--- /dev/null
+++ b/libavcodec/elsdec.c
@@ -0,0 +1,422 @@
+/*
+ * 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)
+#define RUNG_SPACE (64 * sizeof(ElsRungNode))
+
+/* 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 const uint32_t els_exp_tab[ELS_JOTS_PER_BYTE * 4 + 1] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1, 1, 1,
+ 1, 2, 2, 2, 3, 4, 4, 5,
+ 6, 7, 8, 10, 11, 13, 16, 18,
+ 21, 25, 29, 34, 40, 47, 54, 64,
+ 74, 87, 101, 118, 138, 161, 188, 219,
+ 256, 298, 348, 406, 474, 552, 645, 752,
+ 877, 1024, 1194, 1393, 1625, 1896, 2211, 2580,
+ 3010, 3511, 4096, 4778, 5573, 6501, 7584, 8847,
+ 10321, 12040, 14045, 16384, 19112, 22295, 26007, 30339,
+ 35391, 41285, 48160, 56180, 65536, 76288, 89088, 103936,
+ 121344, 141312, 165120, 192512, 224512, 262144, 305664, 356608,
+ 416000, 485376, 566016, 660480, 770560, 898816, 1048576, 1223168,
+ 1426688, 1664256, 1941504, 2264832, 2642176, 3082240, 3595520, 4194304,
+ 4892672, 5707520, 6657792, 7766784, 9060096, 10568960, 12328960, 14382080,
+ 16777216,
+};
+
+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]);
+}
+
+void ff_els_decoder_uninit(ElsUnsignedRung *rung)
+{
+ av_free(rung->rem_rung_list);
+}
+
+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;
+ const uint32_t *pAllowable = &els_exp_tab[ELS_JOTS_PER_BYTE * 3];
+
+ 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;
+}
+
+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_realloc(NULL, RUNG_SPACE);
+ if (!ur->rem_rung_list) {
+ ctx->err = AVERROR(ENOMEM);
+ return 0;
+ }
+ memset(ur->rem_rung_list, 0, RUNG_SPACE);
+ 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) {
+ av_free(ur->rem_rung_list);
+ ctx->err = AVERROR(ENOMEM);
+ 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 0000000000..515b49aa71
--- /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_decoder_init(ElsDecCtx *ctx, const uint8_t *in, size_t data_size);
+void ff_els_decoder_uninit(ElsUnsignedRung *rung);
+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 b3d2bc4aba..d0b36f0ea8 100644
--- a/libavcodec/g2meet.c
+++ b/libavcodec/g2meet.c
@@ -1,6 +1,7 @@
/*
- * Go2Webinar decoder
+ * Go2Webinar / Go2Meeting decoder
* Copyright (c) 2012 Konstantin Shishkov
+ * Copyright (c) 2013 Maxim Poliakovski
*
* This file is part of Libav.
*
@@ -21,7 +22,7 @@
/**
* @file
- * Go2Webinar decoder
+ * Go2Webinar / Go2Meeting decoder
*/
#include <inttypes.h>
@@ -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 {
+ 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;
@@ -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 = 0x80;
+ 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++;
+ src_size--;
+ for (extrabytes = 0; (prefix & mask) && (extrabytes < 7); extrabytes++)
+ mask >>= 1;
+ 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);
+ ff_els_decoder_uninit(&c->ec.unsigned_rung);
+
+ 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;
+ uint32_t 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);
@@ -343,6 +1042,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));
}
}
@@ -466,22 +1166,31 @@ 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
- + FF_INPUT_BUFFER_PADDING_SIZE);
- c->kempf_flags = av_mallocz( c->tile_width * aligned_height);
+ c->kempf_buf = av_mallocz((c->tile_width + 1) * aligned_height +
+ FF_INPUT_BUFFER_PADDING_SIZE);
+ c->kempf_flags = av_mallocz(c->tile_width * aligned_height);
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;
@@ -690,10 +1399,7 @@ static int g2m_decode_frame(AVCodecContext *avctx, void *data,
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;
@@ -795,9 +1501,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),
@@ -895,6 +1602,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);
@@ -915,4 +1623,5 @@ AVCodec ff_g2m_decoder = {
.close = g2m_decode_end,
.decode = g2m_decode_frame,
.capabilities = CODEC_CAP_DR1,
+ .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
};
diff --git a/libavcodec/version.h b/libavcodec/version.h
index b0643cc922..850f465797 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -29,8 +29,8 @@
#include "libavutil/version.h"
#define LIBAVCODEC_VERSION_MAJOR 56
-#define LIBAVCODEC_VERSION_MINOR 29
-#define LIBAVCODEC_VERSION_MICRO 1
+#define LIBAVCODEC_VERSION_MINOR 31
+#define LIBAVCODEC_VERSION_MICRO 0
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
LIBAVCODEC_VERSION_MINOR, \