Added support for J2K encoding with libopenjpeg

Note: Some of the previous patches have had two bugs that have been fixed
in this patch.

Signed-off-by: Michael Bradshaw <mbradshaw@sorensonmedia.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
pull/2/head
Michael Bradshaw 13 years ago committed by Michael Niedermayer
parent 32aa9590ac
commit 856b33f578
  1. 1
      Changelog
  2. 1
      MAINTAINERS
  3. 3
      configure
  4. 9
      doc/general.texi
  5. 1
      libavcodec/Makefile
  6. 2
      libavcodec/allcodecs.c
  7. 330
      libavcodec/libopenjpegenc.c
  8. 2
      libavcodec/version.h

@ -241,6 +241,7 @@ version 0.8:
- lut, lutrgb, and lutyuv filters added - lut, lutrgb, and lutyuv filters added
- buffersink libavfilter sink added - buffersink libavfilter sink added
- Bump libswscale for recently reported ABI break - Bump libswscale for recently reported ABI break
- New J2K encoder (via OpenJPEG)
version 0.7: version 0.7:

@ -157,6 +157,7 @@ Codecs:
libgsm.c Michel Bardiaux libgsm.c Michel Bardiaux
libdirac* David Conrad libdirac* David Conrad
libopenjpeg.c Jaikrishnan Menon libopenjpeg.c Jaikrishnan Menon
libopenjpegenc.c Michael Bradshaw
libschroedinger* David Conrad libschroedinger* David Conrad
libspeexdec.c Justin Ruggles libspeexdec.c Justin Ruggles
libtheoraenc.c David Conrad libtheoraenc.c David Conrad

3
configure vendored

@ -183,7 +183,7 @@ External library support:
--enable-libmp3lame enable MP3 encoding via libmp3lame [no] --enable-libmp3lame enable MP3 encoding via libmp3lame [no]
--enable-libnut enable NUT (de)muxing via libnut, --enable-libnut enable NUT (de)muxing via libnut,
native (de)muxer exists [no] native (de)muxer exists [no]
--enable-libopenjpeg enable JPEG 2000 decoding via OpenJPEG [no] --enable-libopenjpeg enable JPEG 2000 encoding/decoding via OpenJPEG [no]
--enable-librtmp enable RTMP[E] support via librtmp [no] --enable-librtmp enable RTMP[E] support via librtmp [no]
--enable-libschroedinger enable Dirac support via libschroedinger [no] --enable-libschroedinger enable Dirac support via libschroedinger [no]
--enable-libspeex enable Speex support via libspeex [no] --enable-libspeex enable Speex support via libspeex [no]
@ -1519,6 +1519,7 @@ libopencore_amrnb_decoder_deps="libopencore_amrnb"
libopencore_amrnb_encoder_deps="libopencore_amrnb" libopencore_amrnb_encoder_deps="libopencore_amrnb"
libopencore_amrwb_decoder_deps="libopencore_amrwb" libopencore_amrwb_decoder_deps="libopencore_amrwb"
libopenjpeg_decoder_deps="libopenjpeg" libopenjpeg_decoder_deps="libopenjpeg"
libopenjpeg_encoder_deps="libopenjpeg"
libschroedinger_decoder_deps="libschroedinger" libschroedinger_decoder_deps="libschroedinger"
libschroedinger_encoder_deps="libschroedinger" libschroedinger_encoder_deps="libschroedinger"
libspeex_decoder_deps="libspeex" libspeex_decoder_deps="libspeex"

