* [FFmpeg-devel] [PATCH 1/2] avcodec/jpeg2000dec: Add support for placeholder passes, CAP, and CPF markers
@ 2024-06-15 3:15 Osamu Watanabe
2024-06-15 3:15 ` [FFmpeg-devel] [PATCH 2/2] avcodec/jpeg2000dec: fix tilepart processing Osamu Watanabe
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Osamu Watanabe @ 2024-06-15 3:15 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Osamu Watanabe, pal
Signed-off-by: Osamu Watanabe <owatanab@es.takushoku-u.ac.jp>
---
libavcodec/jpeg2000.h | 10 +
libavcodec/jpeg2000dec.c | 454 ++++++++++++++++++++++++++++++-------
libavcodec/jpeg2000dec.h | 7 +
libavcodec/jpeg2000htdec.c | 225 ++++++++++--------
libavcodec/jpeg2000htdec.h | 2 +-
5 files changed, 518 insertions(+), 180 deletions(-)
diff --git a/libavcodec/jpeg2000.h b/libavcodec/jpeg2000.h
index d004c08f10..93221d90ca 100644
--- a/libavcodec/jpeg2000.h
+++ b/libavcodec/jpeg2000.h
@@ -37,12 +37,14 @@
enum Jpeg2000Markers {
JPEG2000_SOC = 0xff4f, // start of codestream
+ JPEG2000_CAP = 0xff50, // extended capabilities
JPEG2000_SIZ = 0xff51, // image and tile size
JPEG2000_COD, // coding style default
JPEG2000_COC, // coding style component
JPEG2000_TLM = 0xff55, // tile-part length, main header
JPEG2000_PLM = 0xff57, // packet length, main header
JPEG2000_PLT, // packet length, tile-part header
+ JPEG2000_CPF, // corresponding profile
JPEG2000_QCD = 0xff5c, // quantization default
JPEG2000_QCC, // quantization component
JPEG2000_RGN, // region of interest
@@ -58,6 +60,12 @@ enum Jpeg2000Markers {
JPEG2000_EOC = 0xffd9, // end of codestream
};
+enum JPEG2000_Ccap15_b14_15_params {
+ HTJ2K_HTONLY = 0, // HTONLY, bit 14 and 15 are 0
+ HTJ2K_HTDECLARED, // HTDECLARED, bit 14 = 1 and bit 15 = 0
+ HTJ2K_MIXED = 3, // MIXED, bit 14 and 15 are 1
+};
+
#define JPEG2000_SOP_FIXED_BYTES 0xFF910004
#define JPEG2000_SOP_BYTE_LENGTH 6
@@ -192,6 +200,8 @@ typedef struct Jpeg2000Cblk {
/* specific to HT code-blocks */
int zbp;
int pass_lengths[2];
+ uint8_t modes; // copy of SPcod/SPcoc field to parse HT-MIXED mode
+ uint8_t ht_plhd; // are we looking for HT placeholder passes?
} Jpeg2000Cblk; // code block
typedef struct Jpeg2000Prec {
diff --git a/libavcodec/jpeg2000dec.c b/libavcodec/jpeg2000dec.c
index d15502a527..d299c67cc7 100644
--- a/libavcodec/jpeg2000dec.c
+++ b/libavcodec/jpeg2000dec.c
@@ -54,6 +54,15 @@
#define HAD_COC 0x01
#define HAD_QCC 0x02
+// Values of flag for placeholder passes
+enum HT_PLHD_STATUS {
+ HT_PLHD_OFF,
+ HT_PLHD_ON
+};
+
+#define HT_MIXED 0x80 // bit 7 of SPcod/SPcoc
+
+
/* get_bits functions for JPEG2000 packet bitstream
* It is a get_bit function with a bit-stuffing routine. If the value of the
* byte is 0xFF, the next byte includes an extra zero bit stuffed into the MSB.
@@ -382,6 +391,9 @@ static int get_siz(Jpeg2000DecoderContext *s)
} else if (ncomponents == 1 && s->precision == 8) {
s->avctx->pix_fmt = AV_PIX_FMT_GRAY8;
i = 0;
+ } else if (ncomponents == 1 && s->precision == 12) {
+ s->avctx->pix_fmt = AV_PIX_FMT_GRAY16LE;
+ i = 0;
}
}
@@ -408,6 +420,73 @@ static int get_siz(Jpeg2000DecoderContext *s)
s->avctx->bits_per_raw_sample = s->precision;
return 0;
}
+/* get extended capabilities (CAP) marker segment */
+static int get_cap(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c)
+{
+ uint32_t Pcap;
+ uint16_t Ccap_i[32] = { 0 };
+ uint16_t Ccap_15;
+ uint8_t P;
+
+ if (bytestream2_get_bytes_left(&s->g) < 6) {
+ av_log(s->avctx, AV_LOG_ERROR, "Insufficient space for CAP\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ Pcap = bytestream2_get_be32u(&s->g);
+ s->isHT = (Pcap >> (31 - (15 - 1))) & 1;
+ for (int i = 0; i < 32; i++) {
+ if ((Pcap >> (31 - i)) & 1)
+ Ccap_i[i] = bytestream2_get_be16u(&s->g);
+ }
+ Ccap_15 = Ccap_i[14];
+ if (s->isHT == 1) {
+ av_log(s->avctx, AV_LOG_INFO, "This is an HTJ2K codestream.\n");
+ // Bits 14-15
+ switch ((Ccap_15 >> 14) & 0x3) {
+ case 0x3:
+ s->Ccap15_b14_15 = HTJ2K_MIXED;
+ break;
+ case 0x1:
+ s->Ccap15_b14_15 = HTJ2K_HTDECLARED;
+ break;
+ case 0x0:
+ s->Ccap15_b14_15 = HTJ2K_HTONLY;
+ break;
+ default:
+ av_log(s->avctx, AV_LOG_ERROR, "Unknown CCap value.\n");
+ return AVERROR(EINVAL);
+ break;
+ }
+ // Bit 13
+ if ((Ccap_15 >> 13) & 1) {
+ av_log(s->avctx, AV_LOG_ERROR, "MULTIHT set is not supported.\n");
+ return AVERROR_PATCHWELCOME;
+ }
+ // Bit 12
+ s->Ccap15_b12 = (Ccap_15 >> 12) & 1;
+ // Bit 11
+ s->Ccap15_b11 = (Ccap_15 >> 11) & 1;
+ // Bit 5
+ s->Ccap15_b05 = (Ccap_15 >> 5) & 1;
+ // Bit 0-4
+ P = Ccap_15 & 0x1F;
+ if (!P)
+ s->HT_MAGB = 8;
+ else if (P < 20)
+ s->HT_MAGB = P + 8;
+ else if (P < 31)
+ s->HT_MAGB = 4 * (P - 19) + 27;
+ else
+ s->HT_MAGB = 74;
+
+ if (s->HT_MAGB > 31) {
+ av_log(s->avctx, AV_LOG_ERROR, "Available internal precision is exceeded (MAGB> 31).\n");
+ return AVERROR_PATCHWELCOME;
+ }
+ }
+ return 0;
+}
/* get common part for COD and COC segments */
static int get_cox(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c)
@@ -802,6 +881,15 @@ static int read_crg(Jpeg2000DecoderContext *s, int n)
bytestream2_skip(&s->g, n - 2);
return 0;
}
+
+static int read_cpf(Jpeg2000DecoderContext *s, int n)
+{
+ if (bytestream2_get_bytes_left(&s->g) < (n - 2))
+ return AVERROR_INVALIDDATA;
+ bytestream2_skip(&s->g, n - 2);
+ return 0;
+}
+
/* Tile-part lengths: see ISO 15444-1:2002, section A.7.1
* Used to know the number of tile parts and lengths.
* There may be multiple TLMs in the header.
@@ -965,6 +1053,10 @@ static int init_tile(Jpeg2000DecoderContext *s, int tileno)
comp->roi_shift = s->roi_shift[compno];
if (!codsty->init)
return AVERROR_INVALIDDATA;
+ if (s->isHT && (!s->Ccap15_b05) && (!codsty->transform))
+ av_log(s->avctx, AV_LOG_WARNING, "Transformation = 0 (lossy DWT) is found in HTREV HT set\n");
+ if (s->isHT && s->Ccap15_b14_15 != (codsty->cblk_style >> 6) && s->Ccap15_b14_15 != HTJ2K_HTONLY)
+ av_log(s->avctx, AV_LOG_WARNING, "SPcod/SPcoc value does not match bit 14-15 values of Ccap15\n");
if (ret = ff_jpeg2000_init_component(comp, codsty, qntsty,
s->cbps[compno], s->cdx[compno],
s->cdy[compno], s->avctx))
@@ -1067,100 +1159,275 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile,
int incl, newpasses, llen;
void *tmp;
- if (cblk->npasses)
- incl = get_bits(s, 1);
- else
+ if (!cblk->incl) {
+ incl = 0;
+ cblk->modes = codsty->cblk_style;
+ if (cblk->modes >= JPEG2000_CTSY_HTJ2K_F)
+ cblk->ht_plhd = HT_PLHD_ON;
+ if (layno > 0)
+ incl = tag_tree_decode(s, prec->cblkincl + cblkno, 0 + 1) == 0;
incl = tag_tree_decode(s, prec->cblkincl + cblkno, layno + 1) == layno;
- if (!incl)
- continue;
- else if (incl < 0)
- return incl;
-
- if (!cblk->npasses) {
- int zbp = tag_tree_decode(s, prec->zerobits + cblkno, 100);
- int v = expn[bandno] + numgbits - 1 - zbp;
- if (v < 0 || v > 30) {
- av_log(s->avctx, AV_LOG_ERROR,
- "nonzerobits %d invalid or unsupported\n", v);
- return AVERROR_INVALIDDATA;
+ if (incl) {
+ int zbp = tag_tree_decode(s, prec->zerobits + cblkno, 100);
+ int v = expn[bandno] + numgbits - 1 - (zbp - tile->comp->roi_shift);
+ if (v < 0 || v > 30) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "nonzerobits %d invalid or unsupported\n", v);
+ return AVERROR_INVALIDDATA;
+ }
+ cblk->incl = 1;
+ cblk->nonzerobits = v;
+ cblk->zbp = zbp;
+ cblk->lblock = 3;
}
- cblk->zbp = zbp;
- cblk->nonzerobits = v;
- }
- if ((newpasses = getnpasses(s)) < 0)
- return newpasses;
- av_assert2(newpasses > 0);
- if (cblk->npasses + newpasses >= JPEG2000_MAX_PASSES) {
- avpriv_request_sample(s->avctx, "Too many passes");
- return AVERROR_PATCHWELCOME;
- }
- if ((llen = getlblockinc(s)) < 0)
- return llen;
- if (cblk->lblock + llen + av_log2(newpasses) > 16) {
- avpriv_request_sample(s->avctx,
- "Block with length beyond 16 bits");
- return AVERROR_PATCHWELCOME;
+ } else {
+ incl = get_bits(s, 1);
}
- cblk->lblock += llen;
-
- cblk->nb_lengthinc = 0;
- cblk->nb_terminationsinc = 0;
- av_free(cblk->lengthinc);
- cblk->lengthinc = av_calloc(newpasses, sizeof(*cblk->lengthinc));
- if (!cblk->lengthinc)
- return AVERROR(ENOMEM);
- tmp = av_realloc_array(cblk->data_start, cblk->nb_terminations + newpasses + 1, sizeof(*cblk->data_start));
- if (!tmp)
- return AVERROR(ENOMEM);
- cblk->data_start = tmp;
- do {
- int newpasses1 = 0;
-
- while (newpasses1 < newpasses) {
- newpasses1 ++;
- if (needs_termination(codsty->cblk_style, cblk->npasses + newpasses1 - 1)) {
- cblk->nb_terminationsinc ++;
- break;
+ if (incl) {
+ uint8_t bypass_term_threshold = 0;
+ uint8_t bits_to_read = 0;
+ uint32_t segment_bytes = 0;
+ int32_t segment_passes = 0;
+ uint8_t next_segment_passes = 0;
+ int32_t href_passes, pass_bound;
+ uint32_t tmp_length = 0;
+
+ if ((newpasses = getnpasses(s)) <= 0)
+ return newpasses;
+ if (cblk->npasses + newpasses >= JPEG2000_MAX_PASSES) {
+ avpriv_request_sample(s->avctx, "Too many passes");
+ return AVERROR_PATCHWELCOME;
+ }
+ if ((llen = getlblockinc(s)) < 0)
+ return llen;
+ if (cblk->lblock + llen + av_log2(newpasses) > 16) {
+ avpriv_request_sample(s->avctx,
+ "Block with length beyond 16 bits");
+ return AVERROR_PATCHWELCOME;
+ }
+ cblk->nb_lengthinc = 0;
+ cblk->nb_terminationsinc = 0;
+ av_free(cblk->lengthinc);
+ cblk->lengthinc = av_calloc(newpasses, sizeof(*cblk->lengthinc));
+ if (!cblk->lengthinc)
+ return AVERROR(ENOMEM);
+ tmp = av_realloc_array(cblk->data_start, cblk->nb_terminations + newpasses + 1,
+ sizeof(*cblk->data_start));
+ if (!tmp)
+ return AVERROR(ENOMEM);
+ cblk->data_start = tmp;
+ cblk->lblock += llen;
+
+ if (cblk->ht_plhd) {
+ href_passes = (cblk->npasses + newpasses - 1) % 3;
+ segment_passes = newpasses - href_passes;
+ pass_bound = 2;
+ bits_to_read = cblk->lblock;
+ if (segment_passes < 1) {
+ // No possible HT Cleanup pass here; may have placeholder passes
+ // or an original J2K block bit-stream (in MIXED mode).
+ segment_passes = newpasses;
+ while (pass_bound <= segment_passes) {
+ bits_to_read++;
+ pass_bound += pass_bound;
+ }
+ segment_bytes = get_bits(s, bits_to_read);
+ if (segment_bytes) {
+ if (cblk->modes & HT_MIXED) {
+ cblk->ht_plhd = HT_PLHD_OFF;
+ cblk->modes &= (uint8_t) (~(JPEG2000_CTSY_HTJ2K_F));
+ }
+ else {
+ av_log(s->avctx, AV_LOG_WARNING, "Length information for a HT-codeblock is invalid\n");
+ }
+ }
+ } else {
+ while (pass_bound <= segment_passes) {
+ bits_to_read++;
+ pass_bound += pass_bound;
+ }
+ segment_bytes = get_bits(s, bits_to_read);
+ if (segment_bytes) {
+ // No more placeholder passes
+ if (!(cblk->modes & HT_MIXED)) {
+ // Must be the first HT Cleanup pass
+ if (segment_bytes < 2)
+ av_log(s->avctx, AV_LOG_WARNING, "Length information for a HT-codeblock is invalid\n");
+ next_segment_passes = 2;
+ cblk->ht_plhd = HT_PLHD_OFF;
+ // Write length information for HT CleanUp segment
+ cblk->pass_lengths[0] = segment_bytes;
+ } else if (cblk->lblock > 3 && segment_bytes > 1
+ && (segment_bytes >> (bits_to_read - 1)) == 0) {
+ // Must be the first HT Cleanup pass, since length MSB is 0
+ next_segment_passes = 2;
+ cblk->ht_plhd = HT_PLHD_OFF;
+ // Write length information for HT CleanUp segment
+ cblk->pass_lengths[0] = segment_bytes;
+ } else {
+ // Must have an original (non-HT) block coding pass
+ cblk->modes &= (uint8_t) (~(JPEG2000_CTSY_HTJ2K_F));
+ cblk->ht_plhd = HT_PLHD_OFF;
+ segment_passes = newpasses;
+ while (pass_bound <= segment_passes) {
+ bits_to_read++;
+ pass_bound += pass_bound;
+ segment_bytes <<= 1;
+ segment_bytes += get_bits(s, 1);
+ }
+ }
+ } else {
+ // Probably parsing placeholder passes, but we need to read an
+ // extra length bit to verify this, since prior to the first
+ // HT Cleanup pass, the number of length bits read for a
+ // contributing code-block is dependent on the number of passes
+ // being included, as if it were a non-HT code-block.
+ segment_passes = newpasses;
+ if (pass_bound <= segment_passes) {
+ while (1) {
+ bits_to_read++;
+ pass_bound += pass_bound;
+ segment_bytes <<= 1;
+ segment_bytes += get_bits(s, 1);
+ if (pass_bound > segment_passes)
+ break;
+ }
+ if (segment_bytes) {
+ if (cblk->modes & HT_MIXED) {
+ cblk->modes &= (uint8_t) (~(JPEG2000_CTSY_HTJ2K_F));
+ cblk->ht_plhd = HT_PLHD_OFF;
+ } else {
+ av_log(s->avctx, AV_LOG_WARNING, "Length information for a HT-codeblock is invalid\n");
+ }
+ }
+ }
+ }
}
+ } else if (cblk->modes & JPEG2000_CTSY_HTJ2K_F) {
+ // Quality layer commences with a non-initial HT coding pass
+ if(bits_to_read != 0)
+ av_log(s->avctx, AV_LOG_WARNING, "Length information for a HT-codeblock is invalid\n");
+ segment_passes = cblk->npasses % 3;
+ if (segment_passes == 0) {
+ // newpasses is a HT Cleanup pass; next segment has refinement passes
+ segment_passes = 1;
+ next_segment_passes = 2;
+ if (segment_bytes == 1)
+ av_log(s->avctx, AV_LOG_WARNING, "Length information for a HT-codeblock is invalid\n");
+ } else {
+ // newpasses = 1 means npasses is HT SigProp; 2 means newpasses is
+ // HT MagRef pass
+ segment_passes = newpasses > 1 ? 3 - segment_passes : 1;
+ next_segment_passes = 1;
+ bits_to_read = av_log2(segment_passes);
+ }
+ bits_to_read = (uint8_t) (bits_to_read + cblk->lblock);
+ segment_bytes = get_bits(s, bits_to_read);
+ // Write length information for HT Refinment segment
+ cblk->pass_lengths[1] += segment_bytes;
+ } else if (!(cblk->modes & (JPEG2000_CBLK_TERMALL | JPEG2000_CBLK_BYPASS))) {
+ // Common case for non-HT code-blocks; we have only one segment
+ bits_to_read = (uint8_t) cblk->lblock + av_log2((uint8_t) newpasses);
+ segment_bytes = get_bits(s, bits_to_read);
+ segment_passes = newpasses;
+ } else if (cblk->modes & JPEG2000_CBLK_TERMALL) {
+ // RESTART MODE
+ bits_to_read = cblk->lblock;
+ segment_bytes = get_bits(s, bits_to_read);
+ segment_passes = 1;
+ next_segment_passes = 1;
+ cblk->nb_terminationsinc++;
+ } else {
+ // BYPASS MODE
+ bypass_term_threshold = 10;
+ if(bits_to_read != 0)
+ av_log(s->avctx, AV_LOG_WARNING, "Length information for a codeblock is invalid\n");
+ if (cblk->npasses < bypass_term_threshold) {
+ // May have from 1 to 10 uninterrupted passes before 1st RAW SigProp
+ segment_passes = bypass_term_threshold - cblk->npasses;
+ if (segment_passes > newpasses)
+ segment_passes = newpasses;
+ while ((2 << bits_to_read) <= segment_passes)
+ bits_to_read++;
+ next_segment_passes = 2;
+ } else if ((cblk->npasses - bypass_term_threshold) % 3 < 2) {
+ // 0 means newpasses is a RAW SigProp; 1 means newpasses is a RAW MagRef pass
+ segment_passes = newpasses > 1 ? 2 - (cblk->npasses - bypass_term_threshold) % 3 : 1;
+ bits_to_read = av_log2(segment_passes);
+ next_segment_passes = 1;
+ } else {
+ // newpasses is an isolated Cleanup pass that precedes a RAW SigProp pass
+ segment_passes = 1;
+ next_segment_passes = 2;
+ }
+ bits_to_read = (uint8_t) (bits_to_read + cblk->lblock);
+ segment_bytes = get_bits(s, bits_to_read);
}
-
- if (newpasses > 1 && (codsty->cblk_style & JPEG2000_CTSY_HTJ2K_F)) {
- // Retrieve pass lengths for each pass
- int href_passes = (cblk->npasses + newpasses - 1) % 3;
- int eb = av_log2(newpasses - href_passes);
- int extra_bit = newpasses > 2 ? 1 : 0;
- if ((ret = get_bits(s, llen + eb + 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];
+ // Update cblk->npasses and write length information
+ cblk->npasses = (uint8_t) (cblk->npasses + segment_passes);
+ cblk->lengthinc[cblk->nb_lengthinc++] = segment_bytes;
+
+ if ((cblk->modes & JPEG2000_CTSY_HTJ2K_F) && cblk->ht_plhd == HT_PLHD_OFF) {
+ newpasses -= (uint8_t) segment_passes;
+ while (newpasses > 0) {
+ segment_passes = newpasses > 1 ? next_segment_passes : 1;
+ next_segment_passes = (uint8_t) (3 - next_segment_passes);
+ bits_to_read = (uint8_t) (cblk->lblock + av_log2(segment_passes));
+ segment_bytes = get_bits(s, bits_to_read);
+ newpasses -= (uint8_t) (segment_passes);
+ // This is a FAST Refinement pass
+ // Write length information for HT Refinement segment
+ cblk->pass_lengths[1] += segment_bytes;
+ // Update cblk->npasses and write length information
+ cblk->npasses = (uint8_t) (cblk->npasses + segment_passes);
+ cblk->lengthinc[cblk->nb_lengthinc++] = segment_bytes;
+ }
} else {
- if ((ret = get_bits(s, av_log2(newpasses1) + cblk->lblock)) < 0)
- return ret;
- cblk->pass_lengths[0] = ret;
+ newpasses -= (uint8_t) (segment_passes);
+ while (newpasses > 0) {
+ if (bypass_term_threshold != 0) {
+ segment_passes = newpasses > 1 ? next_segment_passes : 1;
+ next_segment_passes = (uint8_t) (3 - next_segment_passes);
+ bits_to_read = (uint8_t) (cblk->lblock + av_log2(segment_passes));
+ } else {
+ if ((cblk->modes & JPEG2000_CBLK_TERMALL) == 0)
+ av_log(s->avctx, AV_LOG_WARNING, "Corrupted packet header is found.\n");
+ segment_passes = 1;
+ bits_to_read = cblk->lblock;
+ }
+ segment_bytes = get_bits(s, bits_to_read);
+ newpasses -= (uint8_t) (segment_passes);
+
+ // Update cblk->npasses and write length information
+ cblk->npasses = (uint8_t) (cblk->npasses + segment_passes);
+ cblk->lengthinc[cblk->nb_lengthinc++] = segment_bytes;
+ cblk->nb_terminationsinc++;
+ }
}
- if (ret > cblk->data_allocated) {
- size_t new_size = FFMAX(2*cblk->data_allocated, ret);
+
+ for (int i = 0; i < cblk->nb_lengthinc; ++i)
+ tmp_length = (tmp_length < cblk->lengthinc[i]) ? cblk->lengthinc[i] : tmp_length;
+
+ if (tmp_length > cblk->data_allocated) {
+ size_t new_size = FFMAX(2 * cblk->data_allocated, tmp_length);
void *new = av_realloc(cblk->data, new_size);
if (new) {
cblk->data = new;
cblk->data_allocated = new_size;
}
}
- if (ret > cblk->data_allocated) {
+ if (tmp_length > cblk->data_allocated) {
avpriv_request_sample(s->avctx,
"Block with lengthinc greater than %"SIZE_SPECIFIER"",
cblk->data_allocated);
return AVERROR_PATCHWELCOME;
}
- cblk->lengthinc[cblk->nb_lengthinc++] = ret;
- cblk->npasses += newpasses1;
- newpasses -= newpasses1;
- } while(newpasses);
+ } else {
+ // This codeblock has no contribution to the current packet
+ continue;
+ }
}
}
jpeg2000_flush(s);
@@ -1695,7 +1962,7 @@ static int decode_cblk(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *cod
Jpeg2000T1Context *t1, Jpeg2000Cblk *cblk,
int width, int height, int bandpos, uint8_t roi_shift)
{
- int passno = cblk->npasses, pass_t = 2, bpno = cblk->nonzerobits - 1 + roi_shift;
+ int passno = cblk->npasses, pass_t = 2, bpno = cblk->nonzerobits - 1;
int pass_cnt = 0;
int vert_causal_ctx_csty_symbol = codsty->cblk_style & JPEG2000_CBLK_VSC;
int term_cnt = 0;
@@ -1909,7 +2176,7 @@ static inline int tile_codeblocks(const Jpeg2000DecoderContext *s, Jpeg2000Tile
Jpeg2000Band *band = rlevel->band + bandno;
int cblkno = 0, bandpos;
/* See Rec. ITU-T T.800, Equation E-2 */
- int magp = quantsty->expn[subbandno] + quantsty->nguardbits - 1;
+ int M_b = quantsty->expn[subbandno] + quantsty->nguardbits - 1;
bandpos = bandno + (reslevelno > 0);
@@ -1917,8 +2184,8 @@ static inline int tile_codeblocks(const Jpeg2000DecoderContext *s, Jpeg2000Tile
band->coord[1][0] == band->coord[1][1])
continue;
- if ((codsty->cblk_style & JPEG2000_CTSY_HTJ2K_F) && magp >= 31) {
- avpriv_request_sample(s->avctx, "JPEG2000_CTSY_HTJ2K_F and magp >= 31");
+ if ((codsty->cblk_style & JPEG2000_CTSY_HTJ2K_F) && M_b >= 31) {
+ avpriv_request_sample(s->avctx, "JPEG2000_CTSY_HTJ2K_F and M_b >= 31");
return AVERROR_PATCHWELCOME;
}
@@ -1935,11 +2202,11 @@ static inline int tile_codeblocks(const Jpeg2000DecoderContext *s, Jpeg2000Tile
Jpeg2000Cblk *cblk = prec->cblk + cblkno;
- if (codsty->cblk_style & JPEG2000_CTSY_HTJ2K_F)
+ if (cblk->modes & JPEG2000_CTSY_HTJ2K_F)
ret = ff_jpeg2000_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);
+ M_b, comp->roi_shift);
else
ret = decode_cblk(s, codsty, &t1, cblk,
cblk->coord[0][1] - cblk->coord[0][0],
@@ -2178,22 +2445,42 @@ 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_WARNING, "CAP marker segment shall come after SIZ\n");
+ }
+ ret = get_cap(s, codsty);
+ break;
case JPEG2000_COC:
+ if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11))
+ av_log(s->avctx, AV_LOG_WARNING, "COC marker is found in HOMOGENEOUS HT set\n");
ret = get_coc(s, codsty, properties);
break;
case JPEG2000_COD:
+ if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11))
+ av_log(s->avctx, AV_LOG_WARNING, "COD marker is found in HOMOGENEOUS HT set\n");
ret = get_cod(s, codsty, properties);
break;
case JPEG2000_RGN:
+ if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11))
+ av_log(s->avctx, AV_LOG_WARNING, "RGB marker is found in HOMOGENEOUS HT set\n");
ret = get_rgn(s, len);
+ if ((!s->Ccap15_b12) && s->isHT)
+ av_log(s->avctx, AV_LOG_WARNING, "RGN marker is found in RGNFREE HT set\n");
break;
case JPEG2000_QCC:
+ if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11))
+ av_log(s->avctx, AV_LOG_WARNING, "QCC marker is found in HOMOGENEOUS HT set\n");
ret = get_qcc(s, len, qntsty, properties);
break;
case JPEG2000_QCD:
+ if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11))
+ av_log(s->avctx, AV_LOG_WARNING, "QCD marker is found in HOMOGENEOUS HT set\n");
ret = get_qcd(s, len, qntsty, properties);
break;
case JPEG2000_POC:
+ if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11))
+ av_log(s->avctx, AV_LOG_WARNING, "POC marker is found in HOMOGENEOUS HT set\n");
ret = get_poc(s, len, poc);
break;
case JPEG2000_SOT:
@@ -2243,9 +2530,14 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s)
"Cannot have both PPT and PPM marker.\n");
return AVERROR_INVALIDDATA;
}
-
+ if ((!s->Ccap15_b11) && s->isHT)
+ av_log(s->avctx, AV_LOG_WARNING, "PPT marker is found in HOMOGENEOUS HT set\n");
ret = get_ppt(s, len);
break;
+ case JPEG2000_CPF:
+ // Corresponding profile marker
+ ret = read_cpf(s, len);
+ break;
default:
av_log(s->avctx, AV_LOG_ERROR,
"unsupported marker 0x%.4"PRIX16" at pos 0x%X\n",
diff --git a/libavcodec/jpeg2000dec.h b/libavcodec/jpeg2000dec.h
index d0ca6e7a79..326a572722 100644
--- a/libavcodec/jpeg2000dec.h
+++ b/libavcodec/jpeg2000dec.h
@@ -112,6 +112,13 @@ typedef struct Jpeg2000DecoderContext {
Jpeg2000Tile *tile;
Jpeg2000DSPContext dsp;
+ uint8_t isHT; // HTJ2K?
+ uint8_t Ccap15_b14_15; // HTONLY(= 0) or HTDECLARED(= 1) or MIXED(= 3) ?
+ uint8_t Ccap15_b12; // RGNFREE(= 0) or RGN(= 1)?
+ uint8_t Ccap15_b11; // HOMOGENEOUS(= 0) or HETEROGENEOUS(= 1) ?
+ uint8_t Ccap15_b05; // HTREV(= 0) or HTIRV(= 1) ?
+ uint8_t HT_MAGB; // MAGB value
+
/*options parameters*/
int reduction_factor;
} Jpeg2000DecoderContext;
diff --git a/libavcodec/jpeg2000htdec.c b/libavcodec/jpeg2000htdec.c
index eba0936089..beb4a386b0 100644
--- a/libavcodec/jpeg2000htdec.c
+++ b/libavcodec/jpeg2000htdec.c
@@ -122,7 +122,7 @@ static void jpeg2000_init_mel(StateVars *s, uint32_t Pcup)
static void jpeg2000_init_mag_ref(StateVars *s, uint32_t Lref)
{
- s->pos = Lref - 2;
+ s->pos = Lref - 1;
s->bits = 0;
s->last = 0xFF;
s->tmp = 0;
@@ -145,9 +145,10 @@ static void jpeg2000_init_mel_decoder(MelDecoderState *mel_state)
static int jpeg2000_bitbuf_refill_backwards(StateVars *buffer, const uint8_t *array)
{
uint64_t tmp = 0;
- int32_t position = buffer->pos - 4;
uint32_t new_bits = 32;
+ buffer->last = array[buffer->pos + 1];
+
if (buffer->bits_left >= 32)
return 0; // enough data, no need to pull in more bits
@@ -157,9 +158,24 @@ static int jpeg2000_bitbuf_refill_backwards(StateVars *buffer, const uint8_t *ar
* the bottom most bits.
*/
- for(int i = FFMAX(0, position + 1); i <= buffer->pos + 1; i++)
- tmp = 256*tmp + array[i];
-
+ if (buffer->pos >= 3) { // Common case; we have at least 4 bytes available
+ tmp = array[buffer->pos - 3];
+ tmp = (tmp << 8) | array[buffer->pos - 2];
+ tmp = (tmp << 8) | array[buffer->pos - 1];
+ tmp = (tmp << 8) | array[buffer->pos];
+ tmp = (tmp << 8) | buffer->last; // For stuffing bit detection
+ buffer->pos -= 4;
+ } else {
+ if (buffer->pos >= 2)
+ tmp = array[buffer->pos - 2];
+ if (buffer->pos >= 1)
+ tmp = (tmp << 8) | array[buffer->pos - 1];
+ if (buffer->pos >= 0)
+ tmp = (tmp << 8) | array[buffer->pos];
+ buffer->pos = 0;
+ tmp = (tmp << 8) | buffer->last; // For stuffing bit detection
+ }
+ // Now remove any stuffing bits, shifting things down as we go
if ((tmp & 0x7FFF000000) > 0x7F8F000000) {
tmp &= 0x7FFFFFFFFF;
new_bits--;
@@ -176,13 +192,11 @@ static int jpeg2000_bitbuf_refill_backwards(StateVars *buffer, const uint8_t *ar
tmp = (tmp & 0x0000007FFF) + ((tmp & 0xFFFFFF0000) >> 1);
new_bits--;
}
-
- tmp >>= 8; // Remove temporary byte loaded
+ tmp >>= 8; // Shifts away the extra byte we imported
/* 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;
}
@@ -406,6 +420,7 @@ static void recover_mag_sgn(StateVars *mag_sgn, uint8_t pos, uint16_t q, int32_t
E[n] = 32 - ff_clz(v[pos][i] | 1);
mu_n[n] = (v[pos][i] >> 1) + 1;
mu_n[n] <<= pLSB;
+ mu_n[n] |= (1 << (pLSB - 1)); // Add 0.5 (reconstruction parameter = 1/2)
mu_n[n] |= ((uint32_t) (v[pos][i] & 1)) << 31; // sign bit.
}
}
@@ -414,7 +429,7 @@ static void recover_mag_sgn(StateVars *mag_sgn, uint8_t pos, uint16_t q, int32_t
static int jpeg2000_import_bit(StateVars *stream, const uint8_t *array, uint32_t length)
{
int cond = stream->pos < length;
- int pos = FFMIN(stream->pos, length);
+ int pos = FFMIN(stream->pos, length - 1);
if (stream->bits == 0) {
stream->bits = (stream->tmp == 0xFF) ? 7 : 8;
stream->pos += cond;
@@ -426,14 +441,22 @@ static int jpeg2000_import_bit(StateVars *stream, const uint8_t *array, uint32_t
static int jpeg2000_peek_bit(StateVars *stream, const uint8_t *array, uint32_t length)
{
+ uint8_t bit;
+
if (stream->bits == 0) {
- int cond = stream->pos < length;
- int pos = FFMIN(stream->pos, length);
- stream->bits = (stream->tmp == 0xFF) ? 7 : 8;
- stream->pos += cond;
- stream->tmp = cond ? array[pos] : 0xFF;
+ stream->bits = (stream->last == 0xFF) ? 7 : 8;
+ if (stream->pos < length) {
+ stream->tmp = array[stream->pos];
+ stream->pos++;
+ } else {
+ stream->tmp = 0;
+ }
+ stream->last = stream->tmp;
}
- return (stream->tmp >> stream->bits) & 1;
+ bit = stream->tmp & 1;
+ stream->tmp >>= 1;
+ stream->bits--;
+ return bit;
}
static int jpeg2000_decode_mel_sym(MelDecoderState *mel_state,
@@ -994,66 +1017,63 @@ 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 stride)
{
- int local_mbr = 0;
-
- local_mbr |= jpeg2000_get_state(i - 1, j - 1, stride, HT_SHIFT_SIGMA, block_states);
- local_mbr |= jpeg2000_get_state(i - 1, j + 0, stride, HT_SHIFT_SIGMA, block_states);
- local_mbr |= jpeg2000_get_state(i - 1, j + 1, stride, HT_SHIFT_SIGMA, block_states);
-
- local_mbr |= jpeg2000_get_state(i + 0, j - 1, stride, HT_SHIFT_SIGMA, block_states);
- local_mbr |= jpeg2000_get_state(i + 0, j + 1, stride, HT_SHIFT_SIGMA, block_states);
-
- local_mbr |= jpeg2000_get_state(i + 1, j - 1, stride, HT_SHIFT_SIGMA, block_states) * causal_cond;
- local_mbr |= jpeg2000_get_state(i + 1, j + 0, stride, HT_SHIFT_SIGMA, block_states) * causal_cond;
- local_mbr |= jpeg2000_get_state(i + 1, j + 1, stride, HT_SHIFT_SIGMA, block_states) * causal_cond;
-
- local_mbr |= jpeg2000_get_state(i - 1, j - 1, stride, HT_SHIFT_REF, block_states) *
- jpeg2000_get_state(i - 1, j - 1, stride, HT_SHIFT_SCAN, block_states);
- local_mbr |= jpeg2000_get_state(i - 1, j + 0, stride, HT_SHIFT_REF, block_states) *
- jpeg2000_get_state(i - 1, j - 1, stride, HT_SHIFT_SCAN, block_states);
- local_mbr |= jpeg2000_get_state(i - 1, j + 1, stride, HT_SHIFT_REF, block_states) *
- jpeg2000_get_state(i - 1, j + 1, stride, HT_SHIFT_SCAN, block_states);
-
- local_mbr |= jpeg2000_get_state(i + 0, j - 1, stride, HT_SHIFT_REF, block_states) *
- jpeg2000_get_state(i + 0, j - 1, stride, HT_SHIFT_SCAN, block_states);
- local_mbr |= jpeg2000_get_state(i + 0, j + 1, stride, HT_SHIFT_REF, block_states) *
- jpeg2000_get_state(i + 0, j + 1, stride, HT_SHIFT_SCAN, block_states);
-
- local_mbr |= jpeg2000_get_state(i + 1, j - 1, stride, HT_SHIFT_REF, block_states) *
- jpeg2000_get_state(i + 1, j - 1, stride, HT_SHIFT_SCAN, block_states) * causal_cond;
- local_mbr |= jpeg2000_get_state(i + 1, j + 0, stride, HT_SHIFT_REF, block_states) *
- jpeg2000_get_state(i + 1, j + 0, stride, HT_SHIFT_SCAN, block_states) * causal_cond;
- local_mbr |= jpeg2000_get_state(i + 1, j + 1, stride, HT_SHIFT_REF, block_states) *
- jpeg2000_get_state(i + 1, j + 1, stride, HT_SHIFT_SCAN, block_states) * causal_cond;
-
- *mbr |= local_mbr;
+ uint8_t *state_p0 = block_states + i * stride + j;
+ uint8_t *state_p1 = block_states + (i + 1) * stride + j;
+ uint8_t *state_p2 = block_states + (i + 2) * stride + j;
+
+ uint8_t mbr0 = state_p0[0] | state_p0[1] | state_p0[2];
+ uint8_t mbr1 = state_p1[0] | state_p1[2];
+ uint8_t mbr2 = state_p2[0] | state_p2[1] | state_p2[2];
+ *mbr = mbr0 | mbr1 | (mbr2 & causal_cond);
+ *mbr |= (mbr0 >> HT_SHIFT_REF) & (mbr0 >> HT_SHIFT_SCAN);
+ *mbr |= (mbr1 >> HT_SHIFT_REF) & (mbr1 >> HT_SHIFT_SCAN);
+ *mbr |= (mbr2 >> HT_SHIFT_REF) & (mbr2 >> HT_SHIFT_SCAN) & causal_cond;
+ *mbr &= 1;
}
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)
+ uint8_t *magref_segment, uint32_t magref_length,
+ uint8_t is_causal)
{
for (int j = j_s; j < j_s + width; j++) {
uint32_t mbr_info = 0;
for (int i = i_s; i < i_s + height; i++) {
- int modify_state, cond;
+ int modify_state;
uint8_t bit;
- uint8_t causal_cond = i != (i_s + height - 1);
+ uint8_t causal_cond = (is_causal == 0) || (i != (i_s + height - 1));
int32_t *sp = &sample_buf[j + (i * (stride))];
uint8_t mbr = 0;
- if (jpeg2000_get_state(i, j, stride - 2, HT_SHIFT_SIGMA, block_states) == 0)
+ if (jpeg2000_get_state(i, j, stride, HT_SHIFT_SIGMA, block_states) == 0)
jpeg2000_calc_mbr(&mbr, i, j, mbr_info & 0x1EF, causal_cond, block_states, stride);
mbr_info >>= 3;
- cond = mbr != 0;
- bit = jpeg2000_peek_bit(sig_prop, magref_segment, magref_length);
- *sp |= (bit * cond) << pLSB;
- sig_prop->bits -= cond;
- modify_state = (((1 << HT_SHIFT_REF_IND) | (1 << HT_SHIFT_REF)) * cond) | 1 << HT_SHIFT_SCAN;
+
+ modify_state = block_states[(i + 1) * stride + (j + 1)];
+ modify_state |= 1 << HT_SHIFT_SCAN;
+ if (mbr != 0) {
+ modify_state |= 1 << HT_SHIFT_REF_IND;
+ bit = jpeg2000_peek_bit(sig_prop, magref_segment, magref_length);
+ modify_state |= bit << HT_SHIFT_REF;
+ *sp |= bit << pLSB;
+ *sp |= bit << (pLSB - 1); // Add 0.5 (reconstruction parameter = 1/2)
+ }
jpeg2000_modify_state(i, j, stride, modify_state, block_states);
}
}
+ // decode sign
+ for (int j = j_s; j < j_s + width; j++) {
+ for (int i = i_s; i < i_s + height; i++) {
+ uint8_t bit;
+ int32_t *sp = &sample_buf[j + (i * (stride))];
+ uint8_t *state_p = block_states + (i + 1) * stride + (j + 1);
+ if ((state_p[0] >> HT_SHIFT_REF) & 1) {
+ bit = jpeg2000_peek_bit(sig_prop, magref_segment, magref_length);
+ *sp |= (int32_t)bit << 31;
+ }
+ }
+ }
}
/**
@@ -1074,6 +1094,7 @@ static void jpeg2000_decode_sigprop_segment(Jpeg2000Cblk *cblk, uint16_t width,
int last_width;
uint16_t i = 0, j = 0;
+ uint8_t is_causal = cblk->modes & JPEG2000_CBLK_VSC;
jpeg2000_init_zero(&sp_dec);
@@ -1082,14 +1103,14 @@ static void jpeg2000_decode_sigprop_segment(Jpeg2000Cblk *cblk, uint16_t width,
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);
+ magref_length, is_causal);
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);
+ magref_length, is_causal);
i += 4;
}
@@ -1099,20 +1120,20 @@ static void jpeg2000_decode_sigprop_segment(Jpeg2000Cblk *cblk, uint16_t width,
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);
+ magref_length, is_causal);
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);
+ magref_length, is_causal);
}
/**
* See procedure decodeSigPropMag at Rec. ITU-T T.814, 7.5.
*/
-static int
+static void
jpeg2000_decode_magref_segment( uint16_t width, uint16_t block_height, const int stride,
uint8_t *magref_segment,uint32_t magref_length,
uint8_t pLSB, int32_t *sample_buf, uint8_t *block_states)
@@ -1123,7 +1144,8 @@ jpeg2000_decode_magref_segment( uint16_t width, uint16_t block_height, const int
uint16_t height = 4;
uint16_t i_start = 0;
int32_t *sp;
-
+ int32_t bit;
+ int32_t tmp;
jpeg2000_init_mag_ref(&mag_ref, magref_length);
for (int n1 = 0; n1 < num_v_stripe; n1++) {
@@ -1134,9 +1156,13 @@ jpeg2000_decode_magref_segment( uint16_t width, uint16_t block_height, const int
* Rec. ITU-T T.814, Figure 7.
*/
sp = &sample_buf[j + i * stride];
- 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;
+ if (jpeg2000_get_state(i, j, stride, HT_SHIFT_SIGMA, block_states) != 0) {
+ jpeg2000_modify_state(i, j, stride, 1 << HT_SHIFT_REF_IND, block_states);
+ bit = jpeg2000_import_magref_bit(&mag_ref, magref_segment, magref_length);
+ tmp = 0xFFFFFFFE | (uint32_t)bit;
+ tmp <<= pLSB;
+ sp[0] &= tmp;
+ sp[0] |= 1 << (pLSB - 1); // Add 0.5 (reconstruction parameter = 1/2)
}
}
}
@@ -1146,21 +1172,24 @@ jpeg2000_decode_magref_segment( uint16_t width, uint16_t block_height, const int
for (int j = 0; j < width; j++) {
for (int i = i_start; i < i_start + height; i++) {
sp = &sample_buf[j + i * stride];
- 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;
+ if (jpeg2000_get_state(i, j, stride, HT_SHIFT_SIGMA, block_states) != 0) {
+ jpeg2000_modify_state(i, j, stride, 1 << HT_SHIFT_REF_IND, block_states);
+ bit = jpeg2000_import_magref_bit(&mag_ref, magref_segment, magref_length);
+ tmp = 0xFFFFFFFE | (uint32_t)bit;
+ tmp <<= pLSB;
+ sp[0] &= tmp;
+ sp[0] |= 1 << (pLSB - 1); // Add 0.5 (reconstruction parameter = 1/2)
}
}
}
- return 1;
}
int
ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *codsty, Jpeg2000T1Context *t1, Jpeg2000Cblk *cblk,
- int width, int height, int magp, uint8_t roi_shift)
+ int width, int height, int M_b, uint8_t roi_shift)
{
- uint8_t p0 = 0; // Number of placeholder passes
+ uint8_t p0 = 0; // 3 * p0 = 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
@@ -1174,7 +1203,7 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c
int z_blk; // Number of ht coding pass
- uint8_t empty_passes;
+ uint8_t num_plhd_passes; // Number of placeholder passes
StateVars mag_sgn; // Magnitude and Sign
StateVars mel; // Adaptive run-length coding
@@ -1190,8 +1219,8 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c
uint8_t *block_states = NULL;
int32_t n, val; // Post-processing
-
- int32_t M_b = magp;
+ const uint32_t mask = UINT32_MAX >> (M_b + 1); // bit mask for ROI detection
+ uint8_t num_rempass;
const int quad_buf_width = width + 4;
const int quad_buf_height = height + 4;
@@ -1201,22 +1230,17 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c
av_assert0(width * height <= 4096);
av_assert0(width * height > 0);
- if (roi_shift)
- avpriv_report_missing_feature(s->avctx, "ROI shift");
-
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)
- p0 = 0;
- else if (cblk->length == 0)
- p0 = 1;
-
- empty_passes = p0 * 3;
- z_blk = cblk->npasses - empty_passes;
+ num_rempass = cblk->npasses % 3; // Number of remainder passes
+ num_plhd_passes = num_rempass ? cblk->npasses - num_rempass : cblk->npasses - 3;
+ av_assert0(num_plhd_passes % 3 == 0);
+ p0 = num_plhd_passes / 3;
+ z_blk = cblk->npasses - num_plhd_passes;
if (z_blk <= 0)
return 0; // No passes within this set, continue
@@ -1231,7 +1255,11 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c
}
Dcup = cblk->data;
Dref = cblk->data + Lcup; // Dref comes after the refinement segment
+
+ cblk->data[cblk->length] = 0xFF; // an extra byte for refinement segment (buffer->last)
+
S_blk = p0 + cblk->zbp;
+ cblk->zbp = S_blk - 1;
pLSB = 30 - S_blk;
Scup = (Dcup[Lcup - 1] << 4) + (Dcup[Lcup - 2] & 0x0F);
@@ -1277,31 +1305,32 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c
goto free;
}
- if (cblk->npasses > 1)
+ if (z_blk > 1)
jpeg2000_decode_sigprop_segment(cblk, width, height, quad_buf_width, Dref, Lref,
pLSB - 1, sample_buf, block_states);
- if (cblk->npasses > 2) {
-
- if (Lref < 2){
- av_log(s->avctx,AV_LOG_ERROR,"Invalid magnitude refinement length\n");
- ret = AVERROR_INVALIDDATA;
- goto free;
- }
- if ((ret = jpeg2000_decode_magref_segment(width, height, quad_buf_width, Dref, Lref,
- pLSB - 1, sample_buf, block_states)) < 0)
- goto free;
- }
+ if (z_blk > 2)
+ jpeg2000_decode_magref_segment(width, height, quad_buf_width, Dref, Lref,
+ pLSB - 1, sample_buf, block_states);
pLSB = 31 - M_b;
/* Reconstruct the sample values */
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
+ int32_t sign;
+
n = x + (y * t1->stride);
val = sample_buf[x + (y * quad_buf_width)];
+ sign = val & INT32_MIN;
+ val &= INT32_MAX;
+ /* ROI shift, if necessary */
+ if (roi_shift && (((uint32_t)val & ~mask) == 0))
+ val <<= roi_shift;
/* Convert sign-magnitude to two's complement. */
- val = val >> 31 ? 0x80000000 - val : val;
+ if (sign)
+ val = -val;
+ /* Shift down to 1 bit upper from decimal point for reconstruction value (= 0.5) */
val >>= (pLSB - 1);
t1->data[n] = val;
}
diff --git a/libavcodec/jpeg2000htdec.h b/libavcodec/jpeg2000htdec.h
index 572d095c92..8d6919a0de 100644
--- a/libavcodec/jpeg2000htdec.h
+++ b/libavcodec/jpeg2000htdec.h
@@ -29,6 +29,6 @@
int ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *codsty,
Jpeg2000T1Context *t1, Jpeg2000Cblk *cblk, int width,
- int height, int magp, uint8_t roi_shift);
+ int height, int M_b, uint8_t roi_shift);
#endif /* AVCODEC_JPEG2000HTDEC_H */
--
2.34.1
_______________________________________________
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".
^ permalink raw reply [flat|nested] 5+ messages in thread
* [FFmpeg-devel] [PATCH 2/2] avcodec/jpeg2000dec: fix tilepart processing
2024-06-15 3:15 [FFmpeg-devel] [PATCH 1/2] avcodec/jpeg2000dec: Add support for placeholder passes, CAP, and CPF markers Osamu Watanabe
@ 2024-06-15 3:15 ` Osamu Watanabe
2024-06-15 6:00 ` [FFmpeg-devel] [PATCH 1/2] avcodec/jpeg2000dec: Add support for placeholder passes, CAP, and CPF markers Pierre-Anthony Lemieux
2024-06-15 20:11 ` Michael Niedermayer
2 siblings, 0 replies; 5+ messages in thread
From: Osamu Watanabe @ 2024-06-15 3:15 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Osamu Watanabe, pal
This is the same as https://patchwork.ffmpeg.org/project/ffmpeg/patch/20240607002549.2259139-1-owatanab@es.takushoku-u.ac.jp/
Signed-off-by: Osamu Watanabe <owatanab@es.takushoku-u.ac.jp>
---
libavcodec/jpeg2000dec.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/libavcodec/jpeg2000dec.c b/libavcodec/jpeg2000dec.c
index d299c67cc7..395cf34bcd 100644
--- a/libavcodec/jpeg2000dec.c
+++ b/libavcodec/jpeg2000dec.c
@@ -1097,6 +1097,7 @@ static inline void select_header(Jpeg2000DecoderContext *s, const Jpeg2000Tile *
{
s->g = tile->tile_part[*tp_index].header_tpg;
if (bytestream2_get_bytes_left(&s->g) == 0 && s->bit_index == 8) {
+ av_log(s->avctx, AV_LOG_WARNING, "Packet header bytes in PPM marker segment is too short.\n");
if (*tp_index < FF_ARRAY_ELEMS(tile->tile_part) - 1) {
s->g = tile->tile_part[++(*tp_index)].tpg;
}
@@ -1106,10 +1107,18 @@ static inline void select_header(Jpeg2000DecoderContext *s, const Jpeg2000Tile *
static inline void select_stream(Jpeg2000DecoderContext *s, const Jpeg2000Tile *tile,
int *tp_index, const Jpeg2000CodingStyle *codsty)
{
+ int32_t is_endof_tp;
+
s->g = tile->tile_part[*tp_index].tpg;
- if (bytestream2_get_bytes_left(&s->g) == 0 && s->bit_index == 8) {
+ is_endof_tp = bytestream2_get_bytes_left(&s->g) == 0 && s->bit_index == 8;
+ // Following while loop is necessary because a tilepart may include only SOD marker.
+ // Such a tilepart has neither packet header nor compressed data.
+ while (is_endof_tp) {
if (*tp_index < FF_ARRAY_ELEMS(tile->tile_part) - 1) {
s->g = tile->tile_part[++(*tp_index)].tpg;
+ is_endof_tp = bytestream2_get_bytes_left(&s->g) == 0 && s->bit_index == 8;
+ } else {
+ is_endof_tp = 0;
}
}
if (codsty->csty & JPEG2000_CSTY_SOP) {
--
2.34.1
_______________________________________________
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".
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [FFmpeg-devel] [PATCH 1/2] avcodec/jpeg2000dec: Add support for placeholder passes, CAP, and CPF markers
2024-06-15 3:15 [FFmpeg-devel] [PATCH 1/2] avcodec/jpeg2000dec: Add support for placeholder passes, CAP, and CPF markers Osamu Watanabe
2024-06-15 3:15 ` [FFmpeg-devel] [PATCH 2/2] avcodec/jpeg2000dec: fix tilepart processing Osamu Watanabe
@ 2024-06-15 6:00 ` Pierre-Anthony Lemieux
2024-06-15 7:55 ` WATANABE Osamu
2024-06-15 20:11 ` Michael Niedermayer
2 siblings, 1 reply; 5+ messages in thread
From: Pierre-Anthony Lemieux @ 2024-06-15 6:00 UTC (permalink / raw)
To: Osamu Watanabe; +Cc: ffmpeg-devel
Hi Osamu,
Can you provide the list of J2K reference codestreams that this code
allows FFMPEG to support -- not including those already supported [1]?
[1] https://github.com/FFmpeg/FFmpeg/blob/master/tests/fate/jpeg2000.mak
Best,
-- Pierre
On Fri, Jun 14, 2024 at 8:15 PM Osamu Watanabe
<owatanab@es.takushoku-u.ac.jp> wrote:
>
> Signed-off-by: Osamu Watanabe <owatanab@es.takushoku-u.ac.jp>
> ---
> libavcodec/jpeg2000.h | 10 +
> libavcodec/jpeg2000dec.c | 454 ++++++++++++++++++++++++++++++-------
> libavcodec/jpeg2000dec.h | 7 +
> libavcodec/jpeg2000htdec.c | 225 ++++++++++--------
> libavcodec/jpeg2000htdec.h | 2 +-
> 5 files changed, 518 insertions(+), 180 deletions(-)
>
> diff --git a/libavcodec/jpeg2000.h b/libavcodec/jpeg2000.h
> index d004c08f10..93221d90ca 100644
> --- a/libavcodec/jpeg2000.h
> +++ b/libavcodec/jpeg2000.h
> @@ -37,12 +37,14 @@
>
> enum Jpeg2000Markers {
> JPEG2000_SOC = 0xff4f, // start of codestream
> + JPEG2000_CAP = 0xff50, // extended capabilities
> JPEG2000_SIZ = 0xff51, // image and tile size
> JPEG2000_COD, // coding style default
> JPEG2000_COC, // coding style component
> JPEG2000_TLM = 0xff55, // tile-part length, main header
> JPEG2000_PLM = 0xff57, // packet length, main header
> JPEG2000_PLT, // packet length, tile-part header
> + JPEG2000_CPF, // corresponding profile
> JPEG2000_QCD = 0xff5c, // quantization default
> JPEG2000_QCC, // quantization component
> JPEG2000_RGN, // region of interest
> @@ -58,6 +60,12 @@ enum Jpeg2000Markers {
> JPEG2000_EOC = 0xffd9, // end of codestream
> };
>
> +enum JPEG2000_Ccap15_b14_15_params {
> + HTJ2K_HTONLY = 0, // HTONLY, bit 14 and 15 are 0
> + HTJ2K_HTDECLARED, // HTDECLARED, bit 14 = 1 and bit 15 = 0
> + HTJ2K_MIXED = 3, // MIXED, bit 14 and 15 are 1
> +};
> +
> #define JPEG2000_SOP_FIXED_BYTES 0xFF910004
> #define JPEG2000_SOP_BYTE_LENGTH 6
>
> @@ -192,6 +200,8 @@ typedef struct Jpeg2000Cblk {
> /* specific to HT code-blocks */
> int zbp;
> int pass_lengths[2];
> + uint8_t modes; // copy of SPcod/SPcoc field to parse HT-MIXED mode
> + uint8_t ht_plhd; // are we looking for HT placeholder passes?
> } Jpeg2000Cblk; // code block
>
> typedef struct Jpeg2000Prec {
> diff --git a/libavcodec/jpeg2000dec.c b/libavcodec/jpeg2000dec.c
> index d15502a527..d299c67cc7 100644
> --- a/libavcodec/jpeg2000dec.c
> +++ b/libavcodec/jpeg2000dec.c
> @@ -54,6 +54,15 @@
> #define HAD_COC 0x01
> #define HAD_QCC 0x02
>
> +// Values of flag for placeholder passes
> +enum HT_PLHD_STATUS {
> + HT_PLHD_OFF,
> + HT_PLHD_ON
> +};
> +
> +#define HT_MIXED 0x80 // bit 7 of SPcod/SPcoc
> +
> +
> /* get_bits functions for JPEG2000 packet bitstream
> * It is a get_bit function with a bit-stuffing routine. If the value of the
> * byte is 0xFF, the next byte includes an extra zero bit stuffed into the MSB.
> @@ -382,6 +391,9 @@ static int get_siz(Jpeg2000DecoderContext *s)
> } else if (ncomponents == 1 && s->precision == 8) {
> s->avctx->pix_fmt = AV_PIX_FMT_GRAY8;
> i = 0;
> + } else if (ncomponents == 1 && s->precision == 12) {
> + s->avctx->pix_fmt = AV_PIX_FMT_GRAY16LE;
> + i = 0;
> }
> }
>
> @@ -408,6 +420,73 @@ static int get_siz(Jpeg2000DecoderContext *s)
> s->avctx->bits_per_raw_sample = s->precision;
> return 0;
> }
> +/* get extended capabilities (CAP) marker segment */
> +static int get_cap(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c)
> +{
> + uint32_t Pcap;
> + uint16_t Ccap_i[32] = { 0 };
> + uint16_t Ccap_15;
> + uint8_t P;
> +
> + if (bytestream2_get_bytes_left(&s->g) < 6) {
> + av_log(s->avctx, AV_LOG_ERROR, "Insufficient space for CAP\n");
> + return AVERROR_INVALIDDATA;
> + }
> +
> + Pcap = bytestream2_get_be32u(&s->g);
> + s->isHT = (Pcap >> (31 - (15 - 1))) & 1;
> + for (int i = 0; i < 32; i++) {
> + if ((Pcap >> (31 - i)) & 1)
> + Ccap_i[i] = bytestream2_get_be16u(&s->g);
> + }
> + Ccap_15 = Ccap_i[14];
> + if (s->isHT == 1) {
> + av_log(s->avctx, AV_LOG_INFO, "This is an HTJ2K codestream.\n");
> + // Bits 14-15
> + switch ((Ccap_15 >> 14) & 0x3) {
> + case 0x3:
> + s->Ccap15_b14_15 = HTJ2K_MIXED;
> + break;
> + case 0x1:
> + s->Ccap15_b14_15 = HTJ2K_HTDECLARED;
> + break;
> + case 0x0:
> + s->Ccap15_b14_15 = HTJ2K_HTONLY;
> + break;
> + default:
> + av_log(s->avctx, AV_LOG_ERROR, "Unknown CCap value.\n");
> + return AVERROR(EINVAL);
> + break;
> + }
> + // Bit 13
> + if ((Ccap_15 >> 13) & 1) {
> + av_log(s->avctx, AV_LOG_ERROR, "MULTIHT set is not supported.\n");
> + return AVERROR_PATCHWELCOME;
> + }
> + // Bit 12
> + s->Ccap15_b12 = (Ccap_15 >> 12) & 1;
> + // Bit 11
> + s->Ccap15_b11 = (Ccap_15 >> 11) & 1;
> + // Bit 5
> + s->Ccap15_b05 = (Ccap_15 >> 5) & 1;
> + // Bit 0-4
> + P = Ccap_15 & 0x1F;
> + if (!P)
> + s->HT_MAGB = 8;
> + else if (P < 20)
> + s->HT_MAGB = P + 8;
> + else if (P < 31)
> + s->HT_MAGB = 4 * (P - 19) + 27;
> + else
> + s->HT_MAGB = 74;
> +
> + if (s->HT_MAGB > 31) {
> + av_log(s->avctx, AV_LOG_ERROR, "Available internal precision is exceeded (MAGB> 31).\n");
> + return AVERROR_PATCHWELCOME;
> + }
> + }
> + return 0;
> +}
>
> /* get common part for COD and COC segments */
> static int get_cox(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c)
> @@ -802,6 +881,15 @@ static int read_crg(Jpeg2000DecoderContext *s, int n)
> bytestream2_skip(&s->g, n - 2);
> return 0;
> }
> +
> +static int read_cpf(Jpeg2000DecoderContext *s, int n)
> +{
> + if (bytestream2_get_bytes_left(&s->g) < (n - 2))
> + return AVERROR_INVALIDDATA;
> + bytestream2_skip(&s->g, n - 2);
> + return 0;
> +}
> +
> /* Tile-part lengths: see ISO 15444-1:2002, section A.7.1
> * Used to know the number of tile parts and lengths.
> * There may be multiple TLMs in the header.
> @@ -965,6 +1053,10 @@ static int init_tile(Jpeg2000DecoderContext *s, int tileno)
> comp->roi_shift = s->roi_shift[compno];
> if (!codsty->init)
> return AVERROR_INVALIDDATA;
> + if (s->isHT && (!s->Ccap15_b05) && (!codsty->transform))
> + av_log(s->avctx, AV_LOG_WARNING, "Transformation = 0 (lossy DWT) is found in HTREV HT set\n");
> + if (s->isHT && s->Ccap15_b14_15 != (codsty->cblk_style >> 6) && s->Ccap15_b14_15 != HTJ2K_HTONLY)
> + av_log(s->avctx, AV_LOG_WARNING, "SPcod/SPcoc value does not match bit 14-15 values of Ccap15\n");
> if (ret = ff_jpeg2000_init_component(comp, codsty, qntsty,
> s->cbps[compno], s->cdx[compno],
> s->cdy[compno], s->avctx))
> @@ -1067,100 +1159,275 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile,
> int incl, newpasses, llen;
> void *tmp;
>
> - if (cblk->npasses)
> - incl = get_bits(s, 1);
> - else
> + if (!cblk->incl) {
> + incl = 0;
> + cblk->modes = codsty->cblk_style;
> + if (cblk->modes >= JPEG2000_CTSY_HTJ2K_F)
> + cblk->ht_plhd = HT_PLHD_ON;
> + if (layno > 0)
> + incl = tag_tree_decode(s, prec->cblkincl + cblkno, 0 + 1) == 0;
> incl = tag_tree_decode(s, prec->cblkincl + cblkno, layno + 1) == layno;
> - if (!incl)
> - continue;
> - else if (incl < 0)
> - return incl;
> -
> - if (!cblk->npasses) {
> - int zbp = tag_tree_decode(s, prec->zerobits + cblkno, 100);
> - int v = expn[bandno] + numgbits - 1 - zbp;
>
> - if (v < 0 || v > 30) {
> - av_log(s->avctx, AV_LOG_ERROR,
> - "nonzerobits %d invalid or unsupported\n", v);
> - return AVERROR_INVALIDDATA;
> + if (incl) {
> + int zbp = tag_tree_decode(s, prec->zerobits + cblkno, 100);
> + int v = expn[bandno] + numgbits - 1 - (zbp - tile->comp->roi_shift);
> + if (v < 0 || v > 30) {
> + av_log(s->avctx, AV_LOG_ERROR,
> + "nonzerobits %d invalid or unsupported\n", v);
> + return AVERROR_INVALIDDATA;
> + }
> + cblk->incl = 1;
> + cblk->nonzerobits = v;
> + cblk->zbp = zbp;
> + cblk->lblock = 3;
> }
> - cblk->zbp = zbp;
> - cblk->nonzerobits = v;
> - }
> - if ((newpasses = getnpasses(s)) < 0)
> - return newpasses;
> - av_assert2(newpasses > 0);
> - if (cblk->npasses + newpasses >= JPEG2000_MAX_PASSES) {
> - avpriv_request_sample(s->avctx, "Too many passes");
> - return AVERROR_PATCHWELCOME;
> - }
> - if ((llen = getlblockinc(s)) < 0)
> - return llen;
> - if (cblk->lblock + llen + av_log2(newpasses) > 16) {
> - avpriv_request_sample(s->avctx,
> - "Block with length beyond 16 bits");
> - return AVERROR_PATCHWELCOME;
> + } else {
> + incl = get_bits(s, 1);
> }
>
> - cblk->lblock += llen;
> -
> - cblk->nb_lengthinc = 0;
> - cblk->nb_terminationsinc = 0;
> - av_free(cblk->lengthinc);
> - cblk->lengthinc = av_calloc(newpasses, sizeof(*cblk->lengthinc));
> - if (!cblk->lengthinc)
> - return AVERROR(ENOMEM);
> - tmp = av_realloc_array(cblk->data_start, cblk->nb_terminations + newpasses + 1, sizeof(*cblk->data_start));
> - if (!tmp)
> - return AVERROR(ENOMEM);
> - cblk->data_start = tmp;
> - do {
> - int newpasses1 = 0;
> -
> - while (newpasses1 < newpasses) {
> - newpasses1 ++;
> - if (needs_termination(codsty->cblk_style, cblk->npasses + newpasses1 - 1)) {
> - cblk->nb_terminationsinc ++;
> - break;
> + if (incl) {
> + uint8_t bypass_term_threshold = 0;
> + uint8_t bits_to_read = 0;
> + uint32_t segment_bytes = 0;
> + int32_t segment_passes = 0;
> + uint8_t next_segment_passes = 0;
> + int32_t href_passes, pass_bound;
> + uint32_t tmp_length = 0;
> +
> + if ((newpasses = getnpasses(s)) <= 0)
> + return newpasses;
> + if (cblk->npasses + newpasses >= JPEG2000_MAX_PASSES) {
> + avpriv_request_sample(s->avctx, "Too many passes");
> + return AVERROR_PATCHWELCOME;
> + }
> + if ((llen = getlblockinc(s)) < 0)
> + return llen;
> + if (cblk->lblock + llen + av_log2(newpasses) > 16) {
> + avpriv_request_sample(s->avctx,
> + "Block with length beyond 16 bits");
> + return AVERROR_PATCHWELCOME;
> + }
> + cblk->nb_lengthinc = 0;
> + cblk->nb_terminationsinc = 0;
> + av_free(cblk->lengthinc);
> + cblk->lengthinc = av_calloc(newpasses, sizeof(*cblk->lengthinc));
> + if (!cblk->lengthinc)
> + return AVERROR(ENOMEM);
> + tmp = av_realloc_array(cblk->data_start, cblk->nb_terminations + newpasses + 1,
> + sizeof(*cblk->data_start));
> + if (!tmp)
> + return AVERROR(ENOMEM);
> + cblk->data_start = tmp;
> + cblk->lblock += llen;
> +
> + if (cblk->ht_plhd) {
> + href_passes = (cblk->npasses + newpasses - 1) % 3;
> + segment_passes = newpasses - href_passes;
> + pass_bound = 2;
> + bits_to_read = cblk->lblock;
> + if (segment_passes < 1) {
> + // No possible HT Cleanup pass here; may have placeholder passes
> + // or an original J2K block bit-stream (in MIXED mode).
> + segment_passes = newpasses;
> + while (pass_bound <= segment_passes) {
> + bits_to_read++;
> + pass_bound += pass_bound;
> + }
> + segment_bytes = get_bits(s, bits_to_read);
> + if (segment_bytes) {
> + if (cblk->modes & HT_MIXED) {
> + cblk->ht_plhd = HT_PLHD_OFF;
> + cblk->modes &= (uint8_t) (~(JPEG2000_CTSY_HTJ2K_F));
> + }
> + else {
> + av_log(s->avctx, AV_LOG_WARNING, "Length information for a HT-codeblock is invalid\n");
> + }
> + }
> + } else {
> + while (pass_bound <= segment_passes) {
> + bits_to_read++;
> + pass_bound += pass_bound;
> + }
> + segment_bytes = get_bits(s, bits_to_read);
> + if (segment_bytes) {
> + // No more placeholder passes
> + if (!(cblk->modes & HT_MIXED)) {
> + // Must be the first HT Cleanup pass
> + if (segment_bytes < 2)
> + av_log(s->avctx, AV_LOG_WARNING, "Length information for a HT-codeblock is invalid\n");
> + next_segment_passes = 2;
> + cblk->ht_plhd = HT_PLHD_OFF;
> + // Write length information for HT CleanUp segment
> + cblk->pass_lengths[0] = segment_bytes;
> + } else if (cblk->lblock > 3 && segment_bytes > 1
> + && (segment_bytes >> (bits_to_read - 1)) == 0) {
> + // Must be the first HT Cleanup pass, since length MSB is 0
> + next_segment_passes = 2;
> + cblk->ht_plhd = HT_PLHD_OFF;
> + // Write length information for HT CleanUp segment
> + cblk->pass_lengths[0] = segment_bytes;
> + } else {
> + // Must have an original (non-HT) block coding pass
> + cblk->modes &= (uint8_t) (~(JPEG2000_CTSY_HTJ2K_F));
> + cblk->ht_plhd = HT_PLHD_OFF;
> + segment_passes = newpasses;
> + while (pass_bound <= segment_passes) {
> + bits_to_read++;
> + pass_bound += pass_bound;
> + segment_bytes <<= 1;
> + segment_bytes += get_bits(s, 1);
> + }
> + }
> + } else {
> + // Probably parsing placeholder passes, but we need to read an
> + // extra length bit to verify this, since prior to the first
> + // HT Cleanup pass, the number of length bits read for a
> + // contributing code-block is dependent on the number of passes
> + // being included, as if it were a non-HT code-block.
> + segment_passes = newpasses;
> + if (pass_bound <= segment_passes) {
> + while (1) {
> + bits_to_read++;
> + pass_bound += pass_bound;
> + segment_bytes <<= 1;
> + segment_bytes += get_bits(s, 1);
> + if (pass_bound > segment_passes)
> + break;
> + }
> + if (segment_bytes) {
> + if (cblk->modes & HT_MIXED) {
> + cblk->modes &= (uint8_t) (~(JPEG2000_CTSY_HTJ2K_F));
> + cblk->ht_plhd = HT_PLHD_OFF;
> + } else {
> + av_log(s->avctx, AV_LOG_WARNING, "Length information for a HT-codeblock is invalid\n");
> + }
> + }
> + }
> + }
> }
> + } else if (cblk->modes & JPEG2000_CTSY_HTJ2K_F) {
> + // Quality layer commences with a non-initial HT coding pass
> + if(bits_to_read != 0)
> + av_log(s->avctx, AV_LOG_WARNING, "Length information for a HT-codeblock is invalid\n");
> + segment_passes = cblk->npasses % 3;
> + if (segment_passes == 0) {
> + // newpasses is a HT Cleanup pass; next segment has refinement passes
> + segment_passes = 1;
> + next_segment_passes = 2;
> + if (segment_bytes == 1)
> + av_log(s->avctx, AV_LOG_WARNING, "Length information for a HT-codeblock is invalid\n");
> + } else {
> + // newpasses = 1 means npasses is HT SigProp; 2 means newpasses is
> + // HT MagRef pass
> + segment_passes = newpasses > 1 ? 3 - segment_passes : 1;
> + next_segment_passes = 1;
> + bits_to_read = av_log2(segment_passes);
> + }
> + bits_to_read = (uint8_t) (bits_to_read + cblk->lblock);
> + segment_bytes = get_bits(s, bits_to_read);
> + // Write length information for HT Refinment segment
> + cblk->pass_lengths[1] += segment_bytes;
> + } else if (!(cblk->modes & (JPEG2000_CBLK_TERMALL | JPEG2000_CBLK_BYPASS))) {
> + // Common case for non-HT code-blocks; we have only one segment
> + bits_to_read = (uint8_t) cblk->lblock + av_log2((uint8_t) newpasses);
> + segment_bytes = get_bits(s, bits_to_read);
> + segment_passes = newpasses;
> + } else if (cblk->modes & JPEG2000_CBLK_TERMALL) {
> + // RESTART MODE
> + bits_to_read = cblk->lblock;
> + segment_bytes = get_bits(s, bits_to_read);
> + segment_passes = 1;
> + next_segment_passes = 1;
> + cblk->nb_terminationsinc++;
> + } else {
> + // BYPASS MODE
> + bypass_term_threshold = 10;
> + if(bits_to_read != 0)
> + av_log(s->avctx, AV_LOG_WARNING, "Length information for a codeblock is invalid\n");
> + if (cblk->npasses < bypass_term_threshold) {
> + // May have from 1 to 10 uninterrupted passes before 1st RAW SigProp
> + segment_passes = bypass_term_threshold - cblk->npasses;
> + if (segment_passes > newpasses)
> + segment_passes = newpasses;
> + while ((2 << bits_to_read) <= segment_passes)
> + bits_to_read++;
> + next_segment_passes = 2;
> + } else if ((cblk->npasses - bypass_term_threshold) % 3 < 2) {
> + // 0 means newpasses is a RAW SigProp; 1 means newpasses is a RAW MagRef pass
> + segment_passes = newpasses > 1 ? 2 - (cblk->npasses - bypass_term_threshold) % 3 : 1;
> + bits_to_read = av_log2(segment_passes);
> + next_segment_passes = 1;
> + } else {
> + // newpasses is an isolated Cleanup pass that precedes a RAW SigProp pass
> + segment_passes = 1;
> + next_segment_passes = 2;
> + }
> + bits_to_read = (uint8_t) (bits_to_read + cblk->lblock);
> + segment_bytes = get_bits(s, bits_to_read);
> }
> -
> - if (newpasses > 1 && (codsty->cblk_style & JPEG2000_CTSY_HTJ2K_F)) {
> - // Retrieve pass lengths for each pass
> - int href_passes = (cblk->npasses + newpasses - 1) % 3;
> - int eb = av_log2(newpasses - href_passes);
> - int extra_bit = newpasses > 2 ? 1 : 0;
> - if ((ret = get_bits(s, llen + eb + 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];
> + // Update cblk->npasses and write length information
> + cblk->npasses = (uint8_t) (cblk->npasses + segment_passes);
> + cblk->lengthinc[cblk->nb_lengthinc++] = segment_bytes;
> +
> + if ((cblk->modes & JPEG2000_CTSY_HTJ2K_F) && cblk->ht_plhd == HT_PLHD_OFF) {
> + newpasses -= (uint8_t) segment_passes;
> + while (newpasses > 0) {
> + segment_passes = newpasses > 1 ? next_segment_passes : 1;
> + next_segment_passes = (uint8_t) (3 - next_segment_passes);
> + bits_to_read = (uint8_t) (cblk->lblock + av_log2(segment_passes));
> + segment_bytes = get_bits(s, bits_to_read);
> + newpasses -= (uint8_t) (segment_passes);
> + // This is a FAST Refinement pass
> + // Write length information for HT Refinement segment
> + cblk->pass_lengths[1] += segment_bytes;
> + // Update cblk->npasses and write length information
> + cblk->npasses = (uint8_t) (cblk->npasses + segment_passes);
> + cblk->lengthinc[cblk->nb_lengthinc++] = segment_bytes;
> + }
> } else {
> - if ((ret = get_bits(s, av_log2(newpasses1) + cblk->lblock)) < 0)
> - return ret;
> - cblk->pass_lengths[0] = ret;
> + newpasses -= (uint8_t) (segment_passes);
> + while (newpasses > 0) {
> + if (bypass_term_threshold != 0) {
> + segment_passes = newpasses > 1 ? next_segment_passes : 1;
> + next_segment_passes = (uint8_t) (3 - next_segment_passes);
> + bits_to_read = (uint8_t) (cblk->lblock + av_log2(segment_passes));
> + } else {
> + if ((cblk->modes & JPEG2000_CBLK_TERMALL) == 0)
> + av_log(s->avctx, AV_LOG_WARNING, "Corrupted packet header is found.\n");
> + segment_passes = 1;
> + bits_to_read = cblk->lblock;
> + }
> + segment_bytes = get_bits(s, bits_to_read);
> + newpasses -= (uint8_t) (segment_passes);
> +
> + // Update cblk->npasses and write length information
> + cblk->npasses = (uint8_t) (cblk->npasses + segment_passes);
> + cblk->lengthinc[cblk->nb_lengthinc++] = segment_bytes;
> + cblk->nb_terminationsinc++;
> + }
> }
> - if (ret > cblk->data_allocated) {
> - size_t new_size = FFMAX(2*cblk->data_allocated, ret);
> +
> + for (int i = 0; i < cblk->nb_lengthinc; ++i)
> + tmp_length = (tmp_length < cblk->lengthinc[i]) ? cblk->lengthinc[i] : tmp_length;
> +
> + if (tmp_length > cblk->data_allocated) {
> + size_t new_size = FFMAX(2 * cblk->data_allocated, tmp_length);
> void *new = av_realloc(cblk->data, new_size);
> if (new) {
> cblk->data = new;
> cblk->data_allocated = new_size;
> }
> }
> - if (ret > cblk->data_allocated) {
> + if (tmp_length > cblk->data_allocated) {
> avpriv_request_sample(s->avctx,
> "Block with lengthinc greater than %"SIZE_SPECIFIER"",
> cblk->data_allocated);
> return AVERROR_PATCHWELCOME;
> }
> - cblk->lengthinc[cblk->nb_lengthinc++] = ret;
> - cblk->npasses += newpasses1;
> - newpasses -= newpasses1;
> - } while(newpasses);
> + } else {
> + // This codeblock has no contribution to the current packet
> + continue;
> + }
> }
> }
> jpeg2000_flush(s);
> @@ -1695,7 +1962,7 @@ static int decode_cblk(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *cod
> Jpeg2000T1Context *t1, Jpeg2000Cblk *cblk,
> int width, int height, int bandpos, uint8_t roi_shift)
> {
> - int passno = cblk->npasses, pass_t = 2, bpno = cblk->nonzerobits - 1 + roi_shift;
> + int passno = cblk->npasses, pass_t = 2, bpno = cblk->nonzerobits - 1;
> int pass_cnt = 0;
> int vert_causal_ctx_csty_symbol = codsty->cblk_style & JPEG2000_CBLK_VSC;
> int term_cnt = 0;
> @@ -1909,7 +2176,7 @@ static inline int tile_codeblocks(const Jpeg2000DecoderContext *s, Jpeg2000Tile
> Jpeg2000Band *band = rlevel->band + bandno;
> int cblkno = 0, bandpos;
> /* See Rec. ITU-T T.800, Equation E-2 */
> - int magp = quantsty->expn[subbandno] + quantsty->nguardbits - 1;
> + int M_b = quantsty->expn[subbandno] + quantsty->nguardbits - 1;
>
> bandpos = bandno + (reslevelno > 0);
>
> @@ -1917,8 +2184,8 @@ static inline int tile_codeblocks(const Jpeg2000DecoderContext *s, Jpeg2000Tile
> band->coord[1][0] == band->coord[1][1])
> continue;
>
> - if ((codsty->cblk_style & JPEG2000_CTSY_HTJ2K_F) && magp >= 31) {
> - avpriv_request_sample(s->avctx, "JPEG2000_CTSY_HTJ2K_F and magp >= 31");
> + if ((codsty->cblk_style & JPEG2000_CTSY_HTJ2K_F) && M_b >= 31) {
> + avpriv_request_sample(s->avctx, "JPEG2000_CTSY_HTJ2K_F and M_b >= 31");
> return AVERROR_PATCHWELCOME;
> }
>
> @@ -1935,11 +2202,11 @@ static inline int tile_codeblocks(const Jpeg2000DecoderContext *s, Jpeg2000Tile
>
> Jpeg2000Cblk *cblk = prec->cblk + cblkno;
>
> - if (codsty->cblk_style & JPEG2000_CTSY_HTJ2K_F)
> + if (cblk->modes & JPEG2000_CTSY_HTJ2K_F)
> ret = ff_jpeg2000_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);
> + M_b, comp->roi_shift);
> else
> ret = decode_cblk(s, codsty, &t1, cblk,
> cblk->coord[0][1] - cblk->coord[0][0],
> @@ -2178,22 +2445,42 @@ 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_WARNING, "CAP marker segment shall come after SIZ\n");
> + }
> + ret = get_cap(s, codsty);
> + break;
> case JPEG2000_COC:
> + if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11))
> + av_log(s->avctx, AV_LOG_WARNING, "COC marker is found in HOMOGENEOUS HT set\n");
> ret = get_coc(s, codsty, properties);
> break;
> case JPEG2000_COD:
> + if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11))
> + av_log(s->avctx, AV_LOG_WARNING, "COD marker is found in HOMOGENEOUS HT set\n");
> ret = get_cod(s, codsty, properties);
> break;
> case JPEG2000_RGN:
> + if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11))
> + av_log(s->avctx, AV_LOG_WARNING, "RGB marker is found in HOMOGENEOUS HT set\n");
> ret = get_rgn(s, len);
> + if ((!s->Ccap15_b12) && s->isHT)
> + av_log(s->avctx, AV_LOG_WARNING, "RGN marker is found in RGNFREE HT set\n");
> break;
> case JPEG2000_QCC:
> + if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11))
> + av_log(s->avctx, AV_LOG_WARNING, "QCC marker is found in HOMOGENEOUS HT set\n");
> ret = get_qcc(s, len, qntsty, properties);
> break;
> case JPEG2000_QCD:
> + if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11))
> + av_log(s->avctx, AV_LOG_WARNING, "QCD marker is found in HOMOGENEOUS HT set\n");
> ret = get_qcd(s, len, qntsty, properties);
> break;
> case JPEG2000_POC:
> + if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11))
> + av_log(s->avctx, AV_LOG_WARNING, "POC marker is found in HOMOGENEOUS HT set\n");
> ret = get_poc(s, len, poc);
> break;
> case JPEG2000_SOT:
> @@ -2243,9 +2530,14 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s)
> "Cannot have both PPT and PPM marker.\n");
> return AVERROR_INVALIDDATA;
> }
> -
> + if ((!s->Ccap15_b11) && s->isHT)
> + av_log(s->avctx, AV_LOG_WARNING, "PPT marker is found in HOMOGENEOUS HT set\n");
> ret = get_ppt(s, len);
> break;
> + case JPEG2000_CPF:
> + // Corresponding profile marker
> + ret = read_cpf(s, len);
> + break;
> default:
> av_log(s->avctx, AV_LOG_ERROR,
> "unsupported marker 0x%.4"PRIX16" at pos 0x%X\n",
> diff --git a/libavcodec/jpeg2000dec.h b/libavcodec/jpeg2000dec.h
> index d0ca6e7a79..326a572722 100644
> --- a/libavcodec/jpeg2000dec.h
> +++ b/libavcodec/jpeg2000dec.h
> @@ -112,6 +112,13 @@ typedef struct Jpeg2000DecoderContext {
> Jpeg2000Tile *tile;
> Jpeg2000DSPContext dsp;
>
> + uint8_t isHT; // HTJ2K?
> + uint8_t Ccap15_b14_15; // HTONLY(= 0) or HTDECLARED(= 1) or MIXED(= 3) ?
> + uint8_t Ccap15_b12; // RGNFREE(= 0) or RGN(= 1)?
> + uint8_t Ccap15_b11; // HOMOGENEOUS(= 0) or HETEROGENEOUS(= 1) ?
> + uint8_t Ccap15_b05; // HTREV(= 0) or HTIRV(= 1) ?
> + uint8_t HT_MAGB; // MAGB value
> +
> /*options parameters*/
> int reduction_factor;
> } Jpeg2000DecoderContext;
> diff --git a/libavcodec/jpeg2000htdec.c b/libavcodec/jpeg2000htdec.c
> index eba0936089..beb4a386b0 100644
> --- a/libavcodec/jpeg2000htdec.c
> +++ b/libavcodec/jpeg2000htdec.c
> @@ -122,7 +122,7 @@ static void jpeg2000_init_mel(StateVars *s, uint32_t Pcup)
>
> static void jpeg2000_init_mag_ref(StateVars *s, uint32_t Lref)
> {
> - s->pos = Lref - 2;
> + s->pos = Lref - 1;
> s->bits = 0;
> s->last = 0xFF;
> s->tmp = 0;
> @@ -145,9 +145,10 @@ static void jpeg2000_init_mel_decoder(MelDecoderState *mel_state)
> static int jpeg2000_bitbuf_refill_backwards(StateVars *buffer, const uint8_t *array)
> {
> uint64_t tmp = 0;
> - int32_t position = buffer->pos - 4;
> uint32_t new_bits = 32;
>
> + buffer->last = array[buffer->pos + 1];
> +
> if (buffer->bits_left >= 32)
> return 0; // enough data, no need to pull in more bits
>
> @@ -157,9 +158,24 @@ static int jpeg2000_bitbuf_refill_backwards(StateVars *buffer, const uint8_t *ar
> * the bottom most bits.
> */
>
> - for(int i = FFMAX(0, position + 1); i <= buffer->pos + 1; i++)
> - tmp = 256*tmp + array[i];
> -
> + if (buffer->pos >= 3) { // Common case; we have at least 4 bytes available
> + tmp = array[buffer->pos - 3];
> + tmp = (tmp << 8) | array[buffer->pos - 2];
> + tmp = (tmp << 8) | array[buffer->pos - 1];
> + tmp = (tmp << 8) | array[buffer->pos];
> + tmp = (tmp << 8) | buffer->last; // For stuffing bit detection
> + buffer->pos -= 4;
> + } else {
> + if (buffer->pos >= 2)
> + tmp = array[buffer->pos - 2];
> + if (buffer->pos >= 1)
> + tmp = (tmp << 8) | array[buffer->pos - 1];
> + if (buffer->pos >= 0)
> + tmp = (tmp << 8) | array[buffer->pos];
> + buffer->pos = 0;
> + tmp = (tmp << 8) | buffer->last; // For stuffing bit detection
> + }
> + // Now remove any stuffing bits, shifting things down as we go
> if ((tmp & 0x7FFF000000) > 0x7F8F000000) {
> tmp &= 0x7FFFFFFFFF;
> new_bits--;
> @@ -176,13 +192,11 @@ static int jpeg2000_bitbuf_refill_backwards(StateVars *buffer, const uint8_t *ar
> tmp = (tmp & 0x0000007FFF) + ((tmp & 0xFFFFFF0000) >> 1);
> new_bits--;
> }
> -
> - tmp >>= 8; // Remove temporary byte loaded
> + tmp >>= 8; // Shifts away the extra byte we imported
>
> /* 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;
> }
>
> @@ -406,6 +420,7 @@ static void recover_mag_sgn(StateVars *mag_sgn, uint8_t pos, uint16_t q, int32_t
> E[n] = 32 - ff_clz(v[pos][i] | 1);
> mu_n[n] = (v[pos][i] >> 1) + 1;
> mu_n[n] <<= pLSB;
> + mu_n[n] |= (1 << (pLSB - 1)); // Add 0.5 (reconstruction parameter = 1/2)
> mu_n[n] |= ((uint32_t) (v[pos][i] & 1)) << 31; // sign bit.
> }
> }
> @@ -414,7 +429,7 @@ static void recover_mag_sgn(StateVars *mag_sgn, uint8_t pos, uint16_t q, int32_t
> static int jpeg2000_import_bit(StateVars *stream, const uint8_t *array, uint32_t length)
> {
> int cond = stream->pos < length;
> - int pos = FFMIN(stream->pos, length);
> + int pos = FFMIN(stream->pos, length - 1);
> if (stream->bits == 0) {
> stream->bits = (stream->tmp == 0xFF) ? 7 : 8;
> stream->pos += cond;
> @@ -426,14 +441,22 @@ static int jpeg2000_import_bit(StateVars *stream, const uint8_t *array, uint32_t
>
> static int jpeg2000_peek_bit(StateVars *stream, const uint8_t *array, uint32_t length)
> {
> + uint8_t bit;
> +
> if (stream->bits == 0) {
> - int cond = stream->pos < length;
> - int pos = FFMIN(stream->pos, length);
> - stream->bits = (stream->tmp == 0xFF) ? 7 : 8;
> - stream->pos += cond;
> - stream->tmp = cond ? array[pos] : 0xFF;
> + stream->bits = (stream->last == 0xFF) ? 7 : 8;
> + if (stream->pos < length) {
> + stream->tmp = array[stream->pos];
> + stream->pos++;
> + } else {
> + stream->tmp = 0;
> + }
> + stream->last = stream->tmp;
> }
> - return (stream->tmp >> stream->bits) & 1;
> + bit = stream->tmp & 1;
> + stream->tmp >>= 1;
> + stream->bits--;
> + return bit;
> }
>
> static int jpeg2000_decode_mel_sym(MelDecoderState *mel_state,
> @@ -994,66 +1017,63 @@ 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 stride)
> {
> - int local_mbr = 0;
> -
> - local_mbr |= jpeg2000_get_state(i - 1, j - 1, stride, HT_SHIFT_SIGMA, block_states);
> - local_mbr |= jpeg2000_get_state(i - 1, j + 0, stride, HT_SHIFT_SIGMA, block_states);
> - local_mbr |= jpeg2000_get_state(i - 1, j + 1, stride, HT_SHIFT_SIGMA, block_states);
> -
> - local_mbr |= jpeg2000_get_state(i + 0, j - 1, stride, HT_SHIFT_SIGMA, block_states);
> - local_mbr |= jpeg2000_get_state(i + 0, j + 1, stride, HT_SHIFT_SIGMA, block_states);
> -
> - local_mbr |= jpeg2000_get_state(i + 1, j - 1, stride, HT_SHIFT_SIGMA, block_states) * causal_cond;
> - local_mbr |= jpeg2000_get_state(i + 1, j + 0, stride, HT_SHIFT_SIGMA, block_states) * causal_cond;
> - local_mbr |= jpeg2000_get_state(i + 1, j + 1, stride, HT_SHIFT_SIGMA, block_states) * causal_cond;
> -
> - local_mbr |= jpeg2000_get_state(i - 1, j - 1, stride, HT_SHIFT_REF, block_states) *
> - jpeg2000_get_state(i - 1, j - 1, stride, HT_SHIFT_SCAN, block_states);
> - local_mbr |= jpeg2000_get_state(i - 1, j + 0, stride, HT_SHIFT_REF, block_states) *
> - jpeg2000_get_state(i - 1, j - 1, stride, HT_SHIFT_SCAN, block_states);
> - local_mbr |= jpeg2000_get_state(i - 1, j + 1, stride, HT_SHIFT_REF, block_states) *
> - jpeg2000_get_state(i - 1, j + 1, stride, HT_SHIFT_SCAN, block_states);
> -
> - local_mbr |= jpeg2000_get_state(i + 0, j - 1, stride, HT_SHIFT_REF, block_states) *
> - jpeg2000_get_state(i + 0, j - 1, stride, HT_SHIFT_SCAN, block_states);
> - local_mbr |= jpeg2000_get_state(i + 0, j + 1, stride, HT_SHIFT_REF, block_states) *
> - jpeg2000_get_state(i + 0, j + 1, stride, HT_SHIFT_SCAN, block_states);
> -
> - local_mbr |= jpeg2000_get_state(i + 1, j - 1, stride, HT_SHIFT_REF, block_states) *
> - jpeg2000_get_state(i + 1, j - 1, stride, HT_SHIFT_SCAN, block_states) * causal_cond;
> - local_mbr |= jpeg2000_get_state(i + 1, j + 0, stride, HT_SHIFT_REF, block_states) *
> - jpeg2000_get_state(i + 1, j + 0, stride, HT_SHIFT_SCAN, block_states) * causal_cond;
> - local_mbr |= jpeg2000_get_state(i + 1, j + 1, stride, HT_SHIFT_REF, block_states) *
> - jpeg2000_get_state(i + 1, j + 1, stride, HT_SHIFT_SCAN, block_states) * causal_cond;
> -
> - *mbr |= local_mbr;
> + uint8_t *state_p0 = block_states + i * stride + j;
> + uint8_t *state_p1 = block_states + (i + 1) * stride + j;
> + uint8_t *state_p2 = block_states + (i + 2) * stride + j;
> +
> + uint8_t mbr0 = state_p0[0] | state_p0[1] | state_p0[2];
> + uint8_t mbr1 = state_p1[0] | state_p1[2];
> + uint8_t mbr2 = state_p2[0] | state_p2[1] | state_p2[2];
> + *mbr = mbr0 | mbr1 | (mbr2 & causal_cond);
> + *mbr |= (mbr0 >> HT_SHIFT_REF) & (mbr0 >> HT_SHIFT_SCAN);
> + *mbr |= (mbr1 >> HT_SHIFT_REF) & (mbr1 >> HT_SHIFT_SCAN);
> + *mbr |= (mbr2 >> HT_SHIFT_REF) & (mbr2 >> HT_SHIFT_SCAN) & causal_cond;
> + *mbr &= 1;
> }
>
> 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)
> + uint8_t *magref_segment, uint32_t magref_length,
> + uint8_t is_causal)
> {
> for (int j = j_s; j < j_s + width; j++) {
> uint32_t mbr_info = 0;
> for (int i = i_s; i < i_s + height; i++) {
> - int modify_state, cond;
> + int modify_state;
> uint8_t bit;
> - uint8_t causal_cond = i != (i_s + height - 1);
> + uint8_t causal_cond = (is_causal == 0) || (i != (i_s + height - 1));
> int32_t *sp = &sample_buf[j + (i * (stride))];
> uint8_t mbr = 0;
>
> - if (jpeg2000_get_state(i, j, stride - 2, HT_SHIFT_SIGMA, block_states) == 0)
> + if (jpeg2000_get_state(i, j, stride, HT_SHIFT_SIGMA, block_states) == 0)
> jpeg2000_calc_mbr(&mbr, i, j, mbr_info & 0x1EF, causal_cond, block_states, stride);
> mbr_info >>= 3;
> - cond = mbr != 0;
> - bit = jpeg2000_peek_bit(sig_prop, magref_segment, magref_length);
> - *sp |= (bit * cond) << pLSB;
> - sig_prop->bits -= cond;
> - modify_state = (((1 << HT_SHIFT_REF_IND) | (1 << HT_SHIFT_REF)) * cond) | 1 << HT_SHIFT_SCAN;
> +
> + modify_state = block_states[(i + 1) * stride + (j + 1)];
> + modify_state |= 1 << HT_SHIFT_SCAN;
> + if (mbr != 0) {
> + modify_state |= 1 << HT_SHIFT_REF_IND;
> + bit = jpeg2000_peek_bit(sig_prop, magref_segment, magref_length);
> + modify_state |= bit << HT_SHIFT_REF;
> + *sp |= bit << pLSB;
> + *sp |= bit << (pLSB - 1); // Add 0.5 (reconstruction parameter = 1/2)
> + }
> jpeg2000_modify_state(i, j, stride, modify_state, block_states);
> }
> }
> + // decode sign
> + for (int j = j_s; j < j_s + width; j++) {
> + for (int i = i_s; i < i_s + height; i++) {
> + uint8_t bit;
> + int32_t *sp = &sample_buf[j + (i * (stride))];
> + uint8_t *state_p = block_states + (i + 1) * stride + (j + 1);
> + if ((state_p[0] >> HT_SHIFT_REF) & 1) {
> + bit = jpeg2000_peek_bit(sig_prop, magref_segment, magref_length);
> + *sp |= (int32_t)bit << 31;
> + }
> + }
> + }
> }
>
> /**
> @@ -1074,6 +1094,7 @@ static void jpeg2000_decode_sigprop_segment(Jpeg2000Cblk *cblk, uint16_t width,
>
> int last_width;
> uint16_t i = 0, j = 0;
> + uint8_t is_causal = cblk->modes & JPEG2000_CBLK_VSC;
>
> jpeg2000_init_zero(&sp_dec);
>
> @@ -1082,14 +1103,14 @@ static void jpeg2000_decode_sigprop_segment(Jpeg2000Cblk *cblk, uint16_t width,
> 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);
> + magref_length, is_causal);
> 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);
> + magref_length, is_causal);
> i += 4;
> }
>
> @@ -1099,20 +1120,20 @@ static void jpeg2000_decode_sigprop_segment(Jpeg2000Cblk *cblk, uint16_t width,
> 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);
> + magref_length, is_causal);
> 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);
> + magref_length, is_causal);
> }
>
> /**
> * See procedure decodeSigPropMag at Rec. ITU-T T.814, 7.5.
> */
> -static int
> +static void
> jpeg2000_decode_magref_segment( uint16_t width, uint16_t block_height, const int stride,
> uint8_t *magref_segment,uint32_t magref_length,
> uint8_t pLSB, int32_t *sample_buf, uint8_t *block_states)
> @@ -1123,7 +1144,8 @@ jpeg2000_decode_magref_segment( uint16_t width, uint16_t block_height, const int
> uint16_t height = 4;
> uint16_t i_start = 0;
> int32_t *sp;
> -
> + int32_t bit;
> + int32_t tmp;
> jpeg2000_init_mag_ref(&mag_ref, magref_length);
>
> for (int n1 = 0; n1 < num_v_stripe; n1++) {
> @@ -1134,9 +1156,13 @@ jpeg2000_decode_magref_segment( uint16_t width, uint16_t block_height, const int
> * Rec. ITU-T T.814, Figure 7.
> */
> sp = &sample_buf[j + i * stride];
> - 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;
> + if (jpeg2000_get_state(i, j, stride, HT_SHIFT_SIGMA, block_states) != 0) {
> + jpeg2000_modify_state(i, j, stride, 1 << HT_SHIFT_REF_IND, block_states);
> + bit = jpeg2000_import_magref_bit(&mag_ref, magref_segment, magref_length);
> + tmp = 0xFFFFFFFE | (uint32_t)bit;
> + tmp <<= pLSB;
> + sp[0] &= tmp;
> + sp[0] |= 1 << (pLSB - 1); // Add 0.5 (reconstruction parameter = 1/2)
> }
> }
> }
> @@ -1146,21 +1172,24 @@ jpeg2000_decode_magref_segment( uint16_t width, uint16_t block_height, const int
> for (int j = 0; j < width; j++) {
> for (int i = i_start; i < i_start + height; i++) {
> sp = &sample_buf[j + i * stride];
> - 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;
> + if (jpeg2000_get_state(i, j, stride, HT_SHIFT_SIGMA, block_states) != 0) {
> + jpeg2000_modify_state(i, j, stride, 1 << HT_SHIFT_REF_IND, block_states);
> + bit = jpeg2000_import_magref_bit(&mag_ref, magref_segment, magref_length);
> + tmp = 0xFFFFFFFE | (uint32_t)bit;
> + tmp <<= pLSB;
> + sp[0] &= tmp;
> + sp[0] |= 1 << (pLSB - 1); // Add 0.5 (reconstruction parameter = 1/2)
> }
> }
> }
> - return 1;
> }
>
>
> int
> ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *codsty, Jpeg2000T1Context *t1, Jpeg2000Cblk *cblk,
> - int width, int height, int magp, uint8_t roi_shift)
> + int width, int height, int M_b, uint8_t roi_shift)
> {
> - uint8_t p0 = 0; // Number of placeholder passes
> + uint8_t p0 = 0; // 3 * p0 = 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
> @@ -1174,7 +1203,7 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c
>
> int z_blk; // Number of ht coding pass
>
> - uint8_t empty_passes;
> + uint8_t num_plhd_passes; // Number of placeholder passes
>
> StateVars mag_sgn; // Magnitude and Sign
> StateVars mel; // Adaptive run-length coding
> @@ -1190,8 +1219,8 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c
> uint8_t *block_states = NULL;
>
> int32_t n, val; // Post-processing
> -
> - int32_t M_b = magp;
> + const uint32_t mask = UINT32_MAX >> (M_b + 1); // bit mask for ROI detection
> + uint8_t num_rempass;
>
> const int quad_buf_width = width + 4;
> const int quad_buf_height = height + 4;
> @@ -1201,22 +1230,17 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c
> av_assert0(width * height <= 4096);
> av_assert0(width * height > 0);
>
> - if (roi_shift)
> - avpriv_report_missing_feature(s->avctx, "ROI shift");
> -
> 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)
> - p0 = 0;
> - else if (cblk->length == 0)
> - p0 = 1;
> -
> - empty_passes = p0 * 3;
> - z_blk = cblk->npasses - empty_passes;
> + num_rempass = cblk->npasses % 3; // Number of remainder passes
> + num_plhd_passes = num_rempass ? cblk->npasses - num_rempass : cblk->npasses - 3;
> + av_assert0(num_plhd_passes % 3 == 0);
> + p0 = num_plhd_passes / 3;
> + z_blk = cblk->npasses - num_plhd_passes;
>
> if (z_blk <= 0)
> return 0; // No passes within this set, continue
> @@ -1231,7 +1255,11 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c
> }
> Dcup = cblk->data;
> Dref = cblk->data + Lcup; // Dref comes after the refinement segment
> +
> + cblk->data[cblk->length] = 0xFF; // an extra byte for refinement segment (buffer->last)
> +
> S_blk = p0 + cblk->zbp;
> + cblk->zbp = S_blk - 1;
> pLSB = 30 - S_blk;
>
> Scup = (Dcup[Lcup - 1] << 4) + (Dcup[Lcup - 2] & 0x0F);
> @@ -1277,31 +1305,32 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c
> goto free;
> }
>
> - if (cblk->npasses > 1)
> + if (z_blk > 1)
> jpeg2000_decode_sigprop_segment(cblk, width, height, quad_buf_width, Dref, Lref,
> pLSB - 1, sample_buf, block_states);
>
> - if (cblk->npasses > 2) {
> -
> - if (Lref < 2){
> - av_log(s->avctx,AV_LOG_ERROR,"Invalid magnitude refinement length\n");
> - ret = AVERROR_INVALIDDATA;
> - goto free;
> - }
> - if ((ret = jpeg2000_decode_magref_segment(width, height, quad_buf_width, Dref, Lref,
> - pLSB - 1, sample_buf, block_states)) < 0)
> - goto free;
> - }
> + if (z_blk > 2)
> + jpeg2000_decode_magref_segment(width, height, quad_buf_width, Dref, Lref,
> + pLSB - 1, sample_buf, block_states);
>
> pLSB = 31 - M_b;
>
> /* Reconstruct the sample values */
> for (int y = 0; y < height; y++) {
> for (int x = 0; x < width; x++) {
> + int32_t sign;
> +
> n = x + (y * t1->stride);
> val = sample_buf[x + (y * quad_buf_width)];
> + sign = val & INT32_MIN;
> + val &= INT32_MAX;
> + /* ROI shift, if necessary */
> + if (roi_shift && (((uint32_t)val & ~mask) == 0))
> + val <<= roi_shift;
> /* Convert sign-magnitude to two's complement. */
> - val = val >> 31 ? 0x80000000 - val : val;
> + if (sign)
> + val = -val;
> + /* Shift down to 1 bit upper from decimal point for reconstruction value (= 0.5) */
> val >>= (pLSB - 1);
> t1->data[n] = val;
> }
> diff --git a/libavcodec/jpeg2000htdec.h b/libavcodec/jpeg2000htdec.h
> index 572d095c92..8d6919a0de 100644
> --- a/libavcodec/jpeg2000htdec.h
> +++ b/libavcodec/jpeg2000htdec.h
> @@ -29,6 +29,6 @@
>
> int ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *codsty,
> Jpeg2000T1Context *t1, Jpeg2000Cblk *cblk, int width,
> - int height, int magp, uint8_t roi_shift);
> + int height, int M_b, uint8_t roi_shift);
>
> #endif /* AVCODEC_JPEG2000HTDEC_H */
> --
> 2.34.1
>
_______________________________________________
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".
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [FFmpeg-devel] [PATCH 1/2] avcodec/jpeg2000dec: Add support for placeholder passes, CAP, and CPF markers
2024-06-15 6:00 ` [FFmpeg-devel] [PATCH 1/2] avcodec/jpeg2000dec: Add support for placeholder passes, CAP, and CPF markers Pierre-Anthony Lemieux
@ 2024-06-15 7:55 ` WATANABE Osamu
0 siblings, 0 replies; 5+ messages in thread
From: WATANABE Osamu @ 2024-06-15 7:55 UTC (permalink / raw)
To: Pierre-Anthony Lemieux; +Cc: ffmpeg-devel
Hi Pierre,
Here is the list of supported J2K reference codestreams.
p0_10.j2k
p1_01.j2k
p1_02.j2k
p1_03.j2k
p1_04.j2k
p1_05.j2k
p1_06.j2k
ds0_hm_15_b8.j2k
ds0_ht_02_b11.j2k
ds0_ht_02_b12.j2k
ds0_ht_03_b11.j2k
ds0_ht_03_b14.j2k
ds0_ht_04_b11.j2k
ds0_ht_04_b12.j2k
ds0_ht_05_b11.j2k
ds0_ht_05_b12.j2k
ds0_ht_07_b11.j2k
ds0_ht_07_b15.j2k
ds0_ht_07_b16.j2k
ds0_ht_08_b11.j2k
ds0_ht_08_b15.j2k
ds0_ht_08_b16.j2k
ds0_ht_09_b11.j2k
ds0_ht_10_b11.j2k
ds0_ht_11_b10.j2k
ds0_ht_12_b11.j2k
ds0_ht_14_b11.j2k
ds0_ht_15_b11.j2k
ds0_ht_15_b14.j2k
ds0_ht_16_b11.j2k
ds1_ht_01_b11.j2k
ds1_ht_01_b12.j2k
ds1_ht_02_b11.j2k
ds1_ht_02_b12.j2k
ds1_ht_03_b11.j2k
ds1_ht_03_b12.j2k
ds1_ht_04_b9.j2k
ds1_ht_05_b11.j2k
ds1_ht_06_b11.j2k
hifi_ht1_02.j2k
hifi_p1_02.j2k
FYI - the following codestreams are excluded from the list due to their unsupported pixel format in FFMPEG.
p0_06.j2k
p0_13.j2k
p1_07.j2k
ds0_ht_06_b11.j2k
ds0_ht_06_b15.j2k
ds0_ht_06_b18.j2k
ds0_hm_06_b11.j2k
ds0_hm_06_b18.j2k
ds0_ht_13_b11.j2k
ds1_ht_07_b11.j2k
Separate color component should be decodable and I can provide them if necessary.
Best,
Osau
> On Jun 15, 2024, at 15:00, Pierre-Anthony Lemieux <pal@sandflow.com> wrote:
>
> Hi Osamu,
>
> Can you provide the list of J2K reference codestreams that this code
> allows FFMPEG to support -- not including those already supported [1]?
>
> [1] https://github.com/FFmpeg/FFmpeg/blob/master/tests/fate/jpeg2000.mak
>
> Best,
>
> -- Pierre
>
> On Fri, Jun 14, 2024 at 8:15?PM Osamu Watanabe
> <owatanab@es.takushoku-u.ac.jp> wrote:
>>
>> Signed-off-by: Osamu Watanabe <owatanab@es.takushoku-u.ac.jp>
>> ---
>> libavcodec/jpeg2000.h | 10 +
>> libavcodec/jpeg2000dec.c | 454 ++++++++++++++++++++++++++++++-------
>> libavcodec/jpeg2000dec.h | 7 +
>> libavcodec/jpeg2000htdec.c | 225 ++++++++++--------
>> libavcodec/jpeg2000htdec.h | 2 +-
>> 5 files changed, 518 insertions(+), 180 deletions(-)
>>
>> diff --git a/libavcodec/jpeg2000.h b/libavcodec/jpeg2000.h
>> index d004c08f10..93221d90ca 100644
>> --- a/libavcodec/jpeg2000.h
>> +++ b/libavcodec/jpeg2000.h
>> @@ -37,12 +37,14 @@
>>
>> enum Jpeg2000Markers {
>> JPEG2000_SOC = 0xff4f, // start of codestream
>> + JPEG2000_CAP = 0xff50, // extended capabilities
>> JPEG2000_SIZ = 0xff51, // image and tile size
>> JPEG2000_COD, // coding style default
>> JPEG2000_COC, // coding style component
>> JPEG2000_TLM = 0xff55, // tile-part length, main header
>> JPEG2000_PLM = 0xff57, // packet length, main header
>> JPEG2000_PLT, // packet length, tile-part header
>> + JPEG2000_CPF, // corresponding profile
>> JPEG2000_QCD = 0xff5c, // quantization default
>> JPEG2000_QCC, // quantization component
>> JPEG2000_RGN, // region of interest
>> @@ -58,6 +60,12 @@ enum Jpeg2000Markers {
>> JPEG2000_EOC = 0xffd9, // end of codestream
>> };
>>
>> +enum JPEG2000_Ccap15_b14_15_params {
>> + HTJ2K_HTONLY = 0, // HTONLY, bit 14 and 15 are 0
>> + HTJ2K_HTDECLARED, // HTDECLARED, bit 14 = 1 and bit 15 = 0
>> + HTJ2K_MIXED = 3, // MIXED, bit 14 and 15 are 1
>> +};
>> +
>> #define JPEG2000_SOP_FIXED_BYTES 0xFF910004
>> #define JPEG2000_SOP_BYTE_LENGTH 6
>>
>> @@ -192,6 +200,8 @@ typedef struct Jpeg2000Cblk {
>> /* specific to HT code-blocks */
>> int zbp;
>> int pass_lengths[2];
>> + uint8_t modes; // copy of SPcod/SPcoc field to parse HT-MIXED mode
>> + uint8_t ht_plhd; // are we looking for HT placeholder passes?
>> } Jpeg2000Cblk; // code block
>>
>> typedef struct Jpeg2000Prec {
>> diff --git a/libavcodec/jpeg2000dec.c b/libavcodec/jpeg2000dec.c
>> index d15502a527..d299c67cc7 100644
>> --- a/libavcodec/jpeg2000dec.c
>> +++ b/libavcodec/jpeg2000dec.c
>> @@ -54,6 +54,15 @@
>> #define HAD_COC 0x01
>> #define HAD_QCC 0x02
>>
>> +// Values of flag for placeholder passes
>> +enum HT_PLHD_STATUS {
>> + HT_PLHD_OFF,
>> + HT_PLHD_ON
>> +};
>> +
>> +#define HT_MIXED 0x80 // bit 7 of SPcod/SPcoc
>> +
>> +
>> /* get_bits functions for JPEG2000 packet bitstream
>> * It is a get_bit function with a bit-stuffing routine. If the value of the
>> * byte is 0xFF, the next byte includes an extra zero bit stuffed into the MSB.
>> @@ -382,6 +391,9 @@ static int get_siz(Jpeg2000DecoderContext *s)
>> } else if (ncomponents == 1 && s->precision == 8) {
>> s->avctx->pix_fmt = AV_PIX_FMT_GRAY8;
>> i = 0;
>> + } else if (ncomponents == 1 && s->precision == 12) {
>> + s->avctx->pix_fmt = AV_PIX_FMT_GRAY16LE;
>> + i = 0;
>> }
>> }
>>
>> @@ -408,6 +420,73 @@ static int get_siz(Jpeg2000DecoderContext *s)
>> s->avctx->bits_per_raw_sample = s->precision;
>> return 0;
>> }
>> +/* get extended capabilities (CAP) marker segment */
>> +static int get_cap(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c)
>> +{
>> + uint32_t Pcap;
>> + uint16_t Ccap_i[32] = { 0 };
>> + uint16_t Ccap_15;
>> + uint8_t P;
>> +
>> + if (bytestream2_get_bytes_left(&s->g) < 6) {
>> + av_log(s->avctx, AV_LOG_ERROR, "Insufficient space for CAP\n");
>> + return AVERROR_INVALIDDATA;
>> + }
>> +
>> + Pcap = bytestream2_get_be32u(&s->g);
>> + s->isHT = (Pcap >> (31 - (15 - 1))) & 1;
>> + for (int i = 0; i < 32; i++) {
>> + if ((Pcap >> (31 - i)) & 1)
>> + Ccap_i[i] = bytestream2_get_be16u(&s->g);
>> + }
>> + Ccap_15 = Ccap_i[14];
>> + if (s->isHT == 1) {
>> + av_log(s->avctx, AV_LOG_INFO, "This is an HTJ2K codestream.\n");
>> + // Bits 14-15
>> + switch ((Ccap_15 >> 14) & 0x3) {
>> + case 0x3:
>> + s->Ccap15_b14_15 = HTJ2K_MIXED;
>> + break;
>> + case 0x1:
>> + s->Ccap15_b14_15 = HTJ2K_HTDECLARED;
>> + break;
>> + case 0x0:
>> + s->Ccap15_b14_15 = HTJ2K_HTONLY;
>> + break;
>> + default:
>> + av_log(s->avctx, AV_LOG_ERROR, "Unknown CCap value.\n");
>> + return AVERROR(EINVAL);
>> + break;
>> + }
>> + // Bit 13
>> + if ((Ccap_15 >> 13) & 1) {
>> + av_log(s->avctx, AV_LOG_ERROR, "MULTIHT set is not supported.\n");
>> + return AVERROR_PATCHWELCOME;
>> + }
>> + // Bit 12
>> + s->Ccap15_b12 = (Ccap_15 >> 12) & 1;
>> + // Bit 11
>> + s->Ccap15_b11 = (Ccap_15 >> 11) & 1;
>> + // Bit 5
>> + s->Ccap15_b05 = (Ccap_15 >> 5) & 1;
>> + // Bit 0-4
>> + P = Ccap_15 & 0x1F;
>> + if (!P)
>> + s->HT_MAGB = 8;
>> + else if (P < 20)
>> + s->HT_MAGB = P + 8;
>> + else if (P < 31)
>> + s->HT_MAGB = 4 * (P - 19) + 27;
>> + else
>> + s->HT_MAGB = 74;
>> +
>> + if (s->HT_MAGB > 31) {
>> + av_log(s->avctx, AV_LOG_ERROR, "Available internal precision is exceeded (MAGB> 31).\n");
>> + return AVERROR_PATCHWELCOME;
>> + }
>> + }
>> + return 0;
>> +}
>>
>> /* get common part for COD and COC segments */
>> static int get_cox(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c)
>> @@ -802,6 +881,15 @@ static int read_crg(Jpeg2000DecoderContext *s, int n)
>> bytestream2_skip(&s->g, n - 2);
>> return 0;
>> }
>> +
>> +static int read_cpf(Jpeg2000DecoderContext *s, int n)
>> +{
>> + if (bytestream2_get_bytes_left(&s->g) < (n - 2))
>> + return AVERROR_INVALIDDATA;
>> + bytestream2_skip(&s->g, n - 2);
>> + return 0;
>> +}
>> +
>> /* Tile-part lengths: see ISO 15444-1:2002, section A.7.1
>> * Used to know the number of tile parts and lengths.
>> * There may be multiple TLMs in the header.
>> @@ -965,6 +1053,10 @@ static int init_tile(Jpeg2000DecoderContext *s, int tileno)
>> comp->roi_shift = s->roi_shift[compno];
>> if (!codsty->init)
>> return AVERROR_INVALIDDATA;
>> + if (s->isHT && (!s->Ccap15_b05) && (!codsty->transform))
>> + av_log(s->avctx, AV_LOG_WARNING, "Transformation = 0 (lossy DWT) is found in HTREV HT set\n");
>> + if (s->isHT && s->Ccap15_b14_15 != (codsty->cblk_style >> 6) && s->Ccap15_b14_15 != HTJ2K_HTONLY)
>> + av_log(s->avctx, AV_LOG_WARNING, "SPcod/SPcoc value does not match bit 14-15 values of Ccap15\n");
>> if (ret = ff_jpeg2000_init_component(comp, codsty, qntsty,
>> s->cbps[compno], s->cdx[compno],
>> s->cdy[compno], s->avctx))
>> @@ -1067,100 +1159,275 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile,
>> int incl, newpasses, llen;
>> void *tmp;
>>
>> - if (cblk->npasses)
>> - incl = get_bits(s, 1);
>> - else
>> + if (!cblk->incl) {
>> + incl = 0;
>> + cblk->modes = codsty->cblk_style;
>> + if (cblk->modes >= JPEG2000_CTSY_HTJ2K_F)
>> + cblk->ht_plhd = HT_PLHD_ON;
>> + if (layno > 0)
>> + incl = tag_tree_decode(s, prec->cblkincl + cblkno, 0 + 1) == 0;
>> incl = tag_tree_decode(s, prec->cblkincl + cblkno, layno + 1) == layno;
>> - if (!incl)
>> - continue;
>> - else if (incl < 0)
>> - return incl;
>> -
>> - if (!cblk->npasses) {
>> - int zbp = tag_tree_decode(s, prec->zerobits + cblkno, 100);
>> - int v = expn[bandno] + numgbits - 1 - zbp;
>>
>> - if (v < 0 || v > 30) {
>> - av_log(s->avctx, AV_LOG_ERROR,
>> - "nonzerobits %d invalid or unsupported\n", v);
>> - return AVERROR_INVALIDDATA;
>> + if (incl) {
>> + int zbp = tag_tree_decode(s, prec->zerobits + cblkno, 100);
>> + int v = expn[bandno] + numgbits - 1 - (zbp - tile->comp->roi_shift);
>> + if (v < 0 || v > 30) {
>> + av_log(s->avctx, AV_LOG_ERROR,
>> + "nonzerobits %d invalid or unsupported\n", v);
>> + return AVERROR_INVALIDDATA;
>> + }
>> + cblk->incl = 1;
>> + cblk->nonzerobits = v;
>> + cblk->zbp = zbp;
>> + cblk->lblock = 3;
>> }
>> - cblk->zbp = zbp;
>> - cblk->nonzerobits = v;
>> - }
>> - if ((newpasses = getnpasses(s)) < 0)
>> - return newpasses;
>> - av_assert2(newpasses > 0);
>> - if (cblk->npasses + newpasses >= JPEG2000_MAX_PASSES) {
>> - avpriv_request_sample(s->avctx, "Too many passes");
>> - return AVERROR_PATCHWELCOME;
>> - }
>> - if ((llen = getlblockinc(s)) < 0)
>> - return llen;
>> - if (cblk->lblock + llen + av_log2(newpasses) > 16) {
>> - avpriv_request_sample(s->avctx,
>> - "Block with length beyond 16 bits");
>> - return AVERROR_PATCHWELCOME;
>> + } else {
>> + incl = get_bits(s, 1);
>> }
>>
>> - cblk->lblock += llen;
>> -
>> - cblk->nb_lengthinc = 0;
>> - cblk->nb_terminationsinc = 0;
>> - av_free(cblk->lengthinc);
>> - cblk->lengthinc = av_calloc(newpasses, sizeof(*cblk->lengthinc));
>> - if (!cblk->lengthinc)
>> - return AVERROR(ENOMEM);
>> - tmp = av_realloc_array(cblk->data_start, cblk->nb_terminations + newpasses + 1, sizeof(*cblk->data_start));
>> - if (!tmp)
>> - return AVERROR(ENOMEM);
>> - cblk->data_start = tmp;
>> - do {
>> - int newpasses1 = 0;
>> -
>> - while (newpasses1 < newpasses) {
>> - newpasses1 ++;
>> - if (needs_termination(codsty->cblk_style, cblk->npasses + newpasses1 - 1)) {
>> - cblk->nb_terminationsinc ++;
>> - break;
>> + if (incl) {
>> + uint8_t bypass_term_threshold = 0;
>> + uint8_t bits_to_read = 0;
>> + uint32_t segment_bytes = 0;
>> + int32_t segment_passes = 0;
>> + uint8_t next_segment_passes = 0;
>> + int32_t href_passes, pass_bound;
>> + uint32_t tmp_length = 0;
>> +
>> + if ((newpasses = getnpasses(s)) <= 0)
>> + return newpasses;
>> + if (cblk->npasses + newpasses >= JPEG2000_MAX_PASSES) {
>> + avpriv_request_sample(s->avctx, "Too many passes");
>> + return AVERROR_PATCHWELCOME;
>> + }
>> + if ((llen = getlblockinc(s)) < 0)
>> + return llen;
>> + if (cblk->lblock + llen + av_log2(newpasses) > 16) {
>> + avpriv_request_sample(s->avctx,
>> + "Block with length beyond 16 bits");
>> + return AVERROR_PATCHWELCOME;
>> + }
>> + cblk->nb_lengthinc = 0;
>> + cblk->nb_terminationsinc = 0;
>> + av_free(cblk->lengthinc);
>> + cblk->lengthinc = av_calloc(newpasses, sizeof(*cblk->lengthinc));
>> + if (!cblk->lengthinc)
>> + return AVERROR(ENOMEM);
>> + tmp = av_realloc_array(cblk->data_start, cblk->nb_terminations + newpasses + 1,
>> + sizeof(*cblk->data_start));
>> + if (!tmp)
>> + return AVERROR(ENOMEM);
>> + cblk->data_start = tmp;
>> + cblk->lblock += llen;
>> +
>> + if (cblk->ht_plhd) {
>> + href_passes = (cblk->npasses + newpasses - 1) % 3;
>> + segment_passes = newpasses - href_passes;
>> + pass_bound = 2;
>> + bits_to_read = cblk->lblock;
>> + if (segment_passes < 1) {
>> + // No possible HT Cleanup pass here; may have placeholder passes
>> + // or an original J2K block bit-stream (in MIXED mode).
>> + segment_passes = newpasses;
>> + while (pass_bound <= segment_passes) {
>> + bits_to_read++;
>> + pass_bound += pass_bound;
>> + }
>> + segment_bytes = get_bits(s, bits_to_read);
>> + if (segment_bytes) {
>> + if (cblk->modes & HT_MIXED) {
>> + cblk->ht_plhd = HT_PLHD_OFF;
>> + cblk->modes &= (uint8_t) (~(JPEG2000_CTSY_HTJ2K_F));
>> + }
>> + else {
>> + av_log(s->avctx, AV_LOG_WARNING, "Length information for a HT-codeblock is invalid\n");
>> + }
>> + }
>> + } else {
>> + while (pass_bound <= segment_passes) {
>> + bits_to_read++;
>> + pass_bound += pass_bound;
>> + }
>> + segment_bytes = get_bits(s, bits_to_read);
>> + if (segment_bytes) {
>> + // No more placeholder passes
>> + if (!(cblk->modes & HT_MIXED)) {
>> + // Must be the first HT Cleanup pass
>> + if (segment_bytes < 2)
>> + av_log(s->avctx, AV_LOG_WARNING, "Length information for a HT-codeblock is invalid\n");
>> + next_segment_passes = 2;
>> + cblk->ht_plhd = HT_PLHD_OFF;
>> + // Write length information for HT CleanUp segment
>> + cblk->pass_lengths[0] = segment_bytes;
>> + } else if (cblk->lblock > 3 && segment_bytes > 1
>> + && (segment_bytes >> (bits_to_read - 1)) == 0) {
>> + // Must be the first HT Cleanup pass, since length MSB is 0
>> + next_segment_passes = 2;
>> + cblk->ht_plhd = HT_PLHD_OFF;
>> + // Write length information for HT CleanUp segment
>> + cblk->pass_lengths[0] = segment_bytes;
>> + } else {
>> + // Must have an original (non-HT) block coding pass
>> + cblk->modes &= (uint8_t) (~(JPEG2000_CTSY_HTJ2K_F));
>> + cblk->ht_plhd = HT_PLHD_OFF;
>> + segment_passes = newpasses;
>> + while (pass_bound <= segment_passes) {
>> + bits_to_read++;
>> + pass_bound += pass_bound;
>> + segment_bytes <<= 1;
>> + segment_bytes += get_bits(s, 1);
>> + }
>> + }
>> + } else {
>> + // Probably parsing placeholder passes, but we need to read an
>> + // extra length bit to verify this, since prior to the first
>> + // HT Cleanup pass, the number of length bits read for a
>> + // contributing code-block is dependent on the number of passes
>> + // being included, as if it were a non-HT code-block.
>> + segment_passes = newpasses;
>> + if (pass_bound <= segment_passes) {
>> + while (1) {
>> + bits_to_read++;
>> + pass_bound += pass_bound;
>> + segment_bytes <<= 1;
>> + segment_bytes += get_bits(s, 1);
>> + if (pass_bound > segment_passes)
>> + break;
>> + }
>> + if (segment_bytes) {
>> + if (cblk->modes & HT_MIXED) {
>> + cblk->modes &= (uint8_t) (~(JPEG2000_CTSY_HTJ2K_F));
>> + cblk->ht_plhd = HT_PLHD_OFF;
>> + } else {
>> + av_log(s->avctx, AV_LOG_WARNING, "Length information for a HT-codeblock is invalid\n");
>> + }
>> + }
>> + }
>> + }
>> }
>> + } else if (cblk->modes & JPEG2000_CTSY_HTJ2K_F) {
>> + // Quality layer commences with a non-initial HT coding pass
>> + if(bits_to_read != 0)
>> + av_log(s->avctx, AV_LOG_WARNING, "Length information for a HT-codeblock is invalid\n");
>> + segment_passes = cblk->npasses % 3;
>> + if (segment_passes == 0) {
>> + // newpasses is a HT Cleanup pass; next segment has refinement passes
>> + segment_passes = 1;
>> + next_segment_passes = 2;
>> + if (segment_bytes == 1)
>> + av_log(s->avctx, AV_LOG_WARNING, "Length information for a HT-codeblock is invalid\n");
>> + } else {
>> + // newpasses = 1 means npasses is HT SigProp; 2 means newpasses is
>> + // HT MagRef pass
>> + segment_passes = newpasses > 1 ? 3 - segment_passes : 1;
>> + next_segment_passes = 1;
>> + bits_to_read = av_log2(segment_passes);
>> + }
>> + bits_to_read = (uint8_t) (bits_to_read + cblk->lblock);
>> + segment_bytes = get_bits(s, bits_to_read);
>> + // Write length information for HT Refinment segment
>> + cblk->pass_lengths[1] += segment_bytes;
>> + } else if (!(cblk->modes & (JPEG2000_CBLK_TERMALL | JPEG2000_CBLK_BYPASS))) {
>> + // Common case for non-HT code-blocks; we have only one segment
>> + bits_to_read = (uint8_t) cblk->lblock + av_log2((uint8_t) newpasses);
>> + segment_bytes = get_bits(s, bits_to_read);
>> + segment_passes = newpasses;
>> + } else if (cblk->modes & JPEG2000_CBLK_TERMALL) {
>> + // RESTART MODE
>> + bits_to_read = cblk->lblock;
>> + segment_bytes = get_bits(s, bits_to_read);
>> + segment_passes = 1;
>> + next_segment_passes = 1;
>> + cblk->nb_terminationsinc++;
>> + } else {
>> + // BYPASS MODE
>> + bypass_term_threshold = 10;
>> + if(bits_to_read != 0)
>> + av_log(s->avctx, AV_LOG_WARNING, "Length information for a codeblock is invalid\n");
>> + if (cblk->npasses < bypass_term_threshold) {
>> + // May have from 1 to 10 uninterrupted passes before 1st RAW SigProp
>> + segment_passes = bypass_term_threshold - cblk->npasses;
>> + if (segment_passes > newpasses)
>> + segment_passes = newpasses;
>> + while ((2 << bits_to_read) <= segment_passes)
>> + bits_to_read++;
>> + next_segment_passes = 2;
>> + } else if ((cblk->npasses - bypass_term_threshold) % 3 < 2) {
>> + // 0 means newpasses is a RAW SigProp; 1 means newpasses is a RAW MagRef pass
>> + segment_passes = newpasses > 1 ? 2 - (cblk->npasses - bypass_term_threshold) % 3 : 1;
>> + bits_to_read = av_log2(segment_passes);
>> + next_segment_passes = 1;
>> + } else {
>> + // newpasses is an isolated Cleanup pass that precedes a RAW SigProp pass
>> + segment_passes = 1;
>> + next_segment_passes = 2;
>> + }
>> + bits_to_read = (uint8_t) (bits_to_read + cblk->lblock);
>> + segment_bytes = get_bits(s, bits_to_read);
>> }
>> -
>> - if (newpasses > 1 && (codsty->cblk_style & JPEG2000_CTSY_HTJ2K_F)) {
>> - // Retrieve pass lengths for each pass
>> - int href_passes = (cblk->npasses + newpasses - 1) % 3;
>> - int eb = av_log2(newpasses - href_passes);
>> - int extra_bit = newpasses > 2 ? 1 : 0;
>> - if ((ret = get_bits(s, llen + eb + 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];
>> + // Update cblk->npasses and write length information
>> + cblk->npasses = (uint8_t) (cblk->npasses + segment_passes);
>> + cblk->lengthinc[cblk->nb_lengthinc++] = segment_bytes;
>> +
>> + if ((cblk->modes & JPEG2000_CTSY_HTJ2K_F) && cblk->ht_plhd == HT_PLHD_OFF) {
>> + newpasses -= (uint8_t) segment_passes;
>> + while (newpasses > 0) {
>> + segment_passes = newpasses > 1 ? next_segment_passes : 1;
>> + next_segment_passes = (uint8_t) (3 - next_segment_passes);
>> + bits_to_read = (uint8_t) (cblk->lblock + av_log2(segment_passes));
>> + segment_bytes = get_bits(s, bits_to_read);
>> + newpasses -= (uint8_t) (segment_passes);
>> + // This is a FAST Refinement pass
>> + // Write length information for HT Refinement segment
>> + cblk->pass_lengths[1] += segment_bytes;
>> + // Update cblk->npasses and write length information
>> + cblk->npasses = (uint8_t) (cblk->npasses + segment_passes);
>> + cblk->lengthinc[cblk->nb_lengthinc++] = segment_bytes;
>> + }
>> } else {
>> - if ((ret = get_bits(s, av_log2(newpasses1) + cblk->lblock)) < 0)
>> - return ret;
>> - cblk->pass_lengths[0] = ret;
>> + newpasses -= (uint8_t) (segment_passes);
>> + while (newpasses > 0) {
>> + if (bypass_term_threshold != 0) {
>> + segment_passes = newpasses > 1 ? next_segment_passes : 1;
>> + next_segment_passes = (uint8_t) (3 - next_segment_passes);
>> + bits_to_read = (uint8_t) (cblk->lblock + av_log2(segment_passes));
>> + } else {
>> + if ((cblk->modes & JPEG2000_CBLK_TERMALL) == 0)
>> + av_log(s->avctx, AV_LOG_WARNING, "Corrupted packet header is found.\n");
>> + segment_passes = 1;
>> + bits_to_read = cblk->lblock;
>> + }
>> + segment_bytes = get_bits(s, bits_to_read);
>> + newpasses -= (uint8_t) (segment_passes);
>> +
>> + // Update cblk->npasses and write length information
>> + cblk->npasses = (uint8_t) (cblk->npasses + segment_passes);
>> + cblk->lengthinc[cblk->nb_lengthinc++] = segment_bytes;
>> + cblk->nb_terminationsinc++;
>> + }
>> }
>> - if (ret > cblk->data_allocated) {
>> - size_t new_size = FFMAX(2*cblk->data_allocated, ret);
>> +
>> + for (int i = 0; i < cblk->nb_lengthinc; ++i)
>> + tmp_length = (tmp_length < cblk->lengthinc[i]) ? cblk->lengthinc[i] : tmp_length;
>> +
>> + if (tmp_length > cblk->data_allocated) {
>> + size_t new_size = FFMAX(2 * cblk->data_allocated, tmp_length);
>> void *new = av_realloc(cblk->data, new_size);
>> if (new) {
>> cblk->data = new;
>> cblk->data_allocated = new_size;
>> }
>> }
>> - if (ret > cblk->data_allocated) {
>> + if (tmp_length > cblk->data_allocated) {
>> avpriv_request_sample(s->avctx,
>> "Block with lengthinc greater than %"SIZE_SPECIFIER"",
>> cblk->data_allocated);
>> return AVERROR_PATCHWELCOME;
>> }
>> - cblk->lengthinc[cblk->nb_lengthinc++] = ret;
>> - cblk->npasses += newpasses1;
>> - newpasses -= newpasses1;
>> - } while(newpasses);
>> + } else {
>> + // This codeblock has no contribution to the current packet
>> + continue;
>> + }
>> }
>> }
>> jpeg2000_flush(s);
>> @@ -1695,7 +1962,7 @@ static int decode_cblk(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *cod
>> Jpeg2000T1Context *t1, Jpeg2000Cblk *cblk,
>> int width, int height, int bandpos, uint8_t roi_shift)
>> {
>> - int passno = cblk->npasses, pass_t = 2, bpno = cblk->nonzerobits - 1 + roi_shift;
>> + int passno = cblk->npasses, pass_t = 2, bpno = cblk->nonzerobits - 1;
>> int pass_cnt = 0;
>> int vert_causal_ctx_csty_symbol = codsty->cblk_style & JPEG2000_CBLK_VSC;
>> int term_cnt = 0;
>> @@ -1909,7 +2176,7 @@ static inline int tile_codeblocks(const Jpeg2000DecoderContext *s, Jpeg2000Tile
>> Jpeg2000Band *band = rlevel->band + bandno;
>> int cblkno = 0, bandpos;
>> /* See Rec. ITU-T T.800, Equation E-2 */
>> - int magp = quantsty->expn[subbandno] + quantsty->nguardbits - 1;
>> + int M_b = quantsty->expn[subbandno] + quantsty->nguardbits - 1;
>>
>> bandpos = bandno + (reslevelno > 0);
>>
>> @@ -1917,8 +2184,8 @@ static inline int tile_codeblocks(const Jpeg2000DecoderContext *s, Jpeg2000Tile
>> band->coord[1][0] == band->coord[1][1])
>> continue;
>>
>> - if ((codsty->cblk_style & JPEG2000_CTSY_HTJ2K_F) && magp >= 31) {
>> - avpriv_request_sample(s->avctx, "JPEG2000_CTSY_HTJ2K_F and magp >= 31");
>> + if ((codsty->cblk_style & JPEG2000_CTSY_HTJ2K_F) && M_b >= 31) {
>> + avpriv_request_sample(s->avctx, "JPEG2000_CTSY_HTJ2K_F and M_b >= 31");
>> return AVERROR_PATCHWELCOME;
>> }
>>
>> @@ -1935,11 +2202,11 @@ static inline int tile_codeblocks(const Jpeg2000DecoderContext *s, Jpeg2000Tile
>>
>> Jpeg2000Cblk *cblk = prec->cblk + cblkno;
>>
>> - if (codsty->cblk_style & JPEG2000_CTSY_HTJ2K_F)
>> + if (cblk->modes & JPEG2000_CTSY_HTJ2K_F)
>> ret = ff_jpeg2000_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);
>> + M_b, comp->roi_shift);
>> else
>> ret = decode_cblk(s, codsty, &t1, cblk,
>> cblk->coord[0][1] - cblk->coord[0][0],
>> @@ -2178,22 +2445,42 @@ 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_WARNING, "CAP marker segment shall come after SIZ\n");
>> + }
>> + ret = get_cap(s, codsty);
>> + break;
>> case JPEG2000_COC:
>> + if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11))
>> + av_log(s->avctx, AV_LOG_WARNING, "COC marker is found in HOMOGENEOUS HT set\n");
>> ret = get_coc(s, codsty, properties);
>> break;
>> case JPEG2000_COD:
>> + if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11))
>> + av_log(s->avctx, AV_LOG_WARNING, "COD marker is found in HOMOGENEOUS HT set\n");
>> ret = get_cod(s, codsty, properties);
>> break;
>> case JPEG2000_RGN:
>> + if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11))
>> + av_log(s->avctx, AV_LOG_WARNING, "RGB marker is found in HOMOGENEOUS HT set\n");
>> ret = get_rgn(s, len);
>> + if ((!s->Ccap15_b12) && s->isHT)
>> + av_log(s->avctx, AV_LOG_WARNING, "RGN marker is found in RGNFREE HT set\n");
>> break;
>> case JPEG2000_QCC:
>> + if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11))
>> + av_log(s->avctx, AV_LOG_WARNING, "QCC marker is found in HOMOGENEOUS HT set\n");
>> ret = get_qcc(s, len, qntsty, properties);
>> break;
>> case JPEG2000_QCD:
>> + if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11))
>> + av_log(s->avctx, AV_LOG_WARNING, "QCD marker is found in HOMOGENEOUS HT set\n");
>> ret = get_qcd(s, len, qntsty, properties);
>> break;
>> case JPEG2000_POC:
>> + if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11))
>> + av_log(s->avctx, AV_LOG_WARNING, "POC marker is found in HOMOGENEOUS HT set\n");
>> ret = get_poc(s, len, poc);
>> break;
>> case JPEG2000_SOT:
>> @@ -2243,9 +2530,14 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s)
>> "Cannot have both PPT and PPM marker.\n");
>> return AVERROR_INVALIDDATA;
>> }
>> -
>> + if ((!s->Ccap15_b11) && s->isHT)
>> + av_log(s->avctx, AV_LOG_WARNING, "PPT marker is found in HOMOGENEOUS HT set\n");
>> ret = get_ppt(s, len);
>> break;
>> + case JPEG2000_CPF:
>> + // Corresponding profile marker
>> + ret = read_cpf(s, len);
>> + break;
>> default:
>> av_log(s->avctx, AV_LOG_ERROR,
>> "unsupported marker 0x%.4"PRIX16" at pos 0x%X\n",
>> diff --git a/libavcodec/jpeg2000dec.h b/libavcodec/jpeg2000dec.h
>> index d0ca6e7a79..326a572722 100644
>> --- a/libavcodec/jpeg2000dec.h
>> +++ b/libavcodec/jpeg2000dec.h
>> @@ -112,6 +112,13 @@ typedef struct Jpeg2000DecoderContext {
>> Jpeg2000Tile *tile;
>> Jpeg2000DSPContext dsp;
>>
>> + uint8_t isHT; // HTJ2K?
>> + uint8_t Ccap15_b14_15; // HTONLY(= 0) or HTDECLARED(= 1) or MIXED(= 3) ?
>> + uint8_t Ccap15_b12; // RGNFREE(= 0) or RGN(= 1)?
>> + uint8_t Ccap15_b11; // HOMOGENEOUS(= 0) or HETEROGENEOUS(= 1) ?
>> + uint8_t Ccap15_b05; // HTREV(= 0) or HTIRV(= 1) ?
>> + uint8_t HT_MAGB; // MAGB value
>> +
>> /*options parameters*/
>> int reduction_factor;
>> } Jpeg2000DecoderContext;
>> diff --git a/libavcodec/jpeg2000htdec.c b/libavcodec/jpeg2000htdec.c
>> index eba0936089..beb4a386b0 100644
>> --- a/libavcodec/jpeg2000htdec.c
>> +++ b/libavcodec/jpeg2000htdec.c
>> @@ -122,7 +122,7 @@ static void jpeg2000_init_mel(StateVars *s, uint32_t Pcup)
>>
>> static void jpeg2000_init_mag_ref(StateVars *s, uint32_t Lref)
>> {
>> - s->pos = Lref - 2;
>> + s->pos = Lref - 1;
>> s->bits = 0;
>> s->last = 0xFF;
>> s->tmp = 0;
>> @@ -145,9 +145,10 @@ static void jpeg2000_init_mel_decoder(MelDecoderState *mel_state)
>> static int jpeg2000_bitbuf_refill_backwards(StateVars *buffer, const uint8_t *array)
>> {
>> uint64_t tmp = 0;
>> - int32_t position = buffer->pos - 4;
>> uint32_t new_bits = 32;
>>
>> + buffer->last = array[buffer->pos + 1];
>> +
>> if (buffer->bits_left >= 32)
>> return 0; // enough data, no need to pull in more bits
>>
>> @@ -157,9 +158,24 @@ static int jpeg2000_bitbuf_refill_backwards(StateVars *buffer, const uint8_t *ar
>> * the bottom most bits.
>> */
>>
>> - for(int i = FFMAX(0, position + 1); i <= buffer->pos + 1; i++)
>> - tmp = 256*tmp + array[i];
>> -
>> + if (buffer->pos >= 3) { // Common case; we have at least 4 bytes available
>> + tmp = array[buffer->pos - 3];
>> + tmp = (tmp << 8) | array[buffer->pos - 2];
>> + tmp = (tmp << 8) | array[buffer->pos - 1];
>> + tmp = (tmp << 8) | array[buffer->pos];
>> + tmp = (tmp << 8) | buffer->last; // For stuffing bit detection
>> + buffer->pos -= 4;
>> + } else {
>> + if (buffer->pos >= 2)
>> + tmp = array[buffer->pos - 2];
>> + if (buffer->pos >= 1)
>> + tmp = (tmp << 8) | array[buffer->pos - 1];
>> + if (buffer->pos >= 0)
>> + tmp = (tmp << 8) | array[buffer->pos];
>> + buffer->pos = 0;
>> + tmp = (tmp << 8) | buffer->last; // For stuffing bit detection
>> + }
>> + // Now remove any stuffing bits, shifting things down as we go
>> if ((tmp & 0x7FFF000000) > 0x7F8F000000) {
>> tmp &= 0x7FFFFFFFFF;
>> new_bits--;
>> @@ -176,13 +192,11 @@ static int jpeg2000_bitbuf_refill_backwards(StateVars *buffer, const uint8_t *ar
>> tmp = (tmp & 0x0000007FFF) + ((tmp & 0xFFFFFF0000) >> 1);
>> new_bits--;
>> }
>> -
>> - tmp >>= 8; // Remove temporary byte loaded
>> + tmp >>= 8; // Shifts away the extra byte we imported
>>
>> /* 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;
>> }
>>
>> @@ -406,6 +420,7 @@ static void recover_mag_sgn(StateVars *mag_sgn, uint8_t pos, uint16_t q, int32_t
>> E[n] = 32 - ff_clz(v[pos][i] | 1);
>> mu_n[n] = (v[pos][i] >> 1) + 1;
>> mu_n[n] <<= pLSB;
>> + mu_n[n] |= (1 << (pLSB - 1)); // Add 0.5 (reconstruction parameter = 1/2)
>> mu_n[n] |= ((uint32_t) (v[pos][i] & 1)) << 31; // sign bit.
>> }
>> }
>> @@ -414,7 +429,7 @@ static void recover_mag_sgn(StateVars *mag_sgn, uint8_t pos, uint16_t q, int32_t
>> static int jpeg2000_import_bit(StateVars *stream, const uint8_t *array, uint32_t length)
>> {
>> int cond = stream->pos < length;
>> - int pos = FFMIN(stream->pos, length);
>> + int pos = FFMIN(stream->pos, length - 1);
>> if (stream->bits == 0) {
>> stream->bits = (stream->tmp == 0xFF) ? 7 : 8;
>> stream->pos += cond;
>> @@ -426,14 +441,22 @@ static int jpeg2000_import_bit(StateVars *stream, const uint8_t *array, uint32_t
>>
>> static int jpeg2000_peek_bit(StateVars *stream, const uint8_t *array, uint32_t length)
>> {
>> + uint8_t bit;
>> +
>> if (stream->bits == 0) {
>> - int cond = stream->pos < length;
>> - int pos = FFMIN(stream->pos, length);
>> - stream->bits = (stream->tmp == 0xFF) ? 7 : 8;
>> - stream->pos += cond;
>> - stream->tmp = cond ? array[pos] : 0xFF;
>> + stream->bits = (stream->last == 0xFF) ? 7 : 8;
>> + if (stream->pos < length) {
>> + stream->tmp = array[stream->pos];
>> + stream->pos++;
>> + } else {
>> + stream->tmp = 0;
>> + }
>> + stream->last = stream->tmp;
>> }
>> - return (stream->tmp >> stream->bits) & 1;
>> + bit = stream->tmp & 1;
>> + stream->tmp >>= 1;
>> + stream->bits--;
>> + return bit;
>> }
>>
>> static int jpeg2000_decode_mel_sym(MelDecoderState *mel_state,
>> @@ -994,66 +1017,63 @@ 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 stride)
>> {
>> - int local_mbr = 0;
>> -
>> - local_mbr |= jpeg2000_get_state(i - 1, j - 1, stride, HT_SHIFT_SIGMA, block_states);
>> - local_mbr |= jpeg2000_get_state(i - 1, j + 0, stride, HT_SHIFT_SIGMA, block_states);
>> - local_mbr |= jpeg2000_get_state(i - 1, j + 1, stride, HT_SHIFT_SIGMA, block_states);
>> -
>> - local_mbr |= jpeg2000_get_state(i + 0, j - 1, stride, HT_SHIFT_SIGMA, block_states);
>> - local_mbr |= jpeg2000_get_state(i + 0, j + 1, stride, HT_SHIFT_SIGMA, block_states);
>> -
>> - local_mbr |= jpeg2000_get_state(i + 1, j - 1, stride, HT_SHIFT_SIGMA, block_states) * causal_cond;
>> - local_mbr |= jpeg2000_get_state(i + 1, j + 0, stride, HT_SHIFT_SIGMA, block_states) * causal_cond;
>> - local_mbr |= jpeg2000_get_state(i + 1, j + 1, stride, HT_SHIFT_SIGMA, block_states) * causal_cond;
>> -
>> - local_mbr |= jpeg2000_get_state(i - 1, j - 1, stride, HT_SHIFT_REF, block_states) *
>> - jpeg2000_get_state(i - 1, j - 1, stride, HT_SHIFT_SCAN, block_states);
>> - local_mbr |= jpeg2000_get_state(i - 1, j + 0, stride, HT_SHIFT_REF, block_states) *
>> - jpeg2000_get_state(i - 1, j - 1, stride, HT_SHIFT_SCAN, block_states);
>> - local_mbr |= jpeg2000_get_state(i - 1, j + 1, stride, HT_SHIFT_REF, block_states) *
>> - jpeg2000_get_state(i - 1, j + 1, stride, HT_SHIFT_SCAN, block_states);
>> -
>> - local_mbr |= jpeg2000_get_state(i + 0, j - 1, stride, HT_SHIFT_REF, block_states) *
>> - jpeg2000_get_state(i + 0, j - 1, stride, HT_SHIFT_SCAN, block_states);
>> - local_mbr |= jpeg2000_get_state(i + 0, j + 1, stride, HT_SHIFT_REF, block_states) *
>> - jpeg2000_get_state(i + 0, j + 1, stride, HT_SHIFT_SCAN, block_states);
>> -
>> - local_mbr |= jpeg2000_get_state(i + 1, j - 1, stride, HT_SHIFT_REF, block_states) *
>> - jpeg2000_get_state(i + 1, j - 1, stride, HT_SHIFT_SCAN, block_states) * causal_cond;
>> - local_mbr |= jpeg2000_get_state(i + 1, j + 0, stride, HT_SHIFT_REF, block_states) *
>> - jpeg2000_get_state(i + 1, j + 0, stride, HT_SHIFT_SCAN, block_states) * causal_cond;
>> - local_mbr |= jpeg2000_get_state(i + 1, j + 1, stride, HT_SHIFT_REF, block_states) *
>> - jpeg2000_get_state(i + 1, j + 1, stride, HT_SHIFT_SCAN, block_states) * causal_cond;
>> -
>> - *mbr |= local_mbr;
>> + uint8_t *state_p0 = block_states + i * stride + j;
>> + uint8_t *state_p1 = block_states + (i + 1) * stride + j;
>> + uint8_t *state_p2 = block_states + (i + 2) * stride + j;
>> +
>> + uint8_t mbr0 = state_p0[0] | state_p0[1] | state_p0[2];
>> + uint8_t mbr1 = state_p1[0] | state_p1[2];
>> + uint8_t mbr2 = state_p2[0] | state_p2[1] | state_p2[2];
>> + *mbr = mbr0 | mbr1 | (mbr2 & causal_cond);
>> + *mbr |= (mbr0 >> HT_SHIFT_REF) & (mbr0 >> HT_SHIFT_SCAN);
>> + *mbr |= (mbr1 >> HT_SHIFT_REF) & (mbr1 >> HT_SHIFT_SCAN);
>> + *mbr |= (mbr2 >> HT_SHIFT_REF) & (mbr2 >> HT_SHIFT_SCAN) & causal_cond;
>> + *mbr &= 1;
>> }
>>
>> 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)
>> + uint8_t *magref_segment, uint32_t magref_length,
>> + uint8_t is_causal)
>> {
>> for (int j = j_s; j < j_s + width; j++) {
>> uint32_t mbr_info = 0;
>> for (int i = i_s; i < i_s + height; i++) {
>> - int modify_state, cond;
>> + int modify_state;
>> uint8_t bit;
>> - uint8_t causal_cond = i != (i_s + height - 1);
>> + uint8_t causal_cond = (is_causal == 0) || (i != (i_s + height - 1));
>> int32_t *sp = &sample_buf[j + (i * (stride))];
>> uint8_t mbr = 0;
>>
>> - if (jpeg2000_get_state(i, j, stride - 2, HT_SHIFT_SIGMA, block_states) == 0)
>> + if (jpeg2000_get_state(i, j, stride, HT_SHIFT_SIGMA, block_states) == 0)
>> jpeg2000_calc_mbr(&mbr, i, j, mbr_info & 0x1EF, causal_cond, block_states, stride);
>> mbr_info >>= 3;
>> - cond = mbr != 0;
>> - bit = jpeg2000_peek_bit(sig_prop, magref_segment, magref_length);
>> - *sp |= (bit * cond) << pLSB;
>> - sig_prop->bits -= cond;
>> - modify_state = (((1 << HT_SHIFT_REF_IND) | (1 << HT_SHIFT_REF)) * cond) | 1 << HT_SHIFT_SCAN;
>> +
>> + modify_state = block_states[(i + 1) * stride + (j + 1)];
>> + modify_state |= 1 << HT_SHIFT_SCAN;
>> + if (mbr != 0) {
>> + modify_state |= 1 << HT_SHIFT_REF_IND;
>> + bit = jpeg2000_peek_bit(sig_prop, magref_segment, magref_length);
>> + modify_state |= bit << HT_SHIFT_REF;
>> + *sp |= bit << pLSB;
>> + *sp |= bit << (pLSB - 1); // Add 0.5 (reconstruction parameter = 1/2)
>> + }
>> jpeg2000_modify_state(i, j, stride, modify_state, block_states);
>> }
>> }
>> + // decode sign
>> + for (int j = j_s; j < j_s + width; j++) {
>> + for (int i = i_s; i < i_s + height; i++) {
>> + uint8_t bit;
>> + int32_t *sp = &sample_buf[j + (i * (stride))];
>> + uint8_t *state_p = block_states + (i + 1) * stride + (j + 1);
>> + if ((state_p[0] >> HT_SHIFT_REF) & 1) {
>> + bit = jpeg2000_peek_bit(sig_prop, magref_segment, magref_length);
>> + *sp |= (int32_t)bit << 31;
>> + }
>> + }
>> + }
>> }
>>
>> /**
>> @@ -1074,6 +1094,7 @@ static void jpeg2000_decode_sigprop_segment(Jpeg2000Cblk *cblk, uint16_t width,
>>
>> int last_width;
>> uint16_t i = 0, j = 0;
>> + uint8_t is_causal = cblk->modes & JPEG2000_CBLK_VSC;
>>
>> jpeg2000_init_zero(&sp_dec);
>>
>> @@ -1082,14 +1103,14 @@ static void jpeg2000_decode_sigprop_segment(Jpeg2000Cblk *cblk, uint16_t width,
>> 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);
>> + magref_length, is_causal);
>> 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);
>> + magref_length, is_causal);
>> i += 4;
>> }
>>
>> @@ -1099,20 +1120,20 @@ static void jpeg2000_decode_sigprop_segment(Jpeg2000Cblk *cblk, uint16_t width,
>> 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);
>> + magref_length, is_causal);
>> 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);
>> + magref_length, is_causal);
>> }
>>
>> /**
>> * See procedure decodeSigPropMag at Rec. ITU-T T.814, 7.5.
>> */
>> -static int
>> +static void
>> jpeg2000_decode_magref_segment( uint16_t width, uint16_t block_height, const int stride,
>> uint8_t *magref_segment,uint32_t magref_length,
>> uint8_t pLSB, int32_t *sample_buf, uint8_t *block_states)
>> @@ -1123,7 +1144,8 @@ jpeg2000_decode_magref_segment( uint16_t width, uint16_t block_height, const int
>> uint16_t height = 4;
>> uint16_t i_start = 0;
>> int32_t *sp;
>> -
>> + int32_t bit;
>> + int32_t tmp;
>> jpeg2000_init_mag_ref(&mag_ref, magref_length);
>>
>> for (int n1 = 0; n1 < num_v_stripe; n1++) {
>> @@ -1134,9 +1156,13 @@ jpeg2000_decode_magref_segment( uint16_t width, uint16_t block_height, const int
>> * Rec. ITU-T T.814, Figure 7.
>> */
>> sp = &sample_buf[j + i * stride];
>> - 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;
>> + if (jpeg2000_get_state(i, j, stride, HT_SHIFT_SIGMA, block_states) != 0) {
>> + jpeg2000_modify_state(i, j, stride, 1 << HT_SHIFT_REF_IND, block_states);
>> + bit = jpeg2000_import_magref_bit(&mag_ref, magref_segment, magref_length);
>> + tmp = 0xFFFFFFFE | (uint32_t)bit;
>> + tmp <<= pLSB;
>> + sp[0] &= tmp;
>> + sp[0] |= 1 << (pLSB - 1); // Add 0.5 (reconstruction parameter = 1/2)
>> }
>> }
>> }
>> @@ -1146,21 +1172,24 @@ jpeg2000_decode_magref_segment( uint16_t width, uint16_t block_height, const int
>> for (int j = 0; j < width; j++) {
>> for (int i = i_start; i < i_start + height; i++) {
>> sp = &sample_buf[j + i * stride];
>> - 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;
>> + if (jpeg2000_get_state(i, j, stride, HT_SHIFT_SIGMA, block_states) != 0) {
>> + jpeg2000_modify_state(i, j, stride, 1 << HT_SHIFT_REF_IND, block_states);
>> + bit = jpeg2000_import_magref_bit(&mag_ref, magref_segment, magref_length);
>> + tmp = 0xFFFFFFFE | (uint32_t)bit;
>> + tmp <<= pLSB;
>> + sp[0] &= tmp;
>> + sp[0] |= 1 << (pLSB - 1); // Add 0.5 (reconstruction parameter = 1/2)
>> }
>> }
>> }
>> - return 1;
>> }
>>
>>
>> int
>> ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *codsty, Jpeg2000T1Context *t1, Jpeg2000Cblk *cblk,
>> - int width, int height, int magp, uint8_t roi_shift)
>> + int width, int height, int M_b, uint8_t roi_shift)
>> {
>> - uint8_t p0 = 0; // Number of placeholder passes
>> + uint8_t p0 = 0; // 3 * p0 = 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
>> @@ -1174,7 +1203,7 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c
>>
>> int z_blk; // Number of ht coding pass
>>
>> - uint8_t empty_passes;
>> + uint8_t num_plhd_passes; // Number of placeholder passes
>>
>> StateVars mag_sgn; // Magnitude and Sign
>> StateVars mel; // Adaptive run-length coding
>> @@ -1190,8 +1219,8 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c
>> uint8_t *block_states = NULL;
>>
>> int32_t n, val; // Post-processing
>> -
>> - int32_t M_b = magp;
>> + const uint32_t mask = UINT32_MAX >> (M_b + 1); // bit mask for ROI detection
>> + uint8_t num_rempass;
>>
>> const int quad_buf_width = width + 4;
>> const int quad_buf_height = height + 4;
>> @@ -1201,22 +1230,17 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c
>> av_assert0(width * height <= 4096);
>> av_assert0(width * height > 0);
>>
>> - if (roi_shift)
>> - avpriv_report_missing_feature(s->avctx, "ROI shift");
>> -
>> 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)
>> - p0 = 0;
>> - else if (cblk->length == 0)
>> - p0 = 1;
>> -
>> - empty_passes = p0 * 3;
>> - z_blk = cblk->npasses - empty_passes;
>> + num_rempass = cblk->npasses % 3; // Number of remainder passes
>> + num_plhd_passes = num_rempass ? cblk->npasses - num_rempass : cblk->npasses - 3;
>> + av_assert0(num_plhd_passes % 3 == 0);
>> + p0 = num_plhd_passes / 3;
>> + z_blk = cblk->npasses - num_plhd_passes;
>>
>> if (z_blk <= 0)
>> return 0; // No passes within this set, continue
>> @@ -1231,7 +1255,11 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c
>> }
>> Dcup = cblk->data;
>> Dref = cblk->data + Lcup; // Dref comes after the refinement segment
>> +
>> + cblk->data[cblk->length] = 0xFF; // an extra byte for refinement segment (buffer->last)
>> +
>> S_blk = p0 + cblk->zbp;
>> + cblk->zbp = S_blk - 1;
>> pLSB = 30 - S_blk;
>>
>> Scup = (Dcup[Lcup - 1] << 4) + (Dcup[Lcup - 2] & 0x0F);
>> @@ -1277,31 +1305,32 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c
>> goto free;
>> }
>>
>> - if (cblk->npasses > 1)
>> + if (z_blk > 1)
>> jpeg2000_decode_sigprop_segment(cblk, width, height, quad_buf_width, Dref, Lref,
>> pLSB - 1, sample_buf, block_states);
>>
>> - if (cblk->npasses > 2) {
>> -
>> - if (Lref < 2){
>> - av_log(s->avctx,AV_LOG_ERROR,"Invalid magnitude refinement length\n");
>> - ret = AVERROR_INVALIDDATA;
>> - goto free;
>> - }
>> - if ((ret = jpeg2000_decode_magref_segment(width, height, quad_buf_width, Dref, Lref,
>> - pLSB - 1, sample_buf, block_states)) < 0)
>> - goto free;
>> - }
>> + if (z_blk > 2)
>> + jpeg2000_decode_magref_segment(width, height, quad_buf_width, Dref, Lref,
>> + pLSB - 1, sample_buf, block_states);
>>
>> pLSB = 31 - M_b;
>>
>> /* Reconstruct the sample values */
>> for (int y = 0; y < height; y++) {
>> for (int x = 0; x < width; x++) {
>> + int32_t sign;
>> +
>> n = x + (y * t1->stride);
>> val = sample_buf[x + (y * quad_buf_width)];
>> + sign = val & INT32_MIN;
>> + val &= INT32_MAX;
>> + /* ROI shift, if necessary */
>> + if (roi_shift && (((uint32_t)val & ~mask) == 0))
>> + val <<= roi_shift;
>> /* Convert sign-magnitude to two's complement. */
>> - val = val >> 31 ? 0x80000000 - val : val;
>> + if (sign)
>> + val = -val;
>> + /* Shift down to 1 bit upper from decimal point for reconstruction value (= 0.5) */
>> val >>= (pLSB - 1);
>> t1->data[n] = val;
>> }
>> diff --git a/libavcodec/jpeg2000htdec.h b/libavcodec/jpeg2000htdec.h
>> index 572d095c92..8d6919a0de 100644
>> --- a/libavcodec/jpeg2000htdec.h
>> +++ b/libavcodec/jpeg2000htdec.h
>> @@ -29,6 +29,6 @@
>>
>> int ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *codsty,
>> Jpeg2000T1Context *t1, Jpeg2000Cblk *cblk, int width,
>> - int height, int magp, uint8_t roi_shift);
>> + int height, int M_b, uint8_t roi_shift);
>>
>> #endif /* AVCODEC_JPEG2000HTDEC_H */
>> --
>> 2.34.1
>>
_______________________________________________
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".
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [FFmpeg-devel] [PATCH 1/2] avcodec/jpeg2000dec: Add support for placeholder passes, CAP, and CPF markers
2024-06-15 3:15 [FFmpeg-devel] [PATCH 1/2] avcodec/jpeg2000dec: Add support for placeholder passes, CAP, and CPF markers Osamu Watanabe
2024-06-15 3:15 ` [FFmpeg-devel] [PATCH 2/2] avcodec/jpeg2000dec: fix tilepart processing Osamu Watanabe
2024-06-15 6:00 ` [FFmpeg-devel] [PATCH 1/2] avcodec/jpeg2000dec: Add support for placeholder passes, CAP, and CPF markers Pierre-Anthony Lemieux
@ 2024-06-15 20:11 ` Michael Niedermayer
2 siblings, 0 replies; 5+ messages in thread
From: Michael Niedermayer @ 2024-06-15 20:11 UTC (permalink / raw)
To: FFmpeg development discussions and patches
[-- Attachment #1.1: Type: text/plain, Size: 942 bytes --]
On Sat, Jun 15, 2024 at 12:15:16PM +0900, Osamu Watanabe wrote:
> Signed-off-by: Osamu Watanabe <owatanab@es.takushoku-u.ac.jp>
> ---
> libavcodec/jpeg2000.h | 10 +
> libavcodec/jpeg2000dec.c | 454 ++++++++++++++++++++++++++++++-------
> libavcodec/jpeg2000dec.h | 7 +
> libavcodec/jpeg2000htdec.c | 225 ++++++++++--------
> libavcodec/jpeg2000htdec.h | 2 +-
> 5 files changed, 518 insertions(+), 180 deletions(-)
this breaks decoding of
tickets/4631/199.jp2
https://trac.ffmpeg.org/attachment/ticket/4631/199.jp2
and others
thx
[...]
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
If you drop bombs on a foreign country and kill a hundred thousand
innocent people, expect your government to call the consequence
"unprovoked inhuman terrorist attacks" and use it to justify dropping
more bombs and killing more people. The technology changed, the idea is old.
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]
[-- Attachment #2: Type: text/plain, Size: 251 bytes --]
_______________________________________________
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".
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2024-06-15 20:11 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-06-15 3:15 [FFmpeg-devel] [PATCH 1/2] avcodec/jpeg2000dec: Add support for placeholder passes, CAP, and CPF markers Osamu Watanabe
2024-06-15 3:15 ` [FFmpeg-devel] [PATCH 2/2] avcodec/jpeg2000dec: fix tilepart processing Osamu Watanabe
2024-06-15 6:00 ` [FFmpeg-devel] [PATCH 1/2] avcodec/jpeg2000dec: Add support for placeholder passes, CAP, and CPF markers Pierre-Anthony Lemieux
2024-06-15 7:55 ` WATANABE Osamu
2024-06-15 20:11 ` Michael Niedermayer
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