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:
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user