jpeg2000dec: convert the decoder to the receive_frame API

Convert the decoder to the receive_frame API (one codestream per
packet; skipped frames pull the next packet instead of returning
empty-handed), finish threading setup before the tile decode, and do
not leave a partially initialized frame on the output on error.

Move the tag-tree size, exp2fi and band stepsize helpers into the
shared header as ff_-prefixed inlines so code outside jpeg2000.c can
derive the same geometry and quantization parameters.
This commit is contained in:
Lynne committed 2026-10-06 15:11:26 +09:00
1 parent 2ed5830108
commit 6287ad1f9b
3 files changed
+108 -57

No files matched your search

+39 -50
View File
@@ -39,18 +39,6 @@
/* tag tree routines */
static int32_t tag_tree_size(int w, int h)
{
int64_t res = 0;
while (w > 1 || h > 1) {
res += w * (int64_t)h;
av_assert0(res + 1 < INT32_MAX);
w = (w + 1) >> 1;
h = (h + 1) >> 1;
}
return (int32_t)(res + 1);
}
/* allocate the memory for tag tree */
static Jpeg2000TgtNode *ff_jpeg2000_tag_tree_init(int w, int h)
{
@@ -58,7 +46,7 @@ static Jpeg2000TgtNode *ff_jpeg2000_tag_tree_init(int w, int h)
Jpeg2000TgtNode *res, *t, *t2;
int32_t tt_size;
tt_size = tag_tree_size(w, h);
tt_size = ff_jpeg2000_tag_tree_size(w, h);
t = res = av_calloc(tt_size, sizeof(*t));
if (!res)
@@ -85,7 +73,7 @@ static Jpeg2000TgtNode *ff_jpeg2000_tag_tree_init(int w, int h)
void ff_tag_tree_zero(Jpeg2000TgtNode *t, int w, int h, int val)
{
int i, siz = tag_tree_size(w, h);
int i, siz = ff_jpeg2000_tag_tree_size(w, h);
for (i = 0; i < siz; i++) {
t[i].val = val;
@@ -199,33 +187,22 @@ void ff_jpeg2000_set_significance(Jpeg2000T1Context *t1, int x, int y,
t1->flags[(y - 1) * t1->stride + x - 1] |= JPEG2000_T1_SIG_SE;
}
/* TODO: Implementation of quantization step not finished, see
* ISO/IEC 15444-1:2002 E.1 and A.6.4. */
// static const uint8_t lut_gain[2][4] = { { 0, 0, 0, 0 }, { 0, 1, 1, 2 } }; (unused)
/**
* 2^(x) for integer x in the range -126..128.
* @return correctly rounded float
*/
static av_always_inline float exp2fi(int x)
float ff_jpeg2000_band_stepsize(AVCodecContext *avctx,
Jpeg2000CodingStyle *codsty,
Jpeg2000QuantStyle *qntsty,
int bandno, int gbandno,
int reslevelno, int cbps)
{
av_assert2(-126 <= x && x <= 128);
/* Normal range */
return av_int2float((x+127) << 23);
}
float fss;
static void init_band_stepsize(AVCodecContext *avctx,
Jpeg2000Band *band,
Jpeg2000CodingStyle *codsty,
Jpeg2000QuantStyle *qntsty,
int bandno, int gbandno, int reslevelno,
int cbps)
{
/* TODO: Implementation of quantization step not finished,
* see ISO/IEC 15444-1:2002 E.1 and A.6.4. */
switch (qntsty->quantsty) {
uint8_t gain;
case JPEG2000_QSTY_NONE:
/* TODO: to verify. No quantization in this case */
band->f_stepsize = 1;
fss = 1;
break;
case JPEG2000_QSTY_SI:
/*TODO: Compute formula to implement. */
@@ -240,35 +217,47 @@ static void init_band_stepsize(AVCodecContext *avctx,
* delta_b = 2 ^ (R_b - expn_b) * (1 + (mant_b / 2 ^ 11))
* R_b = R_I + log2 (gain_b )
* see ISO/IEC 15444-1:2002 E.1.1 eqn. E-3 and E-4 */
gain = cbps;
band->f_stepsize = exp2fi(gain - qntsty->expn[gbandno]);
band->f_stepsize *= qntsty->mant[gbandno] / 2048.0 + 1.0;
gain = cbps;
fss = ff_jpeg2000_exp2fi(gain - qntsty->expn[gbandno]);
fss *= qntsty->mant[gbandno] / 2048.0 + 1.0;
break;
default:
band->f_stepsize = 0;
av_log(avctx, AV_LOG_ERROR, "Unknown quantization format\n");
break;
return 0;
}
if (codsty->transform != FF_DWT53) {
int lband = 0;
switch (bandno + (reslevelno > 0)) {
case 1:
case 2:
band->f_stepsize *= F_LFTG_X * 2;
lband = 1;
break;
case 3:
band->f_stepsize *= F_LFTG_X * F_LFTG_X * 4;
break;
case 1:
case 2:
fss *= F_LFTG_X * 2;
lband = 1;
break;
case 3:
fss *= F_LFTG_X * F_LFTG_X * 4;
break;
}
band->f_stepsize *= pow(F_LFTG_K, 2*(codsty->nreslevels2decode - reslevelno) + lband - 2);
fss *= pow(F_LFTG_K, 2 * (codsty->nreslevels2decode - reslevelno) +
lband - 2);
}
if (band->f_stepsize > (INT_MAX >> 15)) {
band->f_stepsize = 0;
if (fss > (INT_MAX >> 15)) {
av_log(avctx, AV_LOG_ERROR, "stepsize out of range\n");
return 0;
}
return fss;
}
static void init_band_stepsize(AVCodecContext *avctx,
Jpeg2000Band *band,
Jpeg2000CodingStyle *codsty,
Jpeg2000QuantStyle *qntsty,
int bandno, int gbandno, int reslevelno,
int cbps)
{
band->f_stepsize = ff_jpeg2000_band_stepsize(avctx, codsty, qntsty,
bandno, gbandno, reslevelno,
cbps);
band->i_stepsize = (int)floorf(band->f_stepsize * (1 << 15));
}
+36
View File
@@ -31,6 +31,9 @@
#include <stdint.h>
#include "libavutil/avassert.h"
#include "libavutil/intfloat.h"
#include "avcodec.h"
#include "mqc.h"
#include "jpeg2000dwt.h"
@@ -289,6 +292,39 @@ static inline int ff_jpeg2000_getsgnctxno(int flag, int *xorbit)
return ff_jpeg2000_sgnctxno_lut[flag & 15][(flag >> 8) & 15];
}
/* Node count of the tag-tree pyramid over a (w, h) leaf grid. */
static inline int32_t ff_jpeg2000_tag_tree_size(int w, int h)
{
int64_t res = 0;
while (w > 1 || h > 1) {
res += w * (int64_t)h;
av_assert0(res + 1 < INT32_MAX);
w = (w + 1) >> 1;
h = (h + 1) >> 1;
}
return (int32_t)(res + 1);
}
/**
* 2^(x) for integer x in the range -126..128.
* @return correctly rounded float
*/
static av_always_inline float ff_jpeg2000_exp2fi(int x)
{
av_assert2(-126 <= x && x <= 128);
/* Normal range */
return av_int2float((x + 127) << 23);
}
/* Band dequantization step size (ISO/IEC 15444-1:2002 E.1), shared between
* the software decoder's band setup and the Vulkan hwaccel's inline
* geometry. */
float ff_jpeg2000_band_stepsize(AVCodecContext *avctx,
Jpeg2000CodingStyle *codsty,
Jpeg2000QuantStyle *qntsty,
int bandno, int gbandno,
int reslevelno, int cbps);
int ff_jpeg2000_init_component(Jpeg2000Component *comp,
Jpeg2000CodingStyle *codsty,
Jpeg2000QuantStyle *qntsty,
+33 -7
View File
@@ -39,6 +39,7 @@
#include "bytestream.h"
#include "codec_internal.h"
#include "decode.h"
#include "internal.h"
#include "thread.h"
#include "jpeg2000.h"
#include "jpeg2000dsp.h"
@@ -2855,7 +2856,7 @@ static av_cold int jpeg2000_decode_init(AVCodecContext *avctx)
}
static int jpeg2000_decode_frame(AVCodecContext *avctx, AVFrame *picture,
int *got_frame, AVPacket *avpkt)
const AVPacket *avpkt)
{
Jpeg2000DecoderContext *s = avctx->priv_data;
int ret;
@@ -2902,7 +2903,7 @@ static int jpeg2000_decode_frame(AVCodecContext *avctx, AVFrame *picture,
if (avctx->skip_frame >= AVDISCARD_ALL) {
jpeg2000_dec_cleanup(s);
return avpkt->size;
return 0;
}
/* get picture buffer */
@@ -2916,22 +2917,47 @@ static int jpeg2000_decode_frame(AVCodecContext *avctx, AVFrame *picture,
if (++x == s->ncomponents)
picture->flags |= AV_FRAME_FLAG_LOSSLESS;
avctx->execute2(avctx, jpeg2000_decode_tile, picture, NULL, s->numXtiles * s->numYtiles);
ff_thread_finish_setup(avctx);
avctx->execute2(avctx, jpeg2000_decode_tile, picture, NULL,
s->numXtiles * s->numYtiles);
jpeg2000_dec_cleanup(s);
*got_frame = 1;
if (s->avctx->pix_fmt == AV_PIX_FMT_PAL8)
memcpy(picture->data[1], s->palette, 256 * sizeof(uint32_t));
return bytestream2_tell(&s->g);
return 0;
end:
/* Do not leave a partially initialized frame on the output. */
av_frame_unref(picture);
jpeg2000_dec_cleanup(s);
return ret;
}
static int jpeg2000_receive_frame(AVCodecContext *avctx, AVFrame *frame)
{
AVPacket *const avpkt = avctx->internal->in_pkt;
int ret;
/* One codestream per packet. Loop so that skipped frames (produce no
* output) transparently pull the next packet instead of returning to the
* caller empty-handed. */
do {
ret = ff_decode_get_packet(avctx, avpkt);
if (ret < 0)
return ret;
ret = jpeg2000_decode_frame(avctx, frame, avpkt);
av_packet_unref(avpkt);
if (ret < 0)
return ret;
} while (!frame->buf[0]);
return 0;
}
#define OFFSET(x) offsetof(Jpeg2000DecoderContext, x)
#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
@@ -2956,7 +2982,7 @@ const FFCodec ff_jpeg2000_decoder = {
.p.capabilities = AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_DR1,
.priv_data_size = sizeof(Jpeg2000DecoderContext),
.init = jpeg2000_decode_init,
FF_CODEC_DECODE_CB(jpeg2000_decode_frame),
FF_CODEC_RECEIVE_FRAME_CB(jpeg2000_receive_frame),
.p.priv_class = &jpeg2000_class,
.p.max_lowres = 5,
.p.profiles = NULL_IF_CONFIG_SMALL(ff_jpeg2000_profiles),