@ -15,6 +15,14 @@ FFmpeg can be hooked up with a number of external libraries to add support
for more formats. None of them are used by default, their use has to be for more formats. None of them are used by default, their use has to be
explicitly requested by passing the appropriate flags to @file{./configure}. explicitly requested by passing the appropriate flags to @file{./configure}.
@section OpenJPEG
FFmpeg can use the OpenJPEG libraries for encoding/decoding J2K videos. Go to
@url{http://www.openjpeg.org/} to get the libraries and follow the installation
instructions. To enable using OpenJPEG in FFmpeg, pass @code{--enable-libopenjpeg} to
@file{./configure}.
@section OpenCORE AMR @section OpenCORE AMR
FFmpeg can make use of the OpenCORE libraries for AMR-NB FFmpeg can make use of the OpenCORE libraries for AMR-NB
@ -447,6 +455,7 @@ following image formats are supported:
@tab Used in the game Cyberia from Interplay. @tab Used in the game Cyberia from Interplay.
@item Interplay MVE video @tab @tab X @item Interplay MVE video @tab @tab X
@tab Used in Interplay .MVE files. @tab Used in Interplay .MVE files.
@item J2K @tab X @tab X
@item Karl Morton's video codec @tab @tab X @item Karl Morton's video codec @tab @tab X
@tab Codec used in Worms games. @tab Codec used in Worms games.
@item Kega Game Video (KGV1) @tab @tab X @item Kega Game Video (KGV1) @tab @tab X

@ -606,6 +606,7 @@ OBJS-$(CONFIG_LIBOPENCORE_AMRNB_DECODER) += libopencore-amr.o
OBJS-$(CONFIG_LIBOPENCORE_AMRNB_ENCODER) += libopencore-amr.o OBJS-$(CONFIG_LIBOPENCORE_AMRNB_ENCODER) += libopencore-amr.o
OBJS-$(CONFIG_LIBOPENCORE_AMRWB_DECODER) += libopencore-amr.o OBJS-$(CONFIG_LIBOPENCORE_AMRWB_DECODER) += libopencore-amr.o
OBJS-$(CONFIG_LIBOPENJPEG_DECODER) += libopenjpegdec.o OBJS-$(CONFIG_LIBOPENJPEG_DECODER) += libopenjpegdec.o
OBJS-$(CONFIG_LIBOPENJPEG_ENCODER) += libopenjpegenc.o
OBJS-$(CONFIG_LIBSCHROEDINGER_DECODER) += libschroedingerdec.o \ OBJS-$(CONFIG_LIBSCHROEDINGER_DECODER) += libschroedingerdec.o \
libschroedinger.o \ libschroedinger.o \
libdirac_libschro.o libdirac_libschro.o

@ -391,7 +391,7 @@ void avcodec_register_all(void)
REGISTER_ENCODER (LIBMP3LAME, libmp3lame); REGISTER_ENCODER (LIBMP3LAME, libmp3lame);
REGISTER_ENCDEC (LIBOPENCORE_AMRNB, libopencore_amrnb); REGISTER_ENCDEC (LIBOPENCORE_AMRNB, libopencore_amrnb);
REGISTER_DECODER (LIBOPENCORE_AMRWB, libopencore_amrwb); REGISTER_DECODER (LIBOPENCORE_AMRWB, libopencore_amrwb);
REGISTER_DECODER (LIBOPENJPEG, libopenjpeg); REGISTER_ENCDEC (LIBOPENJPEG, libopenjpeg);
REGISTER_ENCDEC (LIBSCHROEDINGER, libschroedinger); REGISTER_ENCDEC (LIBSCHROEDINGER, libschroedinger);
REGISTER_ENCDEC (LIBSPEEX, libspeex); REGISTER_ENCDEC (LIBSPEEX, libspeex);
REGISTER_DECODER (LIBSTAGEFRIGHT_H264, libstagefright_h264); REGISTER_DECODER (LIBSTAGEFRIGHT_H264, libstagefright_h264);

@ -0,0 +1,330 @@
/*
* JPEG 2000 encoding support via OpenJPEG
* Copyright (c) 2011 Michael Bradshaw <mbradshaw@sorensonmedia.com>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* JPEG 2000 encoder using libopenjpeg
*/
#include "libavutil/imgutils.h"
#include "avcodec.h"
#include "libavutil/intreadwrite.h"
#define OPJ_STATIC
#include <openjpeg.h>
typedef struct {
opj_image_t *image;
opj_cparameters_t enc_params;
opj_cinfo_t *compress;
opj_event_mgr_t event_mgr;
} LibOpenJPEGContext;
static void error_callback(const char *msg, void *data)
{
av_log((AVCodecContext*)data, AV_LOG_ERROR, "libopenjpeg: %s\n", msg);
}
static void warning_callback(const char *msg, void *data)
{
av_log((AVCodecContext*)data, AV_LOG_WARNING, "libopenjpeg: %s\n", msg);
}
static opj_image_t *mj2_create_image(AVCodecContext *avctx, opj_cparameters_t *parameters)
{
opj_image_cmptparm_t *cmptparm;
opj_image_t *img;
int i;
int bpp;
int sub_dx[4];
int sub_dy[4];
int numcomps = 0;
OPJ_COLOR_SPACE color_space = CLRSPC_UNKNOWN;
switch (avctx->pix_fmt) {
case PIX_FMT_GRAY8:
color_space = CLRSPC_GRAY;
numcomps = 1;
bpp = 8;
sub_dx[0] = 1;
sub_dy[0] = 1;
break;
case PIX_FMT_RGB24:
color_space = CLRSPC_SRGB;
numcomps = 3;
bpp = 24;
sub_dx[0] = sub_dx[1] = sub_dx[2] = 1;
sub_dy[0] = sub_dy[1] = sub_dy[2] = 1;
break;
case PIX_FMT_RGBA:
color_space = CLRSPC_SRGB;
numcomps = 4;
bpp = 32;
sub_dx[0] = sub_dx[1] = sub_dx[2] = sub_dx[3] = 1;
sub_dy[0] = sub_dy[1] = sub_dy[2] = sub_dy[3] = 1;
break;
case PIX_FMT_YUV420P:
color_space = CLRSPC_SYCC;
numcomps = 3;
bpp = 12;
sub_dx[0] = 1;
sub_dx[1] = sub_dx[2] = 2;
sub_dy[0] = 1;
sub_dy[1] = sub_dy[2] = 2;
break;
case PIX_FMT_YUV422P:
color_space = CLRSPC_SYCC;
numcomps = 3;
bpp = 16;
sub_dx[0] = 1;
sub_dx[1] = sub_dx[2] = 2;
sub_dy[0] = sub_dy[1] = sub_dy[2] = 1;
break;
case PIX_FMT_YUV440P:
color_space = CLRSPC_SYCC;
numcomps = 3;
bpp = 16;
sub_dx[0] = sub_dx[1] = sub_dx[2] = 1;
sub_dy[0] = 1;
sub_dy[1] = sub_dy[2] = 2;
break;
case PIX_FMT_YUV444P:
color_space = CLRSPC_SYCC;
numcomps = 3;
bpp = 24;
sub_dx[0] = sub_dx[1] = sub_dx[2] = 1;
sub_dy[0] = sub_dy[1] = sub_dy[2] = 1;
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_malloc(numcomps * sizeof(opj_image_cmptparm_t));
if (!cmptparm) {
av_log(avctx, AV_LOG_ERROR, "Not enough memory");
return NULL;
}
memset(cmptparm, 0, numcomps * sizeof(opj_image_cmptparm_t));
for (i = 0; i < numcomps; i++) {
cmptparm[i].prec = 8;
cmptparm[i].bpp = bpp;
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;
opj_set_default_encoder_parameters(&ctx->enc_params);
ctx->enc_params.tcp_numlayers = 1;
ctx->enc_params.tcp_rates[0] = avctx->compression_level > 0 ? avctx->compression_level : 0;
ctx->enc_params.cp_disto_alloc = 1;
ctx->compress = opj_create_compress(CODEC_J2K);
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_freep(&ctx->compress);
ctx->compress = NULL;
av_log(avctx, AV_LOG_ERROR, "Error allocating coded frame\n");
return AVERROR(ENOMEM);
}
ctx->image = mj2_create_image(avctx, &ctx->enc_params);
if (!ctx->image) {
av_freep(&ctx->compress);
ctx->compress = NULL;
av_freep(&avctx->coded_frame);
avctx->coded_frame = NULL;
av_log(avctx, AV_LOG_ERROR, "Error creating the mj2 image\n");
return AVERROR(EINVAL);
}
memset(&ctx->event_mgr, 0, sizeof(opj_event_mgr_t));
ctx->event_mgr.error_handler = error_callback;
ctx->event_mgr.warning_handler = warning_callback;
ctx->event_mgr.info_handler = NULL;
opj_set_event_mgr((opj_common_ptr)ctx->compress, &ctx->event_mgr, avctx);
return 0;
}
static int libopenjpeg_copy_rgba(AVCodecContext *avctx, AVFrame *frame, opj_image_t *image, int numcomps)
{
int compno;
int x;
int y;
if (numcomps != 1 && numcomps != 3 && numcomps != 4) {
return 0;
}
for (compno = 0; compno < numcomps; ++compno) {
if (image->comps[compno].w > frame->linesize[0] / numcomps) {
return 0;
}
}
for (compno = 0; compno < numcomps; ++compno) {
for (y = 0; y < avctx->height; ++y) {
for (x = 0; x < avctx->width; ++x) {
image->comps[compno].data[y * avctx->width + x] = frame->data[0][y * frame->linesize[0] + x * numcomps + compno];
}
}
}
return 1;
}
static int libopenjpeg_copy_yuv(AVCodecContext *avctx, AVFrame *frame, opj_image_t *image)
{
int compno;
int x;
int y;
int width;
int height;
const int numcomps = 3;
for (compno = 0; compno < numcomps; ++compno) {
if (image->comps[compno].w > frame->linesize[compno]) {
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) {
for (x = 0; x < width; ++x) {
image->comps[compno].data[y * width + x] = frame->data[compno][y * frame->linesize[compno] + x];
}
}
}
return 1;
}
static int libopenjpeg_encode_frame(AVCodecContext *avctx, uint8_t *buf, int buf_size, void *data)
{
AVFrame *frame = data;
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 len = 0;
// 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_GRAY8:
cpyresult = libopenjpeg_copy_rgba(avctx, frame, image, 1);
break;
case PIX_FMT_RGB24:
cpyresult = libopenjpeg_copy_rgba(avctx, frame, image, 3);
break;
case PIX_FMT_RGBA:
cpyresult = libopenjpeg_copy_rgba(avctx, frame, image, 4);
break;
case PIX_FMT_YUV420P:
case PIX_FMT_YUV422P:
case PIX_FMT_YUV440P:
case PIX_FMT_YUV444P:
cpyresult = libopenjpeg_copy_yuv(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 -1;
}
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)) {
opj_cio_close(stream);
av_log(avctx, AV_LOG_ERROR, "Error during the opj encode\n");
return -1;
}
len = cio_tell(stream);
if (len > buf_size) {
opj_cio_close(stream);
av_log(avctx, AV_LOG_ERROR, "Error with buf_size, not large enough to hold the frame\n");
return -1;
}
memcpy(buf, stream->buffer, len);
opj_cio_close(stream);
return len;
}
static av_cold int libopenjpeg_encode_close(AVCodecContext *avctx)
{
LibOpenJPEGContext *ctx = avctx->priv_data;
opj_destroy_compress(ctx->compress);
opj_image_destroy(ctx->image);
av_freep(&avctx->coded_frame);
return 0 ;
}
AVCodec ff_libopenjpeg_encoder = {
.name = "libopenjpeg",
.type = AVMEDIA_TYPE_VIDEO,
.id = CODEC_ID_JPEG2000,
.priv_data_size = sizeof(LibOpenJPEGContext),
.init = libopenjpeg_encode_init,
.encode = libopenjpeg_encode_frame,
.close = libopenjpeg_encode_close,
.decode = NULL,
.capabilities = 0,
.pix_fmts = (const enum PixelFormat[]){PIX_FMT_GRAY8,PIX_FMT_RGB24,PIX_FMT_RGBA,PIX_FMT_YUV420P,PIX_FMT_YUV422P,PIX_FMT_YUV440P,PIX_FMT_YUV444P},
.long_name = NULL_IF_CONFIG_SMALL("OpenJPEG based JPEG 2000 encoder/decoder"),
} ;

@ -21,7 +21,7 @@
#define AVCODEC_VERSION_H #define AVCODEC_VERSION_H
#define LIBAVCODEC_VERSION_MAJOR 53 #define LIBAVCODEC_VERSION_MAJOR 53
#define LIBAVCODEC_VERSION_MINOR 34 #define LIBAVCODEC_VERSION_MINOR 35
#define LIBAVCODEC_VERSION_MICRO 0 #define LIBAVCODEC_VERSION_MICRO 0
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \

Loading…
Cancel
Save