Update avcodec to 20080825

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27566 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
David McPaul
2008-09-15 14:14:13 +00:00
parent c0d69ba2f1
commit 875bbde053
35 changed files with 8150 additions and 0 deletions
@@ -0,0 +1,49 @@
/*
* LCL (LossLess Codec Library) Codec
* Copyright (c) 2002-2004 Roberto Togni
*
* 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
*/
#ifndef FFMPEG_LCL_H
#define FFMPEG_LCL_H
#define BMPTYPE_YUV 1
#define BMPTYPE_RGB 2
#define IMGTYPE_YUV111 0
#define IMGTYPE_YUV422 1
#define IMGTYPE_RGB24 2
#define IMGTYPE_YUV411 3
#define IMGTYPE_YUV211 4
#define IMGTYPE_YUV420 5
#define COMP_MSZH 0
#define COMP_MSZH_NOCOMP 1
#define COMP_ZLIB_HISPEED 1
#define COMP_ZLIB_HICOMP 9
#define COMP_ZLIB_NORMAL -1
#define FLAG_MULTITHREAD 1
#define FLAG_NULLFRAME 2
#define FLAG_PNGFILTER 4
#define FLAGMASK_UNUSED 0xf8
#define CODEC_MSZH 1
#define CODEC_ZLIB 3
#endif /* FFMPEG_LCL_H */
@@ -0,0 +1,717 @@
/*
* LCL (LossLess Codec Library) Codec
* Copyright (c) 2002-2004 Roberto Togni
*
* 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 lcl.c
* LCL (LossLess Codec Library) Video Codec
* Decoder for MSZH and ZLIB codecs
* Experimental encoder for ZLIB RGB24
*
* Fourcc: MSZH, ZLIB
*
* Original Win32 dll:
* Ver2.23 By Kenji Oshima 2000.09.20
* avimszh.dll, avizlib.dll
*
* A description of the decoding algorithm can be found here:
* http://www.pcisys.net/~melanson/codecs
*
* Supports: BGR24 (RGB 24bpp)
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "avcodec.h"
#include "bitstream.h"
#include "lcl.h"
#ifdef CONFIG_ZLIB
#include <zlib.h>
#endif
/*
* Decoder context
*/
typedef struct LclDecContext {
AVFrame pic;
// Image type
int imgtype;
// Compression type
int compression;
// Flags
int flags;
// Decompressed data size
unsigned int decomp_size;
// Decompression buffer
unsigned char* decomp_buf;
#ifdef CONFIG_ZLIB
z_stream zstream;
#endif
} LclDecContext;
/*
*
* Helper functions
*
*/
static inline unsigned char fix (int pix14)
{
int tmp;
tmp = (pix14 + 0x80000) >> 20;
if (tmp < 0)
return 0;
if (tmp > 255)
return 255;
return tmp;
}
static inline unsigned char get_b (unsigned char yq, signed char bq)
{
return fix((yq << 20) + bq * 1858076);
}
static inline unsigned char get_g (unsigned char yq, signed char bq, signed char rq)
{
return fix((yq << 20) - bq * 360857 - rq * 748830);
}
static inline unsigned char get_r (unsigned char yq, signed char rq)
{
return fix((yq << 20) + rq * 1470103);
}
static unsigned int mszh_decomp(unsigned char * srcptr, int srclen, unsigned char * destptr, unsigned int destsize)
{
unsigned char *destptr_bak = destptr;
unsigned char *destptr_end = destptr + destsize;
unsigned char mask = 0;
unsigned char maskbit = 0;
unsigned int ofs, cnt;
while ((srclen > 0) && (destptr < destptr_end)) {
if (maskbit == 0) {
mask = *(srcptr++);
maskbit = 8;
srclen--;
continue;
}
if ((mask & (1 << (--maskbit))) == 0) {
if (destptr + 4 > destptr_end)
break;
*(int*)destptr = *(int*)srcptr;
srclen -= 4;
destptr += 4;
srcptr += 4;
} else {
ofs = *(srcptr++);
cnt = *(srcptr++);
ofs += cnt * 256;
cnt = ((cnt >> 3) & 0x1f) + 1;
ofs &= 0x7ff;
srclen -= 2;
cnt *= 4;
if (destptr + cnt > destptr_end) {
cnt = destptr_end - destptr;
}
for (; cnt > 0; cnt--) {
*(destptr) = *(destptr - ofs);
destptr++;
}
}
}
return (destptr - destptr_bak);
}
/*
*
* Decode a frame
*
*/
static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, const uint8_t *buf, int buf_size)
{
LclDecContext * const c = avctx->priv_data;
unsigned char *encoded = (unsigned char *)buf;
unsigned int pixel_ptr;
int row, col;
unsigned char *outptr;
unsigned int width = avctx->width; // Real image width
unsigned int height = avctx->height; // Real image height
unsigned int mszh_dlen;
unsigned char yq, y1q, uq, vq;
int uqvq;
unsigned int mthread_inlen, mthread_outlen;
#ifdef CONFIG_ZLIB
int zret; // Zlib return code
#endif
unsigned int len = buf_size;
if(c->pic.data[0])
avctx->release_buffer(avctx, &c->pic);
c->pic.reference = 0;
c->pic.buffer_hints = FF_BUFFER_HINTS_VALID;
if(avctx->get_buffer(avctx, &c->pic) < 0){
av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
return -1;
}
outptr = c->pic.data[0]; // Output image pointer
/* Decompress frame */
switch (avctx->codec_id) {
case CODEC_ID_MSZH:
switch (c->compression) {
case COMP_MSZH:
if (c->flags & FLAG_MULTITHREAD) {
mthread_inlen = *((unsigned int*)encoded);
mthread_outlen = *((unsigned int*)(encoded+4));
if (mthread_outlen > c->decomp_size) // this should not happen
mthread_outlen = c->decomp_size;
mszh_dlen = mszh_decomp(encoded + 8, mthread_inlen, c->decomp_buf, c->decomp_size);
if (mthread_outlen != mszh_dlen) {
av_log(avctx, AV_LOG_ERROR, "Mthread1 decoded size differs (%d != %d)\n",
mthread_outlen, mszh_dlen);
return -1;
}
mszh_dlen = mszh_decomp(encoded + 8 + mthread_inlen, len - mthread_inlen,
c->decomp_buf + mthread_outlen, c->decomp_size - mthread_outlen);
if (mthread_outlen != mszh_dlen) {
av_log(avctx, AV_LOG_ERROR, "Mthread2 decoded size differs (%d != %d)\n",
mthread_outlen, mszh_dlen);
return -1;
}
encoded = c->decomp_buf;
len = c->decomp_size;
} else {
mszh_dlen = mszh_decomp(encoded, len, c->decomp_buf, c->decomp_size);
if (c->decomp_size != mszh_dlen) {
av_log(avctx, AV_LOG_ERROR, "Decoded size differs (%d != %d)\n",
c->decomp_size, mszh_dlen);
return -1;
}
encoded = c->decomp_buf;
len = mszh_dlen;
}
break;
case COMP_MSZH_NOCOMP:
break;
default:
av_log(avctx, AV_LOG_ERROR, "BUG! Unknown MSZH compression in frame decoder.\n");
return -1;
}
break;
case CODEC_ID_ZLIB:
#ifdef CONFIG_ZLIB
/* Using the original dll with normal compression (-1) and RGB format
* gives a file with ZLIB fourcc, but frame is really uncompressed.
* To be sure that's true check also frame size */
if ((c->compression == COMP_ZLIB_NORMAL) && (c->imgtype == IMGTYPE_RGB24) &&
(len == width * height * 3))
break;
zret = inflateReset(&(c->zstream));
if (zret != Z_OK) {
av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", zret);
return -1;
}
if (c->flags & FLAG_MULTITHREAD) {
mthread_inlen = *((unsigned int*)encoded);
mthread_outlen = *((unsigned int*)(encoded+4));
if (mthread_outlen > c->decomp_size)
mthread_outlen = c->decomp_size;
c->zstream.next_in = encoded + 8;
c->zstream.avail_in = mthread_inlen;
c->zstream.next_out = c->decomp_buf;
c->zstream.avail_out = c->decomp_size;
zret = inflate(&(c->zstream), Z_FINISH);
if ((zret != Z_OK) && (zret != Z_STREAM_END)) {
av_log(avctx, AV_LOG_ERROR, "Mthread1 inflate error: %d\n", zret);
return -1;
}
if (mthread_outlen != (unsigned int)(c->zstream.total_out)) {
av_log(avctx, AV_LOG_ERROR, "Mthread1 decoded size differs (%u != %lu)\n",
mthread_outlen, c->zstream.total_out);
return -1;
}
zret = inflateReset(&(c->zstream));
if (zret != Z_OK) {
av_log(avctx, AV_LOG_ERROR, "Mthread2 inflate reset error: %d\n", zret);
return -1;
}
c->zstream.next_in = encoded + 8 + mthread_inlen;
c->zstream.avail_in = len - mthread_inlen;
c->zstream.next_out = c->decomp_buf + mthread_outlen;
c->zstream.avail_out = c->decomp_size - mthread_outlen;
zret = inflate(&(c->zstream), Z_FINISH);
if ((zret != Z_OK) && (zret != Z_STREAM_END)) {
av_log(avctx, AV_LOG_ERROR, "Mthread2 inflate error: %d\n", zret);
return -1;
}
if (mthread_outlen != (unsigned int)(c->zstream.total_out)) {
av_log(avctx, AV_LOG_ERROR, "Mthread2 decoded size differs (%d != %lu)\n",
mthread_outlen, c->zstream.total_out);
return -1;
}
} else {
c->zstream.next_in = encoded;
c->zstream.avail_in = len;
c->zstream.next_out = c->decomp_buf;
c->zstream.avail_out = c->decomp_size;
zret = inflate(&(c->zstream), Z_FINISH);
if ((zret != Z_OK) && (zret != Z_STREAM_END)) {
av_log(avctx, AV_LOG_ERROR, "Inflate error: %d\n", zret);
return -1;
}
if (c->decomp_size != (unsigned int)(c->zstream.total_out)) {
av_log(avctx, AV_LOG_ERROR, "Decoded size differs (%d != %lu)\n",
c->decomp_size, c->zstream.total_out);
return -1;
}
}
encoded = c->decomp_buf;
len = c->decomp_size;
#else
av_log(avctx, AV_LOG_ERROR, "BUG! Zlib support not compiled in frame decoder.\n");
return -1;
#endif
break;
default:
av_log(avctx, AV_LOG_ERROR, "BUG! Unknown codec in frame decoder compression switch.\n");
return -1;
}
/* Apply PNG filter */
if ((avctx->codec_id == CODEC_ID_ZLIB) && (c->flags & FLAG_PNGFILTER)) {
switch (c->imgtype) {
case IMGTYPE_YUV111:
case IMGTYPE_RGB24:
for (row = 0; row < height; row++) {
pixel_ptr = row * width * 3;
yq = encoded[pixel_ptr++];
uqvq = AV_RL16(encoded+pixel_ptr);
pixel_ptr += 2;
for (col = 1; col < width; col++) {
encoded[pixel_ptr] = yq -= encoded[pixel_ptr];
uqvq -= AV_RL16(encoded+pixel_ptr+1);
AV_WL16(encoded+pixel_ptr+1, uqvq);
pixel_ptr += 3;
}
}
break;
case IMGTYPE_YUV422:
for (row = 0; row < height; row++) {
pixel_ptr = row * width * 2;
yq = uq = vq =0;
for (col = 0; col < width/4; col++) {
encoded[pixel_ptr] = yq -= encoded[pixel_ptr];
encoded[pixel_ptr+1] = yq -= encoded[pixel_ptr+1];
encoded[pixel_ptr+2] = yq -= encoded[pixel_ptr+2];
encoded[pixel_ptr+3] = yq -= encoded[pixel_ptr+3];
encoded[pixel_ptr+4] = uq -= encoded[pixel_ptr+4];
encoded[pixel_ptr+5] = uq -= encoded[pixel_ptr+5];
encoded[pixel_ptr+6] = vq -= encoded[pixel_ptr+6];
encoded[pixel_ptr+7] = vq -= encoded[pixel_ptr+7];
pixel_ptr += 8;
}
}
break;
case IMGTYPE_YUV411:
for (row = 0; row < height; row++) {
pixel_ptr = row * width / 2 * 3;
yq = uq = vq =0;
for (col = 0; col < width/4; col++) {
encoded[pixel_ptr] = yq -= encoded[pixel_ptr];
encoded[pixel_ptr+1] = yq -= encoded[pixel_ptr+1];
encoded[pixel_ptr+2] = yq -= encoded[pixel_ptr+2];
encoded[pixel_ptr+3] = yq -= encoded[pixel_ptr+3];
encoded[pixel_ptr+4] = uq -= encoded[pixel_ptr+4];
encoded[pixel_ptr+5] = vq -= encoded[pixel_ptr+5];
pixel_ptr += 6;
}
}
break;
case IMGTYPE_YUV211:
for (row = 0; row < height; row++) {
pixel_ptr = row * width * 2;
yq = uq = vq =0;
for (col = 0; col < width/2; col++) {
encoded[pixel_ptr] = yq -= encoded[pixel_ptr];
encoded[pixel_ptr+1] = yq -= encoded[pixel_ptr+1];
encoded[pixel_ptr+2] = uq -= encoded[pixel_ptr+2];
encoded[pixel_ptr+3] = vq -= encoded[pixel_ptr+3];
pixel_ptr += 4;
}
}
break;
case IMGTYPE_YUV420:
for (row = 0; row < height/2; row++) {
pixel_ptr = row * width * 3;
yq = y1q = uq = vq =0;
for (col = 0; col < width/2; col++) {
encoded[pixel_ptr] = yq -= encoded[pixel_ptr];
encoded[pixel_ptr+1] = yq -= encoded[pixel_ptr+1];
encoded[pixel_ptr+2] = y1q -= encoded[pixel_ptr+2];
encoded[pixel_ptr+3] = y1q -= encoded[pixel_ptr+3];
encoded[pixel_ptr+4] = uq -= encoded[pixel_ptr+4];
encoded[pixel_ptr+5] = vq -= encoded[pixel_ptr+5];
pixel_ptr += 6;
}
}
break;
default:
av_log(avctx, AV_LOG_ERROR, "BUG! Unknown imagetype in pngfilter switch.\n");
return -1;
}
}
/* Convert colorspace */
switch (c->imgtype) {
case IMGTYPE_YUV111:
for (row = height - 1; row >= 0; row--) {
pixel_ptr = row * c->pic.linesize[0];
for (col = 0; col < width; col++) {
outptr[pixel_ptr++] = get_b(encoded[0], encoded[1]);
outptr[pixel_ptr++] = get_g(encoded[0], encoded[1], encoded[2]);
outptr[pixel_ptr++] = get_r(encoded[0], encoded[2]);
encoded += 3;
}
}
break;
case IMGTYPE_YUV422:
for (row = height - 1; row >= 0; row--) {
pixel_ptr = row * c->pic.linesize[0];
for (col = 0; col < width/4; col++) {
outptr[pixel_ptr++] = get_b(encoded[0], encoded[4]);
outptr[pixel_ptr++] = get_g(encoded[0], encoded[4], encoded[6]);
outptr[pixel_ptr++] = get_r(encoded[0], encoded[6]);
outptr[pixel_ptr++] = get_b(encoded[1], encoded[4]);
outptr[pixel_ptr++] = get_g(encoded[1], encoded[4], encoded[6]);
outptr[pixel_ptr++] = get_r(encoded[1], encoded[6]);
outptr[pixel_ptr++] = get_b(encoded[2], encoded[5]);
outptr[pixel_ptr++] = get_g(encoded[2], encoded[5], encoded[7]);
outptr[pixel_ptr++] = get_r(encoded[2], encoded[7]);
outptr[pixel_ptr++] = get_b(encoded[3], encoded[5]);
outptr[pixel_ptr++] = get_g(encoded[3], encoded[5], encoded[7]);
outptr[pixel_ptr++] = get_r(encoded[3], encoded[7]);
encoded += 8;
}
}
break;
case IMGTYPE_RGB24:
for (row = height - 1; row >= 0; row--) {
pixel_ptr = row * c->pic.linesize[0];
for (col = 0; col < width; col++) {
outptr[pixel_ptr++] = encoded[0];
outptr[pixel_ptr++] = encoded[1];
outptr[pixel_ptr++] = encoded[2];
encoded += 3;
}
}
break;
case IMGTYPE_YUV411:
for (row = height - 1; row >= 0; row--) {
pixel_ptr = row * c->pic.linesize[0];
for (col = 0; col < width/4; col++) {
outptr[pixel_ptr++] = get_b(encoded[0], encoded[4]);
outptr[pixel_ptr++] = get_g(encoded[0], encoded[4], encoded[5]);
outptr[pixel_ptr++] = get_r(encoded[0], encoded[5]);
outptr[pixel_ptr++] = get_b(encoded[1], encoded[4]);
outptr[pixel_ptr++] = get_g(encoded[1], encoded[4], encoded[5]);
outptr[pixel_ptr++] = get_r(encoded[1], encoded[5]);
outptr[pixel_ptr++] = get_b(encoded[2], encoded[4]);
outptr[pixel_ptr++] = get_g(encoded[2], encoded[4], encoded[5]);
outptr[pixel_ptr++] = get_r(encoded[2], encoded[5]);
outptr[pixel_ptr++] = get_b(encoded[3], encoded[4]);
outptr[pixel_ptr++] = get_g(encoded[3], encoded[4], encoded[5]);
outptr[pixel_ptr++] = get_r(encoded[3], encoded[5]);
encoded += 6;
}
}
break;
case IMGTYPE_YUV211:
for (row = height - 1; row >= 0; row--) {
pixel_ptr = row * c->pic.linesize[0];
for (col = 0; col < width/2; col++) {
outptr[pixel_ptr++] = get_b(encoded[0], encoded[2]);
outptr[pixel_ptr++] = get_g(encoded[0], encoded[2], encoded[3]);
outptr[pixel_ptr++] = get_r(encoded[0], encoded[3]);
outptr[pixel_ptr++] = get_b(encoded[1], encoded[2]);
outptr[pixel_ptr++] = get_g(encoded[1], encoded[2], encoded[3]);
outptr[pixel_ptr++] = get_r(encoded[1], encoded[3]);
encoded += 4;
}
}
break;
case IMGTYPE_YUV420:
for (row = height / 2 - 1; row >= 0; row--) {
pixel_ptr = 2 * row * c->pic.linesize[0];
for (col = 0; col < width/2; col++) {
outptr[pixel_ptr] = get_b(encoded[0], encoded[4]);
outptr[pixel_ptr+1] = get_g(encoded[0], encoded[4], encoded[5]);
outptr[pixel_ptr+2] = get_r(encoded[0], encoded[5]);
outptr[pixel_ptr+3] = get_b(encoded[1], encoded[4]);
outptr[pixel_ptr+4] = get_g(encoded[1], encoded[4], encoded[5]);
outptr[pixel_ptr+5] = get_r(encoded[1], encoded[5]);
outptr[pixel_ptr-c->pic.linesize[0]] = get_b(encoded[2], encoded[4]);
outptr[pixel_ptr-c->pic.linesize[0]+1] = get_g(encoded[2], encoded[4], encoded[5]);
outptr[pixel_ptr-c->pic.linesize[0]+2] = get_r(encoded[2], encoded[5]);
outptr[pixel_ptr-c->pic.linesize[0]+3] = get_b(encoded[3], encoded[4]);
outptr[pixel_ptr-c->pic.linesize[0]+4] = get_g(encoded[3], encoded[4], encoded[5]);
outptr[pixel_ptr-c->pic.linesize[0]+5] = get_r(encoded[3], encoded[5]);
pixel_ptr += 6;
encoded += 6;
}
}
break;
default:
av_log(avctx, AV_LOG_ERROR, "BUG! Unknown imagetype in image decoder.\n");
return -1;
}
*data_size = sizeof(AVFrame);
*(AVFrame*)data = c->pic;
/* always report that the buffer was completely consumed */
return buf_size;
}
/*
*
* Init lcl decoder
*
*/
static av_cold int decode_init(AVCodecContext *avctx)
{
LclDecContext * const c = avctx->priv_data;
unsigned int basesize = avctx->width * avctx->height;
unsigned int max_basesize = ((avctx->width + 3) & ~3) * ((avctx->height + 3) & ~3);
unsigned int max_decomp_size;
int zret; // Zlib return code
c->pic.data[0] = NULL;
#ifdef CONFIG_ZLIB
// Needed if zlib unused or init aborted before inflateInit
memset(&(c->zstream), 0, sizeof(z_stream));
#endif
if (avctx->extradata_size < 8) {
av_log(avctx, AV_LOG_ERROR, "Extradata size too small.\n");
return 1;
}
if (avcodec_check_dimensions(avctx, avctx->width, avctx->height) < 0) {
return 1;
}
/* Check codec type */
if (((avctx->codec_id == CODEC_ID_MSZH) && (*((char *)avctx->extradata + 7) != CODEC_MSZH)) ||
((avctx->codec_id == CODEC_ID_ZLIB) && (*((char *)avctx->extradata + 7) != CODEC_ZLIB))) {
av_log(avctx, AV_LOG_ERROR, "Codec id and codec type mismatch. This should not happen.\n");
}
/* Detect image type */
switch (c->imgtype = *((char *)avctx->extradata + 4)) {
case IMGTYPE_YUV111:
c->decomp_size = basesize * 3;
max_decomp_size = max_basesize * 3;
av_log(avctx, AV_LOG_INFO, "Image type is YUV 1:1:1.\n");
break;
case IMGTYPE_YUV422:
c->decomp_size = basesize * 2;
max_decomp_size = max_basesize * 2;
av_log(avctx, AV_LOG_INFO, "Image type is YUV 4:2:2.\n");
break;
case IMGTYPE_RGB24:
c->decomp_size = basesize * 3;
max_decomp_size = max_basesize * 3;
av_log(avctx, AV_LOG_INFO, "Image type is RGB 24.\n");
break;
case IMGTYPE_YUV411:
c->decomp_size = basesize / 2 * 3;
max_decomp_size = max_basesize / 2 * 3;
av_log(avctx, AV_LOG_INFO, "Image type is YUV 4:1:1.\n");
break;
case IMGTYPE_YUV211:
c->decomp_size = basesize * 2;
max_decomp_size = max_basesize * 2;
av_log(avctx, AV_LOG_INFO, "Image type is YUV 2:1:1.\n");
break;
case IMGTYPE_YUV420:
c->decomp_size = basesize / 2 * 3;
max_decomp_size = max_basesize / 2 * 3;
av_log(avctx, AV_LOG_INFO, "Image type is YUV 4:2:0.\n");
break;
default:
av_log(avctx, AV_LOG_ERROR, "Unsupported image format %d.\n", c->imgtype);
return 1;
}
/* Detect compression method */
c->compression = *((char *)avctx->extradata + 5);
switch (avctx->codec_id) {
case CODEC_ID_MSZH:
switch (c->compression) {
case COMP_MSZH:
av_log(avctx, AV_LOG_INFO, "Compression enabled.\n");
break;
case COMP_MSZH_NOCOMP:
c->decomp_size = 0;
av_log(avctx, AV_LOG_INFO, "No compression.\n");
break;
default:
av_log(avctx, AV_LOG_ERROR, "Unsupported compression format for MSZH (%d).\n", c->compression);
return 1;
}
break;
case CODEC_ID_ZLIB:
#ifdef CONFIG_ZLIB
switch (c->compression) {
case COMP_ZLIB_HISPEED:
av_log(avctx, AV_LOG_INFO, "High speed compression.\n");
break;
case COMP_ZLIB_HICOMP:
av_log(avctx, AV_LOG_INFO, "High compression.\n");
break;
case COMP_ZLIB_NORMAL:
av_log(avctx, AV_LOG_INFO, "Normal compression.\n");
break;
default:
if ((c->compression < Z_NO_COMPRESSION) || (c->compression > Z_BEST_COMPRESSION)) {
av_log(avctx, AV_LOG_ERROR, "Unsupported compression level for ZLIB: (%d).\n", c->compression);
return 1;
}
av_log(avctx, AV_LOG_INFO, "Compression level for ZLIB: (%d).\n", c->compression);
}
#else
av_log(avctx, AV_LOG_ERROR, "Zlib support not compiled.\n");
return 1;
#endif
break;
default:
av_log(avctx, AV_LOG_ERROR, "BUG! Unknown codec in compression switch.\n");
return 1;
}
/* Allocate decompression buffer */
if (c->decomp_size) {
if ((c->decomp_buf = av_malloc(max_decomp_size)) == NULL) {
av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n");
return 1;
}
}
/* Detect flags */
c->flags = *((char *)avctx->extradata + 6);
if (c->flags & FLAG_MULTITHREAD)
av_log(avctx, AV_LOG_INFO, "Multithread encoder flag set.\n");
if (c->flags & FLAG_NULLFRAME)
av_log(avctx, AV_LOG_INFO, "Nullframe insertion flag set.\n");
if ((avctx->codec_id == CODEC_ID_ZLIB) && (c->flags & FLAG_PNGFILTER))
av_log(avctx, AV_LOG_INFO, "PNG filter flag set.\n");
if (c->flags & FLAGMASK_UNUSED)
av_log(avctx, AV_LOG_ERROR, "Unknown flag set (%d).\n", c->flags);
/* If needed init zlib */
if (avctx->codec_id == CODEC_ID_ZLIB) {
#ifdef CONFIG_ZLIB
c->zstream.zalloc = Z_NULL;
c->zstream.zfree = Z_NULL;
c->zstream.opaque = Z_NULL;
zret = inflateInit(&(c->zstream));
if (zret != Z_OK) {
av_log(avctx, AV_LOG_ERROR, "Inflate init error: %d\n", zret);
return 1;
}
#else
av_log(avctx, AV_LOG_ERROR, "Zlib support not compiled.\n");
return 1;
#endif
}
avctx->pix_fmt = PIX_FMT_BGR24;
return 0;
}
/*
*
* Uninit lcl decoder
*
*/
static av_cold int decode_end(AVCodecContext *avctx)
{
LclDecContext * const c = avctx->priv_data;
if (c->pic.data[0])
avctx->release_buffer(avctx, &c->pic);
#ifdef CONFIG_ZLIB
inflateEnd(&(c->zstream));
#endif
return 0;
}
#ifdef CONFIG_MSZH_DECODER
AVCodec mszh_decoder = {
"mszh",
CODEC_TYPE_VIDEO,
CODEC_ID_MSZH,
sizeof(LclDecContext),
decode_init,
NULL,
decode_end,
decode_frame,
CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("LCL (LossLess Codec Library) MSZH"),
};
#endif
#ifdef CONFIG_ZLIB_DECODER
AVCodec zlib_decoder = {
"zlib",
CODEC_TYPE_VIDEO,
CODEC_ID_ZLIB,
sizeof(LclDecContext),
decode_init,
NULL,
decode_end,
decode_frame,
CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("LCL (LossLess Codec Library) ZLIB"),
};
#endif
@@ -0,0 +1,232 @@
/*
* LCL (LossLess Codec Library) Codec
* Copyright (c) 2002-2004 Roberto Togni
*
* 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 lcl.c
* LCL (LossLess Codec Library) Video Codec
* Decoder for MSZH and ZLIB codecs
* Experimental encoder for ZLIB RGB24
*
* Fourcc: MSZH, ZLIB
*
* Original Win32 dll:
* Ver2.23 By Kenji Oshima 2000.09.20
* avimszh.dll, avizlib.dll
*
* A description of the decoding algorithm can be found here:
* http://www.pcisys.net/~melanson/codecs
*
* Supports: BGR24 (RGB 24bpp)
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "avcodec.h"
#include "bitstream.h"
#include "lcl.h"
#ifdef CONFIG_ZLIB
#include <zlib.h>
#endif
/*
* Decoder context
*/
typedef struct LclEncContext {
AVCodecContext *avctx;
AVFrame pic;
PutBitContext pb;
// Image type
int imgtype;
// Compression type
int compression;
// Flags
int flags;
// Decompressed data size
unsigned int decomp_size;
// Maximum compressed data size
unsigned int max_comp_size;
// Compression buffer
unsigned char* comp_buf;
#ifdef CONFIG_ZLIB
z_stream zstream;
#endif
} LclEncContext;
/*
*
* Encode a frame
*
*/
static int encode_frame(AVCodecContext *avctx, unsigned char *buf, int buf_size, void *data){
LclEncContext *c = avctx->priv_data;
AVFrame *pict = data;
AVFrame * const p = &c->pic;
int i;
int zret; // Zlib return code
#ifndef CONFIG_ZLIB
av_log(avctx, AV_LOG_ERROR, "Zlib support not compiled in.\n");
return -1;
#else
init_put_bits(&c->pb, buf, buf_size);
*p = *pict;
p->pict_type= FF_I_TYPE;
p->key_frame= 1;
if(avctx->pix_fmt != PIX_FMT_BGR24){
av_log(avctx, AV_LOG_ERROR, "Format not supported!\n");
return -1;
}
zret = deflateReset(&(c->zstream));
if (zret != Z_OK) {
av_log(avctx, AV_LOG_ERROR, "Deflate reset error: %d\n", zret);
return -1;
}
c->zstream.next_out = c->comp_buf;
c->zstream.avail_out = c->max_comp_size;
for(i = avctx->height - 1; i >= 0; i--) {
c->zstream.next_in = p->data[0]+p->linesize[0]*i;
c->zstream.avail_in = avctx->width*3;
zret = deflate(&(c->zstream), Z_NO_FLUSH);
if (zret != Z_OK) {
av_log(avctx, AV_LOG_ERROR, "Deflate error: %d\n", zret);
return -1;
}
}
zret = deflate(&(c->zstream), Z_FINISH);
if (zret != Z_STREAM_END) {
av_log(avctx, AV_LOG_ERROR, "Deflate error: %d\n", zret);
return -1;
}
for (i = 0; i < c->zstream.total_out; i++)
put_bits(&c->pb, 8, c->comp_buf[i]);
flush_put_bits(&c->pb);
return c->zstream.total_out;
#endif
}
/*
*
* Init lcl encoder
*
*/
static av_cold int encode_init(AVCodecContext *avctx)
{
LclEncContext *c = avctx->priv_data;
int zret; // Zlib return code
#ifndef CONFIG_ZLIB
av_log(avctx, AV_LOG_ERROR, "Zlib support not compiled.\n");
return 1;
#else
c->avctx= avctx;
assert(avctx->width && avctx->height);
avctx->extradata= av_mallocz(8);
avctx->coded_frame= &c->pic;
// Will be user settable someday
c->compression = 6;
c->flags = 0;
switch(avctx->pix_fmt){
case PIX_FMT_BGR24:
c->imgtype = IMGTYPE_RGB24;
c->decomp_size = avctx->width * avctx->height * 3;
avctx->bits_per_sample= 24;
break;
default:
av_log(avctx, AV_LOG_ERROR, "Input pixel format %s not supported\n", avcodec_get_pix_fmt_name(avctx->pix_fmt));
return -1;
}
((uint8_t*)avctx->extradata)[0]= 4;
((uint8_t*)avctx->extradata)[1]= 0;
((uint8_t*)avctx->extradata)[2]= 0;
((uint8_t*)avctx->extradata)[3]= 0;
((uint8_t*)avctx->extradata)[4]= c->imgtype;
((uint8_t*)avctx->extradata)[5]= c->compression;
((uint8_t*)avctx->extradata)[6]= c->flags;
((uint8_t*)avctx->extradata)[7]= CODEC_ZLIB;
c->avctx->extradata_size= 8;
c->zstream.zalloc = Z_NULL;
c->zstream.zfree = Z_NULL;
c->zstream.opaque = Z_NULL;
zret = deflateInit(&(c->zstream), c->compression);
if (zret != Z_OK) {
av_log(avctx, AV_LOG_ERROR, "Deflate init error: %d\n", zret);
return 1;
}
/* Conservative upper bound taken from zlib v1.2.1 source */
c->max_comp_size = c->decomp_size + ((c->decomp_size + 7) >> 3) +
((c->decomp_size + 63) >> 6) + 11;
if ((c->comp_buf = av_malloc(c->max_comp_size)) == NULL) {
av_log(avctx, AV_LOG_ERROR, "Can't allocate compression buffer.\n");
return 1;
}
return 0;
#endif
}
/*
*
* Uninit lcl encoder
*
*/
static av_cold int encode_end(AVCodecContext *avctx)
{
LclEncContext *c = avctx->priv_data;
av_freep(&avctx->extradata);
av_freep(&c->comp_buf);
#ifdef CONFIG_ZLIB
deflateEnd(&(c->zstream));
#endif
return 0;
}
AVCodec zlib_encoder = {
"zlib",
CODEC_TYPE_VIDEO,
CODEC_ID_ZLIB,
sizeof(LclEncContext),
encode_init,
encode_frame,
encode_end,
.long_name = NULL_IF_CONFIG_SMALL("LCL (LossLess Codec Library) ZLIB"),
};
@@ -0,0 +1,227 @@
/*
* A52 decoder using liba52
* Copyright (c) 2001 Fabrice Bellard.
*
* 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 a52dec.c
* A52 decoder using liba52
*/
#include "avcodec.h"
#include <a52dec/a52.h>
#ifdef CONFIG_LIBA52BIN
#include <dlfcn.h>
static const char* liba52name = "liba52.so.0";
#endif
/**
* liba52 - Copyright (C) Aaron Holtzman
* released under the GPL license.
*/
typedef struct AC3DecodeState {
int flags;
int channels;
a52_state_t* state;
sample_t* samples;
/*
* virtual method table
*
* using this function table so the liba52 doesn't
* have to be really linked together with ffmpeg
* and might be linked in runtime - this allows binary
* distribution of ffmpeg library which doens't depend
* on liba52 library - but if user has it installed
* it will be used - user might install such library
* separately
*/
void* handle;
a52_state_t* (*a52_init)(uint32_t mm_accel);
sample_t* (*a52_samples)(a52_state_t * state);
int (*a52_syncinfo)(uint8_t * buf, int * flags,
int * sample_rate, int * bit_rate);
int (*a52_frame)(a52_state_t * state, uint8_t * buf, int * flags,
sample_t * level, sample_t bias);
void (*a52_dynrng)(a52_state_t * state,
sample_t (* call) (sample_t, void *), void * data);
int (*a52_block)(a52_state_t * state);
void (*a52_free)(a52_state_t * state);
} AC3DecodeState;
#ifdef CONFIG_LIBA52BIN
static void* dlsymm(void* handle, const char* symbol)
{
void* f = dlsym(handle, symbol);
if (!f)
av_log( NULL, AV_LOG_ERROR, "A52 Decoder - function '%s' can't be resolved\n", symbol);
return f;
}
#endif
static av_cold int a52_decode_init(AVCodecContext *avctx)
{
AC3DecodeState *s = avctx->priv_data;
#ifdef CONFIG_LIBA52BIN
s->handle = dlopen(liba52name, RTLD_LAZY);
if (!s->handle)
{
av_log( avctx, AV_LOG_ERROR, "A52 library %s could not be opened! \n%s\n", liba52name, dlerror());
return -1;
}
s->a52_init = (a52_state_t* (*)(uint32_t)) dlsymm(s->handle, "a52_init");
s->a52_samples = (sample_t* (*)(a52_state_t*)) dlsymm(s->handle, "a52_samples");
s->a52_syncinfo = (int (*)(uint8_t*, int*, int*, int*)) dlsymm(s->handle, "a52_syncinfo");
s->a52_frame = (int (*)(a52_state_t*, uint8_t*, int*, sample_t*, sample_t)) dlsymm(s->handle, "a52_frame");
s->a52_block = (int (*)(a52_state_t*)) dlsymm(s->handle, "a52_block");
s->a52_free = (void (*)(a52_state_t*)) dlsymm(s->handle, "a52_free");
if (!s->a52_init || !s->a52_samples || !s->a52_syncinfo
|| !s->a52_frame || !s->a52_block || !s->a52_free)
{
dlclose(s->handle);
return -1;
}
#else
s->handle = 0;
s->a52_init = a52_init;
s->a52_samples = a52_samples;
s->a52_syncinfo = a52_syncinfo;
s->a52_frame = a52_frame;
s->a52_block = a52_block;
s->a52_free = a52_free;
#endif
s->state = s->a52_init(0); /* later use CPU flags */
s->samples = s->a52_samples(s->state);
/* allow downmixing to stereo or mono */
if (avctx->channels > 0 && avctx->request_channels > 0 &&
avctx->request_channels < avctx->channels &&
avctx->request_channels <= 2) {
avctx->channels = avctx->request_channels;
}
avctx->sample_fmt = SAMPLE_FMT_S16;
return 0;
}
/**** the following function comes from a52dec */
static inline void float_to_int (float * _f, int16_t * s16, int nchannels)
{
int i, j, c;
int32_t * f = (int32_t *) _f; // XXX assumes IEEE float format
j = 0;
nchannels *= 256;
for (i = 0; i < 256; i++) {
for (c = 0; c < nchannels; c += 256)
s16[j++] = av_clip_int16(f[i + c] - 0x43c00000);
}
}
/**** end */
#define HEADER_SIZE 7
static int a52_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
uint8_t *buf, int buf_size)
{
AC3DecodeState *s = avctx->priv_data;
int flags, i, len;
int sample_rate, bit_rate;
short *out_samples = data;
float level;
static const int ac3_channels[8] = {
2, 1, 2, 3, 3, 4, 4, 5
};
*data_size= 0;
if (buf_size < HEADER_SIZE) {
av_log(avctx, AV_LOG_ERROR, "Error decoding frame, not enough bytes for header\n");
return -1;
}
len = s->a52_syncinfo(buf, &s->flags, &sample_rate, &bit_rate);
if (len == 0) {
av_log(avctx, AV_LOG_ERROR, "Error decoding frame, no sync byte at begin\n");
return -1;
}
if (buf_size < len) {
av_log(avctx, AV_LOG_ERROR, "Error decoding frame, not enough bytes\n");
return -1;
}
/* update codec info */
avctx->sample_rate = sample_rate;
s->channels = ac3_channels[s->flags & 7];
if (s->flags & A52_LFE)
s->channels++;
if (avctx->request_channels > 0 &&
avctx->request_channels <= 2 &&
avctx->request_channels < s->channels) {
avctx->channels = avctx->request_channels;
} else {
avctx->channels = s->channels;
}
avctx->bit_rate = bit_rate;
flags = s->flags;
if (avctx->channels == 1)
flags = A52_MONO;
else if (avctx->channels == 2)
flags = A52_STEREO;
else
flags |= A52_ADJUST_LEVEL;
level = 1;
if (s->a52_frame(s->state, buf, &flags, &level, 384)) {
fail:
av_log(avctx, AV_LOG_ERROR, "Error decoding frame\n");
return -1;
}
for (i = 0; i < 6; i++) {
if (s->a52_block(s->state))
goto fail;
float_to_int(s->samples, out_samples + i * 256 * avctx->channels, avctx->channels);
}
*data_size = 6 * avctx->channels * 256 * sizeof(int16_t);
return len;
}
static av_cold int a52_decode_end(AVCodecContext *avctx)
{
AC3DecodeState *s = avctx->priv_data;
s->a52_free(s->state);
#ifdef CONFIG_LIBA52BIN
dlclose(s->handle);
#endif
return 0;
}
AVCodec liba52_decoder = {
"liba52",
CODEC_TYPE_AUDIO,
CODEC_ID_AC3,
sizeof(AC3DecodeState),
a52_decode_init,
NULL,
a52_decode_end,
a52_decode_frame,
.long_name = NULL_IF_CONFIG_SMALL("liba52 ATSC A/52 / AC-3"),
};
@@ -0,0 +1,719 @@
/*
* AMR Audio decoder stub
* Copyright (c) 2003 the ffmpeg project
*
* 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
* Adaptive Multi-Rate (AMR) Audio decoder stub.
*
* This code implements both an AMR-NarrowBand (AMR-NB) and an AMR-WideBand
* (AMR-WB) audio encoder/decoder through external reference code from
* http://www.3gpp.org/. The license of the code from 3gpp is unclear so you
* have to download the code separately. Two versions exists: One fixed-point
* and one floating-point. For some reason the float encoder is significantly
* faster at least on a P4 1.5GHz (0.9s instead of 9.9s on a 30s audio clip
* at MR102). Both float and fixed point are supported for AMR-NB, but only
* float for AMR-WB.
*
* \section AMR-NB
*
* \subsection Float
* The float version (default) can be downloaded from:
* http://www.3gpp.org/ftp/Specs/archive/26_series/26.104/26104-610.zip
*
* \subsection Fixed-point
* The fixed-point (TS26.073) can be downloaded from:
* http://www.3gpp.org/ftp/Specs/archive/26_series/26.073/26073-600.zip
*
* \subsection Specification
* The specification for AMR-NB can be found in TS 26.071
* (http://www.3gpp.org/ftp/Specs/html-info/26071.htm) and some other
* info at http://www.3gpp.org/ftp/Specs/html-info/26-series.htm.
*
* \section AMR-WB
*
* \subsection Float
* The reference code can be downloaded from:
* http://www.3gpp.org/ftp/Specs/archive/26_series/26.204/26204-600.zip
*
* \subsection Fixed-point
* If someone wants to use the fixed point version it can be downloaded from:
* http://www.3gpp.org/ftp/Specs/archive/26_series/26.173/26173-571.zip.
*
* \subsection Specification
* The specification for AMR-WB can be found in TS 26.171
* (http://www.3gpp.org/ftp/Specs/html-info/26171.htm) and some other
* info at http://www.3gpp.org/ftp/Specs/html-info/26-series.htm.
*
*/
#include "avcodec.h"
#ifdef CONFIG_LIBAMR_NB_FIXED
#define MMS_IO
#include "amr/sp_dec.h"
#include "amr/d_homing.h"
#include "amr/typedef.h"
#include "amr/sp_enc.h"
#include "amr/sid_sync.h"
#include "amr/e_homing.h"
#else
#include <amrnb/interf_dec.h>
#include <amrnb/interf_enc.h>
#endif
static const char *nb_bitrate_unsupported =
"bitrate not supported: use one of 4.75k, 5.15k, 5.9k, 6.7k, 7.4k, 7.95k, 10.2k or 12.2k\n";
static const char *wb_bitrate_unsupported =
"bitrate not supported: use one of 6.6k, 8.85k, 12.65k, 14.25k, 15.85k, 18.25k, 19.85k, 23.05k, or 23.85k\n";
/* Common code for fixed and float version*/
typedef struct AMR_bitrates
{
int rate;
enum Mode mode;
} AMR_bitrates;
/* Match desired bitrate */
static int getBitrateMode(int bitrate)
{
/* make the correspondance between bitrate and mode */
AMR_bitrates rates[]={ {4750,MR475},
{5150,MR515},
{5900,MR59},
{6700,MR67},
{7400,MR74},
{7950,MR795},
{10200,MR102},
{12200,MR122},
};
int i;
for(i=0;i<8;i++)
{
if(rates[i].rate==bitrate)
{
return rates[i].mode;
}
}
/* no bitrate matching, return an error */
return -1;
}
static void amr_decode_fix_avctx(AVCodecContext * avctx)
{
const int is_amr_wb = 1 + (avctx->codec_id == CODEC_ID_AMR_WB);
if(avctx->sample_rate == 0)
{
avctx->sample_rate = 8000 * is_amr_wb;
}
if(avctx->channels == 0)
{
avctx->channels = 1;
}
avctx->frame_size = 160 * is_amr_wb;
avctx->sample_fmt = SAMPLE_FMT_S16;
}
#ifdef CONFIG_LIBAMR_NB_FIXED
/* fixed point version*/
/* frame size in serial bitstream file (frame type + serial stream + flags) */
#define SERIAL_FRAMESIZE (1+MAX_SERIAL_SIZE+5)
typedef struct AMRContext {
int frameCount;
Speech_Decode_FrameState *speech_decoder_state;
enum RXFrameType rx_type;
enum Mode mode;
Word16 reset_flag;
Word16 reset_flag_old;
int enc_bitrate;
Speech_Encode_FrameState *enstate;
sid_syncState *sidstate;
enum TXFrameType tx_frametype;
} AMRContext;
static int amr_nb_decode_init(AVCodecContext * avctx)
{
AMRContext *s = avctx->priv_data;
s->frameCount=0;
s->speech_decoder_state=NULL;
s->rx_type = (enum RXFrameType)0;
s->mode= (enum Mode)0;
s->reset_flag=0;
s->reset_flag_old=1;
if(Speech_Decode_Frame_init(&s->speech_decoder_state, "Decoder"))
{
av_log(avctx, AV_LOG_ERROR, "Speech_Decode_Frame_init error\n");
return -1;
}
amr_decode_fix_avctx(avctx);
if(avctx->channels > 1)
{
av_log(avctx, AV_LOG_ERROR, "amr_nb: multichannel decoding not supported\n");
return -1;
}
return 0;
}
static int amr_nb_encode_init(AVCodecContext * avctx)
{
AMRContext *s = avctx->priv_data;
s->frameCount=0;
s->speech_decoder_state=NULL;
s->rx_type = (enum RXFrameType)0;
s->mode= (enum Mode)0;
s->reset_flag=0;
s->reset_flag_old=1;
if(avctx->sample_rate!=8000)
{
av_log(avctx, AV_LOG_ERROR, "Only 8000Hz sample rate supported\n");
return -1;
}
if(avctx->channels!=1)
{
av_log(avctx, AV_LOG_ERROR, "Only mono supported\n");
return -1;
}
avctx->frame_size=160;
avctx->coded_frame= avcodec_alloc_frame();
if(Speech_Encode_Frame_init(&s->enstate, 0, "encoder") || sid_sync_init (&s->sidstate))
{
av_log(avctx, AV_LOG_ERROR, "Speech_Encode_Frame_init error\n");
return -1;
}
if((s->enc_bitrate=getBitrateMode(avctx->bit_rate))<0)
{
av_log(avctx, AV_LOG_ERROR, nb_bitrate_unsupported);
return -1;
}
return 0;
}
static int amr_nb_encode_close(AVCodecContext * avctx)
{
AMRContext *s = avctx->priv_data;
Speech_Encode_Frame_exit(&s->enstate);
sid_sync_exit (&s->sidstate);
av_freep(&avctx->coded_frame);
return 0;
}
static int amr_nb_decode_close(AVCodecContext * avctx)
{
AMRContext *s = avctx->priv_data;
Speech_Decode_Frame_exit(&s->speech_decoder_state);
return 0;
}
static int amr_nb_decode_frame(AVCodecContext * avctx,
void *data, int *data_size,
uint8_t * buf, int buf_size)
{
AMRContext *s = avctx->priv_data;
uint8_t*amrData=buf;
int offset=0;
UWord8 toc, q, ft;
Word16 serial[SERIAL_FRAMESIZE]; /* coded bits */
Word16 *synth;
UWord8 *packed_bits;
static Word16 packed_size[16] = {12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0};
int i;
//printf("amr_decode_frame data_size=%i buf=0x%X buf_size=%d frameCount=%d!!\n",*data_size,buf,buf_size,s->frameCount);
synth=data;
toc=amrData[offset];
/* read rest of the frame based on ToC byte */
q = (toc >> 2) & 0x01;
ft = (toc >> 3) & 0x0F;
//printf("offset=%d, packet_size=%d amrData= 0x%X %X %X %X\n",offset,packed_size[ft],amrData[offset],amrData[offset+1],amrData[offset+2],amrData[offset+3]);
offset++;
packed_bits=amrData+offset;
offset+=packed_size[ft];
//Unsort and unpack bits
s->rx_type = UnpackBits(q, ft, packed_bits, &s->mode, &serial[1]);
//We have a new frame
s->frameCount++;
if (s->rx_type == RX_NO_DATA)
{
s->mode = s->speech_decoder_state->prev_mode;
}
else {
s->speech_decoder_state->prev_mode = s->mode;
}
/* if homed: check if this frame is another homing frame */
if (s->reset_flag_old == 1)
{
/* only check until end of first subframe */
s->reset_flag = decoder_homing_frame_test_first(&serial[1], s->mode);
}
/* produce encoder homing frame if homed & input=decoder homing frame */
if ((s->reset_flag != 0) && (s->reset_flag_old != 0))
{
for (i = 0; i < L_FRAME; i++)
{
synth[i] = EHF_MASK;
}
}
else
{
/* decode frame */
Speech_Decode_Frame(s->speech_decoder_state, s->mode, &serial[1], s->rx_type, synth);
}
//Each AMR-frame results in 160 16-bit samples
*data_size=160*2;
/* if not homed: check whether current frame is a homing frame */
if (s->reset_flag_old == 0)
{
/* check whole frame */
s->reset_flag = decoder_homing_frame_test(&serial[1], s->mode);
}
/* reset decoder if current frame is a homing frame */
if (s->reset_flag != 0)
{
Speech_Decode_Frame_reset(s->speech_decoder_state);
}
s->reset_flag_old = s->reset_flag;
return offset;
}
static int amr_nb_encode_frame(AVCodecContext *avctx,
unsigned char *frame/*out*/, int buf_size, void *data/*in*/)
{
short serial_data[250] = {0};
AMRContext *s = avctx->priv_data;
int written;
s->reset_flag = encoder_homing_frame_test(data);
Speech_Encode_Frame(s->enstate, s->enc_bitrate, data, &serial_data[1], &s->mode);
/* add frame type and mode */
sid_sync (s->sidstate, s->mode, &s->tx_frametype);
written = PackBits(s->mode, s->enc_bitrate, s->tx_frametype, &serial_data[1], frame);
if (s->reset_flag != 0)
{
Speech_Encode_Frame_reset(s->enstate);
sid_sync_reset(s->sidstate);
}
return written;
}
#elif defined(CONFIG_LIBAMR_NB) /* Float point version*/
typedef struct AMRContext {
int frameCount;
void * decState;
int *enstate;
int enc_bitrate;
} AMRContext;
static int amr_nb_decode_init(AVCodecContext * avctx)
{
AMRContext *s = avctx->priv_data;
s->frameCount=0;
s->decState=Decoder_Interface_init();
if(!s->decState)
{
av_log(avctx, AV_LOG_ERROR, "Decoder_Interface_init error\r\n");
return -1;
}
amr_decode_fix_avctx(avctx);
if(avctx->channels > 1)
{
av_log(avctx, AV_LOG_ERROR, "amr_nb: multichannel decoding not supported\n");
return -1;
}
return 0;
}
static int amr_nb_encode_init(AVCodecContext * avctx)
{
AMRContext *s = avctx->priv_data;
s->frameCount=0;
if(avctx->sample_rate!=8000)
{
av_log(avctx, AV_LOG_ERROR, "Only 8000Hz sample rate supported\n");
return -1;
}
if(avctx->channels!=1)
{
av_log(avctx, AV_LOG_ERROR, "Only mono supported\n");
return -1;
}
avctx->frame_size=160;
avctx->coded_frame= avcodec_alloc_frame();
s->enstate=Encoder_Interface_init(0);
if(!s->enstate)
{
av_log(avctx, AV_LOG_ERROR, "Encoder_Interface_init error\n");
return -1;
}
if((s->enc_bitrate=getBitrateMode(avctx->bit_rate))<0)
{
av_log(avctx, AV_LOG_ERROR, nb_bitrate_unsupported);
return -1;
}
return 0;
}
static int amr_nb_decode_close(AVCodecContext * avctx)
{
AMRContext *s = avctx->priv_data;
Decoder_Interface_exit(s->decState);
return 0;
}
static int amr_nb_encode_close(AVCodecContext * avctx)
{
AMRContext *s = avctx->priv_data;
Encoder_Interface_exit(s->enstate);
av_freep(&avctx->coded_frame);
return 0;
}
static int amr_nb_decode_frame(AVCodecContext * avctx,
void *data, int *data_size,
uint8_t * buf, int buf_size)
{
AMRContext *s = avctx->priv_data;
uint8_t*amrData=buf;
static const uint8_t block_size[16]={ 12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0 };
enum Mode dec_mode;
int packet_size;
/* av_log(NULL,AV_LOG_DEBUG,"amr_decode_frame buf=%p buf_size=%d frameCount=%d!!\n",buf,buf_size,s->frameCount); */
dec_mode = (buf[0] >> 3) & 0x000F;
packet_size = block_size[dec_mode]+1;
if(packet_size > buf_size) {
av_log(avctx, AV_LOG_ERROR, "amr frame too short (%u, should be %u)\n", buf_size, packet_size);
return -1;
}
s->frameCount++;
/* av_log(NULL,AV_LOG_DEBUG,"packet_size=%d amrData= 0x%X %X %X %X\n",packet_size,amrData[0],amrData[1],amrData[2],amrData[3]); */
/* call decoder */
Decoder_Interface_Decode(s->decState, amrData, data, 0);
*data_size=160*2;
return packet_size;
}
static int amr_nb_encode_frame(AVCodecContext *avctx,
unsigned char *frame/*out*/, int buf_size, void *data/*in*/)
{
AMRContext *s = avctx->priv_data;
int written;
if((s->enc_bitrate=getBitrateMode(avctx->bit_rate))<0)
{
av_log(avctx, AV_LOG_ERROR, nb_bitrate_unsupported);
return -1;
}
written = Encoder_Interface_Encode(s->enstate,
s->enc_bitrate,
data,
frame,
0);
/* av_log(NULL,AV_LOG_DEBUG,"amr_nb_encode_frame encoded %u bytes, bitrate %u, first byte was %#02x\n",written, s->enc_bitrate, frame[0] ); */
return written;
}
#endif
#if defined(CONFIG_LIBAMR_NB) || defined(CONFIG_LIBAMR_NB_FIXED)
AVCodec libamr_nb_decoder =
{
"libamr_nb",
CODEC_TYPE_AUDIO,
CODEC_ID_AMR_NB,
sizeof(AMRContext),
amr_nb_decode_init,
NULL,
amr_nb_decode_close,
amr_nb_decode_frame,
.long_name = NULL_IF_CONFIG_SMALL("libamr-nb Adaptive Multi-Rate (AMR) Narrow-Band"),
};
AVCodec libamr_nb_encoder =
{
"libamr_nb",
CODEC_TYPE_AUDIO,
CODEC_ID_AMR_NB,
sizeof(AMRContext),
amr_nb_encode_init,
amr_nb_encode_frame,
amr_nb_encode_close,
NULL,
.sample_fmts = (enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_NONE},
.long_name = NULL_IF_CONFIG_SMALL("libamr-nb Adaptive Multi-Rate (AMR) Narrow-Band"),
};
#endif
/* -----------AMR wideband ------------*/
#ifdef CONFIG_LIBAMR_WB
#ifdef _TYPEDEF_H
//To avoid duplicate typedefs from typedef in amr-nb
#define typedef_h
#endif
#include <amrwb/enc_if.h>
#include <amrwb/dec_if.h>
#include <amrwb/if_rom.h>
/* Common code for fixed and float version*/
typedef struct AMRWB_bitrates
{
int rate;
int mode;
} AMRWB_bitrates;
static int getWBBitrateMode(int bitrate)
{
/* make the correspondance between bitrate and mode */
AMRWB_bitrates rates[]={ {6600,0},
{8850,1},
{12650,2},
{14250,3},
{15850,4},
{18250,5},
{19850,6},
{23050,7},
{23850,8},
};
int i;
for(i=0;i<9;i++)
{
if(rates[i].rate==bitrate)
{
return rates[i].mode;
}
}
/* no bitrate matching, return an error */
return -1;
}
typedef struct AMRWBContext {
int frameCount;
void *state;
int mode;
Word16 allow_dtx;
} AMRWBContext;
static int amr_wb_encode_init(AVCodecContext * avctx)
{
AMRWBContext *s = avctx->priv_data;
s->frameCount=0;
if(avctx->sample_rate!=16000)
{
av_log(avctx, AV_LOG_ERROR, "Only 16000Hz sample rate supported\n");
return -1;
}
if(avctx->channels!=1)
{
av_log(avctx, AV_LOG_ERROR, "Only mono supported\n");
return -1;
}
if((s->mode=getWBBitrateMode(avctx->bit_rate))<0)
{
av_log(avctx, AV_LOG_ERROR, wb_bitrate_unsupported);
return -1;
}
avctx->frame_size=320;
avctx->coded_frame= avcodec_alloc_frame();
s->state = E_IF_init();
s->allow_dtx=0;
return 0;
}
static int amr_wb_encode_close(AVCodecContext * avctx)
{
AMRWBContext *s = avctx->priv_data;
E_IF_exit(s->state);
av_freep(&avctx->coded_frame);
s->frameCount++;
return 0;
}
static int amr_wb_encode_frame(AVCodecContext *avctx,
unsigned char *frame/*out*/, int buf_size, void *data/*in*/)
{
AMRWBContext *s = avctx->priv_data;
int size;
if((s->mode=getWBBitrateMode(avctx->bit_rate))<0)
{
av_log(avctx, AV_LOG_ERROR, wb_bitrate_unsupported);
return -1;
}
size = E_IF_encode(s->state, s->mode, data, frame, s->allow_dtx);
return size;
}
static int amr_wb_decode_init(AVCodecContext * avctx)
{
AMRWBContext *s = avctx->priv_data;
s->frameCount=0;
s->state = D_IF_init();
amr_decode_fix_avctx(avctx);
if(avctx->channels > 1)
{
av_log(avctx, AV_LOG_ERROR, "amr_wb: multichannel decoding not supported\n");
return -1;
}
return 0;
}
static int amr_wb_decode_frame(AVCodecContext * avctx,
void *data, int *data_size,
uint8_t * buf, int buf_size)
{
AMRWBContext *s = avctx->priv_data;
uint8_t*amrData=buf;
int mode;
int packet_size;
static const uint8_t block_size[16] = {18, 23, 33, 37, 41, 47, 51, 59, 61, 6, 6, 0, 0, 0, 1, 1};
if(buf_size==0) {
/* nothing to do */
return 0;
}
mode = (amrData[0] >> 3) & 0x000F;
packet_size = block_size[mode];
if(packet_size > buf_size) {
av_log(avctx, AV_LOG_ERROR, "amr frame too short (%u, should be %u)\n", buf_size, packet_size+1);
return -1;
}
s->frameCount++;
D_IF_decode( s->state, amrData, data, _good_frame);
*data_size=320*2;
return packet_size;
}
static int amr_wb_decode_close(AVCodecContext * avctx)
{
AMRWBContext *s = avctx->priv_data;
D_IF_exit(s->state);
return 0;
}
AVCodec libamr_wb_decoder =
{
"libamr_wb",
CODEC_TYPE_AUDIO,
CODEC_ID_AMR_WB,
sizeof(AMRWBContext),
amr_wb_decode_init,
NULL,
amr_wb_decode_close,
amr_wb_decode_frame,
.long_name = NULL_IF_CONFIG_SMALL("libamr-wb Adaptive Multi-Rate (AMR) Wide-Band"),
};
AVCodec libamr_wb_encoder =
{
"libamr_wb",
CODEC_TYPE_AUDIO,
CODEC_ID_AMR_WB,
sizeof(AMRWBContext),
amr_wb_encode_init,
amr_wb_encode_frame,
amr_wb_encode_close,
NULL,
.sample_fmts = (enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_NONE},
.long_name = NULL_IF_CONFIG_SMALL("libamr-wb Adaptive Multi-Rate (AMR) Wide-Band"),
};
#endif //CONFIG_LIBAMR_WB
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2008 BBC, Anuradha Suraparaju <asuraparaju at gmail dot 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 libdirac.h
* data structures common to libdiracenc.c and libdiracdec.c
*/
#ifndef FFMPEG_LIBDIRAC_H
#define FFMPEG_LIBDIRAC_H
#include "config.h"
#ifdef CONFIG_LIBDIRAC
#include "avcodec.h"
#include <libdirac_common/dirac_types.h>
/**
* Table providing a Dirac chroma format to FFmpeg pixel format mapping.
*/
static const struct {
enum PixelFormat ff_pix_fmt;
dirac_chroma_t dirac_pix_fmt;
} ffmpeg_dirac_pixel_format_map[] = {
{ PIX_FMT_YUV420P, format420 },
{ PIX_FMT_YUV422P, format422 },
{ PIX_FMT_YUV444P, format444 },
};
#endif /* CONFIG_LIBDIRAC */
#endif /* FFMPEG_LIBDIRAC_H */
@@ -0,0 +1,117 @@
/*
* Copyright (c) 2008 BBC, Anuradha Suraparaju <asuraparaju at gmail dot 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 libdirac_libschro.c
* functions common to libdirac and libschroedinger
*/
#include "libdirac_libschro.h"
static const FfmpegDiracSchroVideoFormatInfo ff_dirac_schro_video_format_info[] = {
{ 640, 480, 24000, 1001},
{ 176, 120, 15000, 1001},
{ 176, 144, 25, 2 },
{ 352, 240, 15000, 1001},
{ 352, 288, 25, 2 },
{ 704, 480, 15000, 1001},
{ 704, 576, 25, 2 },
{ 720, 480, 30000, 1001},
{ 720, 576, 25, 1 },
{ 1280, 720, 60000, 1001},
{ 1280, 720, 50, 1 },
{ 1920, 1080, 30000, 1001},
{ 1920, 1080, 25, 1 },
{ 1920, 1080, 60000, 1001},
{ 1920, 1080, 50, 1 },
{ 2048, 1080, 24, 1 },
{ 4096, 2160, 24, 1 },
};
unsigned int ff_dirac_schro_get_video_format_idx (AVCodecContext *avccontext)
{
unsigned int ret_idx = 0;
unsigned int idx;
unsigned int num_formats = sizeof(ff_dirac_schro_video_format_info) /
sizeof(ff_dirac_schro_video_format_info[0]);
for (idx = 1 ; idx < num_formats; ++idx ) {
const FfmpegDiracSchroVideoFormatInfo *vf =
&ff_dirac_schro_video_format_info[idx];
if (avccontext->width == vf->width &&
avccontext->height == vf->height){
ret_idx = idx;
if (avccontext->time_base.den == vf->frame_rate_num &&
avccontext->time_base.num == vf->frame_rate_denom) {
return idx;
}
}
}
return ret_idx;
}
void ff_dirac_schro_queue_init (FfmpegDiracSchroQueue *queue)
{
queue->p_head = queue->p_tail = NULL;
queue->size = 0;
}
void ff_dirac_schro_queue_free (FfmpegDiracSchroQueue *queue,
void (*free_func)(void *))
{
while (queue->p_head) {
free_func( ff_dirac_schro_queue_pop(queue) );
}
}
int ff_dirac_schro_queue_push_back (FfmpegDiracSchroQueue *queue, void *p_data)
{
FfmpegDiracSchroQueueElement *p_new =
av_mallocz(sizeof(FfmpegDiracSchroQueueElement));
if (p_new == NULL)
return -1;
p_new->data = p_data;
if (queue->p_head == NULL)
queue->p_head = p_new;
else
queue->p_tail->next = p_new;
queue->p_tail = p_new;
++queue->size;
return 0;
}
void *ff_dirac_schro_queue_pop (FfmpegDiracSchroQueue *queue)
{
FfmpegDiracSchroQueueElement *top = queue->p_head;
if (top != NULL) {
void *data = top->data;
queue->p_head = queue->p_head->next;
--queue->size;
av_freep (&top);
return data;
}
return NULL;
}
@@ -0,0 +1,109 @@
/*
* Copyright (c) 2008 BBC, Anuradha Suraparaju <asuraparaju at gmail dot 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 libdirac_libschro.h
* data structures common to libdirac and libschroedinger
*/
#ifndef FFMPEG_LIBDIRAC_LIBSCHRO_H
#define FFMPEG_LIBDIRAC_LIBSCHRO_H
#include "avcodec.h"
typedef struct
{
uint16_t width;
uint16_t height;
uint16_t frame_rate_num;
uint16_t frame_rate_denom;
} FfmpegDiracSchroVideoFormatInfo;
/**
* Returns the index into the Dirac Schro common video format info table
*/
unsigned int ff_dirac_schro_get_video_format_idx (AVCodecContext *avccontext);
/**
* contains a single encoded frame returned from Dirac or Schroedinger
*/
typedef struct FfmpegDiracSchroEncodedFrame
{
/** encoded frame data */
uint8_t *p_encbuf;
/** encoded frame size */
uint32_t size;
/** encoded frame number. Will be used as pts */
uint32_t frame_num;
/** key frame flag. 1 : is key frame , 0 : in not key frame */
uint16_t key_frame;
} FfmpegDiracSchroEncodedFrame;
/**
* queue element
*/
typedef struct FfmpegDiracSchroQueueElement
{
/** Data to be stored in queue*/
void *data;
/** Pointer to next element queue */
struct FfmpegDiracSchroQueueElement *next;
} FfmpegDiracSchroQueueElement;
/**
* A simple queue implementation used in libdirac and libschroedinger
*/
typedef struct FfmpegDiracSchroQueue
{
/** Pointer to head of queue */
FfmpegDiracSchroQueueElement *p_head;
/** Pointer to tail of queue */
FfmpegDiracSchroQueueElement *p_tail;
/** Queue size*/
int size;
} FfmpegDiracSchroQueue;
/**
* Initialise the queue
*/
void ff_dirac_schro_queue_init(FfmpegDiracSchroQueue *queue);
/**
* Add an element to the end of the queue
*/
int ff_dirac_schro_queue_push_back (FfmpegDiracSchroQueue *queue, void *p_data);
/**
* Return the first element in the queue
*/
void *ff_dirac_schro_queue_pop (FfmpegDiracSchroQueue *queue);
/**
* Free the queue resources. free_func is a function supplied by the caller to
* free any resources allocated by the caller. The data field of the queue
* element is passed to it.
*/
void ff_dirac_schro_queue_free(FfmpegDiracSchroQueue *queue,
void (*free_func)(void *));
#endif /* FFMPEG_LIBDIRAC_LIBSCHRO_H */
@@ -0,0 +1,209 @@
/*
* Dirac decoder support via libdirac library
* Copyright (c) 2005 BBC, Andrew Kennedy <dirac at rd dot bbc dot co dot uk>
* Copyright (c) 2006-2008 BBC, Anuradha Suraparaju <asuraparaju at gmail dot 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 libdiracdec.c
* Dirac decoder support via libdirac library; more details about the Dirac
* project can be found at http://dirac.sourceforge.net/.
* The libdirac_decoder library implements Dirac specification version 2.2
* (http://dirac.sourceforge.net/specification.html).
*/
#include "libdirac.h"
#undef NDEBUG
#include <assert.h>
#include <libdirac_decoder/dirac_parser.h>
/** contains a single frame returned from Dirac */
typedef struct FfmpegDiracDecoderParams
{
/** decoder handle */
dirac_decoder_t* p_decoder;
/** buffer to hold decoded frame */
unsigned char* p_out_frame_buf;
} FfmpegDiracDecoderParams;
/**
* returns FFmpeg chroma format
*/
static enum PixelFormat GetFfmpegChromaFormat(dirac_chroma_t dirac_pix_fmt)
{
int num_formats = sizeof(ffmpeg_dirac_pixel_format_map) /
sizeof(ffmpeg_dirac_pixel_format_map[0]);
int idx;
for (idx = 0; idx < num_formats; ++idx) {
if (ffmpeg_dirac_pixel_format_map[idx].dirac_pix_fmt == dirac_pix_fmt) {
return ffmpeg_dirac_pixel_format_map[idx].ff_pix_fmt;
}
}
return PIX_FMT_NONE;
}
static int libdirac_decode_init(AVCodecContext *avccontext)
{
FfmpegDiracDecoderParams *p_dirac_params = avccontext->priv_data ;
p_dirac_params->p_decoder = dirac_decoder_init(avccontext->debug);
if (!p_dirac_params->p_decoder)
return -1;
return 0 ;
}
static int libdirac_decode_frame(AVCodecContext *avccontext,
void *data, int *data_size,
const uint8_t *buf, int buf_size)
{
FfmpegDiracDecoderParams *p_dirac_params = avccontext->priv_data;
AVPicture *picture = data;
AVPicture pic;
int pict_size;
unsigned char *buffer[3];
*data_size = 0;
if (buf_size>0)
/* set data to decode into buffer */
dirac_buffer (p_dirac_params->p_decoder, buf, buf+buf_size);
while (1) {
/* parse data and process result */
DecoderState state = dirac_parse (p_dirac_params->p_decoder);
switch (state)
{
case STATE_BUFFER:
return buf_size;
case STATE_SEQUENCE:
{
/* tell FFmpeg about sequence details */
dirac_sourceparams_t *src_params =
&p_dirac_params->p_decoder->src_params;
if (avcodec_check_dimensions(avccontext, src_params->width,
src_params->height) < 0) {
av_log(avccontext, AV_LOG_ERROR, "Invalid dimensions (%dx%d)\n",
src_params->width, src_params->height);
avccontext->height = avccontext->width = 0;
return -1;
}
avccontext->height = src_params->height;
avccontext->width = src_params->width;
avccontext->pix_fmt = GetFfmpegChromaFormat(src_params->chroma);
if (avccontext->pix_fmt == PIX_FMT_NONE) {
av_log (avccontext, AV_LOG_ERROR,
"Dirac chroma format %d not supported currently\n",
src_params->chroma);
return -1;
}
avccontext->time_base.den = src_params->frame_rate.numerator;
avccontext->time_base.num = src_params->frame_rate.denominator;
/* calculate output dimensions */
avpicture_fill(&pic, NULL, avccontext->pix_fmt,
avccontext->width, avccontext->height);
pict_size = avpicture_get_size(avccontext->pix_fmt,
avccontext->width,
avccontext->height);
/* allocate output buffer */
if (p_dirac_params->p_out_frame_buf == NULL)
p_dirac_params->p_out_frame_buf = av_malloc (pict_size);
buffer[0] = p_dirac_params->p_out_frame_buf;
buffer[1] = p_dirac_params->p_out_frame_buf +
pic.linesize[0] * avccontext->height;
buffer[2] = buffer[1] +
pic.linesize[1] * src_params->chroma_height;
/* tell Dirac about output destination */
dirac_set_buf(p_dirac_params->p_decoder, buffer, NULL);
break;
}
case STATE_SEQUENCE_END:
break;
case STATE_PICTURE_AVAIL:
/* fill picture with current buffer data from Dirac */
avpicture_fill(picture, p_dirac_params->p_out_frame_buf,
avccontext->pix_fmt,
avccontext->width, avccontext->height);
*data_size = sizeof(AVPicture);
return buf_size;
case STATE_INVALID:
return -1;
default:
break;
}
}
return buf_size;
}
static int libdirac_decode_close(AVCodecContext *avccontext)
{
FfmpegDiracDecoderParams *p_dirac_params = avccontext->priv_data;
dirac_decoder_close (p_dirac_params->p_decoder);
av_freep(&p_dirac_params->p_out_frame_buf);
return 0 ;
}
static void libdirac_flush (AVCodecContext *avccontext)
{
/* Got a seek request. We will need free memory held in the private
* context and free the current Dirac decoder handle and then open
* a new decoder handle. */
libdirac_decode_close (avccontext);
libdirac_decode_init (avccontext);
return;
}
AVCodec libdirac_decoder = {
"libdirac",
CODEC_TYPE_VIDEO,
CODEC_ID_DIRAC,
sizeof(FfmpegDiracDecoderParams),
libdirac_decode_init,
NULL,
libdirac_decode_close,
libdirac_decode_frame,
CODEC_CAP_DELAY,
.flush = libdirac_flush,
.long_name = NULL_IF_CONFIG_SMALL("libdirac Dirac 2.2"),
} ;
@@ -0,0 +1,420 @@
/*
* Dirac encoding support via libdirac library
* Copyright (c) 2005 BBC, Andrew Kennedy <dirac at rd dot bbc dot co dot uk>
* Copyright (c) 2006-2008 BBC, Anuradha Suraparaju <asuraparaju at gmail dot 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 libdiracenc.c
* Dirac encoding support via libdirac library; more details about the
* Dirac project can be found at http://dirac.sourceforge.net/.
* The libdirac_encoder library implements Dirac specification version 2.2
* (http://dirac.sourceforge.net/specification.html).
*/
#include "libdirac_libschro.h"
#include "libdirac.h"
#undef NDEBUG
#include <assert.h>
#include <libdirac_encoder/dirac_encoder.h>
/** Dirac encoder private data */
typedef struct FfmpegDiracEncoderParams
{
/** Dirac encoder context */
dirac_encoder_context_t enc_ctx;
/** frame being encoded */
AVFrame picture;
/** frame size */
int frame_size;
/** Dirac encoder handle */
dirac_encoder_t* p_encoder;
/** input frame buffer */
unsigned char *p_in_frame_buf;
/** buffer to store encoder output before writing it to the frame queue */
unsigned char *enc_buf;
/** size of encoder buffer */
int enc_buf_size;
/** queue storing encoded frames */
FfmpegDiracSchroQueue enc_frame_queue;
/** end of sequence signalled by user, 0 - false, 1 - true */
int eos_signalled;
/** end of sequence returned by encoder, 0 - false, 1 - true */
int eos_pulled;
} FfmpegDiracEncoderParams;
/**
* Works out Dirac-compatible chroma format.
*/
static dirac_chroma_t GetDiracChromaFormat(enum PixelFormat ff_pix_fmt)
{
int num_formats = sizeof(ffmpeg_dirac_pixel_format_map) /
sizeof(ffmpeg_dirac_pixel_format_map[0]);
int idx;
for (idx = 0; idx < num_formats; ++idx) {
if (ffmpeg_dirac_pixel_format_map[idx].ff_pix_fmt == ff_pix_fmt) {
return ffmpeg_dirac_pixel_format_map[idx].dirac_pix_fmt;
}
}
return formatNK;
}
/**
* Dirac video preset table. Ensure that this tables matches up correctly
* with the ff_dirac_schro_video_format_info table in libdirac_libschro.c.
*/
static const VideoFormat ff_dirac_video_formats[]={
VIDEO_FORMAT_CUSTOM ,
VIDEO_FORMAT_QSIF525 ,
VIDEO_FORMAT_QCIF ,
VIDEO_FORMAT_SIF525 ,
VIDEO_FORMAT_CIF ,
VIDEO_FORMAT_4SIF525 ,
VIDEO_FORMAT_4CIF ,
VIDEO_FORMAT_SD_480I60 ,
VIDEO_FORMAT_SD_576I50 ,
VIDEO_FORMAT_HD_720P60 ,
VIDEO_FORMAT_HD_720P50 ,
VIDEO_FORMAT_HD_1080I60 ,
VIDEO_FORMAT_HD_1080I50 ,
VIDEO_FORMAT_HD_1080P60 ,
VIDEO_FORMAT_HD_1080P50 ,
VIDEO_FORMAT_DIGI_CINEMA_2K24 ,
VIDEO_FORMAT_DIGI_CINEMA_4K24 ,
};
/**
* Returns the video format preset matching the input video dimensions and
* time base.
*/
static VideoFormat GetDiracVideoFormatPreset (AVCodecContext *avccontext)
{
unsigned int num_formats = sizeof(ff_dirac_video_formats) /
sizeof(ff_dirac_video_formats[0]);
unsigned int idx = ff_dirac_schro_get_video_format_idx (avccontext);
return (idx < num_formats) ?
ff_dirac_video_formats[idx] : VIDEO_FORMAT_CUSTOM;
}
static int libdirac_encode_init(AVCodecContext *avccontext)
{
FfmpegDiracEncoderParams* p_dirac_params = avccontext->priv_data;
int no_local = 1;
int verbose = avccontext->debug;
VideoFormat preset;
/* get Dirac preset */
preset = GetDiracVideoFormatPreset(avccontext);
/* initialize the encoder context */
dirac_encoder_context_init (&(p_dirac_params->enc_ctx), preset);
p_dirac_params->enc_ctx.src_params.chroma =
GetDiracChromaFormat(avccontext->pix_fmt);
if (p_dirac_params->enc_ctx.src_params.chroma == formatNK) {
av_log (avccontext, AV_LOG_ERROR,
"Unsupported pixel format %d. This codec supports only "
"Planar YUV formats (yuv420p, yuv422p, yuv444p\n",
avccontext->pix_fmt);
return -1;
}
p_dirac_params->enc_ctx.src_params.frame_rate.numerator =
avccontext->time_base.den;
p_dirac_params->enc_ctx.src_params.frame_rate.denominator =
avccontext->time_base.num;
p_dirac_params->enc_ctx.src_params.width = avccontext->width;
p_dirac_params->enc_ctx.src_params.height = avccontext->height;
p_dirac_params->frame_size = avpicture_get_size(avccontext->pix_fmt,
avccontext->width,
avccontext->height);
avccontext->coded_frame = &p_dirac_params->picture;
if (no_local) {
p_dirac_params->enc_ctx.decode_flag = 0;
p_dirac_params->enc_ctx.instr_flag = 0;
} else {
p_dirac_params->enc_ctx.decode_flag = 1;
p_dirac_params->enc_ctx.instr_flag = 1;
}
/* Intra-only sequence */
if (avccontext->gop_size == 0 )
p_dirac_params->enc_ctx.enc_params.num_L1 = 0;
else
avccontext->has_b_frames = 1;
if (avccontext->flags & CODEC_FLAG_QSCALE) {
if (avccontext->global_quality != 0) {
p_dirac_params->enc_ctx.enc_params.qf =
avccontext->global_quality / (FF_QP2LAMBDA*10.0);
/* if it is not default bitrate then send target rate. */
if (avccontext->bit_rate >= 1000 &&
avccontext->bit_rate != 200000) {
p_dirac_params->enc_ctx.enc_params.trate =
avccontext->bit_rate / 1000;
}
} else
p_dirac_params->enc_ctx.enc_params.lossless = 1;
} else if (avccontext->bit_rate >= 1000)
p_dirac_params->enc_ctx.enc_params.trate = avccontext->bit_rate / 1000;
if ((preset > VIDEO_FORMAT_QCIF || preset < VIDEO_FORMAT_QSIF525) &&
avccontext->bit_rate == 200000) {
p_dirac_params->enc_ctx.enc_params.trate = 0;
}
if (avccontext->flags & CODEC_FLAG_INTERLACED_ME) {
/* all material can be coded as interlaced or progressive
* irrespective of the type of source material */
p_dirac_params->enc_ctx.enc_params.picture_coding_mode = 1;
}
p_dirac_params->p_encoder = dirac_encoder_init (&(p_dirac_params->enc_ctx),
verbose );
if (!p_dirac_params->p_encoder) {
av_log(avccontext, AV_LOG_ERROR,
"Unrecoverable Error: dirac_encoder_init failed. ");
return EXIT_FAILURE;
}
/* allocate enough memory for the incoming data */
p_dirac_params->p_in_frame_buf = av_malloc(p_dirac_params->frame_size);
/* initialize the encoded frame queue */
ff_dirac_schro_queue_init(&p_dirac_params->enc_frame_queue);
return 0 ;
}
static void DiracFreeFrame (void *data)
{
FfmpegDiracSchroEncodedFrame *enc_frame = data;
av_freep (&(enc_frame->p_encbuf));
av_free(enc_frame);
}
static int libdirac_encode_frame(AVCodecContext *avccontext,
unsigned char *frame,
int buf_size, void *data)
{
int enc_size = 0;
dirac_encoder_state_t state;
FfmpegDiracEncoderParams* p_dirac_params = avccontext->priv_data;
FfmpegDiracSchroEncodedFrame* p_frame_output = NULL;
FfmpegDiracSchroEncodedFrame* p_next_output_frame = NULL;
int go = 1;
int last_frame_in_sequence = 0;
if (data == NULL) {
/* push end of sequence if not already signalled */
if (!p_dirac_params->eos_signalled) {
dirac_encoder_end_sequence( p_dirac_params->p_encoder );
p_dirac_params->eos_signalled = 1;
}
} else {
/* Allocate frame data to Dirac input buffer.
* Input line size may differ from what the codec supports,
* especially when transcoding from one format to another.
* So use avpicture_layout to copy the frame. */
avpicture_layout ((AVPicture *)data, avccontext->pix_fmt,
avccontext->width, avccontext->height,
p_dirac_params->p_in_frame_buf,
p_dirac_params->frame_size);
/* load next frame */
if (dirac_encoder_load (p_dirac_params->p_encoder,
p_dirac_params->p_in_frame_buf,
p_dirac_params->frame_size ) < 0) {
av_log(avccontext, AV_LOG_ERROR, "Unrecoverable Encoder Error."
" dirac_encoder_load failed...\n");
return -1;
}
}
if (p_dirac_params->eos_pulled)
go = 0;
while(go) {
p_dirac_params->p_encoder->enc_buf.buffer = frame;
p_dirac_params->p_encoder->enc_buf.size = buf_size;
/* process frame */
state = dirac_encoder_output ( p_dirac_params->p_encoder );
switch (state)
{
case ENC_STATE_AVAIL:
case ENC_STATE_EOS:
assert (p_dirac_params->p_encoder->enc_buf.size > 0);
/* All non-frame data is prepended to actual frame data to
* be able to set the pts correctly. So we don't write data
* to the frame output queue until we actually have a frame
*/
p_dirac_params->enc_buf = av_realloc (
p_dirac_params->enc_buf,
p_dirac_params->enc_buf_size +
p_dirac_params->p_encoder->enc_buf.size
);
memcpy(p_dirac_params->enc_buf + p_dirac_params->enc_buf_size,
p_dirac_params->p_encoder->enc_buf.buffer,
p_dirac_params->p_encoder->enc_buf.size);
p_dirac_params->enc_buf_size +=
p_dirac_params->p_encoder->enc_buf.size;
if (state == ENC_STATE_EOS) {
p_dirac_params->eos_pulled = 1;
go = 0;
}
/* If non-frame data, don't output it until it we get an
* encoded frame back from the encoder. */
if (p_dirac_params->p_encoder->enc_pparams.pnum == -1)
break;
/* create output frame */
p_frame_output = av_mallocz(sizeof(FfmpegDiracSchroEncodedFrame));
/* set output data */
p_frame_output->size = p_dirac_params->enc_buf_size;
p_frame_output->p_encbuf = p_dirac_params->enc_buf;
p_frame_output->frame_num =
p_dirac_params->p_encoder->enc_pparams.pnum;
if (p_dirac_params->p_encoder->enc_pparams.ptype == INTRA_PICTURE &&
p_dirac_params->p_encoder->enc_pparams.rtype == REFERENCE_PICTURE)
p_frame_output->key_frame = 1;
ff_dirac_schro_queue_push_back (&p_dirac_params->enc_frame_queue,
p_frame_output);
p_dirac_params->enc_buf_size = 0;
p_dirac_params->enc_buf = NULL;
break;
case ENC_STATE_BUFFER:
go = 0;
break;
case ENC_STATE_INVALID:
av_log(avccontext, AV_LOG_ERROR,
"Unrecoverable Dirac Encoder Error. Quitting...\n");
return -1;
default:
av_log(avccontext, AV_LOG_ERROR, "Unknown Dirac Encoder state\n");
return -1;
}
}
/* copy 'next' frame in queue */
if (p_dirac_params->enc_frame_queue.size == 1 &&
p_dirac_params->eos_pulled)
last_frame_in_sequence = 1;
p_next_output_frame =
ff_dirac_schro_queue_pop(&p_dirac_params->enc_frame_queue);
if (p_next_output_frame == NULL)
return 0;
memcpy(frame, p_next_output_frame->p_encbuf, p_next_output_frame->size);
avccontext->coded_frame->key_frame = p_next_output_frame->key_frame;
/* Use the frame number of the encoded frame as the pts. It is OK to do
* so since Dirac is a constant framerate codec. It expects input to be
* of constant framerate. */
avccontext->coded_frame->pts = p_next_output_frame->frame_num;
enc_size = p_next_output_frame->size;
/* Append the end of sequence information to the last frame in the
* sequence. */
if (last_frame_in_sequence && p_dirac_params->enc_buf_size > 0)
{
memcpy (frame + enc_size, p_dirac_params->enc_buf,
p_dirac_params->enc_buf_size);
enc_size += p_dirac_params->enc_buf_size;
av_freep (&p_dirac_params->enc_buf);
p_dirac_params->enc_buf_size = 0;
}
/* free frame */
DiracFreeFrame(p_next_output_frame);
return enc_size;
}
static int libdirac_encode_close(AVCodecContext *avccontext)
{
FfmpegDiracEncoderParams* p_dirac_params = avccontext->priv_data;
/* close the encoder */
dirac_encoder_close(p_dirac_params->p_encoder );
/* free data in the output frame queue */
ff_dirac_schro_queue_free(&p_dirac_params->enc_frame_queue,
DiracFreeFrame);
/* free the encoder buffer */
if (p_dirac_params->enc_buf_size)
av_freep(&p_dirac_params->enc_buf);
/* free the input frame buffer */
av_freep(&p_dirac_params->p_in_frame_buf);
return 0 ;
}
AVCodec libdirac_encoder = {
"libdirac",
CODEC_TYPE_VIDEO,
CODEC_ID_DIRAC,
sizeof(FfmpegDiracEncoderParams),
libdirac_encode_init,
libdirac_encode_frame,
libdirac_encode_close,
.capabilities= CODEC_CAP_DELAY,
.pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_YUV422P, PIX_FMT_YUV444P, -1},
.long_name= NULL_IF_CONFIG_SMALL("libdirac Dirac 2.2"),
} ;
@@ -0,0 +1,156 @@
/*
* Interface to libfaac for aac encoding
* Copyright (c) 2002 Gildas Bazin <[email protected]>
*
* 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 libfaac.c
* Interface to libfaac for aac encoding.
*/
#include "avcodec.h"
#include <faac.h>
typedef struct FaacAudioContext {
faacEncHandle faac_handle;
} FaacAudioContext;
static av_cold int Faac_encode_init(AVCodecContext *avctx)
{
FaacAudioContext *s = avctx->priv_data;
faacEncConfigurationPtr faac_cfg;
unsigned long samples_input, max_bytes_output;
/* number of channels */
if (avctx->channels < 1 || avctx->channels > 6)
return -1;
s->faac_handle = faacEncOpen(avctx->sample_rate,
avctx->channels,
&samples_input, &max_bytes_output);
/* check faac version */
faac_cfg = faacEncGetCurrentConfiguration(s->faac_handle);
if (faac_cfg->version != FAAC_CFG_VERSION) {
av_log(avctx, AV_LOG_ERROR, "wrong libfaac version (compiled for: %d, using %d)\n", FAAC_CFG_VERSION, faac_cfg->version);
faacEncClose(s->faac_handle);
return -1;
}
/* put the options in the configuration struct */
switch(avctx->profile) {
case FF_PROFILE_AAC_MAIN:
faac_cfg->aacObjectType = MAIN;
break;
case FF_PROFILE_UNKNOWN:
case FF_PROFILE_AAC_LOW:
faac_cfg->aacObjectType = LOW;
break;
case FF_PROFILE_AAC_SSR:
faac_cfg->aacObjectType = SSR;
break;
case FF_PROFILE_AAC_LTP:
faac_cfg->aacObjectType = LTP;
break;
default:
av_log(avctx, AV_LOG_ERROR, "invalid AAC profile\n");
faacEncClose(s->faac_handle);
return -1;
}
faac_cfg->mpegVersion = MPEG4;
faac_cfg->useTns = 0;
faac_cfg->allowMidside = 1;
faac_cfg->bitRate = avctx->bit_rate / avctx->channels;
faac_cfg->bandWidth = avctx->cutoff;
if(avctx->flags & CODEC_FLAG_QSCALE) {
faac_cfg->bitRate = 0;
faac_cfg->quantqual = avctx->global_quality / FF_QP2LAMBDA;
}
faac_cfg->outputFormat = 1;
faac_cfg->inputFormat = FAAC_INPUT_16BIT;
avctx->frame_size = samples_input / avctx->channels;
avctx->coded_frame= avcodec_alloc_frame();
avctx->coded_frame->key_frame= 1;
/* Set decoder specific info */
avctx->extradata_size = 0;
if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) {
unsigned char *buffer = NULL;
unsigned long decoder_specific_info_size;
if (!faacEncGetDecoderSpecificInfo(s->faac_handle, &buffer,
&decoder_specific_info_size)) {
avctx->extradata = av_malloc(decoder_specific_info_size + FF_INPUT_BUFFER_PADDING_SIZE);
avctx->extradata_size = decoder_specific_info_size;
memcpy(avctx->extradata, buffer, avctx->extradata_size);
faac_cfg->outputFormat = 0;
}
#undef free
free(buffer);
#define free please_use_av_free
}
if (!faacEncSetConfiguration(s->faac_handle, faac_cfg)) {
av_log(avctx, AV_LOG_ERROR, "libfaac doesn't support this output format!\n");
return -1;
}
return 0;
}
static int Faac_encode_frame(AVCodecContext *avctx,
unsigned char *frame, int buf_size, void *data)
{
FaacAudioContext *s = avctx->priv_data;
int bytes_written;
bytes_written = faacEncEncode(s->faac_handle,
data,
avctx->frame_size * avctx->channels,
frame,
buf_size);
return bytes_written;
}
static av_cold int Faac_encode_close(AVCodecContext *avctx)
{
FaacAudioContext *s = avctx->priv_data;
av_freep(&avctx->coded_frame);
av_freep(&avctx->extradata);
faacEncClose(s->faac_handle);
return 0;
}
AVCodec libfaac_encoder = {
"libfaac",
CODEC_TYPE_AUDIO,
CODEC_ID_AAC,
sizeof(FaacAudioContext),
Faac_encode_init,
Faac_encode_frame,
Faac_encode_close,
.sample_fmts = (enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_NONE},
.long_name = NULL_IF_CONFIG_SMALL("libfaac AAC (Advanced Audio Codec)"),
};
@@ -0,0 +1,340 @@
/*
* Faad decoder
* Copyright (c) 2003 Zdenek Kabelac.
* Copyright (c) 2004 Thomas Raivio.
*
* 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 faad.c
* AAC decoder.
*
* still a bit unfinished - but it plays something
*/
#include "avcodec.h"
#include "faad.h"
#ifndef FAADAPI
#define FAADAPI
#endif
/*
* when CONFIG_LIBFAADBIN is defined the libfaad will be opened at runtime
*/
//#undef CONFIG_LIBFAADBIN
//#define CONFIG_LIBFAADBIN
#ifdef CONFIG_LIBFAADBIN
#include <dlfcn.h>
static const char* libfaadname = "libfaad.so";
#else
#define dlopen(a)
#define dlclose(a)
#endif
typedef struct {
void* handle; /* dlopen handle */
void* faac_handle; /* FAAD library handle */
int sample_size;
int init;
/* faad calls */
faacDecHandle FAADAPI (*faacDecOpen)(void);
faacDecConfigurationPtr FAADAPI (*faacDecGetCurrentConfiguration)(faacDecHandle hDecoder);
#ifndef FAAD2_VERSION
int FAADAPI (*faacDecSetConfiguration)(faacDecHandle hDecoder,
faacDecConfigurationPtr config);
int FAADAPI (*faacDecInit)(faacDecHandle hDecoder,
unsigned char *buffer,
unsigned long *samplerate,
unsigned long *channels);
int FAADAPI (*faacDecInit2)(faacDecHandle hDecoder, unsigned char *pBuffer,
unsigned long SizeOfDecoderSpecificInfo,
unsigned long *samplerate, unsigned long *channels);
int FAADAPI (*faacDecDecode)(faacDecHandle hDecoder,
unsigned char *buffer,
unsigned long *bytesconsumed,
short *sample_buffer,
unsigned long *samples);
#else
unsigned char FAADAPI (*faacDecSetConfiguration)(faacDecHandle hDecoder,
faacDecConfigurationPtr config);
long FAADAPI (*faacDecInit)(faacDecHandle hDecoder,
unsigned char *buffer,
unsigned long buffer_size,
unsigned long *samplerate,
unsigned char *channels);
char FAADAPI (*faacDecInit2)(faacDecHandle hDecoder, unsigned char *pBuffer,
unsigned long SizeOfDecoderSpecificInfo,
unsigned long *samplerate, unsigned char *channels);
void *FAADAPI (*faacDecDecode)(faacDecHandle hDecoder,
faacDecFrameInfo *hInfo,
unsigned char *buffer,
unsigned long buffer_size);
char* FAADAPI (*faacDecGetErrorMessage)(unsigned char errcode);
#endif
void FAADAPI (*faacDecClose)(faacDecHandle hDecoder);
} FAACContext;
static const unsigned long faac_srates[] =
{
96000, 88200, 64000, 48000, 44100, 32000,
24000, 22050, 16000, 12000, 11025, 8000
};
static void channel_setup(AVCodecContext *avctx)
{
#ifdef FAAD2_VERSION
FAACContext *s = avctx->priv_data;
if (avctx->request_channels > 0 && avctx->request_channels == 2 &&
avctx->request_channels < avctx->channels) {
faacDecConfigurationPtr faac_cfg;
avctx->channels = 2;
faac_cfg = s->faacDecGetCurrentConfiguration(s->faac_handle);
faac_cfg->downMatrix = 1;
s->faacDecSetConfiguration(s->faac_handle, faac_cfg);
}
#endif
}
static int faac_init_mp4(AVCodecContext *avctx)
{
FAACContext *s = avctx->priv_data;
unsigned long samplerate;
#ifndef FAAD2_VERSION
unsigned long channels;
#else
unsigned char channels;
#endif
int r = 0;
if (avctx->extradata){
r = s->faacDecInit2(s->faac_handle, (uint8_t*) avctx->extradata,
avctx->extradata_size,
&samplerate, &channels);
if (r < 0){
av_log(avctx, AV_LOG_ERROR,
"faacDecInit2 failed r:%d sr:%ld ch:%ld s:%d\n",
r, samplerate, (long)channels, avctx->extradata_size);
} else {
avctx->sample_rate = samplerate;
avctx->channels = channels;
channel_setup(avctx);
s->init = 1;
}
}
return r;
}
static int faac_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
uint8_t *buf, int buf_size)
{
FAACContext *s = avctx->priv_data;
#ifndef FAAD2_VERSION
unsigned long bytesconsumed;
short *sample_buffer = NULL;
unsigned long samples;
int out;
#else
faacDecFrameInfo frame_info;
void *out;
#endif
if(buf_size == 0)
return 0;
#ifndef FAAD2_VERSION
out = s->faacDecDecode(s->faac_handle,
(unsigned char*)buf,
&bytesconsumed,
data,
&samples);
samples *= s->sample_size;
if (data_size)
*data_size = samples;
return (buf_size < (int)bytesconsumed)
? buf_size : (int)bytesconsumed;
#else
if(!s->init){
unsigned long srate;
unsigned char channels;
int r = s->faacDecInit(s->faac_handle, buf, buf_size, &srate, &channels);
if(r < 0){
av_log(avctx, AV_LOG_ERROR, "faac: codec init failed.\n");
return -1;
}
avctx->sample_rate = srate;
avctx->channels = channels;
channel_setup(avctx);
s->init = 1;
}
out = s->faacDecDecode(s->faac_handle, &frame_info, (unsigned char*)buf, (unsigned long)buf_size);
if (frame_info.error > 0) {
av_log(avctx, AV_LOG_ERROR, "faac: frame decoding failed: %s\n",
s->faacDecGetErrorMessage(frame_info.error));
return -1;
}
if (!avctx->frame_size)
avctx->frame_size = frame_info.samples/avctx->channels;
frame_info.samples *= s->sample_size;
memcpy(data, out, frame_info.samples); // CHECKME - can we cheat this one
if (data_size)
*data_size = frame_info.samples;
return (buf_size < (int)frame_info.bytesconsumed)
? buf_size : (int)frame_info.bytesconsumed;
#endif
}
static av_cold int faac_decode_end(AVCodecContext *avctx)
{
FAACContext *s = avctx->priv_data;
s->faacDecClose(s->faac_handle);
dlclose(s->handle);
return 0;
}
static av_cold int faac_decode_init(AVCodecContext *avctx)
{
FAACContext *s = avctx->priv_data;
faacDecConfigurationPtr faac_cfg;
#ifdef CONFIG_LIBFAADBIN
const char* err = 0;
s->handle = dlopen(libfaadname, RTLD_LAZY);
if (!s->handle)
{
av_log(avctx, AV_LOG_ERROR, "FAAD library: %s could not be opened! \n%s\n",
libfaadname, dlerror());
return -1;
}
#define dfaac(a) do { \
const char* n = AV_STRINGIFY(faacDec ## a); \
if (!err && !(s->faacDec ## a = dlsym(s->handle, n))) { \
err = n; \
} \
} while(0)
#else /* !CONFIG_LIBFAADBIN */
#define dfaac(a) s->faacDec ## a = faacDec ## a
#endif /* CONFIG_LIBFAADBIN */
// resolve all needed function calls
dfaac(Open);
dfaac(Close);
dfaac(GetCurrentConfiguration);
dfaac(SetConfiguration);
dfaac(Init);
dfaac(Init2);
dfaac(Decode);
#ifdef FAAD2_VERSION
dfaac(GetErrorMessage);
#endif
#undef dfaac
#ifdef CONFIG_LIBFAADBIN
if (err) {
dlclose(s->handle);
av_log(avctx, AV_LOG_ERROR, "FAAD library: cannot resolve %s in %s!\n",
err, libfaadname);
return -1;
}
#endif
s->faac_handle = s->faacDecOpen();
if (!s->faac_handle) {
av_log(avctx, AV_LOG_ERROR, "FAAD library: cannot create handler!\n");
faac_decode_end(avctx);
return -1;
}
faac_cfg = s->faacDecGetCurrentConfiguration(s->faac_handle);
if (faac_cfg) {
switch (avctx->bits_per_sample) {
case 8: av_log(avctx, AV_LOG_ERROR, "FAADlib unsupported bps %d\n", avctx->bits_per_sample); break;
default:
case 16:
#ifdef FAAD2_VERSION
faac_cfg->outputFormat = FAAD_FMT_16BIT;
#endif
s->sample_size = 2;
break;
case 24:
#ifdef FAAD2_VERSION
faac_cfg->outputFormat = FAAD_FMT_24BIT;
#endif
s->sample_size = 3;
break;
case 32:
#ifdef FAAD2_VERSION
faac_cfg->outputFormat = FAAD_FMT_32BIT;
#endif
s->sample_size = 4;
break;
}
faac_cfg->defSampleRate = (!avctx->sample_rate) ? 44100 : avctx->sample_rate;
faac_cfg->defObjectType = LC;
}
s->faacDecSetConfiguration(s->faac_handle, faac_cfg);
faac_init_mp4(avctx);
if(!s->init && avctx->channels > 0)
channel_setup(avctx);
avctx->sample_fmt = SAMPLE_FMT_S16;
return 0;
}
#define AAC_CODEC(id, name, long_name_) \
AVCodec name ## _decoder = { \
#name, \
CODEC_TYPE_AUDIO, \
id, \
sizeof(FAACContext), \
faac_decode_init, \
NULL, \
faac_decode_end, \
faac_decode_frame, \
.long_name = NULL_IF_CONFIG_SMALL(long_name_), \
}
// FIXME - raw AAC files - maybe just one entry will be enough
AAC_CODEC(CODEC_ID_AAC, libfaad, "libfaad AAC (Advanced Audio Codec)");
#if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0)
// If it's mp4 file - usually embeded into Qt Mov
AAC_CODEC(CODEC_ID_MPEG4AAC, mpeg4aac, "libfaad AAC (Advanced Audio Codec)");
#endif
#undef AAC_CODEC
@@ -0,0 +1,178 @@
/*
* Interface to libgsm for gsm encoding/decoding
* Copyright (c) 2005 Alban Bedel <[email protected]>
* Copyright (c) 2006, 2007 Michel Bardiaux <[email protected]>
*
* 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 libgsm.c
* Interface to libgsm for gsm encoding/decoding
*/
// The idiosyncrasies of GSM-in-WAV are explained at http://kbs.cs.tu-berlin.de/~jutta/toast.html
#include "avcodec.h"
#include <gsm.h>
// gsm.h misses some essential constants
#define GSM_BLOCK_SIZE 33
#define GSM_MS_BLOCK_SIZE 65
#define GSM_FRAME_SIZE 160
static av_cold int libgsm_init(AVCodecContext *avctx) {
if (avctx->channels > 1) {
av_log(avctx, AV_LOG_ERROR, "Mono required for GSM, got %d channels\n",
avctx->channels);
return -1;
}
if(avctx->codec->decode){
if(!avctx->channels)
avctx->channels= 1;
if(!avctx->sample_rate)
avctx->sample_rate= 8000;
avctx->sample_fmt = SAMPLE_FMT_S16;
}else{
if (avctx->sample_rate != 8000) {
av_log(avctx, AV_LOG_ERROR, "Sample rate 8000Hz required for GSM, got %dHz\n",
avctx->sample_rate);
if(avctx->strict_std_compliance > FF_COMPLIANCE_INOFFICIAL)
return -1;
}
if (avctx->bit_rate != 13000 /* Official */ &&
avctx->bit_rate != 13200 /* Very common */ &&
avctx->bit_rate != 0 /* Unknown; a.o. mov does not set bitrate when decoding */ ) {
av_log(avctx, AV_LOG_ERROR, "Bitrate 13000bps required for GSM, got %dbps\n",
avctx->bit_rate);
if(avctx->strict_std_compliance > FF_COMPLIANCE_INOFFICIAL)
return -1;
}
}
avctx->priv_data = gsm_create();
switch(avctx->codec_id) {
case CODEC_ID_GSM:
avctx->frame_size = GSM_FRAME_SIZE;
avctx->block_align = GSM_BLOCK_SIZE;
break;
case CODEC_ID_GSM_MS: {
int one = 1;
gsm_option(avctx->priv_data, GSM_OPT_WAV49, &one);
avctx->frame_size = 2*GSM_FRAME_SIZE;
avctx->block_align = GSM_MS_BLOCK_SIZE;
}
}
avctx->coded_frame= avcodec_alloc_frame();
avctx->coded_frame->key_frame= 1;
return 0;
}
static av_cold int libgsm_close(AVCodecContext *avctx) {
gsm_destroy(avctx->priv_data);
avctx->priv_data = NULL;
return 0;
}
static int libgsm_encode_frame(AVCodecContext *avctx,
unsigned char *frame, int buf_size, void *data) {
// we need a full block
if(buf_size < avctx->block_align) return 0;
switch(avctx->codec_id) {
case CODEC_ID_GSM:
gsm_encode(avctx->priv_data,data,frame);
break;
case CODEC_ID_GSM_MS:
gsm_encode(avctx->priv_data,data,frame);
gsm_encode(avctx->priv_data,((short*)data)+GSM_FRAME_SIZE,frame+32);
}
return avctx->block_align;
}
AVCodec libgsm_encoder = {
"libgsm",
CODEC_TYPE_AUDIO,
CODEC_ID_GSM,
0,
libgsm_init,
libgsm_encode_frame,
libgsm_close,
.sample_fmts = (enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_NONE},
.long_name = NULL_IF_CONFIG_SMALL("libgsm GSM"),
};
AVCodec libgsm_ms_encoder = {
"libgsm_ms",
CODEC_TYPE_AUDIO,
CODEC_ID_GSM_MS,
0,
libgsm_init,
libgsm_encode_frame,
libgsm_close,
.sample_fmts = (enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_NONE},
.long_name = NULL_IF_CONFIG_SMALL("libgsm GSM Microsoft variant"),
};
static int libgsm_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
uint8_t *buf, int buf_size) {
*data_size = 0; /* In case of error */
if(buf_size < avctx->block_align) return -1;
switch(avctx->codec_id) {
case CODEC_ID_GSM:
if(gsm_decode(avctx->priv_data,buf,data)) return -1;
*data_size = GSM_FRAME_SIZE*sizeof(int16_t);
break;
case CODEC_ID_GSM_MS:
if(gsm_decode(avctx->priv_data,buf,data) ||
gsm_decode(avctx->priv_data,buf+33,((int16_t*)data)+GSM_FRAME_SIZE)) return -1;
*data_size = GSM_FRAME_SIZE*sizeof(int16_t)*2;
}
return avctx->block_align;
}
AVCodec libgsm_decoder = {
"libgsm",
CODEC_TYPE_AUDIO,
CODEC_ID_GSM,
0,
libgsm_init,
NULL,
libgsm_close,
libgsm_decode_frame,
.long_name = NULL_IF_CONFIG_SMALL("libgsm GSM"),
};
AVCodec libgsm_ms_decoder = {
"libgsm_ms",
CODEC_TYPE_AUDIO,
CODEC_ID_GSM_MS,
0,
libgsm_init,
NULL,
libgsm_close,
libgsm_decode_frame,
.long_name = NULL_IF_CONFIG_SMALL("libgsm GSM Microsoft variant"),
};
@@ -0,0 +1,226 @@
/*
* Interface to libmp3lame for mp3 encoding
* Copyright (c) 2002 Lennert Buytenhek <[email protected]>
*
* 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 mp3lameaudio.c
* Interface to libmp3lame for mp3 encoding.
*/
#include "avcodec.h"
#include "mpegaudio.h"
#include <lame/lame.h>
#define BUFFER_SIZE (7200 + MPA_FRAME_SIZE + MPA_FRAME_SIZE/4)
typedef struct Mp3AudioContext {
lame_global_flags *gfp;
int stereo;
uint8_t buffer[BUFFER_SIZE];
int buffer_index;
} Mp3AudioContext;
static av_cold int MP3lame_encode_init(AVCodecContext *avctx)
{
Mp3AudioContext *s = avctx->priv_data;
if (avctx->channels > 2)
return -1;
s->stereo = avctx->channels > 1 ? 1 : 0;
if ((s->gfp = lame_init()) == NULL)
goto err;
lame_set_in_samplerate(s->gfp, avctx->sample_rate);
lame_set_out_samplerate(s->gfp, avctx->sample_rate);
lame_set_num_channels(s->gfp, avctx->channels);
if(avctx->compression_level == FF_COMPRESSION_DEFAULT) {
lame_set_quality(s->gfp, 5);
} else {
lame_set_quality(s->gfp, avctx->compression_level);
}
/* lame 3.91 doesn't work in mono */
lame_set_mode(s->gfp, JOINT_STEREO);
lame_set_brate(s->gfp, avctx->bit_rate/1000);
if(avctx->flags & CODEC_FLAG_QSCALE) {
lame_set_brate(s->gfp, 0);
lame_set_VBR(s->gfp, vbr_default);
lame_set_VBR_q(s->gfp, avctx->global_quality / (float)FF_QP2LAMBDA);
}
lame_set_bWriteVbrTag(s->gfp,0);
lame_set_disable_reservoir(s->gfp, avctx->flags2 & CODEC_FLAG2_BIT_RESERVOIR ? 0 : 1);
if (lame_init_params(s->gfp) < 0)
goto err_close;
avctx->frame_size = lame_get_framesize(s->gfp);
avctx->coded_frame= avcodec_alloc_frame();
avctx->coded_frame->key_frame= 1;
return 0;
err_close:
lame_close(s->gfp);
err:
return -1;
}
static const int sSampleRates[3] = {
44100, 48000, 32000
};
static const int sBitRates[2][3][15] = {
{ { 0, 32, 64, 96,128,160,192,224,256,288,320,352,384,416,448},
{ 0, 32, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,384},
{ 0, 32, 40, 48, 56, 64, 80, 96,112,128,160,192,224,256,320}
},
{ { 0, 32, 48, 56, 64, 80, 96,112,128,144,160,176,192,224,256},
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160},
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160}
},
};
static const int sSamplesPerFrame[2][3] =
{
{ 384, 1152, 1152 },
{ 384, 1152, 576 }
};
static const int sBitsPerSlot[3] = {
32,
8,
8
};
static int mp3len(void *data, int *samplesPerFrame, int *sampleRate)
{
uint32_t header = AV_RB32(data);
int layerID = 3 - ((header >> 17) & 0x03);
int bitRateID = ((header >> 12) & 0x0f);
int sampleRateID = ((header >> 10) & 0x03);
int bitsPerSlot = sBitsPerSlot[layerID];
int isPadded = ((header >> 9) & 0x01);
static int const mode_tab[4]= {2,3,1,0};
int mode= mode_tab[(header >> 19) & 0x03];
int mpeg_id= mode>0;
int temp0, temp1, bitRate;
if ( (( header >> 21 ) & 0x7ff) != 0x7ff || mode == 3 || layerID==3 || sampleRateID==3) {
return -1;
}
if(!samplesPerFrame) samplesPerFrame= &temp0;
if(!sampleRate ) sampleRate = &temp1;
// *isMono = ((header >> 6) & 0x03) == 0x03;
*sampleRate = sSampleRates[sampleRateID]>>mode;
bitRate = sBitRates[mpeg_id][layerID][bitRateID] * 1000;
*samplesPerFrame = sSamplesPerFrame[mpeg_id][layerID];
//av_log(NULL, AV_LOG_DEBUG, "sr:%d br:%d spf:%d l:%d m:%d\n", *sampleRate, bitRate, *samplesPerFrame, layerID, mode);
return *samplesPerFrame * bitRate / (bitsPerSlot * *sampleRate) + isPadded;
}
static int MP3lame_encode_frame(AVCodecContext *avctx,
unsigned char *frame, int buf_size, void *data)
{
Mp3AudioContext *s = avctx->priv_data;
int len;
int lame_result;
/* lame 3.91 dies on '1-channel interleaved' data */
if(data){
if (s->stereo) {
lame_result = lame_encode_buffer_interleaved(
s->gfp,
data,
avctx->frame_size,
s->buffer + s->buffer_index,
BUFFER_SIZE - s->buffer_index
);
} else {
lame_result = lame_encode_buffer(
s->gfp,
data,
data,
avctx->frame_size,
s->buffer + s->buffer_index,
BUFFER_SIZE - s->buffer_index
);
}
}else{
lame_result= lame_encode_flush(
s->gfp,
s->buffer + s->buffer_index,
BUFFER_SIZE - s->buffer_index
);
}
if(lame_result==-1) {
/* output buffer too small */
av_log(avctx, AV_LOG_ERROR, "lame: output buffer too small (buffer index: %d, free bytes: %d)\n", s->buffer_index, BUFFER_SIZE - s->buffer_index);
return 0;
}
s->buffer_index += lame_result;
if(s->buffer_index<4)
return 0;
len= mp3len(s->buffer, NULL, NULL);
//av_log(avctx, AV_LOG_DEBUG, "in:%d packet-len:%d index:%d\n", avctx->frame_size, len, s->buffer_index);
if(len <= s->buffer_index){
memcpy(frame, s->buffer, len);
s->buffer_index -= len;
memmove(s->buffer, s->buffer+len, s->buffer_index);
//FIXME fix the audio codec API, so we do not need the memcpy()
/*for(i=0; i<len; i++){
av_log(avctx, AV_LOG_DEBUG, "%2X ", frame[i]);
}*/
return len;
}else
return 0;
}
static av_cold int MP3lame_encode_close(AVCodecContext *avctx)
{
Mp3AudioContext *s = avctx->priv_data;
av_freep(&avctx->coded_frame);
lame_close(s->gfp);
return 0;
}
AVCodec libmp3lame_encoder = {
"libmp3lame",
CODEC_TYPE_AUDIO,
CODEC_ID_MP3,
sizeof(Mp3AudioContext),
MP3lame_encode_init,
MP3lame_encode_frame,
MP3lame_encode_close,
.capabilities= CODEC_CAP_DELAY,
.sample_fmts = (enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_NONE},
.long_name= NULL_IF_CONFIG_SMALL("libmp3lame MP3 (MPEG audio layer 3)"),
};
@@ -0,0 +1,80 @@
/*
* Copyright (c) 2008 BBC, Anuradha Suraparaju <asuraparaju at gmail dot 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 libschroedinger.c
* function definitions common to libschroedingerdec.c and libschroedingerenc.c
*/
#include "libdirac_libschro.h"
#include "libschroedinger.h"
/**
* Schroedinger video preset table. Ensure that this tables matches up correctly
* with the ff_dirac_schro_video_format_info table in libdirac_libschro.c.
*/
static const SchroVideoFormatEnum ff_schro_video_formats[]={
SCHRO_VIDEO_FORMAT_CUSTOM ,
SCHRO_VIDEO_FORMAT_QSIF ,
SCHRO_VIDEO_FORMAT_QCIF ,
SCHRO_VIDEO_FORMAT_SIF ,
SCHRO_VIDEO_FORMAT_CIF ,
SCHRO_VIDEO_FORMAT_4SIF ,
SCHRO_VIDEO_FORMAT_4CIF ,
SCHRO_VIDEO_FORMAT_SD480I_60 ,
SCHRO_VIDEO_FORMAT_SD576I_50 ,
SCHRO_VIDEO_FORMAT_HD720P_60 ,
SCHRO_VIDEO_FORMAT_HD720P_50 ,
SCHRO_VIDEO_FORMAT_HD1080I_60 ,
SCHRO_VIDEO_FORMAT_HD1080I_50 ,
SCHRO_VIDEO_FORMAT_HD1080P_60 ,
SCHRO_VIDEO_FORMAT_HD1080P_50 ,
SCHRO_VIDEO_FORMAT_DC2K_24 ,
SCHRO_VIDEO_FORMAT_DC4K_24 ,
};
SchroVideoFormatEnum ff_get_schro_video_format_preset(AVCodecContext *avccontext)
{
unsigned int num_formats = sizeof(ff_schro_video_formats) /
sizeof(ff_schro_video_formats[0]);
unsigned int idx = ff_dirac_schro_get_video_format_idx (avccontext);
return (idx < num_formats) ?
ff_schro_video_formats[idx] : SCHRO_VIDEO_FORMAT_CUSTOM;
}
int ff_get_schro_frame_format (SchroChromaFormat schro_pix_fmt,
SchroFrameFormat *schro_frame_fmt)
{
unsigned int num_formats = sizeof(ffmpeg_schro_pixel_format_map) /
sizeof(ffmpeg_schro_pixel_format_map[0]);
int idx;
for (idx = 0; idx < num_formats; ++idx) {
if (ffmpeg_schro_pixel_format_map[idx].schro_pix_fmt == schro_pix_fmt) {
*schro_frame_fmt =
ffmpeg_schro_pixel_format_map[idx].schro_frame_fmt;
return 0;
}
}
return -1;
}
@@ -0,0 +1,61 @@
/*
* Copyright (c) 2008 BBC, Anuradha Suraparaju <asuraparaju at gmail dot 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 libschroedinger.h
* data structures common to libschroedingerdec.c and libschroedingerenc.c
*/
#ifndef FFMPEG_LIBSCHROEDINGER_H
#define FFMPEG_LIBSCHROEDINGER_H
#include "config.h"
#ifdef CONFIG_LIBSCHROEDINGER
#include <schroedinger/schrobitstream.h>
#include <schroedinger/schroframe.h>
#include "avcodec.h"
static const struct {
enum PixelFormat ff_pix_fmt;
SchroChromaFormat schro_pix_fmt;
SchroFrameFormat schro_frame_fmt;
} ffmpeg_schro_pixel_format_map[] = {
{ PIX_FMT_YUV420P, SCHRO_CHROMA_420, SCHRO_FRAME_FORMAT_U8_420 },
{ PIX_FMT_YUV422P, SCHRO_CHROMA_422, SCHRO_FRAME_FORMAT_U8_422 },
{ PIX_FMT_YUV444P, SCHRO_CHROMA_444, SCHRO_FRAME_FORMAT_U8_444 },
};
/**
* Returns the video format preset matching the input video dimensions and
* time base.
*/
SchroVideoFormatEnum ff_get_schro_video_format_preset (AVCodecContext *avccontext);
/**
* Sets the Schroedinger frame format corresponding to the Schro chroma format
* passed. Returns 0 on success, -1 on failure.
*/
int ff_get_schro_frame_format (SchroChromaFormat schro_chroma_fmt,
SchroFrameFormat *schro_frame_fmt);
#endif /* CONFIG_LIBSCHROEDINGER */
#endif /* FFMPEG_LIBSCHROEDINGER_H */
@@ -0,0 +1,369 @@
/*
* Dirac decoder support via Schroedinger libraries
* Copyright (c) 2008 BBC, Anuradha Suraparaju <asuraparaju at gmail dot 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 libschroedingerdec.c
* Dirac decoder support via libschroedinger-1.0 libraries. More details about
* the Schroedinger project can be found at http://www.diracvideo.org/.
* The library implements Dirac Specification Version 2.2.
* (http://dirac.sourceforge.net/specification.html).
*/
#include "avcodec.h"
#include "libdirac_libschro.h"
#include "libschroedinger.h"
#undef NDEBUG
#include <assert.h>
#include <schroedinger/schro.h>
#include <schroedinger/schrodebug.h>
#include <schroedinger/schrovideoformat.h>
/** libschroedinger decoder private data */
typedef struct FfmpegSchroDecoderParams
{
/** Schroedinger video format */
SchroVideoFormat *format;
/** Schroedinger frame format */
SchroFrameFormat frame_format;
/** decoder handle */
SchroDecoder* decoder;
/** queue storing decoded frames */
FfmpegDiracSchroQueue dec_frame_queue;
/** end of sequence signalled */
int eos_signalled;
/** end of sequence pulled */
int eos_pulled;
/** decoded picture */
AVPicture dec_pic;
} FfmpegSchroDecoderParams;
typedef struct FfmpegSchroParseUnitContext
{
const uint8_t *buf;
int buf_size;
} FfmpegSchroParseUnitContext;
static void libschroedinger_decode_buffer_free (SchroBuffer *schro_buf,
void *priv);
static void FfmpegSchroParseContextInit (FfmpegSchroParseUnitContext *parse_ctx,
const uint8_t *buf, int buf_size)
{
parse_ctx->buf = buf;
parse_ctx->buf_size = buf_size;
}
static SchroBuffer* FfmpegFindNextSchroParseUnit (FfmpegSchroParseUnitContext *parse_ctx)
{
SchroBuffer *enc_buf = NULL;
int next_pu_offset = 0;
unsigned char *in_buf;
if (parse_ctx->buf_size < 13 ||
parse_ctx->buf[0] != 'B' ||
parse_ctx->buf[1] != 'B' ||
parse_ctx->buf[2] != 'C' ||
parse_ctx->buf[3] != 'D')
return NULL;
next_pu_offset = (parse_ctx->buf[5] << 24) +
(parse_ctx->buf[6] << 16) +
(parse_ctx->buf[7] << 8) +
parse_ctx->buf[8];
if (next_pu_offset == 0 &&
SCHRO_PARSE_CODE_IS_END_OF_SEQUENCE(parse_ctx->buf[4]))
next_pu_offset = 13;
if (next_pu_offset <= 0 || parse_ctx->buf_size < next_pu_offset)
return NULL;
in_buf = av_malloc(next_pu_offset);
memcpy (in_buf, parse_ctx->buf, next_pu_offset);
enc_buf = schro_buffer_new_with_data (in_buf, next_pu_offset);
enc_buf->free = libschroedinger_decode_buffer_free;
enc_buf->priv = in_buf;
parse_ctx->buf += next_pu_offset;
parse_ctx->buf_size -= next_pu_offset;
return enc_buf;
}
/**
* Returns FFmpeg chroma format.
*/
static enum PixelFormat GetFfmpegChromaFormat(SchroChromaFormat schro_pix_fmt)
{
int num_formats = sizeof(ffmpeg_schro_pixel_format_map) /
sizeof(ffmpeg_schro_pixel_format_map[0]);
int idx;
for (idx = 0; idx < num_formats; ++idx) {
if (ffmpeg_schro_pixel_format_map[idx].schro_pix_fmt == schro_pix_fmt) {
return ffmpeg_schro_pixel_format_map[idx].ff_pix_fmt;
}
}
return PIX_FMT_NONE;
}
static int libschroedinger_decode_init(AVCodecContext *avccontext)
{
FfmpegSchroDecoderParams *p_schro_params = avccontext->priv_data ;
/* First of all, initialize our supporting libraries. */
schro_init();
schro_debug_set_level(avccontext->debug);
p_schro_params->decoder = schro_decoder_new();
schro_decoder_set_skip_ratio(p_schro_params->decoder, 1);
if (!p_schro_params->decoder)
return -1;
/* Initialize the decoded frame queue. */
ff_dirac_schro_queue_init (&p_schro_params->dec_frame_queue);
return 0 ;
}
static void libschroedinger_decode_buffer_free (SchroBuffer *schro_buf,
void *priv)
{
av_freep(&priv);
}
static void libschroedinger_decode_frame_free (void *frame)
{
schro_frame_unref(frame);
}
static void libschroedinger_handle_first_access_unit(AVCodecContext *avccontext)
{
FfmpegSchroDecoderParams *p_schro_params = avccontext->priv_data;
SchroDecoder *decoder = p_schro_params->decoder;
p_schro_params->format = schro_decoder_get_video_format (decoder);
/* Tell FFmpeg about sequence details. */
if(avcodec_check_dimensions(avccontext, p_schro_params->format->width,
p_schro_params->format->height) < 0) {
av_log(avccontext, AV_LOG_ERROR, "invalid dimensions (%dx%d)\n",
p_schro_params->format->width, p_schro_params->format->height);
avccontext->height = avccontext->width = 0;
return;
}
avccontext->height = p_schro_params->format->height;
avccontext->width = p_schro_params->format->width;
avccontext->pix_fmt =
GetFfmpegChromaFormat(p_schro_params->format->chroma_format);
if (ff_get_schro_frame_format( p_schro_params->format->chroma_format,
&p_schro_params->frame_format) == -1) {
av_log (avccontext, AV_LOG_ERROR,
"This codec currently only supports planar YUV 4:2:0, 4:2:2 "
"and 4:4:4 formats.\n");
return;
}
avccontext->time_base.den = p_schro_params->format->frame_rate_numerator;
avccontext->time_base.num = p_schro_params->format->frame_rate_denominator;
if (p_schro_params->dec_pic.data[0] == NULL)
{
avpicture_alloc(&p_schro_params->dec_pic,
avccontext->pix_fmt,
avccontext->width,
avccontext->height);
}
}
static int libschroedinger_decode_frame(AVCodecContext *avccontext,
void *data, int *data_size,
const uint8_t *buf, int buf_size)
{
FfmpegSchroDecoderParams *p_schro_params = avccontext->priv_data;
SchroDecoder *decoder = p_schro_params->decoder;
SchroVideoFormat *format;
AVPicture *picture = data;
SchroBuffer *enc_buf;
SchroFrame* frame;
int state;
int go = 1;
int outer = 1;
FfmpegSchroParseUnitContext parse_ctx;
*data_size = 0;
FfmpegSchroParseContextInit (&parse_ctx, buf, buf_size);
if (buf_size == 0) {
if (!p_schro_params->eos_signalled) {
state = schro_decoder_push_end_of_stream(decoder);
p_schro_params->eos_signalled = 1;
}
}
/* Loop through all the individual parse units in the input buffer */
do {
if ((enc_buf = FfmpegFindNextSchroParseUnit(&parse_ctx))) {
/* Push buffer into decoder. */
state = schro_decoder_push (decoder, enc_buf);
if (state == SCHRO_DECODER_FIRST_ACCESS_UNIT)
libschroedinger_handle_first_access_unit(avccontext);
go = 1;
}
else
outer = 0;
format = p_schro_params->format;
while (go) {
/* Parse data and process result. */
state = schro_decoder_wait (decoder);
switch (state)
{
case SCHRO_DECODER_FIRST_ACCESS_UNIT:
libschroedinger_handle_first_access_unit (avccontext);
break;
case SCHRO_DECODER_NEED_BITS:
/* Need more input data - stop iterating over what we have. */
go = 0;
break;
case SCHRO_DECODER_NEED_FRAME:
/* Decoder needs a frame - create one and push it in. */
frame = schro_frame_new_and_alloc(NULL,
p_schro_params->frame_format,
format->width,
format->height);
schro_decoder_add_output_picture (decoder, frame);
break;
case SCHRO_DECODER_OK:
/* Pull a frame out of the decoder. */
frame = schro_decoder_pull (decoder);
if (frame) {
ff_dirac_schro_queue_push_back(
&p_schro_params->dec_frame_queue,
frame);
}
break;
case SCHRO_DECODER_EOS:
go = 0;
p_schro_params->eos_pulled = 1;
schro_decoder_reset (decoder);
outer = 0;
break;
case SCHRO_DECODER_ERROR:
return -1;
break;
}
}
} while(outer);
/* Grab next frame to be returned from the top of the queue. */
frame = ff_dirac_schro_queue_pop(&p_schro_params->dec_frame_queue);
if (frame != NULL) {
memcpy (p_schro_params->dec_pic.data[0],
frame->components[0].data,
frame->components[0].length);
memcpy (p_schro_params->dec_pic.data[1],
frame->components[1].data,
frame->components[1].length);
memcpy (p_schro_params->dec_pic.data[2],
frame->components[2].data,
frame->components[2].length);
/* Fill picture with current buffer data from Schroedinger. */
avpicture_fill(picture, p_schro_params->dec_pic.data[0],
avccontext->pix_fmt,
avccontext->width, avccontext->height);
*data_size = sizeof(AVPicture);
/* Now free the frame resources. */
libschroedinger_decode_frame_free (frame);
}
return buf_size;
}
static int libschroedinger_decode_close(AVCodecContext *avccontext)
{
FfmpegSchroDecoderParams *p_schro_params = avccontext->priv_data;
/* Free the decoder. */
schro_decoder_free (p_schro_params->decoder);
av_freep(&p_schro_params->format);
avpicture_free (&p_schro_params->dec_pic);
/* Free data in the output frame queue. */
ff_dirac_schro_queue_free (&p_schro_params->dec_frame_queue,
libschroedinger_decode_frame_free);
return 0 ;
}
static void libschroedinger_flush (AVCodecContext *avccontext)
{
/* Got a seek request. Free the decoded frames queue and then reset
* the decoder */
FfmpegSchroDecoderParams *p_schro_params = avccontext->priv_data;
/* Free data in the output frame queue. */
ff_dirac_schro_queue_free (&p_schro_params->dec_frame_queue,
libschroedinger_decode_frame_free);
ff_dirac_schro_queue_init (&p_schro_params->dec_frame_queue);
schro_decoder_reset(p_schro_params->decoder);
p_schro_params->eos_pulled = 0;
p_schro_params->eos_signalled = 0;
}
AVCodec libschroedinger_decoder = {
"libschroedinger",
CODEC_TYPE_VIDEO,
CODEC_ID_DIRAC,
sizeof(FfmpegSchroDecoderParams),
libschroedinger_decode_init,
NULL,
libschroedinger_decode_close,
libschroedinger_decode_frame,
CODEC_CAP_DELAY,
.flush = libschroedinger_flush,
.long_name = NULL_IF_CONFIG_SMALL("libschroedinger Dirac 2.2"),
};
@@ -0,0 +1,433 @@
/*
* Dirac encoder support via Schroedinger libraries
* Copyright (c) 2008 BBC, Anuradha Suraparaju <asuraparaju at gmail dot 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 libschroedingerenc.c
* Dirac encoder support via libschroedinger-1.0 libraries. More details about
* the Schroedinger project can be found at http://www.diracvideo.org/.
* The library implements Dirac Specification Version 2.2
* (http://dirac.sourceforge.net/specification.html).
*/
#undef NDEBUG
#include <assert.h>
#include <schroedinger/schro.h>
#include <schroedinger/schrodebug.h>
#include <schroedinger/schrovideoformat.h>
#include "avcodec.h"
#include "libdirac_libschro.h"
#include "libschroedinger.h"
/** libschroedinger encoder private data */
typedef struct FfmpegSchroEncoderParams
{
/** Schroedinger video format */
SchroVideoFormat *format;
/** Schroedinger frame format */
SchroFrameFormat frame_format;
/** frame being encoded */
AVFrame picture;
/** frame size */
int frame_size;
/** Schroedinger encoder handle*/
SchroEncoder* encoder;
/** buffer to store encoder output before writing it to the frame queue*/
unsigned char *enc_buf;
/** Size of encoder buffer*/
int enc_buf_size;
/** queue storing encoded frames */
FfmpegDiracSchroQueue enc_frame_queue;
/** end of sequence signalled */
int eos_signalled;
/** end of sequence pulled */
int eos_pulled;
} FfmpegSchroEncoderParams;
/**
* Works out Schro-compatible chroma format.
*/
static int SetSchroChromaFormat(AVCodecContext *avccontext)
{
int num_formats = sizeof(ffmpeg_schro_pixel_format_map) /
sizeof(ffmpeg_schro_pixel_format_map[0]);
int idx;
FfmpegSchroEncoderParams* p_schro_params = avccontext->priv_data;
for (idx = 0; idx < num_formats; ++idx) {
if (ffmpeg_schro_pixel_format_map[idx].ff_pix_fmt ==
avccontext->pix_fmt) {
p_schro_params->format->chroma_format =
ffmpeg_schro_pixel_format_map[idx].schro_pix_fmt;
return 0;
}
}
av_log (avccontext, AV_LOG_ERROR,
"This codec currently only supports planar YUV 4:2:0, 4:2:2"
" and 4:4:4 formats.\n");
return -1;
}
static int libschroedinger_encode_init(AVCodecContext *avccontext)
{
FfmpegSchroEncoderParams* p_schro_params = avccontext->priv_data;
SchroVideoFormatEnum preset;
/* Initialize the libraries that libschroedinger depends on. */
schro_init();
/* Create an encoder object. */
p_schro_params->encoder = schro_encoder_new();
if (!p_schro_params->encoder) {
av_log(avccontext, AV_LOG_ERROR,
"Unrecoverable Error: schro_encoder_new failed. ");
return -1;
}
/* Initialize the format. */
preset = ff_get_schro_video_format_preset(avccontext);
p_schro_params->format =
schro_encoder_get_video_format(p_schro_params->encoder);
schro_video_format_set_std_video_format (p_schro_params->format, preset);
p_schro_params->format->width = avccontext->width;
p_schro_params->format->height = avccontext->height;
if (SetSchroChromaFormat(avccontext) == -1)
return -1;
if (ff_get_schro_frame_format(p_schro_params->format->chroma_format,
&p_schro_params->frame_format) == -1) {
av_log (avccontext, AV_LOG_ERROR,
"This codec currently supports only planar YUV 4:2:0, 4:2:2"
" and 4:4:4 formats.\n");
return -1;
}
p_schro_params->format->frame_rate_numerator = avccontext->time_base.den;
p_schro_params->format->frame_rate_denominator = avccontext->time_base.num;
p_schro_params->frame_size = avpicture_get_size(avccontext->pix_fmt,
avccontext->width,
avccontext->height);
avccontext->coded_frame = &p_schro_params->picture;
if (avccontext->gop_size == 0){
schro_encoder_setting_set_double (p_schro_params->encoder,
"gop_structure",
SCHRO_ENCODER_GOP_INTRA_ONLY);
}
else {
schro_encoder_setting_set_double (p_schro_params->encoder,
"gop_structure",
SCHRO_ENCODER_GOP_BIREF);
avccontext->has_b_frames = 1;
}
/* FIXME - Need to handle SCHRO_ENCODER_RATE_CONTROL_LOW_DELAY. */
if (avccontext->flags & CODEC_FLAG_QSCALE) {
if (avccontext->global_quality == 0) {
/* lossless coding */
schro_encoder_setting_set_double (p_schro_params->encoder,
"rate_control",
SCHRO_ENCODER_RATE_CONTROL_LOSSLESS);
} else {
int noise_threshold;
schro_encoder_setting_set_double (p_schro_params->encoder,
"rate_control",
SCHRO_ENCODER_RATE_CONTROL_CONSTANT_NOISE_THRESHOLD);
noise_threshold = avccontext->global_quality/FF_QP2LAMBDA;
if (noise_threshold > 100)
noise_threshold = 100;
schro_encoder_setting_set_double (p_schro_params->encoder,
"noise_threshold",
noise_threshold);
}
}
else {
schro_encoder_setting_set_double ( p_schro_params->encoder,
"rate_control",
SCHRO_ENCODER_RATE_CONTROL_CONSTANT_BITRATE);
schro_encoder_setting_set_double (p_schro_params->encoder,
"bitrate",
avccontext->bit_rate);
}
if (avccontext->flags & CODEC_FLAG_INTERLACED_ME) {
/* All material can be coded as interlaced or progressive
irrespective of the type of source material. */
schro_encoder_setting_set_double (p_schro_params->encoder,
"interlaced_coding", 1);
}
/* FIXME: Signal range hardcoded to 8-bit data until both libschroedinger
* and libdirac support other bit-depth data. */
schro_video_format_set_std_signal_range(p_schro_params->format,
SCHRO_SIGNAL_RANGE_8BIT_VIDEO);
/* Hardcode motion vector precision to quarter pixel. */
schro_encoder_setting_set_double (p_schro_params->encoder,
"mv_precision", 2);
/* Set the encoder format. */
schro_encoder_set_video_format(p_schro_params->encoder,
p_schro_params->format);
/* Set the debug level. */
schro_debug_set_level (avccontext->debug);
schro_encoder_start (p_schro_params->encoder);
/* Initialize the encoded frame queue. */
ff_dirac_schro_queue_init (&p_schro_params->enc_frame_queue);
return 0 ;
}
static SchroFrame *libschroedinger_frame_from_data (AVCodecContext *avccontext,
void *in_data)
{
FfmpegSchroEncoderParams* p_schro_params = avccontext->priv_data;
SchroFrame *in_frame;
/* Input line size may differ from what the codec supports. Especially
* when transcoding from one format to another. So use avpicture_layout
* to copy the frame. */
in_frame = schro_frame_new_and_alloc (NULL,
p_schro_params->frame_format,
p_schro_params->format->width,
p_schro_params->format->height);
avpicture_layout ((AVPicture *)in_data, avccontext->pix_fmt,
avccontext->width, avccontext->height,
in_frame->components[0].data,
p_schro_params->frame_size);
return in_frame;
}
static void SchroedingerFreeFrame(void *data)
{
FfmpegDiracSchroEncodedFrame *enc_frame = data;
av_freep (&(enc_frame->p_encbuf));
av_free(enc_frame);
}
static int libschroedinger_encode_frame(AVCodecContext *avccontext,
unsigned char *frame,
int buf_size, void *data)
{
int enc_size = 0;
FfmpegSchroEncoderParams* p_schro_params = avccontext->priv_data;
SchroEncoder *encoder = p_schro_params->encoder;
struct FfmpegDiracSchroEncodedFrame* p_frame_output = NULL;
int go = 1;
SchroBuffer *enc_buf;
int presentation_frame;
int parse_code;
int last_frame_in_sequence = 0;
if(data == NULL) {
/* Push end of sequence if not already signalled. */
if (!p_schro_params->eos_signalled) {
schro_encoder_end_of_stream(encoder);
p_schro_params->eos_signalled = 1;
}
} else {
/* Allocate frame data to schro input buffer. */
SchroFrame *in_frame = libschroedinger_frame_from_data (avccontext,
data);
/* Load next frame. */
schro_encoder_push_frame(encoder, in_frame);
}
if (p_schro_params->eos_pulled)
go = 0;
/* Now check to see if we have any output from the encoder. */
while (go) {
SchroStateEnum state;
state = schro_encoder_wait(encoder);
switch (state)
{
case SCHRO_STATE_HAVE_BUFFER:
case SCHRO_STATE_END_OF_STREAM:
enc_buf = schro_encoder_pull (encoder,
&presentation_frame);
assert (enc_buf->length > 0);
assert (enc_buf->length <= buf_size);
parse_code = enc_buf->data[4];
/* All non-frame data is prepended to actual frame data to
* be able to set the pts correctly. So we don't write data
* to the frame output queue until we actually have a frame
*/
p_schro_params->enc_buf = av_realloc (
p_schro_params->enc_buf,
p_schro_params->enc_buf_size + enc_buf->length
);
memcpy(p_schro_params->enc_buf+p_schro_params->enc_buf_size,
enc_buf->data, enc_buf->length);
p_schro_params->enc_buf_size += enc_buf->length;
if (state == SCHRO_STATE_END_OF_STREAM) {
p_schro_params->eos_pulled = 1;
go = 0;
}
if (!SCHRO_PARSE_CODE_IS_PICTURE(parse_code)) {
schro_buffer_unref (enc_buf);
break;
}
/* Create output frame. */
p_frame_output = av_mallocz(sizeof(FfmpegDiracSchroEncodedFrame));
/* Set output data. */
p_frame_output->size = p_schro_params->enc_buf_size;
p_frame_output->p_encbuf = p_schro_params->enc_buf;
if (SCHRO_PARSE_CODE_IS_INTRA(parse_code) &&
SCHRO_PARSE_CODE_IS_REFERENCE(parse_code)) {
p_frame_output->key_frame = 1;
}
/* Parse the coded frame number from the bitstream. Bytes 14
* through 17 represesent the frame number. */
p_frame_output->frame_num = (enc_buf->data[13] << 24) +
(enc_buf->data[14] << 16) +
(enc_buf->data[15] << 8) +
enc_buf->data[16];
ff_dirac_schro_queue_push_back (&p_schro_params->enc_frame_queue,
p_frame_output);
p_schro_params->enc_buf_size = 0;
p_schro_params->enc_buf = NULL;
schro_buffer_unref (enc_buf);
break;
case SCHRO_STATE_NEED_FRAME:
go = 0;
break;
case SCHRO_STATE_AGAIN:
break;
default:
av_log(avccontext, AV_LOG_ERROR, "Unknown Schro Encoder state\n");
return -1;
}
}
/* Copy 'next' frame in queue. */
if (p_schro_params->enc_frame_queue.size == 1 &&
p_schro_params->eos_pulled)
last_frame_in_sequence = 1;
p_frame_output =
ff_dirac_schro_queue_pop (&p_schro_params->enc_frame_queue);
if (p_frame_output == NULL)
return 0;
memcpy(frame, p_frame_output->p_encbuf, p_frame_output->size);
avccontext->coded_frame->key_frame = p_frame_output->key_frame;
/* Use the frame number of the encoded frame as the pts. It is OK to
* do so since Dirac is a constant frame rate codec. It expects input
* to be of constant frame rate. */
avccontext->coded_frame->pts = p_frame_output->frame_num;
enc_size = p_frame_output->size;
/* Append the end of sequence information to the last frame in the
* sequence. */
if (last_frame_in_sequence && p_schro_params->enc_buf_size > 0)
{
memcpy (frame + enc_size, p_schro_params->enc_buf,
p_schro_params->enc_buf_size);
enc_size += p_schro_params->enc_buf_size;
av_freep (&p_schro_params->enc_buf);
p_schro_params->enc_buf_size = 0;
}
/* free frame */
SchroedingerFreeFrame (p_frame_output);
return enc_size;
}
static int libschroedinger_encode_close(AVCodecContext *avccontext)
{
FfmpegSchroEncoderParams* p_schro_params = avccontext->priv_data;
/* Close the encoder. */
schro_encoder_free(p_schro_params->encoder);
/* Free data in the output frame queue. */
ff_dirac_schro_queue_free (&p_schro_params->enc_frame_queue,
SchroedingerFreeFrame);
/* Free the encoder buffer. */
if (p_schro_params->enc_buf_size)
av_freep(&p_schro_params->enc_buf);
/* Free the video format structure. */
av_freep(&p_schro_params->format);
return 0 ;
}
AVCodec libschroedinger_encoder = {
"libschroedinger",
CODEC_TYPE_VIDEO,
CODEC_ID_DIRAC,
sizeof(FfmpegSchroEncoderParams),
libschroedinger_encode_init,
libschroedinger_encode_frame,
libschroedinger_encode_close,
.capabilities= CODEC_CAP_DELAY,
.pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_YUV422P, PIX_FMT_YUV444P, PIX_FMT_NONE},
.long_name= NULL_IF_CONFIG_SMALL("libschroedinger Dirac 2.2"),
};
@@ -0,0 +1,281 @@
/*
* Copyright (c) 2006 Paul Richards <[email protected]>
*
* 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 theoraenc.c
* \brief Theora encoder using libtheora.
* \author Paul Richards <[email protected]>
*
* A lot of this is copy / paste from other output codecs in
* libavcodec or pure guesswork (or both).
*
* I have used t_ prefixes on variables which are libtheora types
* and o_ prefixes on variables which are libogg types.
*/
/* FFmpeg includes */
#include "libavutil/log.h"
#include "avcodec.h"
/* libtheora includes */
#include <theora/theora.h>
typedef struct TheoraContext{
theora_state t_state;
} TheoraContext;
/*!
Concatenates an ogg_packet into the extradata.
*/
static int concatenate_packet(unsigned int* offset, AVCodecContext* avc_context, const ogg_packet* packet)
{
char* message = NULL;
uint8_t* newdata = NULL;
int newsize = avc_context->extradata_size + 2 + packet->bytes;
if (packet->bytes < 0) {
message = "ogg_packet has negative size";
} else if (packet->bytes > 0xffff) {
message = "ogg_packet is larger than 65535 bytes";
} else if (newsize < avc_context->extradata_size) {
message = "extradata_size would overflow";
} else {
newdata = av_realloc(avc_context->extradata, newsize);
if (newdata == NULL) {
message = "av_realloc failed";
}
}
if (message != NULL) {
av_log(avc_context, AV_LOG_ERROR, "concatenate_packet failed: %s\n", message);
return -1;
}
avc_context->extradata = newdata;
avc_context->extradata_size = newsize;
AV_WB16(avc_context->extradata + (*offset), packet->bytes);
*offset += 2;
memcpy( avc_context->extradata + (*offset), packet->packet, packet->bytes );
(*offset) += packet->bytes;
return 0;
}
static int encode_init(AVCodecContext* avc_context)
{
theora_info t_info;
theora_comment t_comment;
ogg_packet o_packet;
unsigned int offset;
TheoraContext *h = avc_context->priv_data;
/* Set up the theora_info struct */
theora_info_init( &t_info );
t_info.width = avc_context->width;
t_info.height = avc_context->height;
t_info.frame_width = avc_context->width;
t_info.frame_height = avc_context->height;
t_info.offset_x = 0;
t_info.offset_y = 0;
/* Swap numerator and denominator as time_base in AVCodecContext gives the
* time period between frames, but theora_info needs the framerate. */
t_info.fps_numerator = avc_context->time_base.den;
t_info.fps_denominator = avc_context->time_base.num;
if (avc_context->sample_aspect_ratio.num != 0) {
t_info.aspect_numerator = avc_context->sample_aspect_ratio.num;
t_info.aspect_denominator = avc_context->sample_aspect_ratio.den;
} else {
t_info.aspect_numerator = 1;
t_info.aspect_denominator = 1;
}
t_info.colorspace = OC_CS_UNSPECIFIED;
t_info.pixelformat = OC_PF_420;
t_info.target_bitrate = avc_context->bit_rate;
t_info.keyframe_frequency = avc_context->gop_size;
t_info.keyframe_frequency_force = avc_context->gop_size;
t_info.keyframe_mindistance = avc_context->keyint_min;
t_info.quality = 0;
t_info.quick_p = 1;
t_info.dropframes_p = 0;
t_info.keyframe_auto_p = 1;
t_info.keyframe_data_target_bitrate = t_info.target_bitrate * 1.5;
t_info.keyframe_auto_threshold = 80;
t_info.noise_sensitivity = 1;
t_info.sharpness = 0;
/* Now initialise libtheora */
if (theora_encode_init( &(h->t_state), &t_info ) != 0) {
av_log(avc_context, AV_LOG_ERROR, "theora_encode_init failed\n");
return -1;
}
/* Clear up theora_info struct */
theora_info_clear( &t_info );
/*
Output first header packet consisting of theora
header, comment, and tables.
Each one is prefixed with a 16bit size, then they
are concatenated together into ffmpeg's extradata.
*/
offset = 0;
/* Header */
theora_encode_header( &(h->t_state), &o_packet );
if (concatenate_packet( &offset, avc_context, &o_packet ) != 0) {
return -1;
}
/* Comment */
theora_comment_init( &t_comment );
theora_encode_comment( &t_comment, &o_packet );
if (concatenate_packet( &offset, avc_context, &o_packet ) != 0) {
return -1;
}
/* Tables */
theora_encode_tables( &(h->t_state), &o_packet );
if (concatenate_packet( &offset, avc_context, &o_packet ) != 0) {
return -1;
}
/* Clear up theora_comment struct */
theora_comment_clear( &t_comment );
/* Set up the output AVFrame */
avc_context->coded_frame= avcodec_alloc_frame();
return 0;
}
static int encode_frame(
AVCodecContext* avc_context,
uint8_t *outbuf,
int buf_size,
void *data)
{
yuv_buffer t_yuv_buffer;
TheoraContext *h = avc_context->priv_data;
AVFrame *frame = data;
ogg_packet o_packet;
int result;
assert(avc_context->pix_fmt == PIX_FMT_YUV420P);
/* Copy planes to the theora yuv_buffer */
if (frame->linesize[1] != frame->linesize[2]) {
av_log(avc_context, AV_LOG_ERROR, "U and V stride differ\n");
return -1;
}
t_yuv_buffer.y_width = avc_context->width;
t_yuv_buffer.y_height = avc_context->height;
t_yuv_buffer.y_stride = frame->linesize[0];
t_yuv_buffer.uv_width = t_yuv_buffer.y_width / 2;
t_yuv_buffer.uv_height = t_yuv_buffer.y_height / 2;
t_yuv_buffer.uv_stride = frame->linesize[1];
t_yuv_buffer.y = frame->data[0];
t_yuv_buffer.u = frame->data[1];
t_yuv_buffer.v = frame->data[2];
/* Now call into theora_encode_YUVin */
result = theora_encode_YUVin( &(h->t_state), &t_yuv_buffer );
if (result != 0) {
const char* message;
switch (result) {
case -1:
message = "differing frame sizes";
break;
case OC_EINVAL:
message = "encoder is not ready or is finished";
break;
default:
message = "unknown reason";
break;
}
av_log(avc_context, AV_LOG_ERROR, "theora_encode_YUVin failed (%s) [%d]\n", message, result);
return -1;
}
/* Pick up returned ogg_packet */
result = theora_encode_packetout( &(h->t_state), 0, &o_packet );
switch (result) {
case 0:
/* No packet is ready */
return 0;
case 1:
/* Success, we have a packet */
break;
default:
av_log(avc_context, AV_LOG_ERROR, "theora_encode_packetout failed [%d]\n", result);
return -1;
}
/* Copy ogg_packet content out to buffer */
if (buf_size < o_packet.bytes) {
av_log(avc_context, AV_LOG_ERROR, "encoded frame too large\n");
return -1;
}
memcpy(outbuf, o_packet.packet, o_packet.bytes);
return o_packet.bytes;
}
static int encode_close(AVCodecContext* avc_context)
{
ogg_packet o_packet;
TheoraContext *h = avc_context->priv_data;
int result;
const char* message;
result = theora_encode_packetout( &(h->t_state), 1, &o_packet );
theora_clear( &(h->t_state) );
switch (result) {
case 0:/* No packet is ready */
case -1:/* Encoding finished */
return 0;
case 1:
/* We have a packet */
message = "gave us a packet";
break;
default:
message = "unknown reason";
break;
}
av_log(avc_context, AV_LOG_ERROR, "theora_encode_packetout failed (%s) [%d]\n", message, result);
return -1;
}
static const enum PixelFormat supported_pixel_formats[] = { PIX_FMT_YUV420P, PIX_FMT_NONE };
/*! AVCodec struct exposed to libavcodec */
AVCodec libtheora_encoder =
{
.name = "libtheora",
.type = CODEC_TYPE_VIDEO,
.id = CODEC_ID_THEORA,
.priv_data_size = sizeof(TheoraContext),
.init = encode_init,
.close = encode_close,
.encode = encode_frame,
.pix_fmts = supported_pixel_formats,
.long_name = NULL_IF_CONFIG_SMALL("libtheora Theora"),
};
@@ -0,0 +1,222 @@
/*
* copyright (c) 2002 Mark Hills <[email protected]>
*
* 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 oggvorbis.c
* Ogg Vorbis codec support via libvorbisenc.
* @author Mark Hills <[email protected]>
*/
#include <vorbis/vorbisenc.h>
#include "avcodec.h"
#include "bytestream.h"
#undef NDEBUG
#include <assert.h>
#define OGGVORBIS_FRAME_SIZE 64
#define BUFFER_SIZE (1024*64)
typedef struct OggVorbisContext {
vorbis_info vi ;
vorbis_dsp_state vd ;
vorbis_block vb ;
uint8_t buffer[BUFFER_SIZE];
int buffer_index;
/* decoder */
vorbis_comment vc ;
ogg_packet op;
} OggVorbisContext ;
static int oggvorbis_init_encoder(vorbis_info *vi, AVCodecContext *avccontext) {
double cfreq;
if(avccontext->flags & CODEC_FLAG_QSCALE) {
/* variable bitrate */
if(vorbis_encode_setup_vbr(vi, avccontext->channels,
avccontext->sample_rate,
avccontext->global_quality / (float)FF_QP2LAMBDA))
return -1;
} else {
/* constant bitrate */
if(vorbis_encode_setup_managed(vi, avccontext->channels,
avccontext->sample_rate, -1, avccontext->bit_rate, -1))
return -1;
#ifdef OGGVORBIS_VBR_BY_ESTIMATE
/* variable bitrate by estimate */
if(vorbis_encode_ctl(vi, OV_ECTL_RATEMANAGE_AVG, NULL))
return -1;
#endif
}
/* cutoff frequency */
if(avccontext->cutoff > 0) {
cfreq = avccontext->cutoff / 1000.0;
if(vorbis_encode_ctl(vi, OV_ECTL_LOWPASS_SET, &cfreq))
return -1;
}
return vorbis_encode_setup_init(vi);
}
static av_cold int oggvorbis_encode_init(AVCodecContext *avccontext) {
OggVorbisContext *context = avccontext->priv_data ;
ogg_packet header, header_comm, header_code;
uint8_t *p;
unsigned int offset, len;
vorbis_info_init(&context->vi) ;
if(oggvorbis_init_encoder(&context->vi, avccontext) < 0) {
av_log(avccontext, AV_LOG_ERROR, "oggvorbis_encode_init: init_encoder failed") ;
return -1 ;
}
vorbis_analysis_init(&context->vd, &context->vi) ;
vorbis_block_init(&context->vd, &context->vb) ;
vorbis_comment_init(&context->vc);
vorbis_comment_add_tag(&context->vc, "encoder", LIBAVCODEC_IDENT) ;
vorbis_analysis_headerout(&context->vd, &context->vc, &header,
&header_comm, &header_code);
len = header.bytes + header_comm.bytes + header_code.bytes;
avccontext->extradata_size= 64 + len + len/255;
p = avccontext->extradata= av_mallocz(avccontext->extradata_size);
p[0] = 2;
offset = 1;
offset += av_xiphlacing(&p[offset], header.bytes);
offset += av_xiphlacing(&p[offset], header_comm.bytes);
memcpy(&p[offset], header.packet, header.bytes);
offset += header.bytes;
memcpy(&p[offset], header_comm.packet, header_comm.bytes);
offset += header_comm.bytes;
memcpy(&p[offset], header_code.packet, header_code.bytes);
offset += header_code.bytes;
avccontext->extradata_size = offset;
avccontext->extradata= av_realloc(avccontext->extradata, avccontext->extradata_size);
/* vorbis_block_clear(&context->vb);
vorbis_dsp_clear(&context->vd);
vorbis_info_clear(&context->vi);*/
vorbis_comment_clear(&context->vc);
avccontext->frame_size = OGGVORBIS_FRAME_SIZE ;
avccontext->coded_frame= avcodec_alloc_frame();
avccontext->coded_frame->key_frame= 1;
return 0 ;
}
static int oggvorbis_encode_frame(AVCodecContext *avccontext,
unsigned char *packets,
int buf_size, void *data)
{
OggVorbisContext *context = avccontext->priv_data ;
float **buffer ;
ogg_packet op ;
signed short *audio = data ;
int l, samples = data ? OGGVORBIS_FRAME_SIZE : 0;
buffer = vorbis_analysis_buffer(&context->vd, samples) ;
if(context->vi.channels == 1) {
for(l = 0 ; l < samples ; l++)
buffer[0][l]=audio[l]/32768.f;
} else {
for(l = 0 ; l < samples ; l++){
buffer[0][l]=audio[l*2]/32768.f;
buffer[1][l]=audio[l*2+1]/32768.f;
}
}
vorbis_analysis_wrote(&context->vd, samples) ;
while(vorbis_analysis_blockout(&context->vd, &context->vb) == 1) {
vorbis_analysis(&context->vb, NULL);
vorbis_bitrate_addblock(&context->vb) ;
while(vorbis_bitrate_flushpacket(&context->vd, &op)) {
/* i'd love to say the following line is a hack, but sadly it's
* not, apparently the end of stream decision is in libogg. */
if(op.bytes==1)
continue;
memcpy(context->buffer + context->buffer_index, &op, sizeof(ogg_packet));
context->buffer_index += sizeof(ogg_packet);
memcpy(context->buffer + context->buffer_index, op.packet, op.bytes);
context->buffer_index += op.bytes;
// av_log(avccontext, AV_LOG_DEBUG, "e%d / %d\n", context->buffer_index, op.bytes);
}
}
l=0;
if(context->buffer_index){
ogg_packet *op2= (ogg_packet*)context->buffer;
op2->packet = context->buffer + sizeof(ogg_packet);
l= op2->bytes;
avccontext->coded_frame->pts= av_rescale_q(op2->granulepos, (AVRational){1, avccontext->sample_rate}, avccontext->time_base);
//FIXME we should reorder the user supplied pts and not assume that they are spaced by 1/sample_rate
memcpy(packets, op2->packet, l);
context->buffer_index -= l + sizeof(ogg_packet);
memcpy(context->buffer, context->buffer + l + sizeof(ogg_packet), context->buffer_index);
// av_log(avccontext, AV_LOG_DEBUG, "E%d\n", l);
}
return l;
}
static av_cold int oggvorbis_encode_close(AVCodecContext *avccontext) {
OggVorbisContext *context = avccontext->priv_data ;
/* ogg_packet op ; */
vorbis_analysis_wrote(&context->vd, 0) ; /* notify vorbisenc this is EOF */
vorbis_block_clear(&context->vb);
vorbis_dsp_clear(&context->vd);
vorbis_info_clear(&context->vi);
av_freep(&avccontext->coded_frame);
av_freep(&avccontext->extradata);
return 0 ;
}
AVCodec libvorbis_encoder = {
"libvorbis",
CODEC_TYPE_AUDIO,
CODEC_ID_VORBIS,
sizeof(OggVorbisContext),
oggvorbis_encode_init,
oggvorbis_encode_frame,
oggvorbis_encode_close,
.capabilities= CODEC_CAP_DELAY,
.sample_fmts = (enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_NONE},
.long_name= NULL_IF_CONFIG_SMALL("libvorbis Vorbis"),
} ;
@@ -0,0 +1,305 @@
/*
* H.264 encoding using the x264 library
* Copyright (C) 2005 Mans Rullgard <[email protected]>
*
* 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
*/
#include "avcodec.h"
#include <x264.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct X264Context {
x264_param_t params;
x264_t *enc;
x264_picture_t pic;
AVFrame out_pic;
} X264Context;
static void
X264_log(void *p, int level, const char *fmt, va_list args)
{
static const int level_map[] = {
[X264_LOG_ERROR] = AV_LOG_ERROR,
[X264_LOG_WARNING] = AV_LOG_WARNING,
[X264_LOG_INFO] = AV_LOG_INFO,
[X264_LOG_DEBUG] = AV_LOG_DEBUG
};
if(level < 0 || level > X264_LOG_DEBUG)
return;
av_vlog(p, level_map[level], fmt, args);
}
static int
encode_nals(uint8_t *buf, int size, x264_nal_t *nals, int nnal)
{
uint8_t *p = buf;
int i;
for(i = 0; i < nnal; i++){
int s = x264_nal_encode(p, &size, 1, nals + i);
if(s < 0)
return -1;
p += s;
}
return p - buf;
}
static int
X264_frame(AVCodecContext *ctx, uint8_t *buf, int bufsize, void *data)
{
X264Context *x4 = ctx->priv_data;
AVFrame *frame = data;
x264_nal_t *nal;
int nnal, i;
x264_picture_t pic_out;
x4->pic.img.i_csp = X264_CSP_I420;
x4->pic.img.i_plane = 3;
if (frame) {
for(i = 0; i < 3; i++){
x4->pic.img.plane[i] = frame->data[i];
x4->pic.img.i_stride[i] = frame->linesize[i];
}
x4->pic.i_pts = frame->pts;
x4->pic.i_type = X264_TYPE_AUTO;
}
if(x264_encoder_encode(x4->enc, &nal, &nnal, frame? &x4->pic: NULL,
&pic_out))
return -1;
bufsize = encode_nals(buf, bufsize, nal, nnal);
if(bufsize < 0)
return -1;
/* FIXME: dts */
x4->out_pic.pts = pic_out.i_pts;
switch(pic_out.i_type){
case X264_TYPE_IDR:
case X264_TYPE_I:
x4->out_pic.pict_type = FF_I_TYPE;
break;
case X264_TYPE_P:
x4->out_pic.pict_type = FF_P_TYPE;
break;
case X264_TYPE_B:
case X264_TYPE_BREF:
x4->out_pic.pict_type = FF_B_TYPE;
break;
}
x4->out_pic.key_frame = pic_out.i_type == X264_TYPE_IDR;
x4->out_pic.quality = (pic_out.i_qpplus1 - 1) * FF_QP2LAMBDA;
return bufsize;
}
static av_cold int
X264_close(AVCodecContext *avctx)
{
X264Context *x4 = avctx->priv_data;
if(x4->enc)
x264_encoder_close(x4->enc);
return 0;
}
static av_cold int
X264_init(AVCodecContext *avctx)
{
X264Context *x4 = avctx->priv_data;
x264_param_default(&x4->params);
x4->params.pf_log = X264_log;
x4->params.p_log_private = avctx;
x4->params.i_keyint_max = avctx->gop_size;
x4->params.rc.i_bitrate = avctx->bit_rate / 1000;
x4->params.rc.i_vbv_buffer_size = avctx->rc_buffer_size / 1000;
x4->params.rc.i_vbv_max_bitrate = avctx->rc_max_rate / 1000;
x4->params.rc.b_stat_write = avctx->flags & CODEC_FLAG_PASS1;
if(avctx->flags & CODEC_FLAG_PASS2) x4->params.rc.b_stat_read = 1;
else{
if(avctx->crf){
x4->params.rc.i_rc_method = X264_RC_CRF;
x4->params.rc.f_rf_constant = avctx->crf;
}else if(avctx->cqp > -1){
x4->params.rc.i_rc_method = X264_RC_CQP;
x4->params.rc.i_qp_constant = avctx->cqp;
}
}
// if neither crf nor cqp modes are selected we have to enable the RC
// we do it this way because we cannot check if the bitrate has been set
if(!(avctx->crf || (avctx->cqp > -1))) x4->params.rc.i_rc_method = X264_RC_ABR;
x4->params.i_bframe = avctx->max_b_frames;
x4->params.b_cabac = avctx->coder_type == FF_CODER_TYPE_AC;
x4->params.b_bframe_adaptive = avctx->b_frame_strategy;
x4->params.i_bframe_bias = avctx->bframebias;
x4->params.b_bframe_pyramid = avctx->flags2 & CODEC_FLAG2_BPYRAMID;
avctx->has_b_frames= avctx->flags2 & CODEC_FLAG2_BPYRAMID ? 2 : !!avctx->max_b_frames;
x4->params.i_keyint_min = avctx->keyint_min;
if(x4->params.i_keyint_min > x4->params.i_keyint_max)
x4->params.i_keyint_min = x4->params.i_keyint_max;
x4->params.i_scenecut_threshold = avctx->scenechange_threshold;
x4->params.b_deblocking_filter = avctx->flags & CODEC_FLAG_LOOP_FILTER;
x4->params.i_deblocking_filter_alphac0 = avctx->deblockalpha;
x4->params.i_deblocking_filter_beta = avctx->deblockbeta;
x4->params.rc.i_qp_min = avctx->qmin;
x4->params.rc.i_qp_max = avctx->qmax;
x4->params.rc.i_qp_step = avctx->max_qdiff;
x4->params.rc.f_qcompress = avctx->qcompress; /* 0.0 => cbr, 1.0 => constant qp */
x4->params.rc.f_qblur = avctx->qblur; /* temporally blur quants */
x4->params.rc.f_complexity_blur = avctx->complexityblur;
x4->params.i_frame_reference = avctx->refs;
x4->params.i_width = avctx->width;
x4->params.i_height = avctx->height;
x4->params.vui.i_sar_width = avctx->sample_aspect_ratio.num;
x4->params.vui.i_sar_height = avctx->sample_aspect_ratio.den;
x4->params.i_fps_num = avctx->time_base.den;
x4->params.i_fps_den = avctx->time_base.num;
x4->params.analyse.inter = 0;
if(avctx->partitions){
if(avctx->partitions & X264_PART_I4X4)
x4->params.analyse.inter |= X264_ANALYSE_I4x4;
if(avctx->partitions & X264_PART_I8X8)
x4->params.analyse.inter |= X264_ANALYSE_I8x8;
if(avctx->partitions & X264_PART_P8X8)
x4->params.analyse.inter |= X264_ANALYSE_PSUB16x16;
if(avctx->partitions & X264_PART_P4X4)
x4->params.analyse.inter |= X264_ANALYSE_PSUB8x8;
if(avctx->partitions & X264_PART_B8X8)
x4->params.analyse.inter |= X264_ANALYSE_BSUB16x16;
}
x4->params.analyse.i_direct_mv_pred = avctx->directpred;
x4->params.analyse.b_weighted_bipred = avctx->flags2 & CODEC_FLAG2_WPRED;
if(avctx->me_method == ME_EPZS)
x4->params.analyse.i_me_method = X264_ME_DIA;
else if(avctx->me_method == ME_HEX)
x4->params.analyse.i_me_method = X264_ME_HEX;
else if(avctx->me_method == ME_UMH)
x4->params.analyse.i_me_method = X264_ME_UMH;
else if(avctx->me_method == ME_FULL)
x4->params.analyse.i_me_method = X264_ME_ESA;
else if(avctx->me_method == ME_TESA)
x4->params.analyse.i_me_method = X264_ME_TESA;
else x4->params.analyse.i_me_method = X264_ME_HEX;
x4->params.analyse.i_me_range = avctx->me_range;
x4->params.analyse.i_subpel_refine = avctx->me_subpel_quality;
x4->params.analyse.b_bidir_me = avctx->bidir_refine > 0;
x4->params.analyse.b_bframe_rdo = avctx->flags2 & CODEC_FLAG2_BRDO;
x4->params.analyse.b_mixed_references =
avctx->flags2 & CODEC_FLAG2_MIXED_REFS;
x4->params.analyse.b_chroma_me = avctx->me_cmp & FF_CMP_CHROMA;
x4->params.analyse.b_transform_8x8 = avctx->flags2 & CODEC_FLAG2_8X8DCT;
x4->params.analyse.b_fast_pskip = avctx->flags2 & CODEC_FLAG2_FASTPSKIP;
x4->params.analyse.i_trellis = avctx->trellis;
x4->params.analyse.i_noise_reduction = avctx->noise_reduction;
if(avctx->level > 0) x4->params.i_level_idc = avctx->level;
x4->params.rc.f_rate_tolerance =
(float)avctx->bit_rate_tolerance/avctx->bit_rate;
if((avctx->rc_buffer_size != 0) &&
(avctx->rc_initial_buffer_occupancy <= avctx->rc_buffer_size)){
x4->params.rc.f_vbv_buffer_init =
(float)avctx->rc_initial_buffer_occupancy/avctx->rc_buffer_size;
}
else x4->params.rc.f_vbv_buffer_init = 0.9;
x4->params.rc.f_ip_factor = 1/fabs(avctx->i_quant_factor);
x4->params.rc.f_pb_factor = avctx->b_quant_factor;
x4->params.analyse.i_chroma_qp_offset = avctx->chromaoffset;
x4->params.rc.psz_rc_eq = avctx->rc_eq;
x4->params.analyse.b_psnr = avctx->flags & CODEC_FLAG_PSNR;
x4->params.i_log_level = X264_LOG_DEBUG;
x4->params.b_aud = avctx->flags2 & CODEC_FLAG2_AUD;
x4->params.i_threads = avctx->thread_count;
x4->params.b_interlaced = avctx->flags & CODEC_FLAG_INTERLACED_DCT;
if(avctx->flags & CODEC_FLAG_GLOBAL_HEADER){
x4->params.b_repeat_headers = 0;
}
x4->enc = x264_encoder_open(&x4->params);
if(!x4->enc)
return -1;
avctx->coded_frame = &x4->out_pic;
if(avctx->flags & CODEC_FLAG_GLOBAL_HEADER){
x264_nal_t *nal;
int nnal, i, s = 0;
x264_encoder_headers(x4->enc, &nal, &nnal);
/* 5 bytes NAL header + worst case escaping */
for(i = 0; i < nnal; i++)
s += 5 + nal[i].i_payload * 4 / 3;
avctx->extradata = av_malloc(s);
avctx->extradata_size = encode_nals(avctx->extradata, s, nal, nnal);
}
return 0;
}
AVCodec libx264_encoder = {
.name = "libx264",
.type = CODEC_TYPE_VIDEO,
.id = CODEC_ID_H264,
.priv_data_size = sizeof(X264Context),
.init = X264_init,
.encode = X264_frame,
.close = X264_close,
.capabilities = CODEC_CAP_DELAY,
.pix_fmts = (enum PixelFormat[]) { PIX_FMT_YUV420P, PIX_FMT_NONE },
.long_name = NULL_IF_CONFIG_SMALL("libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"),
};
@@ -0,0 +1,32 @@
/*
* copyright (C) 2006 Corey Hickey
*
* 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
*/
#ifndef FFMPEG_LIBXVID_INTERNAL_H
#define FFMPEG_LIBXVID_INTERNAL_H
/**
* @file libxvid_internal.h
* common functions for use with the Xvid wrappers
*/
int av_tempfile(char *prefix, char **filename);
#endif /* FFMPEG_LIBXVID_INTERNAL_H */
@@ -0,0 +1,148 @@
/*
* Xvid rate control wrapper for lavc video encoders
*
* Copyright (c) 2006 Michael Niedermayer <[email protected]>
*
* 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
*/
#include <xvid.h>
#include <unistd.h>
#include "avcodec.h"
#include "libxvid_internal.h"
//#include "dsputil.h"
#include "mpegvideo.h"
#undef NDEBUG
#include <assert.h>
extern unsigned int xvid_debug;
int ff_xvid_rate_control_init(MpegEncContext *s){
char *tmp_name;
int fd, i;
xvid_plg_create_t xvid_plg_create;
xvid_plugin_2pass2_t xvid_2pass2;
//xvid_debug=-1;
fd=av_tempfile("xvidrc.", &tmp_name);
if (fd == -1) {
av_log(NULL, AV_LOG_ERROR, "Can't create temporary pass2 file.\n");
return -1;
}
for(i=0; i<s->rc_context.num_entries; i++){
static const char *frame_types = " ipbs";
char tmp[256];
RateControlEntry *rce;
rce= &s->rc_context.entry[i];
snprintf(tmp, sizeof(tmp), "%c %d %d %d %d %d %d\n",
frame_types[rce->pict_type], (int)lrintf(rce->qscale / FF_QP2LAMBDA), rce->i_count, s->mb_num - rce->i_count - rce->skip_count,
rce->skip_count, (rce->i_tex_bits + rce->p_tex_bits + rce->misc_bits+7)/8, (rce->header_bits+rce->mv_bits+7)/8);
//av_log(NULL, AV_LOG_ERROR, "%s\n", tmp);
write(fd, tmp, strlen(tmp));
}
close(fd);
memset(&xvid_2pass2, 0, sizeof(xvid_2pass2));
xvid_2pass2.version= XVID_MAKE_VERSION(1,1,0);
xvid_2pass2.filename= tmp_name;
xvid_2pass2.bitrate= s->avctx->bit_rate;
xvid_2pass2.vbv_size= s->avctx->rc_buffer_size;
xvid_2pass2.vbv_maxrate= s->avctx->rc_max_rate;
xvid_2pass2.vbv_initial= s->avctx->rc_initial_buffer_occupancy;
memset(&xvid_plg_create, 0, sizeof(xvid_plg_create));
xvid_plg_create.version= XVID_MAKE_VERSION(1,1,0);
xvid_plg_create.fbase= s->avctx->time_base.den;
xvid_plg_create.fincr= s->avctx->time_base.num;
xvid_plg_create.param= &xvid_2pass2;
if(xvid_plugin_2pass2(NULL, XVID_PLG_CREATE, &xvid_plg_create, &s->rc_context.non_lavc_opaque)<0){
av_log(NULL, AV_LOG_ERROR, "xvid_plugin_2pass2 failed\n");
return -1;
}
return 0;
}
float ff_xvid_rate_estimate_qscale(MpegEncContext *s, int dry_run){
xvid_plg_data_t xvid_plg_data;
memset(&xvid_plg_data, 0, sizeof(xvid_plg_data));
xvid_plg_data.version= XVID_MAKE_VERSION(1,1,0);
xvid_plg_data.width = s->width;
xvid_plg_data.height= s->height;
xvid_plg_data.mb_width = s->mb_width;
xvid_plg_data.mb_height= s->mb_height;
xvid_plg_data.fbase= s->avctx->time_base.den;
xvid_plg_data.fincr= s->avctx->time_base.num;
xvid_plg_data.min_quant[0]= s->avctx->qmin;
xvid_plg_data.min_quant[1]= s->avctx->qmin;
xvid_plg_data.min_quant[2]= s->avctx->qmin; //FIXME i/b factor & offset
xvid_plg_data.max_quant[0]= s->avctx->qmax;
xvid_plg_data.max_quant[1]= s->avctx->qmax;
xvid_plg_data.max_quant[2]= s->avctx->qmax; //FIXME i/b factor & offset
xvid_plg_data.bquant_offset = 0; // 100 * s->avctx->b_quant_offset;
xvid_plg_data.bquant_ratio = 100; // * s->avctx->b_quant_factor;
#if 0
xvid_plg_data.stats.hlength= X
#endif
if(!s->rc_context.dry_run_qscale){
if(s->picture_number){
xvid_plg_data.length=
xvid_plg_data.stats.length= (s->frame_bits + 7)/8;
xvid_plg_data.frame_num= s->rc_context.last_picture_number;
xvid_plg_data.quant= s->qscale;
xvid_plg_data.type= s->last_pict_type;
if(xvid_plugin_2pass2(s->rc_context.non_lavc_opaque, XVID_PLG_AFTER, &xvid_plg_data, NULL)){
av_log(s->avctx, AV_LOG_ERROR, "xvid_plugin_2pass2(handle, XVID_PLG_AFTER, ...) FAILED\n");
return -1;
}
}
s->rc_context.last_picture_number=
xvid_plg_data.frame_num= s->picture_number;
xvid_plg_data.quant= 0;
if(xvid_plugin_2pass2(s->rc_context.non_lavc_opaque, XVID_PLG_BEFORE, &xvid_plg_data, NULL)){
av_log(s->avctx, AV_LOG_ERROR, "xvid_plugin_2pass2(handle, XVID_PLG_BEFORE, ...) FAILED\n");
return -1;
}
s->rc_context.dry_run_qscale= xvid_plg_data.quant;
}
xvid_plg_data.quant= s->rc_context.dry_run_qscale;
if(!dry_run)
s->rc_context.dry_run_qscale= 0;
if(s->pict_type == FF_B_TYPE) //FIXME this is not exactly identical to xvid
return xvid_plg_data.quant * FF_QP2LAMBDA * s->avctx->b_quant_factor + s->avctx->b_quant_offset;
else
return xvid_plg_data.quant * FF_QP2LAMBDA;
}
void ff_xvid_rate_control_uninit(MpegEncContext *s){
xvid_plg_destroy_t xvid_plg_destroy;
xvid_plugin_2pass2(s->rc_context.non_lavc_opaque, XVID_PLG_DESTROY, &xvid_plg_destroy, NULL);
}
@@ -0,0 +1,782 @@
/*
* Interface to xvidcore for mpeg4 encoding
* Copyright (c) 2004 Adam Thayer <[email protected]>
*
* 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 xvidmpeg4.c
* Interface to xvidcore for MPEG-4 compliant encoding.
* @author Adam Thayer ([email protected])
*/
#include <xvid.h>
#include <unistd.h>
#include "avcodec.h"
#include "libxvid_internal.h"
/**
* Buffer management macros.
*/
#define BUFFER_SIZE 1024
#define BUFFER_REMAINING(x) (BUFFER_SIZE - strlen(x))
#define BUFFER_CAT(x) (&((x)[strlen(x)]))
/* For PPC Use */
extern int has_altivec(void);
/**
* Structure for the private Xvid context.
* This stores all the private context for the codec.
*/
typedef struct xvid_context {
void *encoder_handle; /** Handle for Xvid encoder */
int xsize, ysize; /** Frame size */
int vop_flags; /** VOP flags for Xvid encoder */
int vol_flags; /** VOL flags for Xvid encoder */
int me_flags; /** Motion Estimation flags */
int qscale; /** Do we use constant scale? */
int quicktime_format; /** Are we in a QT-based format? */
AVFrame encoded_picture; /** Encoded frame information */
char *twopassbuffer; /** Character buffer for two-pass */
char *old_twopassbuffer; /** Old character buffer (two-pass) */
char *twopassfile; /** second pass temp file name */
unsigned char *intra_matrix; /** P-Frame Quant Matrix */
unsigned char *inter_matrix; /** I-Frame Quant Matrix */
} xvid_context_t;
/**
* Structure for the private first-pass plugin.
*/
typedef struct xvid_ff_pass1 {
int version; /** Xvid version */
xvid_context_t *context; /** Pointer to private context */
} xvid_ff_pass1_t;
/* Prototypes - See function implementation for details */
int xvid_strip_vol_header(AVCodecContext *avctx, unsigned char *frame, unsigned int header_len, unsigned int frame_len);
int xvid_ff_2pass(void *ref, int opt, void *p1, void *p2);
void xvid_correct_framerate(AVCodecContext *avctx);
/**
* Creates the private context for the encoder.
* All buffers are allocated, settings are loaded from the user,
* and the encoder context created.
*
* @param avctx AVCodecContext pointer to context
* @return Returns 0 on success, -1 on failure
*/
av_cold int ff_xvid_encode_init(AVCodecContext *avctx) {
int xerr, i;
int xvid_flags = avctx->flags;
xvid_context_t *x = avctx->priv_data;
uint16_t *intra, *inter;
int fd;
xvid_plugin_single_t single;
xvid_ff_pass1_t rc2pass1;
xvid_plugin_2pass2_t rc2pass2;
xvid_gbl_init_t xvid_gbl_init;
xvid_enc_create_t xvid_enc_create;
xvid_enc_plugin_t plugins[7];
/* Bring in VOP flags from ffmpeg command-line */
x->vop_flags = XVID_VOP_HALFPEL; /* Bare minimum quality */
if( xvid_flags & CODEC_FLAG_4MV )
x->vop_flags |= XVID_VOP_INTER4V; /* Level 3 */
if( avctx->trellis
#if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0)
|| xvid_flags & CODEC_FLAG_TRELLIS_QUANT
#endif
)
x->vop_flags |= XVID_VOP_TRELLISQUANT; /* Level 5 */
if( xvid_flags & CODEC_FLAG_AC_PRED )
x->vop_flags |= XVID_VOP_HQACPRED; /* Level 6 */
if( xvid_flags & CODEC_FLAG_GRAY )
x->vop_flags |= XVID_VOP_GREYSCALE;
/* Decide which ME quality setting to use */
x->me_flags = 0;
switch( avctx->me_method ) {
case ME_FULL: /* Quality 6 */
x->me_flags |= XVID_ME_EXTSEARCH16
| XVID_ME_EXTSEARCH8;
case ME_EPZS: /* Quality 4 */
x->me_flags |= XVID_ME_ADVANCEDDIAMOND8
| XVID_ME_HALFPELREFINE8
| XVID_ME_CHROMA_PVOP
| XVID_ME_CHROMA_BVOP;
case ME_LOG: /* Quality 2 */
case ME_PHODS:
case ME_X1:
x->me_flags |= XVID_ME_ADVANCEDDIAMOND16
| XVID_ME_HALFPELREFINE16;
case ME_ZERO: /* Quality 0 */
default:
break;
}
/* Decide how we should decide blocks */
switch( avctx->mb_decision ) {
case 2:
x->vop_flags |= XVID_VOP_MODEDECISION_RD;
x->me_flags |= XVID_ME_HALFPELREFINE8_RD
| XVID_ME_QUARTERPELREFINE8_RD
| XVID_ME_EXTSEARCH_RD
| XVID_ME_CHECKPREDICTION_RD;
case 1:
if( !(x->vop_flags & XVID_VOP_MODEDECISION_RD) )
x->vop_flags |= XVID_VOP_FAST_MODEDECISION_RD;
x->me_flags |= XVID_ME_HALFPELREFINE16_RD
| XVID_ME_QUARTERPELREFINE16_RD;
default:
break;
}
/* Bring in VOL flags from ffmpeg command-line */
x->vol_flags = 0;
if( xvid_flags & CODEC_FLAG_GMC ) {
x->vol_flags |= XVID_VOL_GMC;
x->me_flags |= XVID_ME_GME_REFINE;
}
if( xvid_flags & CODEC_FLAG_QPEL ) {
x->vol_flags |= XVID_VOL_QUARTERPEL;
x->me_flags |= XVID_ME_QUARTERPELREFINE16;
if( x->vop_flags & XVID_VOP_INTER4V )
x->me_flags |= XVID_ME_QUARTERPELREFINE8;
}
memset(&xvid_gbl_init, 0, sizeof(xvid_gbl_init));
xvid_gbl_init.version = XVID_VERSION;
xvid_gbl_init.debug = 0;
#ifdef ARCH_POWERPC
/* Xvid's PPC support is borked, use libavcodec to detect */
#ifdef HAVE_ALTIVEC
if( has_altivec() ) {
xvid_gbl_init.cpu_flags = XVID_CPU_FORCE | XVID_CPU_ALTIVEC;
} else
#endif
xvid_gbl_init.cpu_flags = XVID_CPU_FORCE;
#else
/* Xvid can detect on x86 */
xvid_gbl_init.cpu_flags = 0;
#endif
/* Initialize */
xvid_global(NULL, XVID_GBL_INIT, &xvid_gbl_init, NULL);
/* Create the encoder reference */
memset(&xvid_enc_create, 0, sizeof(xvid_enc_create));
xvid_enc_create.version = XVID_VERSION;
/* Store the desired frame size */
xvid_enc_create.width = x->xsize = avctx->width;
xvid_enc_create.height = x->ysize = avctx->height;
/* Xvid can determine the proper profile to use */
/* xvid_enc_create.profile = XVID_PROFILE_S_L3; */
/* We don't use zones */
xvid_enc_create.zones = NULL;
xvid_enc_create.num_zones = 0;
xvid_enc_create.num_threads = avctx->thread_count;
xvid_enc_create.plugins = plugins;
xvid_enc_create.num_plugins = 0;
/* Initialize Buffers */
x->twopassbuffer = NULL;
x->old_twopassbuffer = NULL;
x->twopassfile = NULL;
if( xvid_flags & CODEC_FLAG_PASS1 ) {
memset(&rc2pass1, 0, sizeof(xvid_ff_pass1_t));
rc2pass1.version = XVID_VERSION;
rc2pass1.context = x;
x->twopassbuffer = av_malloc(BUFFER_SIZE);
x->old_twopassbuffer = av_malloc(BUFFER_SIZE);
if( x->twopassbuffer == NULL || x->old_twopassbuffer == NULL ) {
av_log(avctx, AV_LOG_ERROR,
"Xvid: Cannot allocate 2-pass log buffers\n");
return -1;
}
x->twopassbuffer[0] = x->old_twopassbuffer[0] = 0;
plugins[xvid_enc_create.num_plugins].func = xvid_ff_2pass;
plugins[xvid_enc_create.num_plugins].param = &rc2pass1;
xvid_enc_create.num_plugins++;
} else if( xvid_flags & CODEC_FLAG_PASS2 ) {
memset(&rc2pass2, 0, sizeof(xvid_plugin_2pass2_t));
rc2pass2.version = XVID_VERSION;
rc2pass2.bitrate = avctx->bit_rate;
fd = av_tempfile("xvidff.", &(x->twopassfile));
if( fd == -1 ) {
av_log(avctx, AV_LOG_ERROR,
"Xvid: Cannot write 2-pass pipe\n");
return -1;
}
if( avctx->stats_in == NULL ) {
av_log(avctx, AV_LOG_ERROR,
"Xvid: No 2-pass information loaded for second pass\n");
return -1;
}
if( strlen(avctx->stats_in) >
write(fd, avctx->stats_in, strlen(avctx->stats_in)) ) {
close(fd);
av_log(avctx, AV_LOG_ERROR,
"Xvid: Cannot write to 2-pass pipe\n");
return -1;
}
close(fd);
rc2pass2.filename = x->twopassfile;
plugins[xvid_enc_create.num_plugins].func = xvid_plugin_2pass2;
plugins[xvid_enc_create.num_plugins].param = &rc2pass2;
xvid_enc_create.num_plugins++;
} else if( !(xvid_flags & CODEC_FLAG_QSCALE) ) {
/* Single Pass Bitrate Control! */
memset(&single, 0, sizeof(xvid_plugin_single_t));
single.version = XVID_VERSION;
single.bitrate = avctx->bit_rate;
plugins[xvid_enc_create.num_plugins].func = xvid_plugin_single;
plugins[xvid_enc_create.num_plugins].param = &single;
xvid_enc_create.num_plugins++;
}
/* Luminance Masking */
if( 0.0 != avctx->lumi_masking ) {
plugins[xvid_enc_create.num_plugins].func = xvid_plugin_lumimasking;
plugins[xvid_enc_create.num_plugins].param = NULL;
xvid_enc_create.num_plugins++;
}
/* Frame Rate and Key Frames */
xvid_correct_framerate(avctx);
xvid_enc_create.fincr = avctx->time_base.num;
xvid_enc_create.fbase = avctx->time_base.den;
if( avctx->gop_size > 0 )
xvid_enc_create.max_key_interval = avctx->gop_size;
else
xvid_enc_create.max_key_interval = 240; /* Xvid's best default */
/* Quants */
if( xvid_flags & CODEC_FLAG_QSCALE ) x->qscale = 1;
else x->qscale = 0;
xvid_enc_create.min_quant[0] = avctx->qmin;
xvid_enc_create.min_quant[1] = avctx->qmin;
xvid_enc_create.min_quant[2] = avctx->qmin;
xvid_enc_create.max_quant[0] = avctx->qmax;
xvid_enc_create.max_quant[1] = avctx->qmax;
xvid_enc_create.max_quant[2] = avctx->qmax;
/* Quant Matrices */
x->intra_matrix = x->inter_matrix = NULL;
if( avctx->mpeg_quant )
x->vol_flags |= XVID_VOL_MPEGQUANT;
if( (avctx->intra_matrix || avctx->inter_matrix) ) {
x->vol_flags |= XVID_VOL_MPEGQUANT;
if( avctx->intra_matrix ) {
intra = avctx->intra_matrix;
x->intra_matrix = av_malloc(sizeof(unsigned char) * 64);
} else
intra = NULL;
if( avctx->inter_matrix ) {
inter = avctx->inter_matrix;
x->inter_matrix = av_malloc(sizeof(unsigned char) * 64);
} else
inter = NULL;
for( i = 0; i < 64; i++ ) {
if( intra )
x->intra_matrix[i] = (unsigned char)intra[i];
if( inter )
x->inter_matrix[i] = (unsigned char)inter[i];
}
}
/* Misc Settings */
xvid_enc_create.frame_drop_ratio = 0;
xvid_enc_create.global = 0;
if( xvid_flags & CODEC_FLAG_CLOSED_GOP )
xvid_enc_create.global |= XVID_GLOBAL_CLOSED_GOP;
/* Determines which codec mode we are operating in */
avctx->extradata = NULL;
avctx->extradata_size = 0;
if( xvid_flags & CODEC_FLAG_GLOBAL_HEADER ) {
/* In this case, we are claiming to be MPEG4 */
x->quicktime_format = 1;
avctx->codec_id = CODEC_ID_MPEG4;
} else {
/* We are claiming to be Xvid */
x->quicktime_format = 0;
if(!avctx->codec_tag)
avctx->codec_tag = ff_get_fourcc("xvid");
}
/* Bframes */
xvid_enc_create.max_bframes = avctx->max_b_frames;
xvid_enc_create.bquant_offset = 100 * avctx->b_quant_offset;
xvid_enc_create.bquant_ratio = 100 * avctx->b_quant_factor;
if( avctx->max_b_frames > 0 && !x->quicktime_format ) xvid_enc_create.global |= XVID_GLOBAL_PACKED;
/* Create encoder context */
xerr = xvid_encore(NULL, XVID_ENC_CREATE, &xvid_enc_create, NULL);
if( xerr ) {
av_log(avctx, AV_LOG_ERROR, "Xvid: Could not create encoder reference\n");
return -1;
}
x->encoder_handle = xvid_enc_create.handle;
avctx->coded_frame = &x->encoded_picture;
return 0;
}
/**
* Encodes a single frame.
*
* @param avctx AVCodecContext pointer to context
* @param frame Pointer to encoded frame buffer
* @param buf_size Size of encoded frame buffer
* @param data Pointer to AVFrame of unencoded frame
* @return Returns 0 on success, -1 on failure
*/
int ff_xvid_encode_frame(AVCodecContext *avctx,
unsigned char *frame, int buf_size, void *data) {
int xerr, i;
char *tmp;
xvid_context_t *x = avctx->priv_data;
AVFrame *picture = data;
AVFrame *p = &(x->encoded_picture);
xvid_enc_frame_t xvid_enc_frame;
xvid_enc_stats_t xvid_enc_stats;
/* Start setting up the frame */
memset(&xvid_enc_frame, 0, sizeof(xvid_enc_frame));
xvid_enc_frame.version = XVID_VERSION;
memset(&xvid_enc_stats, 0, sizeof(xvid_enc_stats));
xvid_enc_stats.version = XVID_VERSION;
*p = *picture;
/* Let Xvid know where to put the frame. */
xvid_enc_frame.bitstream = frame;
xvid_enc_frame.length = buf_size;
/* Initialize input image fields */
if( avctx->pix_fmt != PIX_FMT_YUV420P ) {
av_log(avctx, AV_LOG_ERROR, "Xvid: Color spaces other than 420p not supported\n");
return -1;
}
xvid_enc_frame.input.csp = XVID_CSP_PLANAR; /* YUV420P */
for( i = 0; i < 4; i++ ) {
xvid_enc_frame.input.plane[i] = picture->data[i];
xvid_enc_frame.input.stride[i] = picture->linesize[i];
}
/* Encoder Flags */
xvid_enc_frame.vop_flags = x->vop_flags;
xvid_enc_frame.vol_flags = x->vol_flags;
xvid_enc_frame.motion = x->me_flags;
xvid_enc_frame.type = XVID_TYPE_AUTO;
/* Pixel aspect ratio setting */
if (avctx->sample_aspect_ratio.num < 1 || avctx->sample_aspect_ratio.num > 255 ||
avctx->sample_aspect_ratio.den < 1 || avctx->sample_aspect_ratio.den > 255) {
av_log(avctx, AV_LOG_ERROR, "Invalid pixel aspect ratio %i/%i\n",
avctx->sample_aspect_ratio.num, avctx->sample_aspect_ratio.den);
return -1;
}
xvid_enc_frame.par = XVID_PAR_EXT;
xvid_enc_frame.par_width = avctx->sample_aspect_ratio.num;
xvid_enc_frame.par_height = avctx->sample_aspect_ratio.den;
/* Quant Setting */
if( x->qscale ) xvid_enc_frame.quant = picture->quality / FF_QP2LAMBDA;
else xvid_enc_frame.quant = 0;
/* Matrices */
xvid_enc_frame.quant_intra_matrix = x->intra_matrix;
xvid_enc_frame.quant_inter_matrix = x->inter_matrix;
/* Encode */
xerr = xvid_encore(x->encoder_handle, XVID_ENC_ENCODE,
&xvid_enc_frame, &xvid_enc_stats);
/* Two-pass log buffer swapping */
avctx->stats_out = NULL;
if( x->twopassbuffer ) {
tmp = x->old_twopassbuffer;
x->old_twopassbuffer = x->twopassbuffer;
x->twopassbuffer = tmp;
x->twopassbuffer[0] = 0;
if( x->old_twopassbuffer[0] != 0 ) {
avctx->stats_out = x->old_twopassbuffer;
}
}
if( 0 <= xerr ) {
p->quality = xvid_enc_stats.quant * FF_QP2LAMBDA;
if( xvid_enc_stats.type == XVID_TYPE_PVOP )
p->pict_type = FF_P_TYPE;
else if( xvid_enc_stats.type == XVID_TYPE_BVOP )
p->pict_type = FF_B_TYPE;
else if( xvid_enc_stats.type == XVID_TYPE_SVOP )
p->pict_type = FF_S_TYPE;
else
p->pict_type = FF_I_TYPE;
if( xvid_enc_frame.out_flags & XVID_KEYFRAME ) {
p->key_frame = 1;
if( x->quicktime_format )
return xvid_strip_vol_header(avctx, frame,
xvid_enc_stats.hlength, xerr);
} else
p->key_frame = 0;
return xerr;
} else {
av_log(avctx, AV_LOG_ERROR, "Xvid: Encoding Error Occurred: %i\n", xerr);
return -1;
}
}
/**
* Destroys the private context for the encoder.
* All buffers are freed, and the Xvid encoder context is destroyed.
*
* @param avctx AVCodecContext pointer to context
* @return Returns 0, success guaranteed
*/
av_cold int ff_xvid_encode_close(AVCodecContext *avctx) {
xvid_context_t *x = avctx->priv_data;
xvid_encore(x->encoder_handle, XVID_ENC_DESTROY, NULL, NULL);
if( avctx->extradata != NULL )
av_free(avctx->extradata);
if( x->twopassbuffer != NULL ) {
av_free(x->twopassbuffer);
av_free(x->old_twopassbuffer);
}
if( x->twopassfile != NULL )
av_free(x->twopassfile);
if( x->intra_matrix != NULL )
av_free(x->intra_matrix);
if( x->inter_matrix != NULL )
av_free(x->inter_matrix);
return 0;
}
/**
* Routine to create a global VO/VOL header for MP4 container.
* What we do here is extract the header from the Xvid bitstream
* as it is encoded. We also strip the repeated headers from the
* bitstream when a global header is requested for MPEG-4 ISO
* compliance.
*
* @param avctx AVCodecContext pointer to context
* @param frame Pointer to encoded frame data
* @param header_len Length of header to search
* @param frame_len Length of encoded frame data
* @return Returns new length of frame data
*/
int xvid_strip_vol_header(AVCodecContext *avctx,
unsigned char *frame,
unsigned int header_len,
unsigned int frame_len) {
int vo_len = 0, i;
for( i = 0; i < header_len - 3; i++ ) {
if( frame[i] == 0x00 &&
frame[i+1] == 0x00 &&
frame[i+2] == 0x01 &&
frame[i+3] == 0xB6 ) {
vo_len = i;
break;
}
}
if( vo_len > 0 ) {
/* We need to store the header, so extract it */
if( avctx->extradata == NULL ) {
avctx->extradata = av_malloc(vo_len);
memcpy(avctx->extradata, frame, vo_len);
avctx->extradata_size = vo_len;
}
/* Less dangerous now, memmove properly copies the two
chunks of overlapping data */
memmove(frame, &(frame[vo_len]), frame_len - vo_len);
return frame_len - vo_len;
} else
return frame_len;
}
/**
* Routine to correct a possibly erroneous framerate being fed to us.
* Xvid currently chokes on framerates where the ticks per frame is
* extremely large. This function works to correct problems in this area
* by estimating a new framerate and taking the simpler fraction of
* the two presented.
*
* @param avctx Context that contains the framerate to correct.
*/
void xvid_correct_framerate(AVCodecContext *avctx) {
int frate, fbase;
int est_frate, est_fbase;
int gcd;
float est_fps, fps;
frate = avctx->time_base.den;
fbase = avctx->time_base.num;
gcd = ff_gcd(frate, fbase);
if( gcd > 1 ) {
frate /= gcd;
fbase /= gcd;
}
if( frate <= 65000 && fbase <= 65000 ) {
avctx->time_base.den = frate;
avctx->time_base.num = fbase;
return;
}
fps = (float)frate / (float)fbase;
est_fps = roundf(fps * 1000.0) / 1000.0;
est_frate = (int)est_fps;
if( est_fps > (int)est_fps ) {
est_frate = (est_frate + 1) * 1000;
est_fbase = (int)roundf((float)est_frate / est_fps);
} else
est_fbase = 1;
gcd = ff_gcd(est_frate, est_fbase);
if( gcd > 1 ) {
est_frate /= gcd;
est_fbase /= gcd;
}
if( fbase > est_fbase ) {
avctx->time_base.den = est_frate;
avctx->time_base.num = est_fbase;
av_log(avctx, AV_LOG_DEBUG,
"Xvid: framerate re-estimated: %.2f, %.3f%% correction\n",
est_fps, (((est_fps - fps)/fps) * 100.0));
} else {
avctx->time_base.den = frate;
avctx->time_base.num = fbase;
}
}
/*
* Xvid 2-Pass Kludge Section
*
* Xvid's default 2-pass doesn't allow us to create data as we need to, so
* this section spends time replacing the first pass plugin so we can write
* statistic information as libavcodec requests in. We have another kludge
* that allows us to pass data to the second pass in Xvid without a custom
* rate-control plugin.
*/
/**
* Initializes the two-pass plugin and context.
*
* @param param Input construction parameter structure
* @param handle Private context handle
* @return Returns XVID_ERR_xxxx on failure, or 0 on success.
*/
static int xvid_ff_2pass_create(xvid_plg_create_t * param,
void ** handle) {
xvid_ff_pass1_t *x = (xvid_ff_pass1_t *)param->param;
char *log = x->context->twopassbuffer;
/* Do a quick bounds check */
if( log == NULL )
return XVID_ERR_FAIL;
/* We use snprintf() */
/* This is because we can safely prevent a buffer overflow */
log[0] = 0;
snprintf(log, BUFFER_REMAINING(log),
"# ffmpeg 2-pass log file, using xvid codec\n");
snprintf(BUFFER_CAT(log), BUFFER_REMAINING(log),
"# Do not modify. libxvidcore version: %d.%d.%d\n\n",
XVID_VERSION_MAJOR(XVID_VERSION),
XVID_VERSION_MINOR(XVID_VERSION),
XVID_VERSION_PATCH(XVID_VERSION));
*handle = x->context;
return 0;
}
/**
* Destroys the two-pass plugin context.
*
* @param ref Context pointer for the plugin
* @param param Destrooy context
* @return Returns 0, success guaranteed
*/
static int xvid_ff_2pass_destroy(xvid_context_t *ref,
xvid_plg_destroy_t *param) {
/* Currently cannot think of anything to do on destruction */
/* Still, the framework should be here for reference/use */
if( ref->twopassbuffer != NULL )
ref->twopassbuffer[0] = 0;
return 0;
}
/**
* Enables fast encode mode during the first pass.
*
* @param ref Context pointer for the plugin
* @param param Frame data
* @return Returns 0, success guaranteed
*/
static int xvid_ff_2pass_before(xvid_context_t *ref,
xvid_plg_data_t *param) {
int motion_remove;
int motion_replacements;
int vop_remove;
/* Nothing to do here, result is changed too much */
if( param->zone && param->zone->mode == XVID_ZONE_QUANT )
return 0;
/* We can implement a 'turbo' first pass mode here */
param->quant = 2;
/* Init values */
motion_remove = ~XVID_ME_CHROMA_PVOP &
~XVID_ME_CHROMA_BVOP &
~XVID_ME_EXTSEARCH16 &
~XVID_ME_ADVANCEDDIAMOND16;
motion_replacements = XVID_ME_FAST_MODEINTERPOLATE |
XVID_ME_SKIP_DELTASEARCH |
XVID_ME_FASTREFINE16 |
XVID_ME_BFRAME_EARLYSTOP;
vop_remove = ~XVID_VOP_MODEDECISION_RD &
~XVID_VOP_FAST_MODEDECISION_RD &
~XVID_VOP_TRELLISQUANT &
~XVID_VOP_INTER4V &
~XVID_VOP_HQACPRED;
param->vol_flags &= ~XVID_VOL_GMC;
param->vop_flags &= vop_remove;
param->motion_flags &= motion_remove;
param->motion_flags |= motion_replacements;
return 0;
}
/**
* Captures statistic data and writes it during first pass.
*
* @param ref Context pointer for the plugin
* @param param Statistic data
* @return Returns XVID_ERR_xxxx on failure, or 0 on success
*/
static int xvid_ff_2pass_after(xvid_context_t *ref,
xvid_plg_data_t *param) {
char *log = ref->twopassbuffer;
char *frame_types = " ipbs";
char frame_type;
/* Quick bounds check */
if( log == NULL )
return XVID_ERR_FAIL;
/* Convert the type given to us into a character */
if( param->type < 5 && param->type > 0 ) {
frame_type = frame_types[param->type];
} else {
return XVID_ERR_FAIL;
}
snprintf(BUFFER_CAT(log), BUFFER_REMAINING(log),
"%c %d %d %d %d %d %d\n",
frame_type, param->stats.quant, param->stats.kblks, param->stats.mblks,
param->stats.ublks, param->stats.length, param->stats.hlength);
return 0;
}
/**
* Dispatch function for our custom plugin.
* This handles the dispatch for the Xvid plugin. It passes data
* on to other functions for actual processing.
*
* @param ref Context pointer for the plugin
* @param cmd The task given for us to complete
* @param p1 First parameter (varies)
* @param p2 Second parameter (varies)
* @return Returns XVID_ERR_xxxx on failure, or 0 on success
*/
int xvid_ff_2pass(void *ref, int cmd, void *p1, void *p2) {
switch( cmd ) {
case XVID_PLG_INFO:
case XVID_PLG_FRAME:
return 0;
case XVID_PLG_BEFORE:
return xvid_ff_2pass_before(ref, p1);
case XVID_PLG_CREATE:
return xvid_ff_2pass_create(p1, p2);
case XVID_PLG_AFTER:
return xvid_ff_2pass_after(ref, p1);
case XVID_PLG_DESTROY:
return xvid_ff_2pass_destroy(ref, p1);
default:
return XVID_ERR_FAIL;
}
}
/**
* Xvid codec definition for libavcodec.
*/
AVCodec libxvid_encoder = {
"libxvid",
CODEC_TYPE_VIDEO,
CODEC_ID_XVID,
sizeof(xvid_context_t),
ff_xvid_encode_init,
ff_xvid_encode_frame,
ff_xvid_encode_close,
.pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_NONE},
.long_name= NULL_IF_CONFIG_SMALL("libxvidcore MPEG-4 part 2"),
};
@@ -0,0 +1,198 @@
/*
* lossless JPEG encoder
* Copyright (c) 2000, 2001 Fabrice Bellard.
* Copyright (c) 2003 Alex Beregszaszi
* Copyright (c) 2003-2004 Michael Niedermayer
*
* Support for external huffman table, various fixes (AVID workaround),
* aspecting, new decode_frame mechanism and apple mjpeg-b support
* by Alex Beregszaszi
*
* 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 ljpegenc.c
* lossless JPEG encoder.
*/
#include "avcodec.h"
#include "dsputil.h"
#include "mpegvideo.h"
#include "mjpeg.h"
#include "mjpegenc.h"
static int encode_picture_lossless(AVCodecContext *avctx, unsigned char *buf, int buf_size, void *data){
MpegEncContext * const s = avctx->priv_data;
MJpegContext * const m = s->mjpeg_ctx;
AVFrame *pict = data;
const int width= s->width;
const int height= s->height;
AVFrame * const p= (AVFrame*)&s->current_picture;
const int predictor= avctx->prediction_method+1;
init_put_bits(&s->pb, buf, buf_size);
*p = *pict;
p->pict_type= FF_I_TYPE;
p->key_frame= 1;
ff_mjpeg_encode_picture_header(s);
s->header_bits= put_bits_count(&s->pb);
if(avctx->pix_fmt == PIX_FMT_RGB32){
int x, y, i;
const int linesize= p->linesize[0];
uint16_t (*buffer)[4]= (void *) s->rd_scratchpad;
int left[3], top[3], topleft[3];
for(i=0; i<3; i++){
buffer[0][i]= 1 << (9 - 1);
}
for(y = 0; y < height; y++) {
const int modified_predictor= y ? predictor : 1;
uint8_t *ptr = p->data[0] + (linesize * y);
if(s->pb.buf_end - s->pb.buf - (put_bits_count(&s->pb)>>3) < width*3*4){
av_log(s->avctx, AV_LOG_ERROR, "encoded frame too large\n");
return -1;
}
for(i=0; i<3; i++){
top[i]= left[i]= topleft[i]= buffer[0][i];
}
for(x = 0; x < width; x++) {
buffer[x][1] = ptr[4*x+0] - ptr[4*x+1] + 0x100;
buffer[x][2] = ptr[4*x+2] - ptr[4*x+1] + 0x100;
buffer[x][0] = (ptr[4*x+0] + 2*ptr[4*x+1] + ptr[4*x+2])>>2;
for(i=0;i<3;i++) {
int pred, diff;
PREDICT(pred, topleft[i], top[i], left[i], modified_predictor);
topleft[i]= top[i];
top[i]= buffer[x+1][i];
left[i]= buffer[x][i];
diff= ((left[i] - pred + 0x100)&0x1FF) - 0x100;
if(i==0)
ff_mjpeg_encode_dc(s, diff, m->huff_size_dc_luminance, m->huff_code_dc_luminance); //FIXME ugly
else
ff_mjpeg_encode_dc(s, diff, m->huff_size_dc_chrominance, m->huff_code_dc_chrominance);
}
}
}
}else{
int mb_x, mb_y, i;
const int mb_width = (width + s->mjpeg_hsample[0] - 1) / s->mjpeg_hsample[0];
const int mb_height = (height + s->mjpeg_vsample[0] - 1) / s->mjpeg_vsample[0];
for(mb_y = 0; mb_y < mb_height; mb_y++) {
if(s->pb.buf_end - s->pb.buf - (put_bits_count(&s->pb)>>3) < mb_width * 4 * 3 * s->mjpeg_hsample[0] * s->mjpeg_vsample[0]){
av_log(s->avctx, AV_LOG_ERROR, "encoded frame too large\n");
return -1;
}
for(mb_x = 0; mb_x < mb_width; mb_x++) {
if(mb_x==0 || mb_y==0){
for(i=0;i<3;i++) {
uint8_t *ptr;
int x, y, h, v, linesize;
h = s->mjpeg_hsample[i];
v = s->mjpeg_vsample[i];
linesize= p->linesize[i];
for(y=0; y<v; y++){
for(x=0; x<h; x++){
int pred;
ptr = p->data[i] + (linesize * (v * mb_y + y)) + (h * mb_x + x); //FIXME optimize this crap
if(y==0 && mb_y==0){
if(x==0 && mb_x==0){
pred= 128;
}else{
pred= ptr[-1];
}
}else{
if(x==0 && mb_x==0){
pred= ptr[-linesize];
}else{
PREDICT(pred, ptr[-linesize-1], ptr[-linesize], ptr[-1], predictor);
}
}
if(i==0)
ff_mjpeg_encode_dc(s, (int8_t)(*ptr - pred), m->huff_size_dc_luminance, m->huff_code_dc_luminance); //FIXME ugly
else
ff_mjpeg_encode_dc(s, (int8_t)(*ptr - pred), m->huff_size_dc_chrominance, m->huff_code_dc_chrominance);
}
}
}
}else{
for(i=0;i<3;i++) {
uint8_t *ptr;
int x, y, h, v, linesize;
h = s->mjpeg_hsample[i];
v = s->mjpeg_vsample[i];
linesize= p->linesize[i];
for(y=0; y<v; y++){
for(x=0; x<h; x++){
int pred;
ptr = p->data[i] + (linesize * (v * mb_y + y)) + (h * mb_x + x); //FIXME optimize this crap
//printf("%d %d %d %d %8X\n", mb_x, mb_y, x, y, ptr);
PREDICT(pred, ptr[-linesize-1], ptr[-linesize], ptr[-1], predictor);
if(i==0)
ff_mjpeg_encode_dc(s, (int8_t)(*ptr - pred), m->huff_size_dc_luminance, m->huff_code_dc_luminance); //FIXME ugly
else
ff_mjpeg_encode_dc(s, (int8_t)(*ptr - pred), m->huff_size_dc_chrominance, m->huff_code_dc_chrominance);
}
}
}
}
}
}
}
emms_c();
ff_mjpeg_encode_picture_trailer(s);
s->picture_number++;
flush_put_bits(&s->pb);
return pbBufPtr(&s->pb) - s->pb.buf;
// return (put_bits_count(&f->pb)+7)/8;
}
AVCodec ljpeg_encoder = { //FIXME avoid MPV_* lossless JPEG should not need them
"ljpeg",
CODEC_TYPE_VIDEO,
CODEC_ID_LJPEG,
sizeof(MpegEncContext),
MPV_encode_init,
encode_picture_lossless,
MPV_encode_end,
.long_name = NULL_IF_CONFIG_SMALL("Lossless JPEG"),
};
@@ -0,0 +1,286 @@
/*
* LOCO codec
* Copyright (c) 2005 Konstantin Shishkov
*
* 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 loco.c
* LOCO codec.
*/
#include "avcodec.h"
#include "bitstream.h"
#include "golomb.h"
enum LOCO_MODE {LOCO_UNKN=0, LOCO_CYUY2=-1, LOCO_CRGB=-2, LOCO_CRGBA=-3, LOCO_CYV12=-4,
LOCO_YUY2=1, LOCO_UYVY=2, LOCO_RGB=3, LOCO_RGBA=4, LOCO_YV12=5};
typedef struct LOCOContext{
AVCodecContext *avctx;
AVFrame pic;
int lossy;
int mode;
} LOCOContext;
typedef struct RICEContext{
GetBitContext gb;
int save, run, run2; /* internal rice decoder state */
int sum, count; /* sum and count for getting rice parameter */
int lossy;
}RICEContext;
static int loco_get_rice_param(RICEContext *r)
{
int cnt = 0;
int val = r->count;
while(r->sum > val && cnt < 9) {
val <<= 1;
cnt++;
}
return cnt;
}
static inline void loco_update_rice_param(RICEContext *r, int val)
{
r->sum += val;
r->count++;
if(r->count == 16) {
r->sum >>= 1;
r->count >>= 1;
}
}
static inline int loco_get_rice(RICEContext *r)
{
int v;
if (r->run > 0) { /* we have zero run */
r->run--;
loco_update_rice_param(r, 0);
return 0;
}
v = get_ur_golomb_jpegls(&r->gb, loco_get_rice_param(r), INT_MAX, 0);
loco_update_rice_param(r, (v+1)>>1);
if (!v) {
if (r->save >= 0) {
r->run = get_ur_golomb_jpegls(&r->gb, 2, INT_MAX, 0);
if(r->run > 1)
r->save += r->run + 1;
else
r->save -= 3;
}
else
r->run2++;
} else {
v = ((v>>1) + r->lossy) ^ -(v&1);
if (r->run2 > 0) {
if (r->run2 > 2)
r->save += r->run2;
else
r->save -= 3;
r->run2 = 0;
}
}
return v;
}
/* LOCO main predictor - LOCO-I/JPEG-LS predictor */
static inline int loco_predict(uint8_t* data, int stride, int step)
{
int a, b, c;
a = data[-stride];
b = data[-step];
c = data[-stride - step];
return mid_pred(a, a + b - c, b);
}
static int loco_decode_plane(LOCOContext *l, uint8_t *data, int width, int height,
int stride, const uint8_t *buf, int buf_size, int step)
{
RICEContext rc;
int val;
int i, j;
init_get_bits(&rc.gb, buf, buf_size*8);
rc.save = 0;
rc.run = 0;
rc.run2 = 0;
rc.lossy = l->lossy;
rc.sum = 8;
rc.count = 1;
/* restore top left pixel */
val = loco_get_rice(&rc);
data[0] = 128 + val;
/* restore top line */
for (i = 1; i < width; i++) {
val = loco_get_rice(&rc);
data[i * step] = data[i * step - step] + val;
}
data += stride;
for (j = 1; j < height; j++) {
/* restore left column */
val = loco_get_rice(&rc);
data[0] = data[-stride] + val;
/* restore all other pixels */
for (i = 1; i < width; i++) {
val = loco_get_rice(&rc);
data[i * step] = loco_predict(&data[i * step], stride, step) + val;
}
data += stride;
}
return (get_bits_count(&rc.gb) + 7) >> 3;
}
static int decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
const uint8_t *buf, int buf_size)
{
LOCOContext * const l = avctx->priv_data;
AVFrame * const p= (AVFrame*)&l->pic;
int decoded;
if(p->data[0])
avctx->release_buffer(avctx, p);
p->reference = 0;
if(avctx->get_buffer(avctx, p) < 0){
av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
return -1;
}
p->key_frame = 1;
switch(l->mode) {
case LOCO_CYUY2: case LOCO_YUY2: case LOCO_UYVY:
decoded = loco_decode_plane(l, p->data[0], avctx->width, avctx->height,
p->linesize[0], buf, buf_size, 1);
buf += decoded; buf_size -= decoded;
decoded = loco_decode_plane(l, p->data[1], avctx->width / 2, avctx->height,
p->linesize[1], buf, buf_size, 1);
buf += decoded; buf_size -= decoded;
decoded = loco_decode_plane(l, p->data[2], avctx->width / 2, avctx->height,
p->linesize[2], buf, buf_size, 1);
break;
case LOCO_CYV12: case LOCO_YV12:
decoded = loco_decode_plane(l, p->data[0], avctx->width, avctx->height,
p->linesize[0], buf, buf_size, 1);
buf += decoded; buf_size -= decoded;
decoded = loco_decode_plane(l, p->data[2], avctx->width / 2, avctx->height / 2,
p->linesize[2], buf, buf_size, 1);
buf += decoded; buf_size -= decoded;
decoded = loco_decode_plane(l, p->data[1], avctx->width / 2, avctx->height / 2,
p->linesize[1], buf, buf_size, 1);
break;
case LOCO_CRGB: case LOCO_RGB:
decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1), avctx->width, avctx->height,
-p->linesize[0], buf, buf_size, 3);
buf += decoded; buf_size -= decoded;
decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1) + 1, avctx->width, avctx->height,
-p->linesize[0], buf, buf_size, 3);
buf += decoded; buf_size -= decoded;
decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1) + 2, avctx->width, avctx->height,
-p->linesize[0], buf, buf_size, 3);
break;
case LOCO_RGBA:
decoded = loco_decode_plane(l, p->data[0], avctx->width, avctx->height,
p->linesize[0], buf, buf_size, 4);
buf += decoded; buf_size -= decoded;
decoded = loco_decode_plane(l, p->data[0] + 1, avctx->width, avctx->height,
p->linesize[0], buf, buf_size, 4);
buf += decoded; buf_size -= decoded;
decoded = loco_decode_plane(l, p->data[0] + 2, avctx->width, avctx->height,
p->linesize[0], buf, buf_size, 4);
buf += decoded; buf_size -= decoded;
decoded = loco_decode_plane(l, p->data[0] + 3, avctx->width, avctx->height,
p->linesize[0], buf, buf_size, 4);
break;
}
*data_size = sizeof(AVFrame);
*(AVFrame*)data = l->pic;
return buf_size;
}
static av_cold int decode_init(AVCodecContext *avctx){
LOCOContext * const l = avctx->priv_data;
int version;
l->avctx = avctx;
if (avctx->extradata_size < 12) {
av_log(avctx, AV_LOG_ERROR, "Extradata size must be >= 12 instead of %i\n",
avctx->extradata_size);
return -1;
}
version = AV_RL32(avctx->extradata);
switch(version) {
case 1:
l->lossy = 0;
break;
case 2:
l->lossy = AV_RL32(avctx->extradata + 8);
break;
default:
l->lossy = AV_RL32(avctx->extradata + 8);
av_log(avctx, AV_LOG_INFO, "This is LOCO codec version %i, please upload file for study\n", version);
}
l->mode = AV_RL32(avctx->extradata + 4);
switch(l->mode) {
case LOCO_CYUY2: case LOCO_YUY2: case LOCO_UYVY:
avctx->pix_fmt = PIX_FMT_YUV422P;
break;
case LOCO_CRGB: case LOCO_RGB:
avctx->pix_fmt = PIX_FMT_BGR24;
break;
case LOCO_CYV12: case LOCO_YV12:
avctx->pix_fmt = PIX_FMT_YUV420P;
break;
case LOCO_CRGBA: case LOCO_RGBA:
avctx->pix_fmt = PIX_FMT_RGB32;
break;
default:
av_log(avctx, AV_LOG_INFO, "Unknown colorspace, index = %i\n", l->mode);
return -1;
}
if(avctx->debug & FF_DEBUG_PICT_INFO)
av_log(avctx, AV_LOG_INFO, "lossy:%i, version:%i, mode: %i\n", l->lossy, version, l->mode);
return 0;
}
AVCodec loco_decoder = {
"loco",
CODEC_TYPE_VIDEO,
CODEC_ID_LOCO,
sizeof(LOCOContext),
decode_init,
NULL,
NULL,
decode_frame,
CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("LOCO"),
};
@@ -0,0 +1,129 @@
/*
* Lowpass IIR filter
* Copyright (c) 2008 Konstantin Shishkov
*
* 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 lowpass.c
* lowpass filter implementation
*/
#include "lowpass.h"
/**********************
* TODO:
* support filters with order != 4
* calculate coefficients for filter instead of taking approximate ones from the table
*********************/
/** filter order */
#define LOWPASS_FILTER_ORDER 4
/**
* IIR filter global parameters
*/
typedef struct FFLPFilterCoeffs{
float gain;
float c[LOWPASS_FILTER_ORDER];
}FFLPFilterCoeffs;
/**
* filter data for 4th order IIR lowpass Butterworth filter
*/
static const FFLPFilterCoeffs lp_filter_coeffs[] = {
{ 9.398085e-01, { -0.0176648009, 0.0000000000, -0.4860288221, 0.0000000000 } },
{ 6.816645e-01, { -0.4646665999, -2.2127207402, -3.9912017501, -3.2380429984 } },
{ 4.998150e-01, { -0.2498216698, -1.3392807613, -2.7693097862, -2.6386277439 } },
{ 3.103469e-01, { -0.0965076902, -0.5977763360, -1.4972580903, -1.7740085241 } },
{ 2.346995e-01, { -0.0557639007, -0.3623690447, -1.0304538354, -1.3066051440 } },
{ 1.528432e-01, { -0.0261686639, -0.1473794606, -0.6204721225, -0.6514716536 } },
{ 6.917529e-02, { -0.0202414073, 0.0780167640, -0.5277442247, 0.3631641670 } },
{ 6.178391e-02, { -0.0223681543, 0.1069446609, -0.5615167033, 0.4883976841 } },
{ 5.298685e-02, { -0.0261686639, 0.1473794606, -0.6204721225, 0.6514716536 } },
{ 2.229030e-02, { -0.0647354087, 0.4172275190, -1.1412129810, 1.4320761385 } },
{ 1.693903e-02, { -0.0823177861, 0.5192354923, -1.3444768251, 1.6365345642 } },
{ 7.374053e-03, { -0.1481421788, 0.8650973862, -1.9894244796, 2.1544844308 } },
{ 5.541768e-03, { -0.1742301048, 0.9921936565, -2.2090801108, 2.3024482658 } },
};
/** cutoff ratios for lp_filter_data[] */
static const float lp_cutoff_ratios[] = {
0.5000000000, 0.4535147392, 0.4166666667, 0.3628117914,
0.3333333333, 0.2916666667, 0.2267573696, 0.2187500000,
0.2083333333, 0.1587301587, 0.1458333333, 0.1133786848,
0.1041666667,
};
/**
* IIR filter state
*/
typedef struct FFLPFilterState{
float x[LOWPASS_FILTER_ORDER];
}FFLPFilterState;
const struct FFLPFilterCoeffs* ff_lowpass_filter_init_coeffs(int order, float cutoff_ratio)
{
int i, size;
//we can create only order-4 filters with cutoff ratio <= 0.5 for now
if(order != LOWPASS_FILTER_ORDER) return NULL;
size = sizeof(lp_cutoff_ratios) / sizeof(lp_cutoff_ratios[0]);
if(cutoff_ratio > lp_cutoff_ratios[0])
return NULL;
for(i = 0; i < size; i++){
if(cutoff_ratio >= lp_cutoff_ratios[i])
break;
}
if(i == size)
i = size - 1;
return &lp_filter_coeffs[i];
}
struct FFLPFilterState* ff_lowpass_filter_init_state(int order)
{
if(order != LOWPASS_FILTER_ORDER) return NULL;
return av_mallocz(sizeof(FFLPFilterState));
}
#define FILTER(i0, i1, i2, i3) \
in = *src * c->gain \
+ c->c[0]*s->x[i0] + c->c[1]*s->x[i1] \
+ c->c[2]*s->x[i2] + c->c[3]*s->x[i3]; \
res = (s->x[i0] + in )*1 \
+ (s->x[i1] + s->x[i3])*4 \
+ s->x[i2] *6; \
*dst = av_clip_int16(lrintf(res)); \
s->x[i0] = in; \
src += sstep; \
dst += dstep; \
void ff_lowpass_filter(const struct FFLPFilterCoeffs *c, struct FFLPFilterState *s, int size, int16_t *src, int sstep, int16_t *dst, int dstep)
{
int i;
for(i = 0; i < size; i += 4){
float in, res;
FILTER(0, 1, 2, 3);
FILTER(1, 2, 3, 0);
FILTER(2, 3, 0, 1);
FILTER(3, 0, 1, 2);
}
}
@@ -0,0 +1,83 @@
/*
* Lowpass IIR filter
* Copyright (c) 2008 Konstantin Shishkov
*
* 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 lowpass.h
* lowpass filter interface
*/
#ifndef FFMPEG_LOWPASS_H
#define FFMPEG_LOWPASS_H
#include "avcodec.h"
struct FFLPFilterCoeffs;
struct FFLPFilterState;
/**
* Initialize filter coefficients.
*
* @param order filter order
* @param cutoff_ratio cutoff to input frequency ratio
*
* @return pointer to filter coefficients structure or NULL if filter cannot be created
*/
const struct FFLPFilterCoeffs* ff_lowpass_filter_init_coeffs(int order, float cutoff_ratio);
/**
* Create new filter state.
*
* @param order filter order
*
* @return pointer to new filter state or NULL if state creation fails
*/
struct FFLPFilterState* ff_lowpass_filter_init_state(int order);
#if 0 //enable with arbitrary order filter implementation, use av_free() for filter state only for now
/**
* Free filter coefficients.
*
* @param coeffs pointer allocated with ff_lowpass_filter_init_coeffs()
*/
void ff_lowpass_filter_free_coeffs(struct FFLPFilterCoeffs *coeffs);
/**
* Free filter state.
*
* @param state pointer allocated with ff_lowpass_filter_init_state()
*/
void ff_lowpass_filter_free_state(struct FFLPFilterState *state);
#endif
/**
* Perform lowpass filtering on input samples.
*
* @param coeffs pointer to filter coefficients
* @param state pointer to filter state
* @param size input length
* @param src source samples
* @param sstep source stride
* @param dst filtered samples (destination may be the same as input)
* @param dstep destination stride
*/
void ff_lowpass_filter(const struct FFLPFilterCoeffs *coeffs, struct FFLPFilterState *state, int size, int16_t *src, int sstep, int16_t *dst, int dstep);
#endif /* FFMPEG_LOWPASS_H */
@@ -0,0 +1,205 @@
/**
* LPC utility code
* Copyright (c) 2006 Justin Ruggles <[email protected]>
*
* 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
*/
#include "lls.h"
#include "dsputil.h"
#include "lpc.h"
/**
* Levinson-Durbin recursion.
* Produces LPC coefficients from autocorrelation data.
*/
static void compute_lpc_coefs(const double *autoc, int max_order,
double lpc[][MAX_LPC_ORDER], double *ref)
{
int i, j, i2;
double r, err, tmp;
double lpc_tmp[MAX_LPC_ORDER];
for(i=0; i<max_order; i++) lpc_tmp[i] = 0;
err = autoc[0];
for(i=0; i<max_order; i++) {
r = -autoc[i+1];
for(j=0; j<i; j++) {
r -= lpc_tmp[j] * autoc[i-j];
}
r /= err;
ref[i] = fabs(r);
err *= 1.0 - (r * r);
i2 = (i >> 1);
lpc_tmp[i] = r;
for(j=0; j<i2; j++) {
tmp = lpc_tmp[j];
lpc_tmp[j] += r * lpc_tmp[i-1-j];
lpc_tmp[i-1-j] += r * tmp;
}
if(i & 1) {
lpc_tmp[j] += lpc_tmp[j] * r;
}
for(j=0; j<=i; j++) {
lpc[i][j] = -lpc_tmp[j];
}
}
}
/**
* Quantize LPC coefficients
*/
static void quantize_lpc_coefs(double *lpc_in, int order, int precision,
int32_t *lpc_out, int *shift, int max_shift, int zero_shift)
{
int i;
double cmax, error;
int32_t qmax;
int sh;
/* define maximum levels */
qmax = (1 << (precision - 1)) - 1;
/* find maximum coefficient value */
cmax = 0.0;
for(i=0; i<order; i++) {
cmax= FFMAX(cmax, fabs(lpc_in[i]));
}
/* if maximum value quantizes to zero, return all zeros */
if(cmax * (1 << max_shift) < 1.0) {
*shift = zero_shift;
memset(lpc_out, 0, sizeof(int32_t) * order);
return;
}
/* calculate level shift which scales max coeff to available bits */
sh = max_shift;
while((cmax * (1 << sh) > qmax) && (sh > 0)) {
sh--;
}
/* since negative shift values are unsupported in decoder, scale down
coefficients instead */
if(sh == 0 && cmax > qmax) {
double scale = ((double)qmax) / cmax;
for(i=0; i<order; i++) {
lpc_in[i] *= scale;
}
}
/* output quantized coefficients and level shift */
error=0;
for(i=0; i<order; i++) {
error += lpc_in[i] * (1 << sh);
lpc_out[i] = av_clip(lrintf(error), -qmax, qmax);
error -= lpc_out[i];
}
*shift = sh;
}
static int estimate_best_order(double *ref, int min_order, int max_order)
{
int i, est;
est = min_order;
for(i=max_order-1; i>=min_order-1; i--) {
if(ref[i] > 0.10) {
est = i+1;
break;
}
}
return est;
}
/**
* Calculate LPC coefficients for multiple orders
*/
int ff_lpc_calc_coefs(DSPContext *s,
const int32_t *samples, int blocksize, int min_order,
int max_order, int precision,
int32_t coefs[][MAX_LPC_ORDER], int *shift, int use_lpc,
int omethod, int max_shift, int zero_shift)
{
double autoc[MAX_LPC_ORDER+1];
double ref[MAX_LPC_ORDER];
double lpc[MAX_LPC_ORDER][MAX_LPC_ORDER];
int i, j, pass;
int opt_order;
assert(max_order >= MIN_LPC_ORDER && max_order <= MAX_LPC_ORDER);
if(use_lpc == 1){
s->flac_compute_autocorr(samples, blocksize, max_order, autoc);
compute_lpc_coefs(autoc, max_order, lpc, ref);
}else{
LLSModel m[2];
double var[MAX_LPC_ORDER+1], weight;
for(pass=0; pass<use_lpc-1; pass++){
av_init_lls(&m[pass&1], max_order);
weight=0;
for(i=max_order; i<blocksize; i++){
for(j=0; j<=max_order; j++)
var[j]= samples[i-j];
if(pass){
double eval, inv, rinv;
eval= av_evaluate_lls(&m[(pass-1)&1], var+1, max_order-1);
eval= (512>>pass) + fabs(eval - var[0]);
inv = 1/eval;
rinv = sqrt(inv);
for(j=0; j<=max_order; j++)
var[j] *= rinv;
weight += inv;
}else
weight++;
av_update_lls(&m[pass&1], var, 1.0);
}
av_solve_lls(&m[pass&1], 0.001, 0);
}
for(i=0; i<max_order; i++){
for(j=0; j<max_order; j++)
lpc[i][j]= m[(pass-1)&1].coeff[i][j];
ref[i]= sqrt(m[(pass-1)&1].variance[i] / weight) * (blocksize - max_order) / 4000;
}
for(i=max_order-1; i>0; i--)
ref[i] = ref[i-1] - ref[i];
}
opt_order = max_order;
if(omethod == ORDER_METHOD_EST) {
opt_order = estimate_best_order(ref, min_order, max_order);
i = opt_order-1;
quantize_lpc_coefs(lpc[i], i+1, precision, coefs[i], &shift[i], max_shift, zero_shift);
} else {
for(i=min_order-1; i<max_order; i++) {
quantize_lpc_coefs(lpc[i], i+1, precision, coefs[i], &shift[i], max_shift, zero_shift);
}
}
return opt_order;
}
@@ -0,0 +1,48 @@
/**
* LPC utility code
* Copyright (c) 2006 Justin Ruggles <[email protected]>
*
* 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
*/
#ifndef FFMPEG_LPC_H
#define FFMPEG_LPC_H
#include <stdint.h>
#include "dsputil.h"
#define ORDER_METHOD_EST 0
#define ORDER_METHOD_2LEVEL 1
#define ORDER_METHOD_4LEVEL 2
#define ORDER_METHOD_8LEVEL 3
#define ORDER_METHOD_SEARCH 4
#define ORDER_METHOD_LOG 5
#define MIN_LPC_ORDER 1
#define MAX_LPC_ORDER 32
/**
* Calculate LPC coefficients for multiple orders
*/
int ff_lpc_calc_coefs(DSPContext *s,
const int32_t *samples, int blocksize, int min_order,
int max_order, int precision,
int32_t coefs[][MAX_LPC_ORDER], int *shift, int use_lpc,
int omethod, int max_shift, int zero_shift);
#endif /* FFMPEG_LPC_H */
@@ -0,0 +1,120 @@
/*
* LSP routines for ACELP-based codecs
*
* Copyright (c) 2008 Vladimir Voroshilov
*
* 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
*/
#include <inttypes.h>
#include "avcodec.h"
#define FRAC_BITS 14
#include "mathops.h"
#include "lsp.h"
#include "acelp_math.h"
void ff_acelp_reorder_lsf(int16_t* lsfq, int lsfq_min_distance, int lsfq_min, int lsfq_max, int lp_order)
{
int i, j;
/* sort lsfq in ascending order. float bubble agorithm,
O(n) if data already sorted, O(n^2) - otherwise */
for(i=0; i<lp_order-1; i++)
for(j=i; j>=0 && lsfq[j] > lsfq[j+1]; j--)
FFSWAP(int16_t, lsfq[j], lsfq[j+1]);
for(i=0; i<lp_order; i++)
{
lsfq[i] = FFMAX(lsfq[i], lsfq_min);
lsfq_min = lsfq[i] + lsfq_min_distance;
}
lsfq[lp_order-1] = FFMIN(lsfq[lp_order-1], lsfq_max);//Is warning required ?
}
void ff_acelp_lsf2lsp(int16_t *lsp, const int16_t *lsf, int lp_order)
{
int i;
/* Convert LSF to LSP, lsp=cos(lsf) */
for(i=0; i<lp_order; i++)
// 20861 = 2.0 / PI in (0.15)
lsp[i] = ff_cos(lsf[i] * 20861 >> 15); // divide by PI and (0,13) -> (0,14)
}
/**
* \brief decodes polynomial coefficients from LSP
* \param f [out] decoded polynomial coefficients (-0x20000000 <= (3.22) <= 0x1fffffff)
* \param lsp LSP coefficients (-0x8000 <= (0.15) <= 0x7fff)
*/
static void lsp2poly(int* f, const int16_t* lsp, int lp_half_order)
{
int i, j;
f[0] = 0x400000; // 1.0 in (3.22)
f[1] = -lsp[0] << 8; // *2 and (0.15) -> (3.22)
for(i=2; i<=lp_half_order; i++)
{
f[i] = f[i-2];
for(j=i; j>1; j--)
f[j] -= MULL(f[j-1], lsp[2*i-2]) - f[j-2]; // (3.22) * (0.15) * 2 -> (3.22)
f[1] -= lsp[2*i-2] << 8;
}
}
void ff_acelp_lsp2lpc(int16_t* lp, const int16_t* lsp, int lp_half_order)
{
int i;
int f1[lp_half_order+1]; // (3.22)
int f2[lp_half_order+1]; // (3.22)
lsp2poly(f1, lsp , lp_half_order);
lsp2poly(f2, lsp+1, lp_half_order);
/* 3.2.6 of G.729, Equations 25 and 26*/
lp[0] = 4096;
for(i=1; i<lp_half_order+1; i++)
{
int ff1 = f1[i] + f1[i-1]; // (3.22)
int ff2 = f2[i] - f2[i-1]; // (3.22)
ff1 += 1 << 10; // for rounding
lp[i] = (ff1 + ff2) >> 11; // divide by 2 and (3.22) -> (3.12)
lp[(lp_half_order << 1) + 1 - i] = (ff1 - ff2) >> 11; // divide by 2 and (3.22) -> (3.12)
}
}
void ff_acelp_lp_decode(int16_t* lp_1st, int16_t* lp_2nd, const int16_t* lsp_2nd, const int16_t* lsp_prev, int lp_order)
{
int16_t lsp_1st[lp_order]; // (0.15)
int i;
/* LSP values for first subframe (3.2.5 of G.729, Equation 24)*/
for(i=0; i<lp_order; i++)
#ifdef G729_BITEXACT
lsp_1st[i] = (lsp_2nd[i] >> 1) + (lsp_prev[i] >> 1);
#else
lsp_1st[i] = (lsp_2nd[i] + lsp_prev[i]) >> 1;
#endif
ff_acelp_lsp2lpc(lp_1st, lsp_1st, lp_order >> 1);
/* LSP values for second subframe (3.2.5 of G.729)*/
ff_acelp_lsp2lpc(lp_2nd, lsp_2nd, lp_order >> 1);
}
@@ -0,0 +1,70 @@
/*
* LSP computing for ACELP-based codecs
*
* Copyright (c) 2008 Vladimir Voroshilov
*
* 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
*/
#ifndef FFMPEG_LSP_H
#define FFMPEG_LSP_H
#include <stdint.h>
/**
(I.F) means fixed-point value with F fractional and I integer bits
*/
/**
* \brief ensure a minimum distance between LSFs
* \param lsfq [in/out] LSF to check and adjust
* \param lsfq_min_distance minimum distance between LSFs
* \param lsfq_min minimum allowed LSF value
* \param lsfq_max maximum allowed LSF value
* \param lp_order LP filter order
*/
void ff_acelp_reorder_lsf(int16_t* lsfq, int lsfq_min_distance, int lsfq_min, int lsfq_max, int lp_order);
/**
* \brief Convert LSF to LSP
* \param lsp [out] LSP coefficients (-0x8000 <= (0.15) < 0x8000)
* \param lsf normalized LSF coefficients (0 <= (2.13) < 0x2000 * PI)
* \param lp_order LP filter order
*
* \remark It is safe to pass the same array into the lsf and lsp parameters.
*/
void ff_acelp_lsf2lsp(int16_t *lsp, const int16_t *lsf, int lp_order);
/**
* \brief LSP to LP conversion (3.2.6 of G.729)
* \param lp [out] decoded LP coefficients (-0x8000 <= (3.12) < 0x8000)
* \param lsp LSP coefficients (-0x8000 <= (0.15) < 0x8000)
* \param lp_half_order LP filter order, divided by 2
*/
void ff_acelp_lsp2lpc(int16_t* lp, const int16_t* lsp, int lp_half_order);
/**
* \brief Interpolate LSP for the first subframe and convert LSP -> LP for both subframes (3.2.5 and 3.2.6 of G.729)
* \param lp_1st [out] decoded LP coefficients for first subframe (-0x8000 <= (3.12) < 0x8000)
* \param lp_2nd [out] decoded LP coefficients for second subframe (-0x8000 <= (3.12) < 0x8000)
* \param lsp_2nd LSP coefficients of the second subframe (-0x8000 <= (0.15) < 0x8000)
* \param lsp_prev LSP coefficients from the second subframe of the previous frame (-0x8000 <= (0.15) < 0x8000)
* \param lp_order LP filter order
*/
void ff_acelp_lp_decode(int16_t* lp_1st, int16_t* lp_2nd, const int16_t* lsp_2nd, const int16_t* lsp_prev, int lp_order);
#endif /* FFMPEG_LSP_H */
@@ -0,0 +1,229 @@
/*
* LZW decoder
* Copyright (c) 2003 Fabrice Bellard.
* Copyright (c) 2006 Konstantin Shishkov.
*
* 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 lzw.c
* @brief LZW decoding routines
* @author Fabrice Bellard
* Modified for use in TIFF by Konstantin Shishkov
*/
#include "avcodec.h"
#include "lzw.h"
#define LZW_MAXBITS 12
#define LZW_SIZTABLE (1<<LZW_MAXBITS)
static const uint16_t mask[17] =
{
0x0000, 0x0001, 0x0003, 0x0007,
0x000F, 0x001F, 0x003F, 0x007F,
0x00FF, 0x01FF, 0x03FF, 0x07FF,
0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF
};
struct LZWState {
const uint8_t *pbuf, *ebuf;
int bbits;
unsigned int bbuf;
int mode; ///< Decoder mode
int cursize; ///< The current code size
int curmask;
int codesize;
int clear_code;
int end_code;
int newcodes; ///< First available code
int top_slot; ///< Highest code for current size
int extra_slot;
int slot; ///< Last read code
int fc, oc;
uint8_t *sp;
uint8_t stack[LZW_SIZTABLE];
uint8_t suffix[LZW_SIZTABLE];
uint16_t prefix[LZW_SIZTABLE];
int bs; ///< current buffer size for GIF
};
/* get one code from stream */
static int lzw_get_code(struct LZWState * s)
{
int c;
if(s->mode == FF_LZW_GIF) {
while (s->bbits < s->cursize) {
if (!s->bs) {
s->bs = *s->pbuf++;
}
s->bbuf |= (*s->pbuf++) << s->bbits;
s->bbits += 8;
s->bs--;
}
c = s->bbuf;
s->bbuf >>= s->cursize;
} else { // TIFF
while (s->bbits < s->cursize) {
s->bbuf = (s->bbuf << 8) | (*s->pbuf++);
s->bbits += 8;
}
c = s->bbuf >> (s->bbits - s->cursize);
}
s->bbits -= s->cursize;
return c & s->curmask;
}
const uint8_t* ff_lzw_cur_ptr(LZWState *p)
{
return ((struct LZWState*)p)->pbuf;
}
void ff_lzw_decode_tail(LZWState *p)
{
struct LZWState *s = (struct LZWState *)p;
if(s->mode == FF_LZW_GIF) {
while(s->pbuf < s->ebuf && s->bs>0){
s->pbuf += s->bs;
s->bs = *s->pbuf++;
}
}else
s->pbuf= s->ebuf;
}
av_cold void ff_lzw_decode_open(LZWState **p)
{
*p = av_mallocz(sizeof(struct LZWState));
}
av_cold void ff_lzw_decode_close(LZWState **p)
{
av_freep(p);
}
/**
* Initialize LZW decoder
* @param s LZW context
* @param csize initial code size in bits
* @param buf input data
* @param buf_size input data size
* @param mode decoder working mode - either GIF or TIFF
*/
int ff_lzw_decode_init(LZWState *p, int csize, const uint8_t *buf, int buf_size, int mode)
{
struct LZWState *s = (struct LZWState *)p;
if(csize < 1 || csize >= LZW_MAXBITS)
return -1;
/* read buffer */
s->pbuf = buf;
s->ebuf = s->pbuf + buf_size;
s->bbuf = 0;
s->bbits = 0;
s->bs = 0;
/* decoder */
s->codesize = csize;
s->cursize = s->codesize + 1;
s->curmask = mask[s->cursize];
s->top_slot = 1 << s->cursize;
s->clear_code = 1 << s->codesize;
s->end_code = s->clear_code + 1;
s->slot = s->newcodes = s->clear_code + 2;
s->oc = s->fc = -1;
s->sp = s->stack;
s->mode = mode;
s->extra_slot = s->mode == FF_LZW_TIFF;
return 0;
}
/**
* Decode given number of bytes
* NOTE: the algorithm here is inspired from the LZW GIF decoder
* written by Steven A. Bennett in 1987.
*
* @param s LZW context
* @param buf output buffer
* @param len number of bytes to decode
* @return number of bytes decoded
*/
int ff_lzw_decode(LZWState *p, uint8_t *buf, int len){
int l, c, code, oc, fc;
uint8_t *sp;
struct LZWState *s = (struct LZWState *)p;
if (s->end_code < 0)
return 0;
l = len;
sp = s->sp;
oc = s->oc;
fc = s->fc;
for (;;) {
while (sp > s->stack) {
*buf++ = *(--sp);
if ((--l) == 0)
goto the_end;
}
c = lzw_get_code(s);
if (c == s->end_code) {
break;
} else if (c == s->clear_code) {
s->cursize = s->codesize + 1;
s->curmask = mask[s->cursize];
s->slot = s->newcodes;
s->top_slot = 1 << s->cursize;
fc= oc= -1;
} else {
code = c;
if (code == s->slot && fc>=0) {
*sp++ = fc;
code = oc;
}else if(code >= s->slot)
break;
while (code >= s->newcodes) {
*sp++ = s->suffix[code];
code = s->prefix[code];
}
*sp++ = code;
if (s->slot < s->top_slot && oc>=0) {
s->suffix[s->slot] = code;
s->prefix[s->slot++] = oc;
}
fc = code;
oc = c;
if (s->slot >= s->top_slot - s->extra_slot) {
if (s->cursize < LZW_MAXBITS) {
s->top_slot <<= 1;
s->curmask = mask[++s->cursize];
}
}
}
}
s->end_code = -1;
the_end:
s->sp = sp;
s->oc = oc;
s->fc = fc;
return len - l;
}
@@ -0,0 +1,59 @@
/*
* LZW decoder
* Copyright (c) 2003 Fabrice Bellard.
* Copyright (c) 2006 Konstantin Shishkov.
*
* 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 lzw.h
* @brief LZW decoding routines
* @author Fabrice Bellard
* Modified for use in TIFF by Konstantin Shishkov
*/
#ifndef FFMPEG_LZW_H
#define FFMPEG_LZW_H
#include "bitstream.h"
enum FF_LZW_MODES{
FF_LZW_GIF,
FF_LZW_TIFF
};
/* clients should not know what LZWState is */
typedef void LZWState;
/* first two functions de/allocate memory for LZWState */
void ff_lzw_decode_open(LZWState **p);
void ff_lzw_decode_close(LZWState **p);
int ff_lzw_decode_init(LZWState *s, int csize, const uint8_t *buf, int buf_size, int mode);
int ff_lzw_decode(LZWState *s, uint8_t *buf, int len);
const uint8_t* ff_lzw_cur_ptr(LZWState *lzw);
void ff_lzw_decode_tail(LZWState *lzw);
/** LZW encode state */
struct LZWEncodeState;
extern const int ff_lzw_encode_state_size;
void ff_lzw_encode_init(struct LZWEncodeState * s, uint8_t * outbuf, int outsize, int maxbits);
int ff_lzw_encode(struct LZWEncodeState * s, const uint8_t * inbuf, int insize);
int ff_lzw_encode_flush(struct LZWEncodeState * s);
#endif /* FFMPEG_LZW_H */
@@ -0,0 +1,262 @@
/*
* LZW encoder
* Copyright (c) 2007 Bartlomiej Wolowiec
*
* 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
*/
/**
* LZW encoder
* @file lzwenc.c
* @author Bartlomiej Wolowiec
*/
#include "avcodec.h"
#include "bitstream.h"
#include "lzw.h"
#define LZW_MAXBITS 12
#define LZW_SIZTABLE (1<<LZW_MAXBITS)
#define LZW_HASH_SIZE 16411
#define LZW_HASH_SHIFT 6
#define LZW_PREFIX_EMPTY -1
#define LZW_PREFIX_FREE -2
/** One code in hash table */
typedef struct Code{
/// Hash code of prefix, LZW_PREFIX_EMPTY if empty prefix, or LZW_PREFIX_FREE if no code
int hash_prefix;
int code; ///< LZW code
uint8_t suffix; ///< Last character in code block
}Code;
/** LZW encode state */
typedef struct LZWEncodeState {
int clear_code; ///< Value of clear code
int end_code; ///< Value of end code
Code tab[LZW_HASH_SIZE]; ///< Hash table
int tabsize; ///< Number of values in hash table
int bits; ///< Actual bits code
int bufsize; ///< Size of output buffer
PutBitContext pb; ///< Put bit context for output
int maxbits; ///< Max bits code
int maxcode; ///< Max value of code
int output_bytes; ///< Number of written bytes
int last_code; ///< Value of last output code or LZW_PREFIX_EMPTY
}LZWEncodeState;
const int ff_lzw_encode_state_size = sizeof(LZWEncodeState);
/**
* Hash function adding character
* @param head LZW code for prefix
* @param add Character to add
* @return New hash value
*/
static inline int hash(int head, const int add)
{
head ^= (add << LZW_HASH_SHIFT);
if (head >= LZW_HASH_SIZE)
head -= LZW_HASH_SIZE;
assert(head >= 0 && head < LZW_HASH_SIZE);
return head;
}
/**
* Hash function calculates next hash value
* @param head Actual hash code
* @param offset Offset calculated by hashOffset
* @return New hash value
*/
static inline int hashNext(int head, const int offset)
{
head -= offset;
if(head < 0)
head += LZW_HASH_SIZE;
return head;
}
/**
* Hash function calculates hash offset
* @param head Actual hash code
* @return Hash offset
*/
static inline int hashOffset(const int head)
{
return head ? LZW_HASH_SIZE - head : 1;
}
/**
* Write one code to stream
* @param s LZW state
* @param c code to write
*/
static inline void writeCode(LZWEncodeState * s, int c)
{
assert(0 <= c && c < 1 << s->bits);
put_bits(&s->pb, s->bits, c);
}
/**
* Find LZW code for block
* @param s LZW state
* @param c Last character in block
* @param hash_prefix LZW code for prefix
* @return LZW code for block or -1 if not found in table
*/
static inline int findCode(LZWEncodeState * s, uint8_t c, int hash_prefix)
{
int h = hash(FFMAX(hash_prefix, 0), c);
int hash_offset = hashOffset(h);
while (s->tab[h].hash_prefix != LZW_PREFIX_FREE) {
if ((s->tab[h].suffix == c)
&& (s->tab[h].hash_prefix == hash_prefix))
return h;
h = hashNext(h, hash_offset);
}
return h;
}
/**
* Add block to LZW code table
* @param s LZW state
* @param c Last character in block
* @param hash_prefix LZW code for prefix
* @param hash_code LZW code for bytes block
*/
static inline void addCode(LZWEncodeState * s, uint8_t c, int hash_prefix, int hash_code)
{
s->tab[hash_code].code = s->tabsize;
s->tab[hash_code].suffix = c;
s->tab[hash_code].hash_prefix = hash_prefix;
s->tabsize++;
if (s->tabsize >= 1 << s->bits)
s->bits++;
}
/**
* Clear LZW code table
* @param s LZW state
*/
static void clearTable(LZWEncodeState * s)
{
int i, h;
writeCode(s, s->clear_code);
s->bits = 9;
for (i = 0; i < LZW_HASH_SIZE; i++) {
s->tab[i].hash_prefix = LZW_PREFIX_FREE;
}
for (i = 0; i < 256; i++) {
h = hash(0, i);
s->tab[h].code = i;
s->tab[h].suffix = i;
s->tab[h].hash_prefix = LZW_PREFIX_EMPTY;
}
s->tabsize = 258;
}
/**
* Calculate number of bytes written
* @param s LZW encode state
* @return Number of bytes written
*/
static int writtenBytes(LZWEncodeState *s){
int ret = put_bits_count(&s->pb) >> 3;
ret -= s->output_bytes;
s->output_bytes += ret;
return ret;
}
/**
* Initialize LZW encoder. Please set s->clear_code, s->end_code and s->maxbits before run.
* @param s LZW state
* @param outbuf Output buffer
* @param outsize Size of output buffer
* @param maxbits Maximum length of code
*/
void ff_lzw_encode_init(LZWEncodeState * s, uint8_t * outbuf, int outsize, int maxbits)
{
s->clear_code = 256;
s->end_code = 257;
s->maxbits = maxbits;
init_put_bits(&s->pb, outbuf, outsize);
s->bufsize = outsize;
assert(9 <= s->maxbits && s->maxbits <= s->maxbits);
s->maxcode = 1 << s->maxbits;
s->output_bytes = 0;
s->last_code = LZW_PREFIX_EMPTY;
s->bits = 9;
}
/**
* LZW main compress function
* @param s LZW state
* @param inbuf Input buffer
* @param insize Size of input buffer
* @return Number of bytes written or -1 on error
*/
int ff_lzw_encode(LZWEncodeState * s, const uint8_t * inbuf, int insize)
{
int i;
if(insize * 3 > (s->bufsize - s->output_bytes) * 2){
return -1;
}
if (s->last_code == LZW_PREFIX_EMPTY)
clearTable(s);
for (i = 0; i < insize; i++) {
uint8_t c = *inbuf++;
int code = findCode(s, c, s->last_code);
if (s->tab[code].hash_prefix == LZW_PREFIX_FREE) {
writeCode(s, s->last_code);
addCode(s, c, s->last_code, code);
code= hash(0, c);
}
s->last_code = s->tab[code].code;
if (s->tabsize >= s->maxcode - 1) {
clearTable(s);
}
}
return writtenBytes(s);
}
/**
* Write end code and flush bitstream
* @param s LZW state
* @return Number of bytes written or -1 on error
*/
int ff_lzw_encode_flush(LZWEncodeState * s)
{
if (s->last_code != -1)
writeCode(s, s->last_code);
writeCode(s, s->end_code);
flush_put_bits(&s->pb);
s->last_code = -1;
return writtenBytes(s);
}