mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-11-21 10:55:51 +02:00
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>
This commit is contained in:
parent
e2bd03a14a
commit
08c2d8f0aa
@ -37,6 +37,7 @@ version <next>:
|
||||
- Hap decoder and encoder
|
||||
- DirectDraw Surface image/texture decoder
|
||||
- rewritten ASF demuxer
|
||||
- Go2Meeting decoding support
|
||||
|
||||
|
||||
version 11:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
422
libavcodec/elsdec.c
Normal file
422
libavcodec/elsdec.c
Normal file
@ -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 */
|
||||
}
|
60
libavcodec/elsdec.h
Normal file
60
libavcodec/elsdec.h
Normal file
@ -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 */
|
@ -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,
|
||||
};
|
||||
|
@ -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, \
|
||||
|
Loading…
Reference in New Issue
Block a user