From: caleb <etemesicaleb@gmail.com> To: ffmpeg-devel@ffmpeg.org Cc: caleb <etemesicaleb@gmail.com>, pal@sandflow.com Subject: [FFmpeg-devel] [PATCH 1/1] avcodec/jpeg2000: Add support for High-Throughput JPEG 2000 (HTJ2K) decoding. Date: Wed, 7 Sep 2022 22:24:17 +0300 Message-ID: <20220907192417.140381-1-etemesicaleb@gmail.com> (raw) This patch satisfies the GSoC 2022 project with the goal of adding a native htj2k decoder to ffmpeg. HTJ2K is specified in Rec. ITU-T 814 | ISO/IEC 15444-15 (https://www.itu.int/rec/T-REC-T.814-201906-I/en) --- libavcodec/j2kenc.c | 28 +- libavcodec/jpeg2000.h | 115 +++- libavcodec/jpeg2000dec.c | 294 +++++---- libavcodec/jpeg2000htdec.c | 1228 ++++++++++++++++++++++++++++++++++++ libavcodec/jpeg2000htdec.h | 210 ++++++ 5 files changed, 1731 insertions(+), 144 deletions(-) create mode 100644 libavcodec/jpeg2000htdec.c create mode 100644 libavcodec/jpeg2000htdec.h diff --git a/libavcodec/j2kenc.c b/libavcodec/j2kenc.c index 0b761d0b00..7218e0f68f 100644 --- a/libavcodec/j2kenc.c +++ b/libavcodec/j2kenc.c @@ -106,7 +106,7 @@ static const int dwt_norms[2][4][10] = { // [dwt_type][band][rlevel] (multiplied typedef struct { Jpeg2000Component *comp; double *layer_rates; -} Jpeg2000Tile; +} Jpeg2000EncTile; typedef struct { AVClass *class; @@ -131,7 +131,7 @@ typedef struct { Jpeg2000CodingStyle codsty; Jpeg2000QuantStyle qntsty; - Jpeg2000Tile *tile; + Jpeg2000EncTile *tile; int layer_rates[100]; uint8_t compression_rate_enc; ///< Is compression done using compression ratio? @@ -171,7 +171,7 @@ static void dump(Jpeg2000EncoderContext *s, FILE *fd) s->width, s->height, s->tile_width, s->tile_height, s->numXtiles, s->numYtiles, s->ncomponents); for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){ - Jpeg2000Tile *tile = s->tile + tileno; + Jpeg2000EncTile *tile = s->tile + tileno; nspaces(fd, 2); fprintf(fd, "tile %d:\n", tileno); for(compno = 0; compno < s->ncomponents; compno++){ @@ -429,7 +429,7 @@ static void compute_rates(Jpeg2000EncoderContext* s) int layno, compno; for (i = 0; i < s->numYtiles; i++) { for (j = 0; j < s->numXtiles; j++) { - Jpeg2000Tile *tile = &s->tile[s->numXtiles * i + j]; + Jpeg2000EncTile *tile = &s->tile[s->numXtiles * i + j]; for (compno = 0; compno < s->ncomponents; compno++) { int tilew = tile->comp[compno].coord[0][1] - tile->comp[compno].coord[0][0]; int tileh = tile->comp[compno].coord[1][1] - tile->comp[compno].coord[1][0]; @@ -462,12 +462,12 @@ static int init_tiles(Jpeg2000EncoderContext *s) s->numXtiles = ff_jpeg2000_ceildiv(s->width, s->tile_width); s->numYtiles = ff_jpeg2000_ceildiv(s->height, s->tile_height); - s->tile = av_calloc(s->numXtiles, s->numYtiles * sizeof(Jpeg2000Tile)); + s->tile = av_calloc(s->numXtiles, s->numYtiles * sizeof(Jpeg2000EncTile)); if (!s->tile) return AVERROR(ENOMEM); for (tileno = 0, tiley = 0; tiley < s->numYtiles; tiley++) for (tilex = 0; tilex < s->numXtiles; tilex++, tileno++){ - Jpeg2000Tile *tile = s->tile + tileno; + Jpeg2000EncTile *tile = s->tile + tileno; tile->comp = av_calloc(s->ncomponents, sizeof(*tile->comp)); if (!tile->comp) @@ -511,7 +511,7 @@ static int init_tiles(Jpeg2000EncoderContext *s) int tileno, compno, i, y, x; \ PIXEL *line; \ for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){ \ - Jpeg2000Tile *tile = s->tile + tileno; \ + Jpeg2000EncTile *tile = s->tile + tileno; \ if (s->planar){ \ for (compno = 0; compno < s->ncomponents; compno++){ \ Jpeg2000Component *comp = tile->comp + compno; \ @@ -703,7 +703,7 @@ static void encode_clnpass(Jpeg2000T1Context *t1, int width, int height, int ban } } -static void encode_cblk(Jpeg2000EncoderContext *s, Jpeg2000T1Context *t1, Jpeg2000Cblk *cblk, Jpeg2000Tile *tile, +static void encode_cblk(Jpeg2000EncoderContext *s, Jpeg2000T1Context *t1, Jpeg2000Cblk *cblk, Jpeg2000EncTile *tile, int width, int height, int bandpos, int lev) { int pass_t = 2, passno, x, y, max=0, nmsedec, bpno; @@ -937,7 +937,7 @@ static int encode_packet(Jpeg2000EncoderContext *s, Jpeg2000ResLevel *rlevel, in return 0; } -static int encode_packets(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile, int tileno, int nlayers) +static int encode_packets(Jpeg2000EncoderContext *s, Jpeg2000EncTile *tile, int tileno, int nlayers) { int compno, reslevelno, layno, ret; Jpeg2000CodingStyle *codsty = &s->codsty; @@ -1183,7 +1183,7 @@ static int encode_packets(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile, int til return 0; } -static void makelayer(Jpeg2000EncoderContext *s, int layno, double thresh, Jpeg2000Tile* tile, int final) +static void makelayer(Jpeg2000EncoderContext *s, int layno, double thresh, Jpeg2000EncTile* tile, int final) { int compno, resno, bandno, precno, cblkno; int passno; @@ -1266,7 +1266,7 @@ static void makelayer(Jpeg2000EncoderContext *s, int layno, double thresh, Jpeg2 } } -static void makelayers(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile) +static void makelayers(Jpeg2000EncoderContext *s, Jpeg2000EncTile *tile) { int precno, compno, reslevelno, bandno, cblkno, lev, passno, layno; int i; @@ -1367,7 +1367,7 @@ static int getcut(Jpeg2000Cblk *cblk, int64_t lambda, int dwt_norm) return res; } -static void truncpasses(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile) +static void truncpasses(Jpeg2000EncoderContext *s, Jpeg2000EncTile *tile) { int precno, compno, reslevelno, bandno, cblkno, lev; Jpeg2000CodingStyle *codsty = &s->codsty; @@ -1401,7 +1401,7 @@ static void truncpasses(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile) } } -static int encode_tile(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile, int tileno) +static int encode_tile(Jpeg2000EncoderContext *s, Jpeg2000EncTile *tile, int tileno) { int compno, reslevelno, bandno, ret; Jpeg2000T1Context t1; @@ -1516,7 +1516,7 @@ static void reinit(Jpeg2000EncoderContext *s) { int tileno, compno; for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){ - Jpeg2000Tile *tile = s->tile + tileno; + Jpeg2000EncTile *tile = s->tile + tileno; for (compno = 0; compno < s->ncomponents; compno++) ff_jpeg2000_reinit(tile->comp + compno, &s->codsty); } diff --git a/libavcodec/jpeg2000.h b/libavcodec/jpeg2000.h index 10b9c4b9b3..88c9c2869f 100644 --- a/libavcodec/jpeg2000.h +++ b/libavcodec/jpeg2000.h @@ -34,6 +34,8 @@ #include "avcodec.h" #include "mqc.h" #include "jpeg2000dwt.h" +#include "jpeg2000dsp.h" +#include "bytestream.h" enum Jpeg2000Markers { JPEG2000_SOC = 0xff4f, // start of codestream @@ -112,7 +114,8 @@ enum Jpeg2000Quantsty { // quantization style #define JPEG2000_CSTY_PREC 0x01 // Precincts defined in coding style #define JPEG2000_CSTY_SOP 0x02 // SOP marker present #define JPEG2000_CSTY_EPH 0x04 // EPH marker present - +#define JPEG2000_CTSY_HTJ2K_F 0x40 // Only HT code-blocks (Rec. ITU-T T.814 | ISO/IEC 15444-15) are present +#define JPEG2000_CTSY_HTJ2K_M 0xC0 // HT code blocks (Rec. ITU-T T.814 | ISO/IEC 15444-15) can be present // Progression orders #define JPEG2000_PGOD_LRCP 0x00 // Layer-resolution level-component-position progression #define JPEG2000_PGOD_RLCP 0x01 // Resolution level-layer-component-position progression @@ -120,6 +123,19 @@ enum Jpeg2000Quantsty { // quantization style #define JPEG2000_PGOD_PCRL 0x03 // Position-component-resolution level-layer progression #define JPEG2000_PGOD_CPRL 0x04 // Component-position-resolution level-layer progression +#define JP2_SIG_TYPE 0x6A502020 +#define JP2_SIG_VALUE 0x0D0A870A +#define JP2_CODESTREAM 0x6A703263 +#define JP2_HEADER 0x6A703268 + +#define HAD_COC 0x01 +#define HAD_QCC 0x02 + +#define MAX_POCS 32 + +// misc constants +#define JPEG2000_RSIZ_BIT (1<<14) + typedef struct Jpeg2000T1Context { int data[6144]; uint16_t flags[6156]; @@ -181,6 +197,7 @@ typedef struct Jpeg2000Cblk { uint16_t *lengthinc; uint8_t nb_lengthinc; uint8_t lblock; + uint8_t zbp; // Zero bit planes. uint8_t *data; size_t data_allocated; int nb_terminations; @@ -188,7 +205,8 @@ typedef struct Jpeg2000Cblk { int *data_start; Jpeg2000Pass *passes; Jpeg2000Layer *layers; - int coord[2][2]; // border coordinates {{x0, x1}, {y0, y1}} + int coord[2][2]; // border coordinates {{x0, x1}, {y0, y1}} + int pass_lengths[2]; // Length of each pass } Jpeg2000Cblk; // code block typedef struct Jpeg2000Prec { @@ -227,6 +245,99 @@ typedef struct Jpeg2000Component { uint8_t roi_shift; // ROI scaling value for the component } Jpeg2000Component; +typedef struct Jpeg2000POCEntry { + uint16_t LYEpoc; + uint16_t CSpoc; + uint16_t CEpoc; + uint8_t RSpoc; + uint8_t REpoc; + uint8_t Ppoc; +} Jpeg2000POCEntry; + +typedef struct Jpeg2000POC { + Jpeg2000POCEntry poc[MAX_POCS]; + int nb_poc; + int is_default; +} Jpeg2000POC; + +typedef struct Jpeg2000TilePart { + uint8_t tile_index; // Tile index who refers the tile-part + const uint8_t *tp_end; + GetByteContext header_tpg; // bit stream of header if PPM header is used + GetByteContext tpg; // bit stream in tile-part +} Jpeg2000TilePart; + +/* RMK: For JPEG2000 DCINEMA 3 tile-parts in a tile + * one per component, so tile_part elements have a size of 3 */ +typedef struct Jpeg2000Tile { + Jpeg2000Component *comp; + uint8_t properties[4]; + Jpeg2000CodingStyle codsty[4]; + Jpeg2000QuantStyle qntsty[4]; + Jpeg2000POC poc; + Jpeg2000TilePart tile_part[32]; + uint8_t has_ppt; // whether this tile has a ppt marker + uint8_t *packed_headers; // contains packed headers. Used only along with PPT marker + int packed_headers_size; // size in bytes of the packed headers + GetByteContext packed_headers_stream; // byte context corresponding to packed headers + uint16_t tp_idx; // Tile-part index + int coord[2][2]; // border coordinates {{x0, x1}, {y0, y1}} +} Jpeg2000DecTile; + +typedef struct Jpeg2000DecoderContext { + AVClass *class; + AVCodecContext *avctx; + GetByteContext g; + + int width, height; + int image_offset_x, image_offset_y; + int tile_offset_x, tile_offset_y; + uint8_t cbps[4]; // bits per sample in particular components + uint8_t sgnd[4]; // if a component is signed + uint8_t properties[4]; + + uint8_t has_ppm; + uint8_t *packed_headers; // contains packed headers. Used only along with PPM marker + int packed_headers_size; + GetByteContext packed_headers_stream; + uint8_t in_tile_headers; + + int cdx[4], cdy[4]; + int precision; + int ncomponents; + int colour_space; + uint32_t palette[256]; + int8_t pal8; + int cdef[4]; + int tile_width, tile_height; + unsigned numXtiles, numYtiles; + int maxtilelen; + AVRational sar; + + Jpeg2000CodingStyle codsty[4]; + Jpeg2000QuantStyle qntsty[4]; + Jpeg2000POC poc; + uint8_t roi_shift[4]; + + int bit_index; + + int curtileno; + + Jpeg2000DecTile *tile; + Jpeg2000DSPContext dsp; + + /*options parameters*/ + int reduction_factor; + + /*Extended capabilities */ + uint8_t is_htj2k; // set to 1 to indicate image uses HTJ2K bitstream, 0 otherwise + + uint32_t pcap; + uint16_t ccap[32]; + + uint16_t *pcpf; //Pcpf_i , found in CPF marker , see section A.6 of HTJ2K spec + +} Jpeg2000DecoderContext; /* misc tools */ static inline int ff_jpeg2000_ceildivpow2(int a, int b) { diff --git a/libavcodec/jpeg2000dec.c b/libavcodec/jpeg2000dec.c index 92966b11f5..cf492c38e9 100644 --- a/libavcodec/jpeg2000dec.c +++ b/libavcodec/jpeg2000dec.c @@ -42,101 +42,8 @@ #include "jpeg2000.h" #include "jpeg2000dsp.h" #include "profiles.h" +#include "jpeg2000htdec.h" -#define JP2_SIG_TYPE 0x6A502020 -#define JP2_SIG_VALUE 0x0D0A870A -#define JP2_CODESTREAM 0x6A703263 -#define JP2_HEADER 0x6A703268 - -#define HAD_COC 0x01 -#define HAD_QCC 0x02 - -#define MAX_POCS 32 - -typedef struct Jpeg2000POCEntry { - uint16_t LYEpoc; - uint16_t CSpoc; - uint16_t CEpoc; - uint8_t RSpoc; - uint8_t REpoc; - uint8_t Ppoc; -} Jpeg2000POCEntry; - -typedef struct Jpeg2000POC { - Jpeg2000POCEntry poc[MAX_POCS]; - int nb_poc; - int is_default; -} Jpeg2000POC; - -typedef struct Jpeg2000TilePart { - uint8_t tile_index; // Tile index who refers the tile-part - const uint8_t *tp_end; - GetByteContext header_tpg; // bit stream of header if PPM header is used - GetByteContext tpg; // bit stream in tile-part -} Jpeg2000TilePart; - -/* RMK: For JPEG2000 DCINEMA 3 tile-parts in a tile - * one per component, so tile_part elements have a size of 3 */ -typedef struct Jpeg2000Tile { - Jpeg2000Component *comp; - uint8_t properties[4]; - Jpeg2000CodingStyle codsty[4]; - Jpeg2000QuantStyle qntsty[4]; - Jpeg2000POC poc; - Jpeg2000TilePart tile_part[32]; - uint8_t has_ppt; // whether this tile has a ppt marker - uint8_t *packed_headers; // contains packed headers. Used only along with PPT marker - int packed_headers_size; // size in bytes of the packed headers - GetByteContext packed_headers_stream; // byte context corresponding to packed headers - uint16_t tp_idx; // Tile-part index - int coord[2][2]; // border coordinates {{x0, x1}, {y0, y1}} -} Jpeg2000Tile; - -typedef struct Jpeg2000DecoderContext { - AVClass *class; - AVCodecContext *avctx; - GetByteContext g; - - int width, height; - int image_offset_x, image_offset_y; - int tile_offset_x, tile_offset_y; - uint8_t cbps[4]; // bits per sample in particular components - uint8_t sgnd[4]; // if a component is signed - uint8_t properties[4]; - - uint8_t has_ppm; - uint8_t *packed_headers; // contains packed headers. Used only along with PPM marker - int packed_headers_size; - GetByteContext packed_headers_stream; - uint8_t in_tile_headers; - - int cdx[4], cdy[4]; - int precision; - int ncomponents; - int colour_space; - uint32_t palette[256]; - int8_t pal8; - int cdef[4]; - int tile_width, tile_height; - unsigned numXtiles, numYtiles; - int maxtilelen; - AVRational sar; - - Jpeg2000CodingStyle codsty[4]; - Jpeg2000QuantStyle qntsty[4]; - Jpeg2000POC poc; - uint8_t roi_shift[4]; - - int bit_index; - - int curtileno; - - Jpeg2000Tile *tile; - Jpeg2000DSPContext dsp; - - /*options parameters*/ - int reduction_factor; -} Jpeg2000DecoderContext; /* get_bits functions for JPEG2000 packet bitstream * It is a get_bit function with a bit-stuffing routine. If the value of the @@ -369,7 +276,7 @@ static int get_siz(Jpeg2000DecoderContext *s) } for (i = 0; i < s->numXtiles * s->numYtiles; i++) { - Jpeg2000Tile *tile = s->tile + i; + Jpeg2000DecTile *tile = s->tile + i; tile->comp = av_mallocz(s->ncomponents * sizeof(*tile->comp)); if (!tile->comp) @@ -520,7 +427,11 @@ static int get_cox(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c) } c->cblk_style = bytestream2_get_byteu(&s->g); - if (c->cblk_style != 0) { // cblk style + if (c->cblk_style & JPEG2000_CTSY_HTJ2K_M || c->cblk_style & JPEG2000_CTSY_HTJ2K_F){ + av_log(s->avctx,AV_LOG_TRACE,"High Throughput jpeg 2000 codestream.\n"); + s->is_htj2k = 1; + } + if (c->cblk_style != 0 && !(c->cblk_style & JPEG2000_CTSY_HTJ2K_F) /*Covers both partial and full htj2k stream */) { // cblk style av_log(s->avctx, AV_LOG_WARNING, "extra cblk styles %X\n", c->cblk_style); if (c->cblk_style & JPEG2000_CBLK_BYPASS) av_log(s->avctx, AV_LOG_WARNING, "Selective arithmetic coding bypass\n"); @@ -626,7 +537,63 @@ static int get_coc(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c, c->init = 1; return 0; } +/* Parse extended capabilities marker */ +static int get_cap(Jpeg2000DecoderContext *s, int len) +{ + int pcap_ones; // contains number of set bits in pcap that are equal to 1. + int lcap; + + if (len < 8 || len > 70) { + // spec requires cap length to be between 8-70 + av_log(s->avctx, AV_LOG_ERROR, "Invalid CAP length '%d'. Length should be between 8-70\n", len); + return AVERROR_INVALIDDATA; + } + + s->pcap = bytestream2_get_be32u(&(s->g)); + + lcap = (len - 6) / 2; + pcap_ones = av_popcount_c(s->pcap); + + if (lcap != pcap_ones) { + // according to the spec ,length is the same as number of set bits in pcap header. + av_log(s->avctx, AV_LOG_ERROR, + "Length of marker`%d` not equal to set bits in Pcap segment(bits set to 1 in Pcap are %d).\n", lcap, pcap_ones); + return AVERROR_INVALIDDATA; + } + /* According to the spec again Ccapⁱ exists if and only if the ith bit of Pcap is set. + * Since pcap can have 32 bits, we loop until we read all Ccaps' of set bits + * + * Also since the spec addresses Pcap¹ as the most significant bit of 1(31st bit),the + * array also takes that into account, storing at ccap[1] if (Pcap & 1<<31) == 1 + */ + for (int i = 1; i < 32; i++) + if (s->pcap & (1 << (32 - i))) + s->ccap[i] = bytestream2_get_be16u(&(s->g)); + + return 0; +} +static int get_cpf(Jpeg2000DecoderContext *s, int len) +{ + int n; + + if ((len < 4) || (len > 65534)) { + av_log(s->avctx, AV_LOG_ERROR, "CPF marker length %d not in range 4-65534", len); + return AVERROR_INVALIDDATA; + } + n = (len - 2) / 2; + + s->pcpf = av_calloc(n, sizeof(uint16_t)); + + if (!s->pcpf) { + av_log(s->avctx, AV_LOG_FATAL, "Out of memory. Cannot reserve space of size %d for Pcpf", n); + return AVERROR_BUG; + } + for (int i = 0; i < n; i++) + s->pcpf[i] = bytestream2_get_be16u(&(s->g)); + + return 0; +} static int get_rgn(Jpeg2000DecoderContext *s, int n) { uint16_t compno; @@ -804,7 +771,6 @@ static int get_poc(Jpeg2000DecoderContext *s, int size, Jpeg2000POC *p) return 0; } - /* Get start of tile segment. */ static int get_sot(Jpeg2000DecoderContext *s, int n) { @@ -847,7 +813,7 @@ static int get_sot(Jpeg2000DecoderContext *s, int n) tp->tp_end = s->g.buffer + Psot - n - 2; if (!TPsot) { - Jpeg2000Tile *tile = s->tile + s->curtileno; + Jpeg2000DecTile *tile = s->tile + s->curtileno; /* copy defaults */ memcpy(tile->codsty, s->codsty, s->ncomponents * sizeof(Jpeg2000CodingStyle)); @@ -962,7 +928,7 @@ static int get_ppm(Jpeg2000DecoderContext *s, int n) static int get_ppt(Jpeg2000DecoderContext *s, int n) { - Jpeg2000Tile *tile; + Jpeg2000DecTile *tile; void *new; if (n < 3) { @@ -1001,7 +967,7 @@ static int init_tile(Jpeg2000DecoderContext *s, int tileno) int compno; int tilex = tileno % s->numXtiles; int tiley = tileno / s->numXtiles; - Jpeg2000Tile *tile = s->tile + tileno; + Jpeg2000DecTile *tile = s->tile + tileno; if (!tile->comp) return AVERROR(ENOMEM); @@ -1036,9 +1002,9 @@ static int init_tile(Jpeg2000DecoderContext *s, int tileno) comp->roi_shift = s->roi_shift[compno]; if (!codsty->init) return AVERROR_INVALIDDATA; - if (ret = ff_jpeg2000_init_component(comp, codsty, qntsty, + if ((ret = ff_jpeg2000_init_component(comp, codsty, qntsty, s->cbps[compno], s->cdx[compno], - s->cdy[compno], s->avctx)) + s->cdy[compno], s->avctx))) return ret; } return 0; @@ -1071,7 +1037,7 @@ static int getlblockinc(Jpeg2000DecoderContext *s) return res; } -static inline void select_header(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, +static inline void select_header(Jpeg2000DecoderContext *s, Jpeg2000DecTile *tile, int *tp_index) { s->g = tile->tile_part[*tp_index].header_tpg; @@ -1082,7 +1048,7 @@ static inline void select_header(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, } } -static inline void select_stream(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, +static inline void select_stream(Jpeg2000DecoderContext *s, Jpeg2000DecTile *tile, int *tp_index, Jpeg2000CodingStyle *codsty) { s->g = tile->tile_part[*tp_index].tpg; @@ -1099,7 +1065,7 @@ static inline void select_stream(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, } } -static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, int *tp_index, +static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000DecTile *tile, int *tp_index, Jpeg2000CodingStyle *codsty, Jpeg2000ResLevel *rlevel, int precno, int layno, uint8_t *expn, int numgbits) @@ -1148,9 +1114,10 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, return incl; if (!cblk->npasses) { - int v = expn[bandno] + numgbits - 1 - - tag_tree_decode(s, prec->zerobits + cblkno, 100); - if (v < 0 || v > 30) { + int zbp = tag_tree_decode(s, prec->zerobits + cblkno, 100); + int v = expn[bandno] + numgbits - 1 - zbp; + cblk->zbp = zbp; + if (/*v < 0 ||*/ v > 30) { av_log(s->avctx, AV_LOG_ERROR, "nonzerobits %d invalid or unsupported\n", v); return AVERROR_INVALIDDATA; @@ -1194,9 +1161,22 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, break; } } - - if ((ret = get_bits(s, av_log2(newpasses1) + cblk->lblock)) < 0) - return ret; + if (newpasses > 1 && s->is_htj2k) { + // retrieve pass lengths for each pass + // for htj2k images + int extra_bit = newpasses > 2 ? 1 : 0; + if ((ret = get_bits(s, llen + 3)) < 0) + return ret; + cblk->pass_lengths[0] = ret; + if ((ret = get_bits(s, llen + 3 + extra_bit)) < 0) + return ret; + cblk->pass_lengths[1] = ret; + ret = cblk->pass_lengths[0] + cblk->pass_lengths[1]; + } else { + if ((ret = get_bits(s, av_log2(newpasses1) + cblk->lblock)) < 0) + return ret; + cblk->pass_lengths[0] = ret; + } if (ret > cblk->data_allocated) { size_t new_size = FFMAX(2*cblk->data_allocated, ret); void *new = av_realloc(cblk->data, new_size); @@ -1297,7 +1277,7 @@ skip_data: return 0; } -static int jpeg2000_decode_packets_po_iteration(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, +static int jpeg2000_decode_packets_po_iteration(Jpeg2000DecoderContext *s, Jpeg2000DecTile *tile, int RSpoc, int CSpoc, int LYEpoc, int REpoc, int CEpoc, int Ppoc, int *tp_index) @@ -1588,7 +1568,7 @@ static int jpeg2000_decode_packets_po_iteration(Jpeg2000DecoderContext *s, Jpeg2 return ret; } -static int jpeg2000_decode_packets(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile) +static int jpeg2000_decode_packets(Jpeg2000DecoderContext *s, Jpeg2000DecTile *tile) { int ret = AVERROR_BUG; int i; @@ -1896,7 +1876,7 @@ static void dequantization_int_97(int x, int y, Jpeg2000Cblk *cblk, } } -static inline void mct_decode(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile) +static inline void mct_decode(Jpeg2000DecoderContext *s, Jpeg2000DecTile *tile) { int i, csize = 1; void *src[3]; @@ -1937,20 +1917,22 @@ static inline void roi_scale_cblk(Jpeg2000Cblk *cblk, } } -static inline void tile_codeblocks(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile) +static inline void tile_codeblocks(Jpeg2000DecoderContext *s, Jpeg2000DecTile *tile) { Jpeg2000T1Context t1; int compno, reslevelno, bandno; + int subbandno; /* Loop on tile components */ for (compno = 0; compno < s->ncomponents; compno++) { - Jpeg2000Component *comp = tile->comp + compno; - Jpeg2000CodingStyle *codsty = tile->codsty + compno; + Jpeg2000Component *comp = tile->comp + compno; + Jpeg2000CodingStyle *codsty = tile->codsty + compno; + Jpeg2000QuantStyle *quantsty = tile->qntsty + compno; int coded = 0; + subbandno = 0; - t1.stride = (1<<codsty->log2_cblk_width) + 2; - + t1.stride = (1 << codsty->log2_cblk_width) + 2; /* Loop on resolution levels */ for (reslevelno = 0; reslevelno < codsty->nreslevels2decode; reslevelno++) { Jpeg2000ResLevel *rlevel = comp->reslevel + reslevelno; @@ -1975,12 +1957,21 @@ static inline void tile_codeblocks(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile for (cblkno = 0; cblkno < prec->nb_codeblocks_width * prec->nb_codeblocks_height; cblkno++) { - int x, y; + int x, y, ret, magp; Jpeg2000Cblk *cblk = prec->cblk + cblkno; - int ret = decode_cblk(s, codsty, &t1, cblk, - cblk->coord[0][1] - cblk->coord[0][0], - cblk->coord[1][1] - cblk->coord[1][0], - bandpos, comp->roi_shift); + // Annex E (Equation E-2) ISO/IEC 15444-1:2019 + magp = quantsty->expn[subbandno] + quantsty->nguardbits - 1; + + if (s->is_htj2k) + ret = decode_htj2k(s, codsty, &t1, cblk, + cblk->coord[0][1] - cblk->coord[0][0], + cblk->coord[1][1] - cblk->coord[1][0], + magp, comp->roi_shift); + else + ret = decode_cblk(s, codsty, &t1, cblk, + cblk->coord[0][1] - cblk->coord[0][0], + cblk->coord[1][1] - cblk->coord[1][0], + bandpos, comp->roi_shift); if (ret) coded = 1; else @@ -1998,6 +1989,7 @@ static inline void tile_codeblocks(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile dequantization_int(x, y, cblk, comp, &t1, band); } /* end cblk */ } /*end prec */ + subbandno+=1; } /* end band */ } /* end reslevel */ @@ -2009,7 +2001,7 @@ static inline void tile_codeblocks(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile } #define WRITE_FRAME(D, PIXEL) \ - static inline void write_frame_ ## D(Jpeg2000DecoderContext * s, Jpeg2000Tile * tile, \ + static inline void write_frame_ ## D(Jpeg2000DecoderContext * s, Jpeg2000DecTile * tile, \ AVFrame * picture, int precision) \ { \ const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(s->avctx->pix_fmt); \ @@ -2080,7 +2072,7 @@ static int jpeg2000_decode_tile(AVCodecContext *avctx, void *td, { Jpeg2000DecoderContext *s = avctx->priv_data; AVFrame *picture = td; - Jpeg2000Tile *tile = s->tile + jobnr; + Jpeg2000DecTile *tile = s->tile + jobnr; tile_codeblocks(s, tile); @@ -2152,9 +2144,30 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) if (marker >= 0xFF30 && marker <= 0xFF3F) continue; if (marker == JPEG2000_SOD) { - Jpeg2000Tile *tile; + Jpeg2000DecTile *tile; Jpeg2000TilePart *tp; + if (codsty->cblk_style & JPEG2000_CTSY_HTJ2K_F) { + /* Confirm Marker constrains according to Annex A of Rec. ITU-T T.814 | ISO/IEC 15444-15 */ + // A.2 + if (!(s->avctx->profile & JPEG2000_RSIZ_BIT)) { + av_log(s->avctx, AV_LOG_ERROR, "Bit 14 of Rsiz is not equal to 1\n"); + return AVERROR_INVALIDDATA; + } + // A.5 + for (int i = 0; i < 4; i++) { + if (s->roi_shift[i] > 37) { + av_log(s->avctx, AV_LOG_ERROR, "ROI coefficient %d is greater than 37.\n", s->roi_shift[i]); + return AVERROR_INVALIDDATA; + } + } + // A.3.1 + if (!(s->pcap & (1 << (17)))) { // 15th MSB of Pcap + av_log(s->avctx, AV_LOG_ERROR, "Bit 15 of Pcap is not equal to 1\n"); + return AVERROR_INVALIDDATA; + } + } + if (!s->tile) { av_log(s->avctx, AV_LOG_ERROR, "Missing SIZ\n"); return AVERROR_INVALIDDATA; @@ -2210,6 +2223,31 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) if (!s->tile) s->numXtiles = s->numYtiles = 0; break; + case JPEG2000_CAP: + if (!(s->ncomponents)) { + av_log(s->avctx, AV_LOG_ERROR, + "Cannot decode a CAP marker without previously decoding a SIZ marker\n"); + return AVERROR_INVALIDDATA; + } + /* + * According to the spec decoding a CAP marker is mandatory only if the 14th bit of Rsiz is set to 1. + * To indicate the decoder needs to implement extended capabilities to decode the image. + * If the bit is not set, we skip over parsing the CAP segment. + */ + if (s->avctx->profile & JPEG2000_RSIZ_BIT) { + if (s->in_tile_headers) { + av_log(s->avctx, AV_LOG_ERROR, "CAP marker can only be in main header"); + return AVERROR_INVALIDDATA; + } + ret = get_cap(s, len); + } else { + av_log(s->avctx, AV_LOG_INFO, "Skipping parsing of the CAP segment"); + bytestream2_skip(&(s->g), len - 2); + } + break; + case JPEG2000_CPF: + ret = get_cpf(s, len); + break; case JPEG2000_COC: ret = get_coc(s, codsty, properties); break; @@ -2302,7 +2340,7 @@ static int jpeg2000_read_bitstream_packets(Jpeg2000DecoderContext *s) int tileno; for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++) { - Jpeg2000Tile *tile = s->tile + tileno; + Jpeg2000DecTile *tile = s->tile + tileno; if ((ret = init_tile(s, tileno)) < 0) return ret; diff --git a/libavcodec/jpeg2000htdec.c b/libavcodec/jpeg2000htdec.c new file mode 100644 index 0000000000..a926e9e933 --- /dev/null +++ b/libavcodec/jpeg2000htdec.c @@ -0,0 +1,1228 @@ +/* + * JPEG2000 High Throughput block decoder + * Copyright (c) 2022 Caleb Etemesi<etemesicaleb@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg 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. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "jpeg2000htdec.h" +#include <stdint.h> +#include <stdlib.h> + +#include "bytestream.h" + +#define J2K_Q1 0 + +#define J2K_Q2 1 + +#define HT_SHIFT_SIGMA 0 +#define HT_SHIFT_SCAN 4 +#define HT_SHIFT_REF 3 +#define HT_SHIFT_REF_IND 2 +/** + * @brief Table 2 in clause 7.3.3 + */ +const static uint8_t MEL_E[13] = {0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 4, 5}; + +/** + * Given a precomputed c, checks whether n % d == 0 + */ +static av_always_inline uint32_t is_divisible(uint32_t n, uint64_t c) +{ + return n * c <= c - 1; +} + +/* Initializers */ + +static void jpeg2000_init_zero(StateVars *s) +{ + s->bits_left = 0; + s->bit_buf = 0; + s->tmp = 0; + s->bits = 0; + s->pos = 0; + s->last = 0; +} + +static void jpeg2000_init_mel(StateVars *s, uint32_t Pcup) +{ + jpeg2000_init_zero(s); + s->pos = Pcup; +} + +static void jpeg2000_init_mag_ref(StateVars *s, uint32_t Lref) +{ + s->pos = Lref - 2; + s->bits = 0; + s->last = 0xFF; + s->tmp = 0; + s->bits_left = 0; + s->bit_buf = 0; +} + +static void jpeg2000_init_mel_decoder(MelDecoderState *mel_state) +{ + mel_state->k = 0; + mel_state->run = 0; + mel_state->one = 0; +} +/** + * @brief Refill the buffer backwards in little Endian while skipping + * over stuffing bits + * + * Stuffing bits are those that appear in the position of any byte whose + * LSBs are all 1's if the last consumed byte was larger than 0x8F + */ +static int jpeg2000_bitbuf_refill_backwards(StateVars *buffer, + const uint8_t *array) +{ + uint64_t tmp = 0; + int32_t position = buffer->pos; + uint32_t new_bits = 32; + uint32_t mask; + + if (buffer->bits_left > 32) + return 0; // enough data, no need to pull in more bits + + /* + * We are reading bits from end to start, and we need to handle them in LE. + * therefore, if we read bytes ABCD, we need to convert + * them to DCBA, but the bitstream is constructed in such a way that it is + * BE when reading from back to front,so we need to swap bytes + * but this doesn't work when position is less than 3, + * we end up reading bits from the MEL byte-stream which + * is a recipe for sleepless nights. + * + * So the trick is to branchlessly read and mask + * depending on whatever was the initial position, + * the mask is simply either 32 bits, 24 bits ,8 bits or 0 bits. + * depending on how many bytes are available, with this, we don't + * read past the end of the buffer,we mask + * bits we already read ensuring we don't read twice. + * and we can do it branchlessly without checking for positions. + * + * We need to watch out for negative shift values which are UB in C hence + * the MAX declarative. + */ + + position -= 4; + mask = (UINT64_C(1) << (FFMIN(4, FFMAX(buffer->pos, 0))) * 8) - 1; + tmp = (array[position + 1] << 24) + (array[position + 2] << 16) + (array[position + 3] << 8) + array[position + 4]; + tmp &= mask; + + // Branchlessly unstuff bits + + // load temporary byte, which preceeds the position we + // currently at, to ensure that we can also un-stuff if the + // stuffed bit is the bottom most bits + tmp <<= 8; + tmp |= array[buffer->pos + 1]; + + if ((tmp & 0x7FFF000000) > 0x7F8F000000) { + tmp &= 0x7FFFFFFFFF; + new_bits--; + } + if ((tmp & 0x007FFF0000) > 0x007F8F0000) { + tmp = (tmp & 0x007FFFFFFF) + ((tmp & 0xFF00000000) >> 1); + new_bits--; + } + if ((tmp & 0x00007FFF00) > 0x00007F8F00) { + tmp = (tmp & 0x00007FFFFF) + ((tmp & 0xFFFF000000) >> 1); + new_bits--; + } + if ((tmp & 0x0000007FFF) > 0x0000007F8F) { + tmp = (tmp & 0x0000007FFF) + ((tmp & 0xFFFFFF0000) >> 1); + new_bits--; + } + // remove temporary byte loaded. + tmp >>= 8; + + // Add bits to the MSB of the bit buffer + buffer->bit_buf |= tmp << buffer->bits_left; + buffer->bits_left += new_bits; + buffer->pos = FFMAX(0, position); + return 0; +} +/** + * @brief Refill the bit-buffer reading new bits going forward + * in the stream while skipping over stuffed bits. + */ +static void jpeg2000_bitbuf_refill_forward(StateVars *buffer, + const uint8_t *array, + uint32_t length) +{ + while (buffer->bits_left < 32) { + buffer->tmp = 0xFF; + buffer->bits = (buffer->last == 0xFF) ? 7 : 8; + if (buffer->pos < length) { + buffer->tmp = array[buffer->pos]; + buffer->pos += 1; + buffer->last = buffer->tmp; + } + buffer->bit_buf |= ((uint64_t)buffer->tmp) << buffer->bits_left; + buffer->bits_left += buffer->bits; + } +} + +/** + * @brief Drops bits from lower bits in the bit buffer + * + * @param buf: Struct containing bit buffers + * @param nbits: Number of bits to remove. + */ +static av_always_inline void jpeg2000_bitbuf_drop_bits_lsb(StateVars *buf, + uint8_t nbits) +{ + if (buf->bits_left < nbits) { + av_log(NULL, AV_LOG_ERROR, "Invalid bit read of %d, bits in buffer are %d\n", nbits, buf->bits_left); + av_assert0(0); + } + buf->bit_buf >>= nbits; + buf->bits_left -= nbits; +} +/** + * @brief Get bits from the bit buffer reading them + * from the least significant bits moving to the most significant bits. + * + * In case there are fewer bits, refill from `buf` moving backwards. + */ +static av_always_inline uint64_t jpeg2000_bitbuf_get_bits_lsb( + StateVars *bit_stream, uint8_t nbits, const uint8_t *buf) +{ + uint64_t bits; + uint64_t mask = (1ull << nbits) - 1; + if (bit_stream->bits_left < nbits) + jpeg2000_bitbuf_refill_backwards(bit_stream, buf); + bits = bit_stream->bit_buf & mask; + jpeg2000_bitbuf_drop_bits_lsb(bit_stream, nbits); + return bits; +} +/** + * @brief Get bits from the bit buffer reading them + * from the least significant bits moving to the most significant bits + * + * In case there are fewer bits, refill from `buf` moving forward + */ +static av_always_inline uint64_t jpeg2000_bitbuf_get_bits_lsb_forward( + StateVars *bit_stream, uint8_t nbits, const uint8_t *buf, uint32_t length) +{ + uint64_t bits; + uint64_t mask = (1ull << nbits) - 1; + if (bit_stream->bits_left <= nbits) + jpeg2000_bitbuf_refill_forward(bit_stream, buf, length); + bits = bit_stream->bit_buf & mask; + jpeg2000_bitbuf_drop_bits_lsb(bit_stream, nbits); + return bits; +} +/** + * @brief Look ahead bit buffer without discarding bits + */ +static av_always_inline uint64_t +jpeg2000_bitbuf_peek_bits_lsb(StateVars *stream, uint8_t nbits) +{ + uint64_t mask = (1ull << nbits) - 1; + + return stream->bit_buf & mask; +} + +/** + * Variable Length Decoding Routines + */ +static void jpeg2000_init_vlc(StateVars *s, uint32_t Lcup, uint32_t Pcup, const uint8_t *Dcup) +{ + s->bits_left = 0; + s->bit_buf = 0; + s->pos = Lcup - 2 - Pcup; + s->last = Dcup[Lcup - 2]; + s->tmp = (s->last) >> 4; + s->bits = ((s->tmp & 7) < 7) ? 4 : 3; + jpeg2000_bitbuf_refill_backwards(s, Dcup + Pcup); + jpeg2000_bitbuf_drop_bits_lsb(s, 4); +} +/** + * Decode prefix codes for VLC segment. + */ +static int jpeg2000_decode_ctx_vlc(Jpeg2000DecoderContext *s, + StateVars *vlc_stream, + const uint16_t *table, + const uint8_t *Dcup, + uint8_t *sig_pat, + uint8_t *res_off, + uint8_t *emb_pat_k, + uint8_t *emb_pat_1, + uint8_t pos, + uint32_t Pcup, + uint16_t context) +{ + // Described in clause 7.3.5 + uint32_t value; + uint8_t len; + uint64_t index; + uint64_t code_word; + + jpeg2000_bitbuf_refill_backwards(vlc_stream, Dcup + Pcup); + + code_word = vlc_stream->bit_buf & 0x7f; + index = code_word + (context << 7); + + // decode table has 1024 entries so ensure array access is in bounds + av_assert0(index < 1024); + + value = table[index]; + + len = (value & 0x000F) >> 1; + + res_off[pos] = (uint8_t)(value & 1); + sig_pat[pos] = (uint8_t)((value & 0x00F0) >> 4); + emb_pat_k[pos] = (uint8_t)((value & 0x0F00) >> 8); + emb_pat_1[pos] = (uint8_t)((value & 0xF000) >> 12); + jpeg2000_bitbuf_drop_bits_lsb(vlc_stream, len); + return 0; +} +/** + * @brief Decode variable length u-vlc prefix + */ +static av_always_inline uint8_t +vlc_decode_u_prefix(StateVars *vlc_stream, const uint8_t *refill_array) +{ + // clause 7.3.6 + // procedure : decodeUPrefix. + + uint8_t bits; + if (vlc_stream->bits_left < 3) + jpeg2000_bitbuf_refill_backwards(vlc_stream, refill_array); + + bits = jpeg2000_bitbuf_peek_bits_lsb(vlc_stream, 3); + + if (bits & 0b1) { + jpeg2000_bitbuf_drop_bits_lsb(vlc_stream, 1); + return 1; + } + if (bits & 0b10) { + jpeg2000_bitbuf_drop_bits_lsb(vlc_stream, 2); + return 2; + } + jpeg2000_bitbuf_drop_bits_lsb(vlc_stream, 3); + + if (bits & 0b100) + return 3; + return 5; +} +/** + * @brief Decode variable length u-vlc suffix + */ +static av_always_inline uint8_t vlc_decode_u_suffix( + StateVars *vlc_stream, uint8_t suffix, const uint8_t *refill_array) +{ + // clause 7.3.6 + // procedure: decodeUSuffix + + uint8_t bits; + if (suffix < 3) + return 0; + + if (vlc_stream->bits_left < 5) + jpeg2000_bitbuf_refill_backwards(vlc_stream, refill_array); + + bits = jpeg2000_bitbuf_peek_bits_lsb(vlc_stream, 5); + + if (suffix == 3) { + jpeg2000_bitbuf_drop_bits_lsb(vlc_stream, 1); + return bits & 1; + } + jpeg2000_bitbuf_drop_bits_lsb(vlc_stream, 5); + + return bits; +} + +/** + * @brief Decode variable length u-vlc suffix + */ +static av_always_inline uint8_t vlc_decode_u_extension( + StateVars *vlc_stream, uint8_t suffix, const uint8_t *refill_array) +{ + // clause 7.3.6 + // procedure decodeUExtension. + if (suffix < 28) + return 0; + return jpeg2000_bitbuf_get_bits_lsb(vlc_stream, 4, refill_array); +} + +/** + * Magnitude and Sign decode procedures +*/ + +static int32_t jpeg2000_decode_mag_sgn(StateVars *mag_sgn_stream, int32_t m_n, int32_t i_n, const uint8_t *buf, uint32_t length) +{ + // clause 7.3.8 + // procedure: decodeMagSgnValue + + int32_t val = 0; + if (m_n > 0) { + val = jpeg2000_bitbuf_get_bits_lsb_forward(mag_sgn_stream, m_n, buf, length); + val += (i_n << m_n); + } + return val; +} + +static av_always_inline void +recover_mag_sgn(StateVars *mag_sgn, uint8_t pos, uint16_t q, int32_t m_n[2], int32_t known_1[2], const uint8_t emb_pat_1[2], int32_t v[2][4], int32_t m[2][4], uint8_t *E, uint32_t *mu_n, const uint8_t *Dcup, uint32_t Pcup, uint32_t pLSB) +{ + for (int i = 0; i < 4; i++) { + int32_t n = 4 * q + i; + m_n[pos] = m[pos][i]; + known_1[pos] = (emb_pat_1[pos] >> i) & 1; + v[pos][i] = jpeg2000_decode_mag_sgn(mag_sgn, m_n[pos], known_1[pos], Dcup, Pcup); + if (m_n[pos] != 0) { + E[n] = 32 - ff_clz(v[pos][i] | 1); + mu_n[n] = (v[pos][i] >> 1) + 1; + mu_n[n] <<= pLSB; + mu_n[n] |= ((uint32_t)(v[pos][i] & 1)) << 31; // sign bit. + } + } +} + +/*MEL stream decoding procedure*/ +static int jpeg2000_import_bit(StateVars *stream, const uint8_t *array, uint32_t length) +{ + if (stream->bits == 0) { + stream->bits = (stream->tmp == 0xFF) ? 7 : 8; + if (stream->pos < length) { + stream->tmp = array[stream->pos]; + stream->pos += 1; + } else + stream->tmp = 0xFF; + } + stream->bits -= 1; + return (stream->tmp >> stream->bits) & 1; +} + +static int jpeg2000_decode_mel_sym(MelDecoderState *mel_state, + StateVars *mel_stream, + const uint8_t *Dcup, + uint32_t Lcup) +{ + + if (mel_state->run == 0 && mel_state->one == 0) { + uint8_t eval; + uint8_t bit; + + eval = MEL_E[mel_state->k]; + bit = jpeg2000_import_bit(mel_stream, Dcup, Lcup); + if (bit == 1) { + mel_state->run = 1 << eval; + mel_state->k = FFMIN(12, mel_state->k + 1); + } else { + mel_state->run = 0; + while (eval > 0) { + bit = jpeg2000_import_bit(mel_stream, Dcup, Lcup); + mel_state->run = (2 * (mel_state->run)) + bit; + eval -= 1; + } + mel_state->k = FFMAX(0, mel_state->k - 1); + mel_state->one = 1; + } + } + if (mel_state->run > 0) { + mel_state->run -= 1; + return 0; + } else { + mel_state->one = 0; + return 1; + } +} +/** Magref decoding procedures */ +static av_always_inline int jpeg2000_import_magref_bit(StateVars *stream, const uint8_t *array, uint32_t length) +{ + return jpeg2000_bitbuf_get_bits_lsb(stream, 1, array); +} + +/* Signal EMB decode */ +static int +jpeg2000_decode_sig_emb(Jpeg2000DecoderContext *s, MelDecoderState *mel_state, StateVars *mel_stream, StateVars *vlc_stream, const uint16_t *vlc_table, const uint8_t *Dcup, uint8_t *sig_pat, uint8_t *res_off, uint8_t *emb_pat_k, uint8_t *emb_pat_1, uint8_t pos, uint16_t context, uint32_t Lcup, uint32_t Pcup) +{ + if (context == 0) { + uint8_t sym; + sym = jpeg2000_decode_mel_sym(mel_state, mel_stream, Dcup, Lcup); + if (sym == 0) { + sig_pat[pos] = 0; + res_off[pos] = 0; + emb_pat_k[pos] = 0; + emb_pat_1[pos] = 0; + return 0; + } + } + return jpeg2000_decode_ctx_vlc(s, vlc_stream, vlc_table, Dcup, sig_pat, + res_off, emb_pat_k, emb_pat_1, pos, Pcup, + context); +} + +static av_always_inline int jpeg2000_get_state(int x1, int x2, int width, int shift_by, const uint8_t *block_states) +{ + return (block_states[(x1 + 1) * (width + 2) + (x2 + 1)] >> shift_by) & 1; +} +static av_always_inline void jpeg2000_modify_state(int x1, int x2, int width, int value, uint8_t *block_states) +{ + block_states[(x1 + 1) * (width + 2) + (x2 + 1)] |= value; +} + +static int jpeg2000_decode_ht_cleanup( + Jpeg2000DecoderContext *s, Jpeg2000Cblk *cblk, Jpeg2000T1Context *t1, MelDecoderState *mel_state, StateVars *mel_stream, StateVars *vlc_stream, StateVars *mag_sgn_stream, const uint8_t *Dcup, uint32_t Lcup, uint32_t Pcup, uint8_t pLSB, int width, int height, int32_t *sample_buf, uint8_t *block_states) +{ + uint16_t q = 0; // Represents current quad position. + uint16_t q1, q2; + uint16_t context1, context2; + uint16_t context = 0; + + uint8_t sig_pat[2] = {0}; // significance pattern + uint8_t res_off[2] = {0}; // residual offset + uint8_t emb_pat_k[2] = {0}; // Exponent Max Bound pattern K + uint8_t emb_pat_1[2] = {0}; // Exponent Max Bound pattern 1. + uint8_t gamma[2] = {0}; + + uint8_t E_n[2] = {0}; + uint8_t E_ne[2] = {0}; + uint8_t E_nw[2] = {0}; + uint8_t E_nf[2] = {0}; + + uint8_t max_e[2] = {0}; + + uint8_t u_pfx[2] = {0}; + uint8_t u_sfx[2] = {0}; + uint8_t u_ext[2] = {0}; + + int32_t u[2] = {0}; + int32_t U[2] = {0}; // Exponent bound (7.3.7) + int32_t m_n[2] = {0}; + int32_t known_1[2] = {0}; + + int32_t m[2][4] = {0}; + int32_t v[2][4] = {0}; + + uint8_t kappa[2] = {1, 1}; + int ret = 0; + + int sp; + + uint64_t c; + + uint8_t *sigma; + uint32_t *mu; + + const uint8_t *vlc_buf = Dcup + Pcup; + // convert to raster-scan + const uint16_t is_border_x = width % 2; + const uint16_t is_border_y = height % 2; + + int j1, j2; + + const uint16_t quad_width = ff_jpeg2000_ceildivpow2(width, 1); + const uint16_t quad_height = ff_jpeg2000_ceildivpow2(height, 1); + + size_t buf_size = 4 * quad_width * quad_height; + + uint8_t *sigma_n = av_calloc(buf_size, sizeof(uint8_t)); + uint8_t *E = av_calloc(buf_size, sizeof(uint8_t)); + uint32_t *mu_n = av_calloc(buf_size, sizeof(uint32_t)); + + if (!sigma_n || !E || !mu_n) { + ret = AVERROR(ENOMEM); + goto free; + } + + sigma = sigma_n; + mu = mu_n; + + while (q < quad_width - 1) { + q1 = q; + q2 = q1 + 1; + + if ((ret = jpeg2000_decode_sig_emb(s, mel_state, mel_stream, vlc_stream, + dec_CxtVLC_table0, Dcup, sig_pat, res_off, + emb_pat_k, emb_pat_1, J2K_Q1, context, Lcup, + Pcup)) + < 0) + goto free; + for (int i = 0; i < 4; i++) + sigma_n[4 * q1 + i] = (sig_pat[J2K_Q1] >> i) & 1; + + // calculate context + context = sigma_n[4 * q1]; // f + context |= sigma_n[4 * q1 + 1]; // sf + context += sigma_n[4 * q1 + 2] << 1; // w << 1 + context += sigma_n[4 * q1 + 3] << 2; + + if ((ret = jpeg2000_decode_sig_emb(s, mel_state, mel_stream, vlc_stream, + dec_CxtVLC_table0, Dcup, sig_pat, res_off, + emb_pat_k, emb_pat_1, J2K_Q2, context, Lcup, + Pcup)) + < 0) + goto free; + + for (int i = 0; i < 4; i++) + sigma_n[4 * q2 + i] = (sig_pat[J2K_Q2] >> i) & 1; + + // calculate context for the next quad + context = sigma_n[4 * q2]; // f + context |= sigma_n[4 * q2 + 1]; // sf + context += sigma_n[4 * q2 + 2] << 1; // w << 1 + context += sigma_n[4 * q2 + 3] << 2; // sw << 2 + + u[0] = 0; + u[1] = 0; + + jpeg2000_bitbuf_refill_backwards(vlc_stream, vlc_buf); + + if (res_off[J2K_Q1] == 1 && res_off[J2K_Q2] == 1) { + + if (jpeg2000_decode_mel_sym(mel_state, mel_stream, Dcup, Lcup) == 1) { + + u_pfx[J2K_Q1] = vlc_decode_u_prefix(vlc_stream, vlc_buf); + u_pfx[J2K_Q2] = vlc_decode_u_prefix(vlc_stream, vlc_buf); + + u_sfx[J2K_Q1] = vlc_decode_u_suffix(vlc_stream, u_pfx[J2K_Q1], vlc_buf); + u_sfx[J2K_Q2] = vlc_decode_u_suffix(vlc_stream, u_pfx[J2K_Q2], vlc_buf); + + u_ext[J2K_Q1] = vlc_decode_u_extension(vlc_stream, u_sfx[J2K_Q1], vlc_buf); + u_ext[J2K_Q2] = vlc_decode_u_extension(vlc_stream, u_sfx[J2K_Q2], vlc_buf); + + u[J2K_Q1] = 2 + u_pfx[J2K_Q1] + u_sfx[J2K_Q1] + (u_ext[J2K_Q1] * 4); + u[J2K_Q2] = 2 + u_pfx[J2K_Q2] + u_sfx[J2K_Q2] + (u_ext[J2K_Q2] * 4); + + } else { + u_pfx[J2K_Q1] = vlc_decode_u_prefix(vlc_stream, vlc_buf); + + if (u_pfx[J2K_Q1] > 2) { + u[J2K_Q2] = jpeg2000_bitbuf_get_bits_lsb(vlc_stream, 1, vlc_buf) + 1; + + u_sfx[J2K_Q1] = vlc_decode_u_suffix(vlc_stream, u_pfx[J2K_Q1], vlc_buf); + + u_ext[J2K_Q1] = vlc_decode_u_extension(vlc_stream, u_sfx[J2K_Q1], vlc_buf); + } else { + u_pfx[J2K_Q2] = vlc_decode_u_prefix(vlc_stream, vlc_buf); + + u_sfx[J2K_Q1] = vlc_decode_u_suffix(vlc_stream, u_pfx[J2K_Q1], vlc_buf); + u_sfx[J2K_Q2] = vlc_decode_u_suffix(vlc_stream, u_pfx[J2K_Q2], vlc_buf); + + u_ext[J2K_Q1] = vlc_decode_u_extension(vlc_stream, u_sfx[J2K_Q1], vlc_buf); + u_ext[J2K_Q2] = vlc_decode_u_extension(vlc_stream, u_sfx[J2K_Q2], vlc_buf); + + u[J2K_Q2] = u_pfx[J2K_Q2] + u_sfx[J2K_Q2] + (u_ext[J2K_Q2] * 4); + } + // clause 7.3.6 (3) + u[J2K_Q1] = u_pfx[J2K_Q1] + u_sfx[J2K_Q1] + (u_ext[J2K_Q1] * 4); + } + + } else if (res_off[J2K_Q1] == 1 || res_off[J2K_Q2] == 1) { + uint8_t pos = res_off[J2K_Q1] == 1 ? 0 : 1; + + u_pfx[pos] = vlc_decode_u_prefix(vlc_stream, vlc_buf); + + u_sfx[pos] = vlc_decode_u_suffix(vlc_stream, u_pfx[pos], vlc_buf); + + u_ext[pos] = vlc_decode_u_extension(vlc_stream, u_sfx[pos], vlc_buf); + + u[pos] = u_pfx[pos] + u_sfx[pos] + (u_ext[pos] * 4); + } + U[J2K_Q1] = kappa[J2K_Q1] + u[J2K_Q1]; + U[J2K_Q2] = kappa[J2K_Q2] + u[J2K_Q2]; + + for (int i = 0; i < 4; i++) { + m[J2K_Q1][i] = sigma_n[4 * q1 + i] * U[J2K_Q1] - ((emb_pat_k[J2K_Q1] >> i) & 1); + m[J2K_Q2][i] = sigma_n[4 * q2 + i] * U[J2K_Q2] - ((emb_pat_k[J2K_Q2] >> i) & 1); + } + + recover_mag_sgn(mag_sgn_stream, J2K_Q1, q1, m_n, known_1, emb_pat_1, v, m, + E, mu_n, Dcup, Pcup, pLSB); + + recover_mag_sgn(mag_sgn_stream, J2K_Q2, q2, m_n, known_1, emb_pat_1, v, m, + E, mu_n, Dcup, Pcup, pLSB); + + // prepare context for the next quad + + // move to the next quad pair + q += 2; + } + if (quad_width % 2 == 1) { + q1 = q; + + if ((ret = jpeg2000_decode_sig_emb(s, mel_state, mel_stream, vlc_stream, + dec_CxtVLC_table0, Dcup, sig_pat, res_off, + emb_pat_k, emb_pat_1, J2K_Q1, context, Lcup, + Pcup)) + < 0) + goto free; + + for (int i = 0; i < 4; i++) + sigma_n[4 * q1 + i] = (sig_pat[J2K_Q1] >> i) & 1; + + u[J2K_Q1] = 0; + + if (res_off[J2K_Q1] == 1) { + u_pfx[J2K_Q1] = vlc_decode_u_prefix(vlc_stream, vlc_buf); + u_sfx[J2K_Q1] = vlc_decode_u_suffix(vlc_stream, u_pfx[J2K_Q1], vlc_buf); + u_ext[J2K_Q1] = vlc_decode_u_extension(vlc_stream, u_sfx[J2K_Q1], vlc_buf); + u[J2K_Q1] = u_pfx[J2K_Q1] + u_sfx[J2K_Q1] + (u_ext[J2K_Q1] * 4); + } + + U[J2K_Q1] = kappa[J2K_Q1] + u[J2K_Q1]; + + for (int i = 0; i < 4; i++) + m[J2K_Q1][i] = sigma_n[4 * q1 + i] * U[J2K_Q1] - ((emb_pat_k[J2K_Q1] >> i) & 1); + + recover_mag_sgn(mag_sgn_stream, J2K_Q1, q1, m_n, known_1, emb_pat_1, v, m, + E, mu_n, Dcup, Pcup, pLSB); + + q++; // move to next quad pair + } + // initial line pair end. + + /* + * As an optimization, we can replace modulo operations with + * checking if a number is divisible , since that's the only thing we need. + * this is paired with is_divisible. + * Credits to Daniel Lemire blog post: + * https://lemire.me/blog/2019/02/08/faster-remainders-when-the-divisor-is-a-constant-beating-compilers-and-libdivide/ + * It's UB on zero, but we can't have a quad being zero, the spec doesn't allow, + * so we error out early in case that's the case. + */ + + c = 1 + UINT64_C(0xffffffffffffffff) / quad_width; + + for (int row = 1; row < quad_height; row++) { + while ((q - (row * quad_width)) < quad_width - 1 && q < (quad_height * quad_width)) { + q1 = q; + q2 = q + 1; + context1 = sigma_n[4 * (q1 - quad_width) + 1]; + context1 += sigma_n[4 * (q1 - quad_width) + 3] << 2; // ne + + if (!is_divisible(q1, c)) { + context1 |= sigma_n[4 * (q1 - quad_width) - 1]; // nw + context1 += (sigma_n[4 * q1 - 1] | sigma_n[4 * q1 - 2]) << 1; // sw| q + } + if (!is_divisible(q1 + 1, c)) + context1 |= sigma_n[4 * (q1 - quad_width) + 5] << 2; + + if ((ret = jpeg2000_decode_sig_emb(s, mel_state, mel_stream, vlc_stream, + dec_CxtVLC_table1, Dcup, sig_pat, res_off, + emb_pat_k, emb_pat_1, J2K_Q1, context1, Lcup, + Pcup)) + < 0) + goto free; + + for (int i = 0; i < 4; i++) + sigma_n[4 * q1 + i] = (sig_pat[J2K_Q1] >> i) & 1; + + context2 = sigma_n[4 * (q2 - quad_width) + 1]; + context2 += sigma_n[4 * (q2 - quad_width) + 3] << 2; + + if (!is_divisible(q2, c)) { + context2 |= sigma_n[4 * (q2 - quad_width) - 1]; + context2 += (sigma_n[4 * q2 - 1] | sigma_n[4 * q2 - 2]) << 1; + } + if (!is_divisible(q2 + 1, c)) + context2 |= sigma_n[4 * (q2 - quad_width) + 5] << 2; + + if ((ret = jpeg2000_decode_sig_emb(s, mel_state, mel_stream, vlc_stream, + dec_CxtVLC_table1, Dcup, sig_pat, res_off, + emb_pat_k, emb_pat_1, J2K_Q2, context2, Lcup, + Pcup)) + < 0) + goto free; + + for (int i = 0; i < 4; i++) + sigma_n[4 * q2 + i] = (sig_pat[J2K_Q2] >> i) & 1; + + u[J2K_Q1] = 0; + u[J2K_Q2] = 0; + + jpeg2000_bitbuf_refill_backwards(vlc_stream, vlc_buf); + + if (res_off[J2K_Q1] == 1 && res_off[J2K_Q2] == 1) { + u_pfx[J2K_Q1] = vlc_decode_u_prefix(vlc_stream, vlc_buf); + u_pfx[J2K_Q2] = vlc_decode_u_prefix(vlc_stream, vlc_buf); + + u_sfx[J2K_Q1] = vlc_decode_u_suffix(vlc_stream, u_pfx[J2K_Q1], vlc_buf); + u_sfx[J2K_Q2] = vlc_decode_u_suffix(vlc_stream, u_pfx[J2K_Q2], vlc_buf); + + u_ext[J2K_Q1] = vlc_decode_u_extension(vlc_stream, u_sfx[J2K_Q1], vlc_buf); + u_ext[J2K_Q2] = vlc_decode_u_extension(vlc_stream, u_sfx[J2K_Q2], vlc_buf); + + u[J2K_Q1] = u_pfx[J2K_Q1] + u_sfx[J2K_Q1] + (u_ext[J2K_Q1] << 2); + u[J2K_Q2] = u_pfx[J2K_Q2] + u_sfx[J2K_Q2] + (u_ext[J2K_Q2] << 2); + + } else if (res_off[J2K_Q1] == 1 || res_off[J2K_Q2] == 1) { + uint8_t pos = res_off[J2K_Q1] == 1 ? 0 : 1; + + u_pfx[pos] = vlc_decode_u_prefix(vlc_stream, vlc_buf); + + u_sfx[pos] = vlc_decode_u_suffix(vlc_stream, u_pfx[pos], vlc_buf); + + u_ext[pos] = vlc_decode_u_extension(vlc_stream, u_sfx[pos], vlc_buf); + + u[pos] = u_pfx[pos] + u_sfx[pos] + (u_ext[pos] << 2); + } + sp = sig_pat[J2K_Q1]; + + gamma[J2K_Q1] = 1; + + if (sp == 0 || sp == 1 || sp == 2 || sp == 4 || sp == 8) + gamma[J2K_Q1] = 0; + + sp = sig_pat[J2K_Q2]; + + gamma[J2K_Q2] = 1; + + if (sp == 0 || sp == 1 || sp == 2 || sp == 4 || sp == 8) + gamma[J2K_Q2] = 0; + + E_n[J2K_Q1] = E[4 * (q1 - quad_width) + 1]; + E_n[J2K_Q2] = E[4 * (q2 - quad_width) + 1]; + + E_ne[J2K_Q1] = E[4 * (q1 - quad_width) + 3]; + E_ne[J2K_Q2] = E[4 * (q2 - quad_width) + 3]; + + E_nw[J2K_Q1] = 0; + E_nw[J2K_Q2] = 0; + + E_nf[J2K_Q1] = 0; + E_nf[J2K_Q2] = 0; + + if (!is_divisible(q1, c)) + E_nw[J2K_Q1] = E[4 * (q1 - quad_width) - 1]; + if (!is_divisible(q2, c)) + E_nw[J2K_Q2] = E[4 * (q2 - quad_width) - 1]; + + if (!is_divisible(q1 + 1, c)) + E_nf[J2K_Q1] = E[4 * (q1 - quad_width) + 5]; + if (!is_divisible(q2 + 1, c)) + E_nf[J2K_Q2] = E[4 * (q2 - quad_width) + 5]; + + max_e[J2K_Q1] = FFMAX(E_nw[J2K_Q1], FFMAX3(E_n[J2K_Q1], E_ne[J2K_Q1], E_nf[J2K_Q1])); + max_e[J2K_Q2] = FFMAX(E_nw[J2K_Q2], FFMAX3(E_n[J2K_Q2], E_ne[J2K_Q2], E_nf[J2K_Q2])); + + kappa[J2K_Q1] = FFMAX(1, gamma[J2K_Q1] * (max_e[J2K_Q1] - 1)); + kappa[J2K_Q2] = FFMAX(1, gamma[J2K_Q2] * (max_e[J2K_Q2] - 1)); + + U[J2K_Q1] = kappa[J2K_Q1] + u[J2K_Q1]; + U[J2K_Q2] = kappa[J2K_Q2] + u[J2K_Q2]; + + for (int i = 0; i < 4; i++) { + m[J2K_Q1][i] = sigma_n[4 * q1 + i] * U[J2K_Q1] - ((emb_pat_k[J2K_Q1] >> i) & 1); + m[J2K_Q2][i] = sigma_n[4 * q2 + i] * U[J2K_Q2] - ((emb_pat_k[J2K_Q2] >> i) & 1); + } + recover_mag_sgn(mag_sgn_stream, J2K_Q1, q1, m_n, known_1, emb_pat_1, v, m, + E, mu_n, Dcup, Pcup, pLSB); + + recover_mag_sgn(mag_sgn_stream, J2K_Q2, q2, m_n, known_1, emb_pat_1, v, m, + E, mu_n, Dcup, Pcup, pLSB); + + // move to the next quad pair + q += 2; + } + if ((quad_width % 2) == 1) { + q1 = q; + // calculate context for current quad + context1 = sigma_n[4 * (q1 - quad_width) + 1]; // n + context1 += (sigma_n[4 * (q1 - quad_width) + 3] << 2); // ne + + if (!is_divisible(q1, c)) { + context1 |= sigma_n[4 * (q1 - quad_width) - 1]; // nw + context1 += (sigma_n[4 * q1 - 1] | sigma_n[4 * q1 - 2]) + << 1; // (sw| w) << 1; + } + if (!is_divisible(q1 + 1, c)) + context1 |= sigma_n[4 * (q1 - quad_width) + 5] << 2; + + if ((ret = jpeg2000_decode_sig_emb(s, mel_state, mel_stream, vlc_stream, + dec_CxtVLC_table1, Dcup, sig_pat, res_off, + emb_pat_k, emb_pat_1, J2K_Q1, context1, Lcup, + Pcup)) + < 0) + goto free; + + for (int i = 0; i < 4; i++) + sigma_n[4 * q1 + i] = (sig_pat[J2K_Q1] >> i) & 1; + + u[J2K_Q1] = 0; + + // Recover mag_sgn value + if (res_off[J2K_Q1] == 1) { + u_pfx[J2K_Q1] = vlc_decode_u_prefix(vlc_stream, vlc_buf); + u_sfx[J2K_Q1] = vlc_decode_u_suffix(vlc_stream, u_pfx[J2K_Q1], vlc_buf); + u_ext[J2K_Q1] = vlc_decode_u_extension(vlc_stream, u_sfx[J2K_Q1], vlc_buf); + u[J2K_Q1] = u_pfx[J2K_Q1] + u_sfx[J2K_Q1] + (u_ext[J2K_Q1] << 2); + } + + sp = sig_pat[J2K_Q1]; + + gamma[J2K_Q1] = 1; + + if (sp == 0 || sp == 1 || sp == 2 || sp == 4 || sp == 8) + gamma[J2K_Q1] = 0; + + E_n[J2K_Q1] = E[4 * (q1 - quad_width) + 1]; + + E_ne[J2K_Q1] = E[4 * (q1 - quad_width) + 3]; + + E_nw[J2K_Q1] = 0; + + E_nf[J2K_Q1] = 0; + + if (!is_divisible(q1, c)) + E_nw[J2K_Q1] = E[4 * (q1 - quad_width) - 1]; + + if (!is_divisible(q1 + 1, c)) + E_nf[J2K_Q1] = E[4 * (q1 - quad_width) + 5]; + + max_e[J2K_Q1] = FFMAX(E_nw[J2K_Q1], FFMAX3(E_n[J2K_Q1], E_ne[J2K_Q1], E_nf[J2K_Q1])); + + kappa[J2K_Q1] = FFMAX(1, gamma[J2K_Q1] * (max_e[J2K_Q1] - 1)); + + U[J2K_Q1] = kappa[J2K_Q1] + u[J2K_Q1]; + + for (int i = 0; i < 4; i++) + m[J2K_Q1][i] = sigma_n[4 * q1 + i] * U[J2K_Q1] - ((emb_pat_k[J2K_Q1] >> i) & 1); + + recover_mag_sgn(mag_sgn_stream, J2K_Q1, q1, m_n, known_1, emb_pat_1, v, m, + E, mu_n, Dcup, Pcup, pLSB); + // move to the next quad + q += 1; + } + } + // convert to raster-scan + for (int y = 0; y < quad_height; y++) { + for (int x = 0; x < quad_width; x++) { + j1 = 2 * y; + j2 = 2 * x; + + // set sample + sample_buf[j2 + (j1 * width)] = (int32_t)*mu; + jpeg2000_modify_state(j1, j2, width, *sigma, block_states); + + sigma += 1; + mu += 1; + + if (y != quad_height - 1 || is_border_y == 0) { + sample_buf[j2 + ((j1 + 1) * width)] = (int32_t)*mu; + jpeg2000_modify_state(j1 + 1, j2, width, *sigma, block_states); + } + + sigma += 1; + mu += 1; + + if (x != quad_width - 1 || is_border_x == 0) { + sample_buf[(j2 + 1) + (j1 * width)] = (int32_t)*mu; + jpeg2000_modify_state(j1, j2 + 1, width, *sigma, block_states); + } + + sigma += 1; + mu += 1; + + if ((y != quad_height - 1 || is_border_y == 0) && (x != quad_width - 1 || is_border_x == 0)) { + sample_buf[(j2 + 1) + (j1 + 1) * width] = (int32_t)*mu; + jpeg2000_modify_state(j1 + 1, j2 + 1, width, *sigma, block_states); + } + sigma += 1; + mu += 1; + } + } + ret = 1; +free: + av_freep(&sigma_n); + av_freep(&E); + av_freep(&mu_n); + return ret; +} + +static void jpeg2000_calc_mbr(uint8_t *mbr, const uint16_t i, const uint16_t j, const uint32_t mbr_info, uint8_t causal_cond, uint8_t *block_states, int width) +{ + + int local_mbr = 0; + local_mbr |= jpeg2000_get_state(i - 1, j - 1, width, HT_SHIFT_SIGMA, block_states); + local_mbr |= jpeg2000_get_state(i - 1, j + 0, width, HT_SHIFT_SIGMA, block_states); + local_mbr |= jpeg2000_get_state(i - 1, j + 1, width, HT_SHIFT_SIGMA, block_states); + + local_mbr |= jpeg2000_get_state(i + 0, j - 1, width, HT_SHIFT_SIGMA, block_states); + local_mbr |= jpeg2000_get_state(i + 0, j + 1, width, HT_SHIFT_SIGMA, block_states); + + local_mbr |= jpeg2000_get_state(i + 1, j - 1, width, HT_SHIFT_SIGMA, block_states) * causal_cond; + local_mbr |= jpeg2000_get_state(i + 1, j + 0, width, HT_SHIFT_SIGMA, block_states) * causal_cond; + local_mbr |= jpeg2000_get_state(i + 1, j + 1, width, HT_SHIFT_SIGMA, block_states) * causal_cond; + + local_mbr |= jpeg2000_get_state(i - 1, j - 1, width, HT_SHIFT_REF, block_states) * jpeg2000_get_state(i - 1, j - 1, width, HT_SHIFT_SCAN, block_states); + local_mbr |= jpeg2000_get_state(i - 1, j + 0, width, HT_SHIFT_REF, block_states) * jpeg2000_get_state(i - 1, j - 1, width, HT_SHIFT_SCAN, block_states); + local_mbr |= jpeg2000_get_state(i - 1, j + 1, width, HT_SHIFT_REF, block_states) * jpeg2000_get_state(i - 1, j + 1, width, HT_SHIFT_SCAN, block_states); + + local_mbr |= jpeg2000_get_state(i + 0, j - 1, width, HT_SHIFT_REF, block_states) * jpeg2000_get_state(i + 0, j - 1, width, HT_SHIFT_SCAN, block_states); + local_mbr |= jpeg2000_get_state(i + 0, j + 1, width, HT_SHIFT_REF, block_states) * jpeg2000_get_state(i + 0, j + 1, width, HT_SHIFT_SCAN, block_states); + + local_mbr |= jpeg2000_get_state(i + 1, j - 1, width, HT_SHIFT_REF, block_states) * jpeg2000_get_state(i + 1, j - 1, width, HT_SHIFT_SCAN, block_states) * causal_cond; + local_mbr |= jpeg2000_get_state(i + 1, j + 0, width, HT_SHIFT_REF, block_states) * jpeg2000_get_state(i + 1, j + 0, width, HT_SHIFT_SCAN, block_states) * causal_cond; + local_mbr |= jpeg2000_get_state(i + 1, j + 1, width, HT_SHIFT_REF, block_states) * jpeg2000_get_state(i + 1, j + 1, width, HT_SHIFT_SCAN, block_states) * causal_cond; + + *mbr |= local_mbr; +} +static void jpeg2000_process_stripes_block(StateVars *sig_prop, int i_s, int j_s, int width, int height, int stride, int pLSB, int32_t *sample_buf, uint8_t *block_states, uint8_t *magref_segment, uint32_t magref_length) +{ + int32_t *sp; + uint8_t causal_cond = 0; + uint8_t bit; + uint8_t mbr; + uint32_t mbr_info; + + for (int j = j_s; j < j_s + width; j++) { + mbr_info = 0; + for (int i = i_s; i < i_s + height; i++) { + sp = &sample_buf[j + (i * (stride - 2))]; + mbr = 0; + causal_cond = i != (i_s + height - 1); + if (jpeg2000_get_state(i, j, stride - 2, HT_SHIFT_SIGMA, block_states) == 0) + jpeg2000_calc_mbr(&mbr, i, j, mbr_info & 0x1EF, causal_cond, block_states, stride - 2); + mbr_info >>= 3; + if (mbr != 0) { + jpeg2000_modify_state(i, j, stride - 2, 1 << HT_SHIFT_REF_IND, block_states); + bit = jpeg2000_import_bit(sig_prop, magref_segment, magref_length); + jpeg2000_modify_state(i, j, stride - 2, 1 << HT_SHIFT_REF, block_states); + *sp |= bit << pLSB; + } + jpeg2000_modify_state(i, j, stride - 2, 1 << HT_SHIFT_SCAN, block_states); + } + } + for (int j = 0; j < j_s + width; j++) { + for (int i = 0; i < i_s + height; i++) { + sp = &sample_buf[j + (i * (stride - 2))]; + if ((*sp & (1 << pLSB)) != 0) + *sp = (*sp & 0x7FFFFFFF) | (jpeg2000_import_bit(sig_prop, magref_segment, magref_length) << 31); + + } + } +} + +static void jpeg2000_decode_sigprop(Jpeg2000Cblk *cblk, uint16_t width, uint16_t height, uint8_t *magref_segment, uint32_t magref_length, uint8_t pLSB, int32_t *sample_buf, uint8_t *block_states) +{ + // Described in clause 7.4 + // procedure: decodeSigPropMag + + StateVars sp_dec; + const uint16_t num_v_stripe = height / 4; + const uint16_t num_h_stripe = width / 4; + int b_width = 4; + int b_height = 4; + int stride = width + 2; + int last_width; + uint16_t i = 0, j = 0; + + jpeg2000_init_zero(&sp_dec); + + for (int n1 = 0; n1 < num_v_stripe; n1++) { + j = 0; + for (int n2 = 0; n2 < num_h_stripe; n2++) { + jpeg2000_process_stripes_block(&sp_dec, i, j, b_width, b_height, stride, pLSB, sample_buf, block_states, magref_segment, magref_length); + j += 4; + } + last_width = width % 4; + if (last_width) + jpeg2000_process_stripes_block(&sp_dec, i, j, last_width, b_height, stride, pLSB, sample_buf, block_states, magref_segment, magref_length); + i += 4; + } + // decode remaining height stripes + b_height = height % 4; + j = 0; + for (int n2 = 0; n2 < num_h_stripe; n2++) { + jpeg2000_process_stripes_block(&sp_dec, i, j, b_width, b_height, stride, pLSB, sample_buf, block_states, magref_segment, magref_length); + j += 4; + } + last_width = width % 4; + if (last_width) + jpeg2000_process_stripes_block(&sp_dec, i, j, last_width, b_height, stride, pLSB, sample_buf, block_states, magref_segment, magref_length); +} + +static int jpeg2000_decode_magref(Jpeg2000Cblk *cblk, uint16_t width, uint16_t block_height, uint8_t *magref_segment, uint32_t magref_length, uint8_t pLSB, int32_t *sample_buf, uint8_t *block_states) +{ + // Described in clause 7.5 + // procedure: decodeSigPropMag + + StateVars mag_ref = {0}; + const uint16_t num_v_stripe = block_height / 4; + uint16_t height = 4; + uint16_t i_start = 0; + int32_t *sp; + + jpeg2000_init_mag_ref(&mag_ref, magref_length); + + for (int n1 = 0; n1 < num_v_stripe; n1++) { + for (int j = 0; j < width; j++) { + for (int i = i_start; i < i_start + height; i++) { + // we move column wise, going from one quad to another + // see figure 7. + sp = &sample_buf[j + i * width]; + if (jpeg2000_get_state(i, j, width, HT_SHIFT_SIGMA, block_states) != 0) { + jpeg2000_modify_state(i, j, width, 1 << HT_SHIFT_REF_IND, block_states); + *sp |= jpeg2000_import_magref_bit(&mag_ref, magref_segment, magref_length) << pLSB; + } + } + } + i_start += 4; + } + height = block_height % 4; + for (int j = 0; j < width; j++) { + for (int i = i_start; i < i_start + height; i++) { + sp = &sample_buf[j + i * width]; + if (jpeg2000_get_state(i, j, width, HT_SHIFT_SIGMA, block_states) != 0) { + jpeg2000_modify_state(i, j, width, 1 << HT_SHIFT_REF_IND, block_states); + *sp |= jpeg2000_import_magref_bit(&mag_ref, magref_segment, magref_length) << pLSB; + } + } + } + return 1; +} + +int decode_htj2k(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *codsty, Jpeg2000T1Context *t1, Jpeg2000Cblk *cblk, int width, int height, int magp, uint8_t roi_shift) +{ + uint8_t p0 = 0; // Number of placeholder passes. + uint32_t Lcup; // Length of HT cleanup segment. + uint32_t Lref; // Length of Refinement segment. + uint32_t Scup; // HT cleanup segment suffix length. + uint32_t Pcup; // HT cleanup segment prefix length. + + uint8_t S_blk; // Number of skipped magnitude bitplanes; + uint8_t pLSB; + + uint8_t *Dcup; // Byte of an HT cleanup segment. + uint8_t *Dref; // Byte of an HT refinement segment. + + int z_blk; // Number of ht coding pass + + uint8_t empty_passes; + + StateVars mag_sgn; // Magnitude and Sign + StateVars mel; // Adaptive run-length coding + StateVars vlc; // Variable Length coding + StateVars sig_prop; // Significance propagation + + MelDecoderState mel_state; + + int ret; + + // Temporary buffers + int32_t *sample_buf; + uint8_t *block_states; + + // Post-processing + int32_t n, val, sign; + + int32_t M_b = magp; + av_assert0(width <= 1024U && height <= 1024U); + av_assert0(width * height <= 4096); + av_assert0(width * height > 0); + + memset(t1->data, 0, t1->stride * height * sizeof(*t1->data)); + memset(t1->flags, 0, t1->stride * (height + 2) * sizeof(*t1->flags)); + + if (cblk->npasses == 0) + return 0; + + if (cblk->npasses > 3) + // Currently use this as a dummy but should be fixed soon + p0 = 0; + else if (cblk->length == 0) + p0 = 1; + + empty_passes = p0 * 3; + z_blk = cblk->npasses - empty_passes; + + if (z_blk <= 0) + // no passes within this set, continue + return 0; + + Lcup = cblk->pass_lengths[0]; + Lref = cblk->pass_lengths[1]; + + if (Lcup < 2) { + av_log(s->avctx, AV_LOG_ERROR, + "Cleanup pass length must be at least 2 bytes in length\n"); + return AVERROR_INVALIDDATA; + } + Dcup = cblk->data; + // Dref comes after the refinement segment. + Dref = cblk->data + Lcup; + S_blk = p0 + cblk->zbp; + + pLSB = 30 - S_blk; + + Scup = (Dcup[Lcup - 1] << 4) + (Dcup[Lcup - 2] & 0x0F); + + if (Scup < 2 || Scup > Lcup || Scup > 4079) { + av_log(s->avctx, AV_LOG_ERROR, "Cleanup pass suffix length is invalid %d\n", + Scup); + ret = AVERROR_INVALIDDATA; + goto free; + } + Pcup = Lcup - Scup; + + // modDcup shall be done before the creation of vlc instance. + Dcup[Lcup - 1] = 0xFF; + Dcup[Lcup - 2] |= 0x0F; + // Magnitude and refinement + jpeg2000_init_zero(&mag_sgn); + jpeg2000_bitbuf_refill_forward(&mag_sgn, Dcup, Pcup); + // Significance propagation + jpeg2000_init_zero(&sig_prop); + // Adaptive run length + jpeg2000_init_mel(&mel, Pcup); + // Variable Length coding. + jpeg2000_init_vlc(&vlc, Lcup, Pcup, Dcup); + + jpeg2000_init_mel_decoder(&mel_state); + + sample_buf = av_calloc(width * height, sizeof(int32_t)); + block_states = av_calloc((width + 4) * (height + 4), sizeof(uint8_t)); + + if (!sample_buf || !block_states) { + ret = AVERROR(ENOMEM); + goto free; + } + if ((ret = jpeg2000_decode_ht_cleanup(s, cblk, t1, &mel_state, &mel, &vlc, &mag_sgn, Dcup, Lcup, Pcup, pLSB, width, height, sample_buf, block_states)) < 0) + goto free; + + if (cblk->npasses > 1) + jpeg2000_decode_sigprop(cblk, width, height, Dref, Lref, pLSB - 1, sample_buf, block_states); + + if (cblk->npasses > 2) + if ((ret = jpeg2000_decode_magref(cblk, width, height, Dref, Lref, pLSB - 1, sample_buf, block_states)) < 0) + goto free; + + pLSB = 31 - M_b; + // Reconstruct the values. + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + n = x + (y * t1->stride); + val = sample_buf[x + (y * width)]; + sign = val & 0x80000000; + val &= 0x7fffffff; + // convert sign-magnitude to twos complement form + if (sign) + val = -val; + val >>= (pLSB - 1); + t1->data[n] = val; + } + } +free: + av_freep(&sample_buf); + av_freep(&block_states); + return ret; +} diff --git a/libavcodec/jpeg2000htdec.h b/libavcodec/jpeg2000htdec.h new file mode 100644 index 0000000000..9e5692810a --- /dev/null +++ b/libavcodec/jpeg2000htdec.h @@ -0,0 +1,210 @@ +/* +* JPEG2000 High Throughput block decoder +* Copyright (c) 2022 Caleb Etemesi<etemesicaleb@gmail.com> +* +* This file is part of FFmpeg. +* +* FFmpeg 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. +* +* FFmpeg 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 FFmpeg; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef AVCODEC_JPEG2000HTDEC_H +#define AVCODEC_JPEG2000HTDEC_H + +#include <stdint.h> +#include "jpeg2000.h" + +typedef struct StateVars { + int32_t pos; + uint32_t bits; + uint32_t tmp; + uint32_t last; + uint8_t bits_left; + uint64_t bit_buf; +} StateVars; + +typedef struct MelDecoderState { + uint8_t k; + uint8_t run; + uint8_t one; +} MelDecoderState; + + + +int decode_htj2k(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *codsty, Jpeg2000T1Context *t1, Jpeg2000Cblk *cblk, int width, int height, int magp, uint8_t roi_shift); + +/** + * @brief CtxVLC tables, borrowed from openhtj2k (https://github.com/osamu620/OpenHTJ2K) (credits to Osamu Watanabe) + */ +static const uint16_t dec_CxtVLC_table1[1024] = { + 0x0016, 0x006A, 0x0046, 0x00DD, 0x0086, 0x888B, 0x0026, 0x444D, 0x0016, 0x00AA, 0x0046, 0x88AD, 0x0086, + 0x003A, 0x0026, 0x00DE, 0x0016, 0x00CA, 0x0046, 0x009D, 0x0086, 0x005A, 0x0026, 0x222D, 0x0016, 0x009A, + 0x0046, 0x007D, 0x0086, 0x01FD, 0x0026, 0x007E, 0x0016, 0x006A, 0x0046, 0x88CD, 0x0086, 0x888B, 0x0026, + 0x111D, 0x0016, 0x00AA, 0x0046, 0x005D, 0x0086, 0x003A, 0x0026, 0x00EE, 0x0016, 0x00CA, 0x0046, 0x00BD, + 0x0086, 0x005A, 0x0026, 0x11FF, 0x0016, 0x009A, 0x0046, 0x003D, 0x0086, 0x04ED, 0x0026, 0x2AAF, 0x0016, + 0x006A, 0x0046, 0x00DD, 0x0086, 0x888B, 0x0026, 0x444D, 0x0016, 0x00AA, 0x0046, 0x88AD, 0x0086, 0x003A, + 0x0026, 0x44EF, 0x0016, 0x00CA, 0x0046, 0x009D, 0x0086, 0x005A, 0x0026, 0x222D, 0x0016, 0x009A, 0x0046, + 0x007D, 0x0086, 0x01FD, 0x0026, 0x00BE, 0x0016, 0x006A, 0x0046, 0x88CD, 0x0086, 0x888B, 0x0026, 0x111D, + 0x0016, 0x00AA, 0x0046, 0x005D, 0x0086, 0x003A, 0x0026, 0x4CCF, 0x0016, 0x00CA, 0x0046, 0x00BD, 0x0086, + 0x005A, 0x0026, 0x00FE, 0x0016, 0x009A, 0x0046, 0x003D, 0x0086, 0x04ED, 0x0026, 0x006F, 0x0002, 0x0088, + 0x0002, 0x005C, 0x0002, 0x0018, 0x0002, 0x00DE, 0x0002, 0x0028, 0x0002, 0x009C, 0x0002, 0x004A, 0x0002, + 0x007E, 0x0002, 0x0088, 0x0002, 0x00CC, 0x0002, 0x0018, 0x0002, 0x888F, 0x0002, 0x0028, 0x0002, 0x00FE, + 0x0002, 0x003A, 0x0002, 0x222F, 0x0002, 0x0088, 0x0002, 0x04FD, 0x0002, 0x0018, 0x0002, 0x00BE, 0x0002, + 0x0028, 0x0002, 0x00BF, 0x0002, 0x004A, 0x0002, 0x006E, 0x0002, 0x0088, 0x0002, 0x00AC, 0x0002, 0x0018, + 0x0002, 0x444F, 0x0002, 0x0028, 0x0002, 0x00EE, 0x0002, 0x003A, 0x0002, 0x113F, 0x0002, 0x0088, 0x0002, + 0x005C, 0x0002, 0x0018, 0x0002, 0x00CF, 0x0002, 0x0028, 0x0002, 0x009C, 0x0002, 0x004A, 0x0002, 0x006F, + 0x0002, 0x0088, 0x0002, 0x00CC, 0x0002, 0x0018, 0x0002, 0x009F, 0x0002, 0x0028, 0x0002, 0x00EF, 0x0002, + 0x003A, 0x0002, 0x233F, 0x0002, 0x0088, 0x0002, 0x04FD, 0x0002, 0x0018, 0x0002, 0x00AF, 0x0002, 0x0028, + 0x0002, 0x44FF, 0x0002, 0x004A, 0x0002, 0x005F, 0x0002, 0x0088, 0x0002, 0x00AC, 0x0002, 0x0018, 0x0002, + 0x007F, 0x0002, 0x0028, 0x0002, 0x00DF, 0x0002, 0x003A, 0x0002, 0x111F, 0x0002, 0x0028, 0x0002, 0x005C, + 0x0002, 0x008A, 0x0002, 0x00BF, 0x0002, 0x0018, 0x0002, 0x00FE, 0x0002, 0x00CC, 0x0002, 0x007E, 0x0002, + 0x0028, 0x0002, 0x8FFF, 0x0002, 0x004A, 0x0002, 0x007F, 0x0002, 0x0018, 0x0002, 0x00DF, 0x0002, 0x00AC, + 0x0002, 0x133F, 0x0002, 0x0028, 0x0002, 0x222D, 0x0002, 0x008A, 0x0002, 0x00BE, 0x0002, 0x0018, 0x0002, + 0x44EF, 0x0002, 0x2AAD, 0x0002, 0x006E, 0x0002, 0x0028, 0x0002, 0x15FF, 0x0002, 0x004A, 0x0002, 0x009E, + 0x0002, 0x0018, 0x0002, 0x00CF, 0x0002, 0x003C, 0x0002, 0x223F, 0x0002, 0x0028, 0x0002, 0x005C, 0x0002, + 0x008A, 0x0002, 0x2BBF, 0x0002, 0x0018, 0x0002, 0x04EF, 0x0002, 0x00CC, 0x0002, 0x006F, 0x0002, 0x0028, + 0x0002, 0x27FF, 0x0002, 0x004A, 0x0002, 0x009F, 0x0002, 0x0018, 0x0002, 0x00DE, 0x0002, 0x00AC, 0x0002, + 0x444F, 0x0002, 0x0028, 0x0002, 0x222D, 0x0002, 0x008A, 0x0002, 0x8AAF, 0x0002, 0x0018, 0x0002, 0x00EE, + 0x0002, 0x2AAD, 0x0002, 0x005F, 0x0002, 0x0028, 0x0002, 0x44FF, 0x0002, 0x004A, 0x0002, 0x888F, 0x0002, + 0x0018, 0x0002, 0xAAAF, 0x0002, 0x003C, 0x0002, 0x111F, 0x0004, 0x8FFD, 0x0028, 0x005C, 0x0004, 0x00BC, + 0x008A, 0x66FF, 0x0004, 0x00CD, 0x0018, 0x111D, 0x0004, 0x009C, 0x003A, 0x8AAF, 0x0004, 0x00FC, 0x0028, + 0x133D, 0x0004, 0x00AC, 0x004A, 0x3BBF, 0x0004, 0x2BBD, 0x0018, 0x5FFF, 0x0004, 0x006C, 0x157D, 0x455F, + 0x0004, 0x2FFD, 0x0028, 0x222D, 0x0004, 0x22AD, 0x008A, 0x44EF, 0x0004, 0x00CC, 0x0018, 0x4FFF, 0x0004, + 0x007C, 0x003A, 0x447F, 0x0004, 0x04DD, 0x0028, 0x233D, 0x0004, 0x009D, 0x004A, 0x00DE, 0x0004, 0x88BD, + 0x0018, 0xAFFF, 0x0004, 0x115D, 0x1FFD, 0x444F, 0x0004, 0x8FFD, 0x0028, 0x005C, 0x0004, 0x00BC, 0x008A, + 0x8CEF, 0x0004, 0x00CD, 0x0018, 0x111D, 0x0004, 0x009C, 0x003A, 0x888F, 0x0004, 0x00FC, 0x0028, 0x133D, + 0x0004, 0x00AC, 0x004A, 0x44DF, 0x0004, 0x2BBD, 0x0018, 0x8AFF, 0x0004, 0x006C, 0x157D, 0x006F, 0x0004, + 0x2FFD, 0x0028, 0x222D, 0x0004, 0x22AD, 0x008A, 0x00EE, 0x0004, 0x00CC, 0x0018, 0x2EEF, 0x0004, 0x007C, + 0x003A, 0x277F, 0x0004, 0x04DD, 0x0028, 0x233D, 0x0004, 0x009D, 0x004A, 0x1BBF, 0x0004, 0x88BD, 0x0018, + 0x37FF, 0x0004, 0x115D, 0x1FFD, 0x333F, 0x0002, 0x0088, 0x0002, 0x02ED, 0x0002, 0x00CA, 0x0002, 0x4CCF, + 0x0002, 0x0048, 0x0002, 0x23FF, 0x0002, 0x001A, 0x0002, 0x888F, 0x0002, 0x0088, 0x0002, 0x006C, 0x0002, + 0x002A, 0x0002, 0x00AF, 0x0002, 0x0048, 0x0002, 0x22EF, 0x0002, 0x00AC, 0x0002, 0x005F, 0x0002, 0x0088, + 0x0002, 0x444D, 0x0002, 0x00CA, 0x0002, 0xCCCF, 0x0002, 0x0048, 0x0002, 0x00FE, 0x0002, 0x001A, 0x0002, + 0x006F, 0x0002, 0x0088, 0x0002, 0x005C, 0x0002, 0x002A, 0x0002, 0x009F, 0x0002, 0x0048, 0x0002, 0x00DF, + 0x0002, 0x03FD, 0x0002, 0x222F, 0x0002, 0x0088, 0x0002, 0x02ED, 0x0002, 0x00CA, 0x0002, 0x8CCF, 0x0002, + 0x0048, 0x0002, 0x11FF, 0x0002, 0x001A, 0x0002, 0x007E, 0x0002, 0x0088, 0x0002, 0x006C, 0x0002, 0x002A, + 0x0002, 0x007F, 0x0002, 0x0048, 0x0002, 0x00EE, 0x0002, 0x00AC, 0x0002, 0x003E, 0x0002, 0x0088, 0x0002, + 0x444D, 0x0002, 0x00CA, 0x0002, 0x00BE, 0x0002, 0x0048, 0x0002, 0x00BF, 0x0002, 0x001A, 0x0002, 0x003F, + 0x0002, 0x0088, 0x0002, 0x005C, 0x0002, 0x002A, 0x0002, 0x009E, 0x0002, 0x0048, 0x0002, 0x00DE, 0x0002, + 0x03FD, 0x0002, 0x111F, 0x0004, 0x8AED, 0x0048, 0x888D, 0x0004, 0x00DC, 0x00CA, 0x3FFF, 0x0004, 0xCFFD, + 0x002A, 0x003D, 0x0004, 0x00BC, 0x005A, 0x8DDF, 0x0004, 0x8FFD, 0x0048, 0x006C, 0x0004, 0x027D, 0x008A, + 0x99FF, 0x0004, 0x00EC, 0x00FA, 0x003C, 0x0004, 0x00AC, 0x001A, 0x009F, 0x0004, 0x2FFD, 0x0048, 0x007C, + 0x0004, 0x44CD, 0x00CA, 0x67FF, 0x0004, 0x1FFD, 0x002A, 0x444D, 0x0004, 0x00AD, 0x005A, 0x8CCF, 0x0004, + 0x4FFD, 0x0048, 0x445D, 0x0004, 0x01BD, 0x008A, 0x4EEF, 0x0004, 0x45DD, 0x00FA, 0x111D, 0x0004, 0x009C, + 0x001A, 0x222F, 0x0004, 0x8AED, 0x0048, 0x888D, 0x0004, 0x00DC, 0x00CA, 0xAFFF, 0x0004, 0xCFFD, 0x002A, + 0x003D, 0x0004, 0x00BC, 0x005A, 0x11BF, 0x0004, 0x8FFD, 0x0048, 0x006C, 0x0004, 0x027D, 0x008A, 0x22EF, + 0x0004, 0x00EC, 0x00FA, 0x003C, 0x0004, 0x00AC, 0x001A, 0x227F, 0x0004, 0x2FFD, 0x0048, 0x007C, 0x0004, + 0x44CD, 0x00CA, 0x5DFF, 0x0004, 0x1FFD, 0x002A, 0x444D, 0x0004, 0x00AD, 0x005A, 0x006F, 0x0004, 0x4FFD, + 0x0048, 0x445D, 0x0004, 0x01BD, 0x008A, 0x11DF, 0x0004, 0x45DD, 0x00FA, 0x111D, 0x0004, 0x009C, 0x001A, + 0x155F, 0x0006, 0x00FC, 0x0018, 0x111D, 0x0048, 0x888D, 0x00AA, 0x4DDF, 0x0006, 0x2AAD, 0x005A, 0x67FF, + 0x0028, 0x223D, 0x00BC, 0xAAAF, 0x0006, 0x00EC, 0x0018, 0x5FFF, 0x0048, 0x006C, 0x008A, 0xCCCF, 0x0006, + 0x009D, 0x00CA, 0x44EF, 0x0028, 0x003C, 0x8FFD, 0x137F, 0x0006, 0x8EED, 0x0018, 0x1FFF, 0x0048, 0x007C, + 0x00AA, 0x4CCF, 0x0006, 0x227D, 0x005A, 0x1DDF, 0x0028, 0x444D, 0x4FFD, 0x155F, 0x0006, 0x00DC, 0x0018, + 0x2EEF, 0x0048, 0x445D, 0x008A, 0x22BF, 0x0006, 0x009C, 0x00CA, 0x8CDF, 0x0028, 0x222D, 0x2FFD, 0x226F, + 0x0006, 0x00FC, 0x0018, 0x111D, 0x0048, 0x888D, 0x00AA, 0x1BBF, 0x0006, 0x2AAD, 0x005A, 0x33FF, 0x0028, + 0x223D, 0x00BC, 0x8AAF, 0x0006, 0x00EC, 0x0018, 0x9BFF, 0x0048, 0x006C, 0x008A, 0x8ABF, 0x0006, 0x009D, + 0x00CA, 0x4EEF, 0x0028, 0x003C, 0x8FFD, 0x466F, 0x0006, 0x8EED, 0x0018, 0xCFFF, 0x0048, 0x007C, 0x00AA, + 0x8CCF, 0x0006, 0x227D, 0x005A, 0xAEEF, 0x0028, 0x444D, 0x4FFD, 0x477F, 0x0006, 0x00DC, 0x0018, 0xAFFF, + 0x0048, 0x445D, 0x008A, 0x2BBF, 0x0006, 0x009C, 0x00CA, 0x44DF, 0x0028, 0x222D, 0x2FFD, 0x133F, 0x00F6, + 0xAFFD, 0x1FFB, 0x003C, 0x0008, 0x23BD, 0x007A, 0x11DF, 0x00F6, 0x45DD, 0x2FFB, 0x4EEF, 0x00DA, 0x177D, + 0xCFFD, 0x377F, 0x00F6, 0x3FFD, 0x8FFB, 0x111D, 0x0008, 0x009C, 0x005A, 0x1BBF, 0x00F6, 0x00CD, 0x00BA, + 0x8DDF, 0x4FFB, 0x006C, 0x9BFD, 0x455F, 0x00F6, 0x67FD, 0x1FFB, 0x002C, 0x0008, 0x00AC, 0x007A, 0x009F, + 0x00F6, 0x00AD, 0x2FFB, 0x7FFF, 0x00DA, 0x004C, 0x5FFD, 0x477F, 0x00F6, 0x00EC, 0x8FFB, 0x001C, 0x0008, + 0x008C, 0x005A, 0x888F, 0x00F6, 0x00CC, 0x00BA, 0x2EEF, 0x4FFB, 0x115D, 0x8AED, 0x113F, 0x00F6, 0xAFFD, + 0x1FFB, 0x003C, 0x0008, 0x23BD, 0x007A, 0x1DDF, 0x00F6, 0x45DD, 0x2FFB, 0xBFFF, 0x00DA, 0x177D, 0xCFFD, + 0x447F, 0x00F6, 0x3FFD, 0x8FFB, 0x111D, 0x0008, 0x009C, 0x005A, 0x277F, 0x00F6, 0x00CD, 0x00BA, 0x22EF, + 0x4FFB, 0x006C, 0x9BFD, 0x444F, 0x00F6, 0x67FD, 0x1FFB, 0x002C, 0x0008, 0x00AC, 0x007A, 0x11BF, 0x00F6, + 0x00AD, 0x2FFB, 0xFFFF, 0x00DA, 0x004C, 0x5FFD, 0x233F, 0x00F6, 0x00EC, 0x8FFB, 0x001C, 0x0008, 0x008C, + 0x005A, 0x006F, 0x00F6, 0x00CC, 0x00BA, 0x8BBF, 0x4FFB, 0x115D, 0x8AED, 0x222F}; + +static const uint16_t dec_CxtVLC_table0[1024] = { + 0x0026, 0x00AA, 0x0046, 0x006C, 0x0086, 0x8AED, 0x0018, 0x8DDF, 0x0026, 0x01BD, 0x0046, 0x5FFF, 0x0086, + 0x027D, 0x005A, 0x155F, 0x0026, 0x003A, 0x0046, 0x444D, 0x0086, 0x4CCD, 0x0018, 0xCCCF, 0x0026, 0x2EFD, + 0x0046, 0x99FF, 0x0086, 0x009C, 0x00CA, 0x133F, 0x0026, 0x00AA, 0x0046, 0x445D, 0x0086, 0x8CCD, 0x0018, + 0x11DF, 0x0026, 0x4FFD, 0x0046, 0xCFFF, 0x0086, 0x009D, 0x005A, 0x007E, 0x0026, 0x003A, 0x0046, 0x1FFF, + 0x0086, 0x88AD, 0x0018, 0x00BE, 0x0026, 0x8FFD, 0x0046, 0x4EEF, 0x0086, 0x888D, 0x00CA, 0x111F, 0x0026, + 0x00AA, 0x0046, 0x006C, 0x0086, 0x8AED, 0x0018, 0x45DF, 0x0026, 0x01BD, 0x0046, 0x22EF, 0x0086, 0x027D, + 0x005A, 0x227F, 0x0026, 0x003A, 0x0046, 0x444D, 0x0086, 0x4CCD, 0x0018, 0x11BF, 0x0026, 0x2EFD, 0x0046, + 0x00FE, 0x0086, 0x009C, 0x00CA, 0x223F, 0x0026, 0x00AA, 0x0046, 0x445D, 0x0086, 0x8CCD, 0x0018, 0x00DE, + 0x0026, 0x4FFD, 0x0046, 0xABFF, 0x0086, 0x009D, 0x005A, 0x006F, 0x0026, 0x003A, 0x0046, 0x6EFF, 0x0086, + 0x88AD, 0x0018, 0x2AAF, 0x0026, 0x8FFD, 0x0046, 0x00EE, 0x0086, 0x888D, 0x00CA, 0x222F, 0x0004, 0x00CA, + 0x0088, 0x027D, 0x0004, 0x4CCD, 0x0028, 0x00FE, 0x0004, 0x2AFD, 0x0048, 0x005C, 0x0004, 0x009D, 0x0018, + 0x00DE, 0x0004, 0x01BD, 0x0088, 0x006C, 0x0004, 0x88AD, 0x0028, 0x11DF, 0x0004, 0x8AED, 0x0048, 0x003C, + 0x0004, 0x888D, 0x0018, 0x111F, 0x0004, 0x00CA, 0x0088, 0x006D, 0x0004, 0x88CD, 0x0028, 0x88FF, 0x0004, + 0x8BFD, 0x0048, 0x444D, 0x0004, 0x009C, 0x0018, 0x00BE, 0x0004, 0x4EFD, 0x0088, 0x445D, 0x0004, 0x00AC, + 0x0028, 0x00EE, 0x0004, 0x45DD, 0x0048, 0x222D, 0x0004, 0x003D, 0x0018, 0x007E, 0x0004, 0x00CA, 0x0088, + 0x027D, 0x0004, 0x4CCD, 0x0028, 0x1FFF, 0x0004, 0x2AFD, 0x0048, 0x005C, 0x0004, 0x009D, 0x0018, 0x11BF, + 0x0004, 0x01BD, 0x0088, 0x006C, 0x0004, 0x88AD, 0x0028, 0x22EF, 0x0004, 0x8AED, 0x0048, 0x003C, 0x0004, + 0x888D, 0x0018, 0x227F, 0x0004, 0x00CA, 0x0088, 0x006D, 0x0004, 0x88CD, 0x0028, 0x4EEF, 0x0004, 0x8BFD, + 0x0048, 0x444D, 0x0004, 0x009C, 0x0018, 0x2AAF, 0x0004, 0x4EFD, 0x0088, 0x445D, 0x0004, 0x00AC, 0x0028, + 0x8DDF, 0x0004, 0x45DD, 0x0048, 0x222D, 0x0004, 0x003D, 0x0018, 0x155F, 0x0004, 0x005A, 0x0088, 0x006C, + 0x0004, 0x88DD, 0x0028, 0x23FF, 0x0004, 0x11FD, 0x0048, 0x444D, 0x0004, 0x00AD, 0x0018, 0x00BE, 0x0004, + 0x137D, 0x0088, 0x155D, 0x0004, 0x00CC, 0x0028, 0x00DE, 0x0004, 0x02ED, 0x0048, 0x111D, 0x0004, 0x009D, + 0x0018, 0x007E, 0x0004, 0x005A, 0x0088, 0x455D, 0x0004, 0x44CD, 0x0028, 0x00EE, 0x0004, 0x1FFD, 0x0048, + 0x003C, 0x0004, 0x00AC, 0x0018, 0x555F, 0x0004, 0x47FD, 0x0088, 0x113D, 0x0004, 0x02BD, 0x0028, 0x477F, + 0x0004, 0x4CDD, 0x0048, 0x8FFF, 0x0004, 0x009C, 0x0018, 0x222F, 0x0004, 0x005A, 0x0088, 0x006C, 0x0004, + 0x88DD, 0x0028, 0x00FE, 0x0004, 0x11FD, 0x0048, 0x444D, 0x0004, 0x00AD, 0x0018, 0x888F, 0x0004, 0x137D, + 0x0088, 0x155D, 0x0004, 0x00CC, 0x0028, 0x8CCF, 0x0004, 0x02ED, 0x0048, 0x111D, 0x0004, 0x009D, 0x0018, + 0x006F, 0x0004, 0x005A, 0x0088, 0x455D, 0x0004, 0x44CD, 0x0028, 0x1DDF, 0x0004, 0x1FFD, 0x0048, 0x003C, + 0x0004, 0x00AC, 0x0018, 0x227F, 0x0004, 0x47FD, 0x0088, 0x113D, 0x0004, 0x02BD, 0x0028, 0x22BF, 0x0004, + 0x4CDD, 0x0048, 0x22EF, 0x0004, 0x009C, 0x0018, 0x233F, 0x0006, 0x4DDD, 0x4FFB, 0xCFFF, 0x0018, 0x113D, + 0x005A, 0x888F, 0x0006, 0x23BD, 0x008A, 0x00EE, 0x002A, 0x155D, 0xAAFD, 0x277F, 0x0006, 0x44CD, 0x8FFB, + 0x44EF, 0x0018, 0x467D, 0x004A, 0x2AAF, 0x0006, 0x00AC, 0x555B, 0x99DF, 0x1FFB, 0x003C, 0x5FFD, 0x266F, + 0x0006, 0x1DDD, 0x4FFB, 0x6EFF, 0x0018, 0x177D, 0x005A, 0x1BBF, 0x0006, 0x88AD, 0x008A, 0x5DDF, 0x002A, + 0x444D, 0x2FFD, 0x667F, 0x0006, 0x00CC, 0x8FFB, 0x2EEF, 0x0018, 0x455D, 0x004A, 0x119F, 0x0006, 0x009C, + 0x555B, 0x8CCF, 0x1FFB, 0x111D, 0x8CED, 0x006E, 0x0006, 0x4DDD, 0x4FFB, 0x3FFF, 0x0018, 0x113D, 0x005A, + 0x11BF, 0x0006, 0x23BD, 0x008A, 0x8DDF, 0x002A, 0x155D, 0xAAFD, 0x222F, 0x0006, 0x44CD, 0x8FFB, 0x00FE, + 0x0018, 0x467D, 0x004A, 0x899F, 0x0006, 0x00AC, 0x555B, 0x00DE, 0x1FFB, 0x003C, 0x5FFD, 0x446F, 0x0006, + 0x1DDD, 0x4FFB, 0x9BFF, 0x0018, 0x177D, 0x005A, 0x00BE, 0x0006, 0x88AD, 0x008A, 0xCDDF, 0x002A, 0x444D, + 0x2FFD, 0x007E, 0x0006, 0x00CC, 0x8FFB, 0x4EEF, 0x0018, 0x455D, 0x004A, 0x377F, 0x0006, 0x009C, 0x555B, + 0x8BBF, 0x1FFB, 0x111D, 0x8CED, 0x233F, 0x0004, 0x00AA, 0x0088, 0x047D, 0x0004, 0x01DD, 0x0028, 0x11DF, + 0x0004, 0x27FD, 0x0048, 0x005C, 0x0004, 0x8AAD, 0x0018, 0x2BBF, 0x0004, 0x009C, 0x0088, 0x006C, 0x0004, + 0x00CC, 0x0028, 0x00EE, 0x0004, 0x8CED, 0x0048, 0x222D, 0x0004, 0x888D, 0x0018, 0x007E, 0x0004, 0x00AA, + 0x0088, 0x006D, 0x0004, 0x88CD, 0x0028, 0x00FE, 0x0004, 0x19FD, 0x0048, 0x003C, 0x0004, 0x2AAD, 0x0018, + 0xAAAF, 0x0004, 0x8BFD, 0x0088, 0x005D, 0x0004, 0x00BD, 0x0028, 0x4CCF, 0x0004, 0x44ED, 0x0048, 0x4FFF, + 0x0004, 0x223D, 0x0018, 0x111F, 0x0004, 0x00AA, 0x0088, 0x047D, 0x0004, 0x01DD, 0x0028, 0x99FF, 0x0004, + 0x27FD, 0x0048, 0x005C, 0x0004, 0x8AAD, 0x0018, 0x00BE, 0x0004, 0x009C, 0x0088, 0x006C, 0x0004, 0x00CC, + 0x0028, 0x00DE, 0x0004, 0x8CED, 0x0048, 0x222D, 0x0004, 0x888D, 0x0018, 0x444F, 0x0004, 0x00AA, 0x0088, + 0x006D, 0x0004, 0x88CD, 0x0028, 0x2EEF, 0x0004, 0x19FD, 0x0048, 0x003C, 0x0004, 0x2AAD, 0x0018, 0x447F, + 0x0004, 0x8BFD, 0x0088, 0x005D, 0x0004, 0x00BD, 0x0028, 0x009F, 0x0004, 0x44ED, 0x0048, 0x67FF, 0x0004, + 0x223D, 0x0018, 0x133F, 0x0006, 0x00CC, 0x008A, 0x9DFF, 0x2FFB, 0x467D, 0x1FFD, 0x99BF, 0x0006, 0x2AAD, + 0x002A, 0x66EF, 0x4FFB, 0x005C, 0x2EED, 0x377F, 0x0006, 0x89BD, 0x004A, 0x00FE, 0x8FFB, 0x006C, 0x67FD, + 0x889F, 0x0006, 0x888D, 0x001A, 0x5DDF, 0x00AA, 0x222D, 0x89DD, 0x444F, 0x0006, 0x2BBD, 0x008A, 0xCFFF, + 0x2FFB, 0x226D, 0x009C, 0x00BE, 0x0006, 0xAAAD, 0x002A, 0x1DDF, 0x4FFB, 0x003C, 0x4DDD, 0x466F, 0x0006, + 0x8AAD, 0x004A, 0xAEEF, 0x8FFB, 0x445D, 0x8EED, 0x177F, 0x0006, 0x233D, 0x001A, 0x4CCF, 0x00AA, 0xAFFF, + 0x88CD, 0x133F, 0x0006, 0x00CC, 0x008A, 0x77FF, 0x2FFB, 0x467D, 0x1FFD, 0x3BBF, 0x0006, 0x2AAD, 0x002A, + 0x00EE, 0x4FFB, 0x005C, 0x2EED, 0x007E, 0x0006, 0x89BD, 0x004A, 0x4EEF, 0x8FFB, 0x006C, 0x67FD, 0x667F, + 0x0006, 0x888D, 0x001A, 0x00DE, 0x00AA, 0x222D, 0x89DD, 0x333F, 0x0006, 0x2BBD, 0x008A, 0x57FF, 0x2FFB, + 0x226D, 0x009C, 0x199F, 0x0006, 0xAAAD, 0x002A, 0x99DF, 0x4FFB, 0x003C, 0x4DDD, 0x155F, 0x0006, 0x8AAD, + 0x004A, 0xCEEF, 0x8FFB, 0x445D, 0x8EED, 0x277F, 0x0006, 0x233D, 0x001A, 0x1BBF, 0x00AA, 0x3FFF, 0x88CD, + 0x111F, 0x0006, 0x45DD, 0x2FFB, 0x111D, 0x0018, 0x467D, 0x8FFD, 0xCCCF, 0x0006, 0x19BD, 0x004A, 0x22EF, + 0x002A, 0x222D, 0x3FFD, 0x888F, 0x0006, 0x00CC, 0x008A, 0x00FE, 0x0018, 0x115D, 0xCFFD, 0x8AAF, 0x0006, + 0x00AC, 0x003A, 0x8CDF, 0x1FFB, 0x133D, 0x66FD, 0x466F, 0x0006, 0x8CCD, 0x2FFB, 0x5FFF, 0x0018, 0x006C, + 0x4FFD, 0xABBF, 0x0006, 0x22AD, 0x004A, 0x00EE, 0x002A, 0x233D, 0xAEFD, 0x377F, 0x0006, 0x2BBD, 0x008A, + 0x55DF, 0x0018, 0x005C, 0x177D, 0x119F, 0x0006, 0x009C, 0x003A, 0x4CCF, 0x1FFB, 0x333D, 0x8EED, 0x444F, + 0x0006, 0x45DD, 0x2FFB, 0x111D, 0x0018, 0x467D, 0x8FFD, 0x99BF, 0x0006, 0x19BD, 0x004A, 0x2EEF, 0x002A, + 0x222D, 0x3FFD, 0x667F, 0x0006, 0x00CC, 0x008A, 0x4EEF, 0x0018, 0x115D, 0xCFFD, 0x899F, 0x0006, 0x00AC, + 0x003A, 0x00DE, 0x1FFB, 0x133D, 0x66FD, 0x226F, 0x0006, 0x8CCD, 0x2FFB, 0x9BFF, 0x0018, 0x006C, 0x4FFD, + 0x00BE, 0x0006, 0x22AD, 0x004A, 0x1DDF, 0x002A, 0x233D, 0xAEFD, 0x007E, 0x0006, 0x2BBD, 0x008A, 0xCEEF, + 0x0018, 0x005C, 0x177D, 0x277F, 0x0006, 0x009C, 0x003A, 0x8BBF, 0x1FFB, 0x333D, 0x8EED, 0x455F, 0x1FF9, + 0x1DDD, 0xAFFB, 0x00DE, 0x8FF9, 0x001C, 0xFFFB, 0x477F, 0x4FF9, 0x177D, 0x3FFB, 0x3BBF, 0x2FF9, 0xAEEF, + 0x8EED, 0x444F, 0x1FF9, 0x22AD, 0x000A, 0x8BBF, 0x8FF9, 0x00FE, 0xCFFD, 0x007E, 0x4FF9, 0x115D, 0x5FFB, + 0x577F, 0x2FF9, 0x8DDF, 0x2EED, 0x333F, 0x1FF9, 0x2BBD, 0xAFFB, 0x88CF, 0x8FF9, 0xBFFF, 0xFFFB, 0x377F, + 0x4FF9, 0x006D, 0x3FFB, 0x00BE, 0x2FF9, 0x66EF, 0x9FFD, 0x133F, 0x1FF9, 0x009D, 0x000A, 0xABBF, 0x8FF9, + 0xDFFF, 0x6FFD, 0x006E, 0x4FF9, 0x002C, 0x5FFB, 0x888F, 0x2FF9, 0xCDDF, 0x4DDD, 0x222F, 0x1FF9, 0x1DDD, + 0xAFFB, 0x4CCF, 0x8FF9, 0x001C, 0xFFFB, 0x277F, 0x4FF9, 0x177D, 0x3FFB, 0x99BF, 0x2FF9, 0xCEEF, 0x8EED, + 0x004E, 0x1FF9, 0x22AD, 0x000A, 0x00AE, 0x8FF9, 0x7FFF, 0xCFFD, 0x005E, 0x4FF9, 0x115D, 0x5FFB, 0x009E, + 0x2FF9, 0x5DDF, 0x2EED, 0x003E, 0x1FF9, 0x2BBD, 0xAFFB, 0x00CE, 0x8FF9, 0xEFFF, 0xFFFB, 0x667F, 0x4FF9, + 0x006D, 0x3FFB, 0x8AAF, 0x2FF9, 0x00EE, 0x9FFD, 0x233F, 0x1FF9, 0x009D, 0x000A, 0x1BBF, 0x8FF9, 0x4EEF, + 0x6FFD, 0x455F, 0x4FF9, 0x002C, 0x5FFB, 0x008E, 0x2FF9, 0x99DF, 0x4DDD, 0x111F}; +#endif /* AVCODEC_JPEG2000HTDEC_H */ \ No newline at end of file -- 2.37.2 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
reply other threads:[~2022-09-07 19:24 UTC|newest] Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20220907192417.140381-1-etemesicaleb@gmail.com \ --to=etemesicaleb@gmail.com \ --cc=ffmpeg-devel@ffmpeg.org \ --cc=pal@sandflow.com \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git