Commit 6287ad1f9b for ffmpeg
commit 6287ad1f9bd168e2a417b91df0a705c8d62925f3
Author: Lynne <dev@lynne.ee>
Date: Sun Jul 26 13:55:17 2026 +0800
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.
diff --git a/libavcodec/jpeg2000.c b/libavcodec/jpeg2000.c
index 6433e13892..a21f9c2a82 100644
--- a/libavcodec/jpeg2000.c
+++ b/libavcodec/jpeg2000.c
@@ -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));
}
diff --git a/libavcodec/jpeg2000.h b/libavcodec/jpeg2000.h
index 93221d90ca..52c00f4268 100644
--- a/libavcodec/jpeg2000.h
+++ b/libavcodec/jpeg2000.h
@@ -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,
diff --git a/libavcodec/jpeg2000dec.c b/libavcodec/jpeg2000dec.c
index 369377e4fc..870678f0b0 100644
--- a/libavcodec/jpeg2000dec.c
+++ b/libavcodec/jpeg2000dec.c
@@ -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);
- jpeg2000_dec_cleanup(s);
+ avctx->execute2(avctx, jpeg2000_decode_tile, picture, NULL,
+ s->numXtiles * s->numYtiles);
- *got_frame = 1;
+ jpeg2000_dec_cleanup(s);
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),