mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2026-10-28 10:04:37 +08:00
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:
1 parent
2ed5830108
commit
6287ad1f9b
3 files changed
+108
-57
No files matched your search
+39
-50
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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),
|
||||
|
||||
Reference in new issue
Block a user