X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fj2kenc.c;h=dcdf4112c09d24402c2b459c22fc8d80858279a3;hb=3d2267019cd7ba318d01babc14fdc82ab5496a7c;hp=68905cc2d364ff33e375eacee65c8f52e809e268;hpb=23c22d37d201a41ad15a15387e43073c8618449e;p=ffmpeg diff --git a/libavcodec/j2kenc.c b/libavcodec/j2kenc.c index 68905cc2d36..dcdf4112c09 100644 --- a/libavcodec/j2kenc.c +++ b/libavcodec/j2kenc.c @@ -31,12 +31,16 @@ #include "bytestream.h" #include "jpeg2000.h" #include "libavutil/common.h" +#include "libavutil/opt.h" #define NMSEDEC_BITS 7 #define NMSEDEC_FRACBITS (NMSEDEC_BITS-1) #define WMSEDEC_SHIFT 13 ///< must be >= 13 #define LAMBDA_SCALE (100000000LL << (WMSEDEC_SHIFT - 13)) +#define CODEC_JP2 1 +#define CODEC_J2K 0 + static int lut_nmsedec_ref [1<buf, 0); // progression level bytestream_put_be16(&s->buf, 1); // num of layers if(s->avctx->pix_fmt == AV_PIX_FMT_YUV444P){ - bytestream_put_byte(&s->buf, 2); // ICT + bytestream_put_byte(&s->buf, 0); // unspecified }else{ bytestream_put_byte(&s->buf, 0); // unspecified } @@ -486,18 +493,18 @@ static void encode_sigpass(Jpeg2000T1Context *t1, int width, int height, int ban for (y0 = 0; y0 < height; y0 += 4) for (x = 0; x < width; x++) for (y = y0; y < height && y < y0+4; y++){ - if (!(t1->flags[y+1][x+1] & JPEG2000_T1_SIG) && (t1->flags[y+1][x+1] & JPEG2000_T1_SIG_NB)){ - int ctxno = ff_jpeg2000_getsigctxno(t1->flags[y+1][x+1], bandno), - bit = t1->data[y][x] & mask ? 1 : 0; + if (!(t1->flags[(y+1) * t1->stride + x+1] & JPEG2000_T1_SIG) && (t1->flags[(y+1) * t1->stride + x+1] & JPEG2000_T1_SIG_NB)){ + int ctxno = ff_jpeg2000_getsigctxno(t1->flags[(y+1) * t1->stride + x+1], bandno), + bit = t1->data[(y) * t1->stride + x] & mask ? 1 : 0; ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, bit); if (bit){ int xorbit; - int ctxno = ff_jpeg2000_getsgnctxno(t1->flags[y+1][x+1], &xorbit); - ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, (t1->flags[y+1][x+1] >> 15) ^ xorbit); - *nmsedec += getnmsedec_sig(t1->data[y][x], bpno + NMSEDEC_FRACBITS); - ff_jpeg2000_set_significance(t1, x, y, t1->flags[y+1][x+1] >> 15); + int ctxno = ff_jpeg2000_getsgnctxno(t1->flags[(y+1) * t1->stride + x+1], &xorbit); + ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, (t1->flags[(y+1) * t1->stride + x+1] >> 15) ^ xorbit); + *nmsedec += getnmsedec_sig(t1->data[(y) * t1->stride + x], bpno + NMSEDEC_FRACBITS); + ff_jpeg2000_set_significance(t1, x, y, t1->flags[(y+1) * t1->stride + x+1] >> 15); } - t1->flags[y+1][x+1] |= JPEG2000_T1_VIS; + t1->flags[(y+1) * t1->stride + x+1] |= JPEG2000_T1_VIS; } } } @@ -508,11 +515,11 @@ static void encode_refpass(Jpeg2000T1Context *t1, int width, int height, int *nm for (y0 = 0; y0 < height; y0 += 4) for (x = 0; x < width; x++) for (y = y0; y < height && y < y0+4; y++) - if ((t1->flags[y+1][x+1] & (JPEG2000_T1_SIG | JPEG2000_T1_VIS)) == JPEG2000_T1_SIG){ - int ctxno = ff_jpeg2000_getrefctxno(t1->flags[y+1][x+1]); - *nmsedec += getnmsedec_ref(t1->data[y][x], bpno + NMSEDEC_FRACBITS); - ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, t1->data[y][x] & mask ? 1:0); - t1->flags[y+1][x+1] |= JPEG2000_T1_REF; + if ((t1->flags[(y+1) * t1->stride + x+1] & (JPEG2000_T1_SIG | JPEG2000_T1_VIS)) == JPEG2000_T1_SIG){ + int ctxno = ff_jpeg2000_getrefctxno(t1->flags[(y+1) * t1->stride + x+1]); + *nmsedec += getnmsedec_ref(t1->data[(y) * t1->stride + x], bpno + NMSEDEC_FRACBITS); + ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, t1->data[(y) * t1->stride + x] & mask ? 1:0); + t1->flags[(y+1) * t1->stride + x+1] |= JPEG2000_T1_REF; } } @@ -522,15 +529,15 @@ static void encode_clnpass(Jpeg2000T1Context *t1, int width, int height, int ban for (y0 = 0; y0 < height; y0 += 4) for (x = 0; x < width; x++){ if (y0 + 3 < height && !( - (t1->flags[y0+1][x+1] & (JPEG2000_T1_SIG_NB | JPEG2000_T1_VIS | JPEG2000_T1_SIG)) || - (t1->flags[y0+2][x+1] & (JPEG2000_T1_SIG_NB | JPEG2000_T1_VIS | JPEG2000_T1_SIG)) || - (t1->flags[y0+3][x+1] & (JPEG2000_T1_SIG_NB | JPEG2000_T1_VIS | JPEG2000_T1_SIG)) || - (t1->flags[y0+4][x+1] & (JPEG2000_T1_SIG_NB | JPEG2000_T1_VIS | JPEG2000_T1_SIG)))) + (t1->flags[(y0+1) * t1->stride + x+1] & (JPEG2000_T1_SIG_NB | JPEG2000_T1_VIS | JPEG2000_T1_SIG)) || + (t1->flags[(y0+2) * t1->stride + x+1] & (JPEG2000_T1_SIG_NB | JPEG2000_T1_VIS | JPEG2000_T1_SIG)) || + (t1->flags[(y0+3) * t1->stride + x+1] & (JPEG2000_T1_SIG_NB | JPEG2000_T1_VIS | JPEG2000_T1_SIG)) || + (t1->flags[(y0+4) * t1->stride + x+1] & (JPEG2000_T1_SIG_NB | JPEG2000_T1_VIS | JPEG2000_T1_SIG)))) { // aggregation mode int rlen; for (rlen = 0; rlen < 4; rlen++) - if (t1->data[y0+rlen][x] & mask) + if (t1->data[(y0+rlen) * t1->stride + x] & mask) break; ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + MQC_CX_RL, rlen != 4); if (rlen == 4) @@ -538,34 +545,34 @@ static void encode_clnpass(Jpeg2000T1Context *t1, int width, int height, int ban ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + MQC_CX_UNI, rlen >> 1); ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + MQC_CX_UNI, rlen & 1); for (y = y0 + rlen; y < y0 + 4; y++){ - if (!(t1->flags[y+1][x+1] & (JPEG2000_T1_SIG | JPEG2000_T1_VIS))){ - int ctxno = ff_jpeg2000_getsigctxno(t1->flags[y+1][x+1], bandno); + if (!(t1->flags[(y+1) * t1->stride + x+1] & (JPEG2000_T1_SIG | JPEG2000_T1_VIS))){ + int ctxno = ff_jpeg2000_getsigctxno(t1->flags[(y+1) * t1->stride + x+1], bandno); if (y > y0 + rlen) - ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, t1->data[y][x] & mask ? 1:0); - if (t1->data[y][x] & mask){ // newly significant + ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, t1->data[(y) * t1->stride + x] & mask ? 1:0); + if (t1->data[(y) * t1->stride + x] & mask){ // newly significant int xorbit; - int ctxno = ff_jpeg2000_getsgnctxno(t1->flags[y+1][x+1], &xorbit); - *nmsedec += getnmsedec_sig(t1->data[y][x], bpno + NMSEDEC_FRACBITS); - ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, (t1->flags[y+1][x+1] >> 15) ^ xorbit); - ff_jpeg2000_set_significance(t1, x, y, t1->flags[y+1][x+1] >> 15); + int ctxno = ff_jpeg2000_getsgnctxno(t1->flags[(y+1) * t1->stride + x+1], &xorbit); + *nmsedec += getnmsedec_sig(t1->data[(y) * t1->stride + x], bpno + NMSEDEC_FRACBITS); + ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, (t1->flags[(y+1) * t1->stride + x+1] >> 15) ^ xorbit); + ff_jpeg2000_set_significance(t1, x, y, t1->flags[(y+1) * t1->stride + x+1] >> 15); } } - t1->flags[y+1][x+1] &= ~JPEG2000_T1_VIS; + t1->flags[(y+1) * t1->stride + x+1] &= ~JPEG2000_T1_VIS; } } else{ for (y = y0; y < y0 + 4 && y < height; y++){ - if (!(t1->flags[y+1][x+1] & (JPEG2000_T1_SIG | JPEG2000_T1_VIS))){ - int ctxno = ff_jpeg2000_getsigctxno(t1->flags[y+1][x+1], bandno); - ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, t1->data[y][x] & mask ? 1:0); - if (t1->data[y][x] & mask){ // newly significant + if (!(t1->flags[(y+1) * t1->stride + x+1] & (JPEG2000_T1_SIG | JPEG2000_T1_VIS))){ + int ctxno = ff_jpeg2000_getsigctxno(t1->flags[(y+1) * t1->stride + x+1], bandno); + ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, t1->data[(y) * t1->stride + x] & mask ? 1:0); + if (t1->data[(y) * t1->stride + x] & mask){ // newly significant int xorbit; - int ctxno = ff_jpeg2000_getsgnctxno(t1->flags[y+1][x+1], &xorbit); - *nmsedec += getnmsedec_sig(t1->data[y][x], bpno + NMSEDEC_FRACBITS); - ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, (t1->flags[y+1][x+1] >> 15) ^ xorbit); - ff_jpeg2000_set_significance(t1, x, y, t1->flags[y+1][x+1] >> 15); + int ctxno = ff_jpeg2000_getsgnctxno(t1->flags[(y+1) * t1->stride + x+1], &xorbit); + *nmsedec += getnmsedec_sig(t1->data[(y) * t1->stride + x], bpno + NMSEDEC_FRACBITS); + ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, (t1->flags[(y+1) * t1->stride + x+1] >> 15) ^ xorbit); + ff_jpeg2000_set_significance(t1, x, y, t1->flags[(y+1) * t1->stride + x+1] >> 15); } } - t1->flags[y+1][x+1] &= ~JPEG2000_T1_VIS; + t1->flags[(y+1) * t1->stride + x+1] &= ~JPEG2000_T1_VIS; } } } @@ -577,16 +584,15 @@ static void encode_cblk(Jpeg2000EncoderContext *s, Jpeg2000T1Context *t1, Jpeg20 int pass_t = 2, passno, x, y, max=0, nmsedec, bpno; int64_t wmsedec = 0; - for (y = 0; y < height+2; y++) - memset(t1->flags[y], 0, (width+2)*sizeof(int)); + memset(t1->flags, 0, t1->stride * (height + 2) * sizeof(*t1->flags)); for (y = 0; y < height; y++){ for (x = 0; x < width; x++){ - if (t1->data[y][x] < 0){ - t1->flags[y+1][x+1] |= JPEG2000_T1_SGN; - t1->data[y][x] = -t1->data[y][x]; + if (t1->data[(y) * t1->stride + x] < 0){ + t1->flags[(y+1) * t1->stride + x+1] |= JPEG2000_T1_SGN; + t1->data[(y) * t1->stride + x] = -t1->data[(y) * t1->stride + x]; } - max = FFMAX(max, t1->data[y][x]); + max = FFMAX(max, t1->data[(y) * t1->stride + x]); } } @@ -820,6 +826,8 @@ static int encode_tile(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile, int tileno for (compno = 0; compno < s->ncomponents; compno++){ Jpeg2000Component *comp = s->tile[tileno].comp + compno; + t1.stride = (1<log2_cblk_width) + 2; + av_log(s->avctx, AV_LOG_DEBUG,"dwt\n"); if ((ret = ff_dwt_encode(&comp->dwt, comp->i_data)) < 0) return ret; @@ -855,14 +863,14 @@ static int encode_tile(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile, int tileno int y, x; if (codsty->transform == FF_DWT53){ for (y = yy0; y < yy1; y++){ - int *ptr = t1.data[y-yy0]; + int *ptr = t1.data + (y-yy0)*t1.stride; for (x = xx0; x < xx1; x++){ *ptr++ = comp->i_data[(comp->coord[0][1] - comp->coord[0][0]) * y + x] << NMSEDEC_FRACBITS; } } } else{ for (y = yy0; y < yy1; y++){ - int *ptr = t1.data[y-yy0]; + int *ptr = t1.data + (y-yy0)*t1.stride; for (x = xx0; x < xx1; x++){ *ptr = (comp->i_data[(comp->coord[0][1] - comp->coord[0][0]) * y + x]); *ptr = (int64_t)*ptr * (int64_t)(16384 * 65536 / band->i_stepsize) >> 15 - NMSEDEC_FRACBITS; @@ -916,11 +924,17 @@ static void reinit(Jpeg2000EncoderContext *s) } } +static void update_size(uint8_t *size, const uint8_t *end) +{ + AV_WB32(size, end-size); +} + static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pict, int *got_packet) { int tileno, ret; Jpeg2000EncoderContext *s = avctx->priv_data; + uint8_t *chunkstart, *jp2cstart, *jp2hstart; if ((ret = ff_alloc_packet2(avctx, pkt, avctx->width*avctx->height*9 + FF_MIN_BUFFER_SIZE)) < 0) return ret; @@ -936,6 +950,57 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, copy_frame(s); reinit(s); + if (s->format == CODEC_JP2) { + av_assert0(s->buf == pkt->data); + + bytestream_put_be32(&s->buf, 0x0000000C); + bytestream_put_be32(&s->buf, 0x6A502020); + bytestream_put_be32(&s->buf, 0x0D0A870A); + + chunkstart = s->buf; + bytestream_put_be32(&s->buf, 0); + bytestream_put_buffer(&s->buf, "ftyp", 4); + bytestream_put_buffer(&s->buf, "jp2\040\040", 4); + bytestream_put_be32(&s->buf, 0); + update_size(chunkstart, s->buf); + + jp2hstart = s->buf; + bytestream_put_be32(&s->buf, 0); + bytestream_put_buffer(&s->buf, "jp2h", 4); + + chunkstart = s->buf; + bytestream_put_be32(&s->buf, 0); + bytestream_put_buffer(&s->buf, "ihdr", 4); + bytestream_put_be32(&s->buf, avctx->height); + bytestream_put_be32(&s->buf, avctx->width); + bytestream_put_be16(&s->buf, s->ncomponents); + bytestream_put_byte(&s->buf, s->cbps[0]); + bytestream_put_byte(&s->buf, 7); + bytestream_put_byte(&s->buf, 0); + bytestream_put_byte(&s->buf, 0); + update_size(chunkstart, s->buf); + + chunkstart = s->buf; + bytestream_put_be32(&s->buf, 0); + bytestream_put_buffer(&s->buf, "colr", 4); + bytestream_put_byte(&s->buf, 1); + bytestream_put_byte(&s->buf, 0); + bytestream_put_byte(&s->buf, 0); + if (s->ncomponents == 1) { + bytestream_put_be32(&s->buf, 17); + } else if (avctx->pix_fmt == AV_PIX_FMT_RGB24) { + bytestream_put_be32(&s->buf, 16); + } else { + bytestream_put_be32(&s->buf, 18); + } + update_size(chunkstart, s->buf); + update_size(jp2hstart, s->buf); + + jp2cstart = s->buf; + bytestream_put_be32(&s->buf, 0); + bytestream_put_buffer(&s->buf, "jp2c", 4); + } + if (s->buf_end - s->buf < 2) return -1; bytestream_put_be16(&s->buf, JPEG2000_SOC); @@ -961,6 +1026,9 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, return -1; bytestream_put_be16(&s->buf, JPEG2000_EOC); + if (s->format == CODEC_JP2) + update_size(jp2cstart, s->buf); + av_log(s->avctx, AV_LOG_DEBUG, "end\n"); pkt->size = s->buf - s->buf_start; pkt->flags |= AV_PKT_FLAG_KEY; @@ -1037,6 +1105,24 @@ static int j2kenc_destroy(AVCodecContext *avctx) return 0; } +// taken from the libopenjpeg wraper so it matches + +#define OFFSET(x) offsetof(Jpeg2000EncoderContext, x) +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption options[] = { + { "format", "Codec Format", OFFSET(format), AV_OPT_TYPE_INT, { .i64 = CODEC_JP2 }, CODEC_J2K, CODEC_JP2, VE, "format" }, + { "j2k", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CODEC_J2K }, 0, 0, VE, "format" }, + { "jp2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CODEC_JP2 }, 0, 0, VE, "format" }, + { NULL } +}; + +static const AVClass j2k_class = { + .class_name = "jpeg 2000 encoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVCodec ff_jpeg2000_encoder = { .name = "jpeg2000", .long_name = NULL_IF_CONFIG_SMALL("JPEG 2000"), @@ -1053,5 +1139,6 @@ AVCodec ff_jpeg2000_encoder = { AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P,*/ AV_PIX_FMT_NONE - } + }, + .priv_class = &j2k_class, };