On 07/13/2012 05:10 AM, Luca Barbato wrote:
> From: Michael Bradshaw <[email protected]>
>
> Based on FFmpeg commits
> commit 713a7854e06964abc8f7d015b94acbed27769d24
> commit 7544ef78051c2b0477687ac4d7da829e61dbf8ac
> commit f06269dda5cab9d5e5dc591fbe3f752aae2b0a2b
> commit 1ef5561a662e96c9b3f554ee76d3a6e7327aba4c
> commit b0f6df28de4f78decd0acec88d860e1719ea8b05
> commit 3f26a874884896641903cf41a0b93bc2b5349cc5
> commit 67d5fcc989a0ee3cc3b3a89e643ee7f099ca6229
> commit dec8eb6b29beb472e94e7e32ad89e180597b7b0d
> commit 8e45005a849c849bbbc28bc16d7ecb4d342b251a
> commit 06b0c6a6559e8f179faaba9641bcb2d68edc7160
> commit b222c28ee885187c5fcded69d8fa98fe60c70a7e
> commit a5b823368a3589dd1e5b11bd4cb0bf7b013a8314
> commit de0735502662c766c5cfccd8dca3473f3e77f65e
> commit df42dd73235c4d89be44a088cb9fb30d27260cf6
> commit 56af084cb5478bc3c0eb2d47d47e82bbe40fbf2d
> commit a02694c92618fae98e5ce85b0a5eed71988a9d40
> commit 0abe25aa7bfa017a18832c6d4b0f59e4fd18f7d5
> commit ee33eb40fc007fe354d381d253625157aa73c525
> commit 36397ea1c7e27ab850149cc61394c2baa26dd532
> commit ffd1017fb89e3fcb4853e2803b05e3d1847916c4
> commit 4093d130d1934edcd098014d306492173527f1f6
> commit ef611095f0d0c1256cbb6654f94cae61a60f2736
> commit ba10207bbe5ebd97b5afc3f19baf4a1ad8f974d5
> commit 40c36196d555496269656dd9f15c8520fa2301cd
> commit 0275b75a7e705ef5a6bd6610f1450671f78000b6
> commit 1b987c4bb03d09debceb667af5f9af897c5ab0cd
> commit 856b33f578d3ca0e17ae69273d1c77248bf61a66
> commit 7c92c03b8d0aec2b593ade85525c7a8f87fecc63
I squashed the whole thing since the bulk of the commits had been
refinements and additional pixel formats.
> ---
> Changelog | 1 +
> configure | 2 +
> doc/general.texi | 2 +
> libavcodec/Makefile | 1 +
> libavcodec/allcodecs.c | 2 +-
> libavcodec/libopenjpegenc.c | 490
> +++++++++++++++++++++++++++++++++++++++++++
> libavcodec/version.h | 2 +-
> 7 files changed, 498 insertions(+), 2 deletions(-)
> create mode 100644 libavcodec/libopenjpegenc.c
>
> diff --git a/Changelog b/Changelog
> index 66994b4..09dae13 100644
> --- a/Changelog
> +++ b/Changelog
> @@ -32,6 +32,7 @@ version <next>:
> - audio channel mapping filter
> - Microsoft ATC Screen decoder
> - RTSP listen mode
> +- JPEG2k encoding support through OpenJPEG
>
>
> version 0.8:
> diff --git a/configure b/configure
> index ffb1e7e..158a0dd 100755
> --- a/configure
> +++ b/configure
> @@ -179,6 +179,7 @@ External library support:
> --enable-libopencv enable video filtering via libopencv [no]
> --enable-libopenjpeg enable JPEG 2000 decoding via OpenJPEG [no]
> --enable-libpulse enable Pulseaudio input via libpulse [no]
> + --enable-libopenjpeg enable JPEG 2000 encoding/decoding via OpenJPEG
> [no]
> --enable-librtmp enable RTMP[E] support via librtmp [no]
> --enable-libschroedinger enable Dirac support via libschroedinger [no]
> --enable-libspeex enable Speex support via libspeex [no]
> @@ -1457,6 +1458,7 @@ libopencore_amrnb_decoder_deps="libopencore_amrnb"
> libopencore_amrnb_encoder_deps="libopencore_amrnb"
> libopencore_amrwb_decoder_deps="libopencore_amrwb"
> libopenjpeg_decoder_deps="libopenjpeg"
> +libopenjpeg_encoder_deps="libopenjpeg"
> libschroedinger_decoder_deps="libschroedinger"
> libschroedinger_encoder_deps="libschroedinger"
> libspeex_decoder_deps="libspeex"
> diff --git a/doc/general.texi b/doc/general.texi
> index 4ea47b4..bf56b19 100644
> --- a/doc/general.texi
> +++ b/doc/general.texi
> @@ -18,6 +18,7 @@ explicitly requested by passing the appropriate flags to
>
> @section OpenCORE and VisualOn libraries
>
> +
That's a stray, I'll amend it already
> Spun off Google Android sources, OpenCore and VisualOn libraries provide
> encoders for a number of audio codecs.
> +static void info_callback(const char *msg, void *data)
> +{
> + av_log((AVCodecContext*)data, AV_LOG_DEBUG, "%s\n", msg);
> +}
Yes the name is misleading, but apparently it is used for debug messages.
> +
> +static opj_image_t *mj2_create_image(AVCodecContext *avctx,
> + opj_cparameters_t *parameters)
> +{
> + opj_image_cmptparm_t *cmptparm;
> + OPJ_COLOR_SPACE color_space;
> + opj_image_t *img;
> + int i;
> + int sub_dx[4];
> + int sub_dy[4];
> + int numcomps = av_pix_fmt_descriptors[avctx->pix_fmt].nb_components;
> +
> + sub_dx[0] = sub_dx[3] = 1;
> + sub_dy[0] = sub_dy[3] = 1;
> + sub_dx[1] = sub_dx[2] =
> + 1 << av_pix_fmt_descriptors[avctx->pix_fmt].log2_chroma_w;
> + sub_dy[1] = sub_dy[2] =
> + 1 << av_pix_fmt_descriptors[avctx->pix_fmt].log2_chroma_h;
> +
> +
> + switch (avctx->pix_fmt) {
> + case PIX_FMT_GRAY8:
> + case PIX_FMT_GRAY16:
> + color_space = CLRSPC_GRAY;
> + break;
> + case PIX_FMT_RGB24:
> + case PIX_FMT_RGBA:
> + case PIX_FMT_RGB48:
> + color_space = CLRSPC_SRGB;
> + break;
> + case PIX_FMT_YUV410P:
> + case PIX_FMT_YUV411P:
> + case PIX_FMT_YUV420P:
> + case PIX_FMT_YUV422P:
> + case PIX_FMT_YUV440P:
> + case PIX_FMT_YUV444P:
> + case PIX_FMT_YUVA420P:
> + case PIX_FMT_YUV420P9:
> + case PIX_FMT_YUV422P9:
> + case PIX_FMT_YUV444P9:
> + case PIX_FMT_YUV420P10:
> + case PIX_FMT_YUV422P10:
> + case PIX_FMT_YUV444P10:
> + case PIX_FMT_YUV420P16:
> + case PIX_FMT_YUV422P16:
> + case PIX_FMT_YUV444P16:
> + color_space = CLRSPC_SYCC;
> + break;
> + default:
> + av_log(avctx, AV_LOG_ERROR,
> + "The requested pixel format '%s' is not supported\n",
> + av_get_pix_fmt_name(avctx->pix_fmt));
> + return NULL;
> + }
> +
> + cmptparm = av_mallocz(numcomps * sizeof(opj_image_cmptparm_t));
> + if (!cmptparm) {
> + av_log(avctx, AV_LOG_ERROR, "Not enough memory");
> + return NULL;
> + }
> +
> + for (i = 0; i < numcomps; i++) {
> + cmptparm[i].prec =
> + av_pix_fmt_descriptors[avctx->pix_fmt].comp[i].depth_minus1 + 1;
> + cmptparm[i].bpp =
> + av_pix_fmt_descriptors[avctx->pix_fmt].comp[i].depth_minus1 + 1;
> + cmptparm[i].sgnd = 0;
> + cmptparm[i].dx = sub_dx[i];
> + cmptparm[i].dy = sub_dy[i];
> + cmptparm[i].w = avctx->width / sub_dx[i];
> + cmptparm[i].h = avctx->height / sub_dy[i];
> + }
> +
> + img = opj_image_create(numcomps, cmptparm, color_space);
> + av_freep(&cmptparm);
> + return img;
> +}
> +
> +static av_cold int libopenjpeg_encode_init(AVCodecContext *avctx)
> +{
> + LibOpenJPEGContext *ctx = avctx->priv_data;
> + int err = AVERROR(ENOMEM);
> +
> + opj_set_default_encoder_parameters(&ctx->enc_params);
> +
> + ctx->enc_params.cp_rsiz = ctx->profile;
> + ctx->enc_params.mode = !!avctx->global_quality;
> + ctx->enc_params.cp_cinema = ctx->cinema_mode;
> + ctx->enc_params.prog_order = ctx->prog_order;
> + ctx->enc_params.numresolution = ctx->numresolution;
> + ctx->enc_params.cp_disto_alloc = ctx->disto_alloc;
> + ctx->enc_params.cp_fixed_alloc = ctx->fixed_alloc;
> + ctx->enc_params.cp_fixed_quality = ctx->fixed_quality;
> + ctx->enc_params.tcp_numlayers = ctx->numlayers;
> + ctx->enc_params.tcp_rates[0] = FFMAX(avctx->compression_level, 0) *
> 2;
> +
> + ctx->compress = opj_create_compress(ctx->format);
> + if (!ctx->compress) {
> + av_log(avctx, AV_LOG_ERROR, "Error creating the compressor\n");
> + return AVERROR(ENOMEM);
> + }
> +
> + avctx->coded_frame = avcodec_alloc_frame();
> + if (!avctx->coded_frame) {
> + av_log(avctx, AV_LOG_ERROR, "Error allocating coded frame\n");
> + goto fail;
> + }
> +
> + ctx->image = mj2_create_image(avctx, &ctx->enc_params);
> + if (!ctx->image) {
> + av_log(avctx, AV_LOG_ERROR, "Error creating the mj2 image\n");
> + err = AVERROR(EINVAL);
> + goto fail;
> + }
> +
> + ctx->event_mgr.info_handler = info_callback;
> + ctx->event_mgr.error_handler = error_callback;
> + ctx->event_mgr.warning_handler = warning_callback;
> + opj_set_event_mgr((opj_common_ptr)ctx->compress, &ctx->event_mgr, avctx);
> +
> + return 0;
> +
> +fail:
> + av_freep(&ctx->compress);
> + av_freep(&avctx->coded_frame);
> + return err;
> +}
> +
> +static int libopenjpeg_copy_packed8(AVCodecContext *avctx,
> + const AVFrame *frame, opj_image_t *image)
> +{
> + int compno;
> + int x;
> + int y;
> + int image_index;
> + int frame_index;
> + const int numcomps = image->numcomps;
> +
> + for (compno = 0; compno < numcomps; ++compno) {
> + if (image->comps[compno].w > frame->linesize[0] / numcomps) {
> + av_log(avctx, AV_LOG_ERROR,
> + "Error: frame's linesize is too small for the image\n");
> + return 0;
> + }
> + }
This chunk looks always the same, probably could be factored out.
> +
> + for (compno = 0; compno < numcomps; ++compno) {
> + for (y = 0; y < avctx->height; ++y) {
> + image_index = y * avctx->width;
> + frame_index = y * frame->linesize[0] + compno;
> + for (x = 0; x < avctx->width; ++x) {
> + image->comps[compno].data[image_index++] =
> + frame->data[0][frame_index];
> + frame_index += numcomps;
> + }
> + }
> + }
not sure if we have a generic permute in dsputil but might be beneficial.
> +static int libopenjpeg_copy_unpacked8(AVCodecContext *avctx,
> + const AVFrame *frame, opj_image_t
> *image)
> +{
> + int compno;
> + int x;
> + int y;
> + int width;
> + int height;
> + int image_index;
> + int frame_index;
> + const int numcomps = image->numcomps;
> +
> + for (compno = 0; compno < numcomps; ++compno) {
> + if (image->comps[compno].w > frame->linesize[compno]) {
> + av_log(avctx, AV_LOG_ERROR,
> + "Error: frame's linesize is too small for the image\n");
> + return 0;
> + }
> + }
> +
> + for (compno = 0; compno < numcomps; ++compno) {
> + width = avctx->width / image->comps[compno].dx;
> + height = avctx->height / image->comps[compno].dy;
> + for (y = 0; y < height; ++y) {
> + image_index = y * width;
> + frame_index = y * frame->linesize[compno];
> + for (x = 0; x < width; ++x) {
> + image->comps[compno].data[image_index++] =
> + frame->data[compno][frame_index++];
> + }
> + }
> + }
memcpy?
> +static int libopenjpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
> + const AVFrame *frame, int *got_packet)
> +{
> + LibOpenJPEGContext *ctx = avctx->priv_data;
> + opj_cinfo_t *compress = ctx->compress;
> + opj_image_t *image = ctx->image;
> + opj_cio_t *stream;
> + int cpyresult = 0;
> + int ret, len;
> +
> + // x0, y0 is the top left corner of the image
> + // x1, y1 is the width, height of the reference grid
> + image->x0 = 0;
> + image->y0 = 0;
> + image->x1 = (avctx->width - 1) * ctx->enc_params.subsampling_dx + 1;
> + image->y1 = (avctx->height - 1) * ctx->enc_params.subsampling_dy + 1;
> +
> + switch (avctx->pix_fmt) {
> + case PIX_FMT_RGB24:
> + case PIX_FMT_RGBA:
> + cpyresult = libopenjpeg_copy_packed8(avctx, frame, image);
> + break;
> + case PIX_FMT_RGB48:
> + cpyresult = libopenjpeg_copy_packed16(avctx, frame, image);
> + break;
> + case PIX_FMT_GRAY8:
> + case PIX_FMT_YUV410P:
> + case PIX_FMT_YUV411P:
> + case PIX_FMT_YUV420P:
> + case PIX_FMT_YUV422P:
> + case PIX_FMT_YUV440P:
> + case PIX_FMT_YUV444P:
> + case PIX_FMT_YUVA420P:
> + cpyresult = libopenjpeg_copy_unpacked8(avctx, frame, image);
> + break;
> + case PIX_FMT_GRAY16:
> + case PIX_FMT_YUV420P9:
> + case PIX_FMT_YUV422P9:
> + case PIX_FMT_YUV444P9:
> + case PIX_FMT_YUV444P10:
> + case PIX_FMT_YUV422P10:
> + case PIX_FMT_YUV420P10:
> + case PIX_FMT_YUV444P16:
> + case PIX_FMT_YUV422P16:
> + case PIX_FMT_YUV420P16:
> + cpyresult = libopenjpeg_copy_unpacked16(avctx, frame, image);
> + break;
> + default:
> + av_log(avctx, AV_LOG_ERROR,
> + "The frame's pixel format '%s' is not supported\n",
> + av_get_pix_fmt_name(avctx->pix_fmt));
> + return AVERROR(EINVAL);
> + break;
> + }
> +
> + if (!cpyresult) {
> + av_log(avctx, AV_LOG_ERROR,
> + "Could not copy the frame data to the internal image
> buffer\n");
> + return AVERROR_INVALIDDATA;
> + }
> +
> + opj_setup_encoder(compress, &ctx->enc_params, image);
> + stream = opj_cio_open((opj_common_ptr)compress, NULL, 0);
> + if (!stream) {
> + av_log(avctx, AV_LOG_ERROR, "Error creating the cio stream\n");
> + return AVERROR(ENOMEM);
> + }
> +
> + if (!opj_encode(compress, stream, image, NULL)) {
this function is a wrapper to the opj_encode_info, we might call it
directly.
> + opj_cio_close(stream);
> + av_log(avctx, AV_LOG_ERROR, "Error during the opj encode\n");
> + return -1;
> + }
> +
> + len = cio_tell(stream);
> + if ((ret = ff_alloc_packet(pkt, len)) < 0) {
> + opj_cio_close(stream);
> + return ret;
> + }
> +
> + memcpy(pkt->data, stream->buffer, len);
I wonder if there is a way to make openjpeg use a provided buffer, we
are spending lots of time moving memory around.
> + pkt->flags |= AV_PKT_FLAG_KEY;
> + *got_packet = 1;
> + opj_cio_close(stream);
> + return 0;
> +}
--
Luca Barbato
Gentoo/linux
http://dev.gentoo.org/~lu_zero
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel