Update avcodec to 20080825

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27560 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
David McPaul
2008-09-15 14:11:11 +00:00
parent 6bac4c81c5
commit eaa51ccd98
15 changed files with 4852 additions and 141 deletions
@@ -0,0 +1,254 @@
/*
* Targa (.tga) image decoder
* 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
*/
#include "avcodec.h"
enum TargaCompr{
TGA_NODATA = 0, // no image data
TGA_PAL = 1, // palettized
TGA_RGB = 2, // true-color
TGA_BW = 3, // black & white or grayscale
TGA_RLE = 8, // flag pointing that data is RLE-coded
};
typedef struct TargaContext {
AVFrame picture;
int width, height;
int bpp;
int color_type;
int compression_type;
} TargaContext;
static void targa_decode_rle(AVCodecContext *avctx, TargaContext *s, const uint8_t *src, uint8_t *dst, int w, int h, int stride, int bpp)
{
int i, x, y;
int depth = (bpp + 1) >> 3;
int type, count;
int diff;
diff = stride - w * depth;
x = y = 0;
while(y < h){
type = *src++;
count = (type & 0x7F) + 1;
type &= 0x80;
if((x + count > w) && (x + count + 1 > (h - y) * w)){
av_log(avctx, AV_LOG_ERROR, "Packet went out of bounds: position (%i,%i) size %i\n", x, y, count);
return;
}
for(i = 0; i < count; i++){
switch(depth){
case 1:
*dst = *src;
break;
case 2:
*((uint16_t*)dst) = AV_RL16(src);
break;
case 3:
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[2];
break;
case 4:
*((uint32_t*)dst) = AV_RL32(src);
break;
}
dst += depth;
if(!type)
src += depth;
x++;
if(x == w){
x = 0;
y++;
dst += diff;
}
}
if(type)
src += depth;
}
}
static int decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
const uint8_t *buf, int buf_size)
{
TargaContext * const s = avctx->priv_data;
AVFrame *picture = data;
AVFrame * const p= (AVFrame*)&s->picture;
uint8_t *dst;
int stride;
int idlen, pal, compr, x, y, w, h, bpp, flags;
int first_clr, colors, csize;
/* parse image header */
idlen = *buf++;
pal = *buf++;
compr = *buf++;
first_clr = AV_RL16(buf); buf += 2;
colors = AV_RL16(buf); buf += 2;
csize = *buf++;
x = AV_RL16(buf); buf += 2;
y = AV_RL16(buf); buf += 2;
w = AV_RL16(buf); buf += 2;
h = AV_RL16(buf); buf += 2;
bpp = *buf++;
flags = *buf++;
//skip identifier if any
buf += idlen;
s->bpp = bpp;
s->width = w;
s->height = h;
switch(s->bpp){
case 8:
avctx->pix_fmt = ((compr & (~TGA_RLE)) == TGA_BW) ? PIX_FMT_GRAY8 : PIX_FMT_PAL8;
break;
case 15:
avctx->pix_fmt = PIX_FMT_RGB555;
break;
case 16:
avctx->pix_fmt = PIX_FMT_RGB555;
break;
case 24:
avctx->pix_fmt = PIX_FMT_BGR24;
break;
case 32:
avctx->pix_fmt = PIX_FMT_RGB32;
break;
default:
av_log(avctx, AV_LOG_ERROR, "Bit depth %i is not supported\n", s->bpp);
return -1;
}
if(s->picture.data[0])
avctx->release_buffer(avctx, &s->picture);
if(avcodec_check_dimensions(avctx, w, h))
return -1;
if(w != avctx->width || h != avctx->height)
avcodec_set_dimensions(avctx, w, h);
if(avctx->get_buffer(avctx, p) < 0){
av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
return -1;
}
if(flags & 0x20){
dst = p->data[0];
stride = p->linesize[0];
}else{ //image is upside-down
dst = p->data[0] + p->linesize[0] * (h - 1);
stride = -p->linesize[0];
}
if(avctx->pix_fmt == PIX_FMT_PAL8 && avctx->palctrl){
memcpy(p->data[1], avctx->palctrl->palette, AVPALETTE_SIZE);
if(avctx->palctrl->palette_changed){
p->palette_has_changed = 1;
avctx->palctrl->palette_changed = 0;
}
}
if(colors){
if((colors + first_clr) > 256){
av_log(avctx, AV_LOG_ERROR, "Incorrect palette: %i colors with offset %i\n", colors, first_clr);
return -1;
}
if(csize != 24){
av_log(avctx, AV_LOG_ERROR, "Palette entry size %i bits is not supported\n", csize);
return -1;
}
if(avctx->pix_fmt != PIX_FMT_PAL8)//should not occur but skip palette anyway
buf += colors * ((csize + 1) >> 3);
else{
int r, g, b, t;
int32_t *pal = ((int32_t*)p->data[1]) + first_clr;
for(t = 0; t < colors; t++){
r = *buf++;
g = *buf++;
b = *buf++;
*pal++ = (b << 16) | (g << 8) | r;
}
p->palette_has_changed = 1;
avctx->palctrl->palette_changed = 0;
}
}
if((compr & (~TGA_RLE)) == TGA_NODATA)
memset(p->data[0], 0, p->linesize[0] * s->height);
else{
if(compr & TGA_RLE)
targa_decode_rle(avctx, s, buf, dst, avctx->width, avctx->height, stride, bpp);
else{
for(y = 0; y < s->height; y++){
#ifdef WORDS_BIGENDIAN
if((s->bpp + 1) >> 3 == 2){
uint16_t *dst16 = (uint16_t*)dst;
for(x = 0; x < s->width; x++)
dst16[x] = AV_RL16(buf + x * 2);
}else if((s->bpp + 1) >> 3 == 4){
uint32_t *dst32 = (uint32_t*)dst;
for(x = 0; x < s->width; x++)
dst32[x] = AV_RL32(buf + x * 4);
}else
#endif
memcpy(dst, buf, s->width * ((s->bpp + 1) >> 3));
dst += stride;
buf += s->width * ((s->bpp + 1) >> 3);
}
}
}
*picture= *(AVFrame*)&s->picture;
*data_size = sizeof(AVPicture);
return buf_size;
}
static av_cold int targa_init(AVCodecContext *avctx){
TargaContext *s = avctx->priv_data;
avcodec_get_frame_defaults((AVFrame*)&s->picture);
avctx->coded_frame= (AVFrame*)&s->picture;
s->picture.data[0] = NULL;
return 0;
}
static av_cold int targa_end(AVCodecContext *avctx){
TargaContext *s = avctx->priv_data;
if(s->picture.data[0])
avctx->release_buffer(avctx, &s->picture);
return 0;
}
AVCodec targa_decoder = {
"targa",
CODEC_TYPE_VIDEO,
CODEC_ID_TARGA,
sizeof(TargaContext),
targa_init,
NULL,
targa_end,
decode_frame,
0,
NULL,
.long_name = NULL_IF_CONFIG_SMALL("Truevision Targa image"),
};
@@ -0,0 +1,160 @@
/*
* Targa (.tga) image encoder
* Copyright (c) 2007 Bobby Bingham
*
* 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 "rle.h"
typedef struct TargaContext {
AVFrame picture;
} TargaContext;
/**
* RLE compress the image, with maximum size of out_size
* @param outbuf Output buffer
* @param out_size Maximum output size
* @param pic Image to compress
* @param bpp Bytes per pixel
* @param w Image width
* @param h Image height
* @return Size of output in bytes, or -1 if larger than out_size
*/
static int targa_encode_rle(uint8_t *outbuf, int out_size, AVFrame *pic,
int bpp, int w, int h)
{
int y,ret;
uint8_t *out;
out = outbuf;
for(y = 0; y < h; y ++) {
ret = ff_rle_encode(out, out_size, pic->data[0] + pic->linesize[0] * y, bpp, w, 0x7f, 0, -1, 0);
if(ret == -1){
return -1;
}
out+= ret;
out_size -= ret;
}
return out - outbuf;
}
static int targa_encode_normal(uint8_t *outbuf, AVFrame *pic, int bpp, int w, int h)
{
int i, n = bpp * w;
uint8_t *out = outbuf;
uint8_t *ptr = pic->data[0];
for(i=0; i < h; i++) {
memcpy(out, ptr, n);
out += n;
ptr += pic->linesize[0];
}
return out - outbuf;
}
static int targa_encode_frame(AVCodecContext *avctx,
unsigned char *outbuf,
int buf_size, void *data){
AVFrame *p = data;
int bpp, picsize, datasize;
uint8_t *out;
if(avctx->width > 0xffff || avctx->height > 0xffff) {
av_log(avctx, AV_LOG_ERROR, "image dimensions too large\n");
return -1;
}
picsize = avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height);
if(buf_size < picsize + 45) {
av_log(avctx, AV_LOG_ERROR, "encoded frame too large\n");
return -1;
}
p->pict_type= FF_I_TYPE;
p->key_frame= 1;
/* zero out the header and only set applicable fields */
memset(outbuf, 0, 12);
AV_WL16(outbuf+12, avctx->width);
AV_WL16(outbuf+14, avctx->height);
outbuf[17] = 0x20; /* origin is top-left. no alpha */
/* TODO: support alpha channel */
switch(avctx->pix_fmt) {
case PIX_FMT_GRAY8:
outbuf[2] = 3; /* uncompressed grayscale image */
outbuf[16] = 8; /* bpp */
break;
case PIX_FMT_RGB555:
outbuf[2] = 2; /* uncompresses true-color image */
outbuf[16] = 16; /* bpp */
break;
case PIX_FMT_BGR24:
outbuf[2] = 2; /* uncompressed true-color image */
outbuf[16] = 24; /* bpp */
break;
default:
return -1;
}
bpp = outbuf[16] >> 3;
out = outbuf + 18; /* skip past the header we just output */
/* try RLE compression */
datasize = targa_encode_rle(out, picsize, p, bpp, avctx->width, avctx->height);
/* if that worked well, mark the picture as RLE compressed */
if(datasize >= 0)
outbuf[2] |= 8;
/* if RLE didn't make it smaller, go back to no compression */
else datasize = targa_encode_normal(out, p, bpp, avctx->width, avctx->height);
out += datasize;
/* The standard recommends including this section, even if we don't use
* any of the features it affords. TODO: take advantage of the pixel
* aspect ratio and encoder ID fields available? */
memcpy(out, "\0\0\0\0\0\0\0\0TRUEVISION-XFILE.", 26);
return out + 26 - outbuf;
}
static av_cold int targa_encode_init(AVCodecContext *avctx)
{
TargaContext *s = avctx->priv_data;
avcodec_get_frame_defaults(&s->picture);
s->picture.key_frame= 1;
avctx->coded_frame= &s->picture;
return 0;
}
AVCodec targa_encoder = {
.name = "targa",
.type = CODEC_TYPE_VIDEO,
.id = CODEC_ID_TARGA,
.priv_data_size = sizeof(TargaContext),
.init = targa_encode_init,
.encode = targa_encode_frame,
.pix_fmts= (enum PixelFormat[]){PIX_FMT_BGR24, PIX_FMT_RGB555, PIX_FMT_GRAY8, PIX_FMT_NONE},
.long_name= NULL_IF_CONFIG_SMALL("Truevision Targa image"),
};
@@ -0,0 +1,304 @@
4xm.c
8bps.c
8svx.c
aac.c
aac_ac3_parser.c
aac_parser.c
aacenc.c
aacpsy.c
aactab.c
aasc.c
ac3.c
ac3_parser.c
ac3dec.c
ac3dec_data.c
ac3enc.c
ac3tab.c
acelp_filters.c
acelp_math.c
acelp_pitch_delay.c
acelp_vectors.c
adpcm.c
adxdec.c
adxenc.c
alac.c
alacenc.c
allcodecs.c
apedec.c
apiexample.c
asv1.c
atrac3.c
audioconvert.c
avs.c
beosthread.c
bethsoftvideo.c
bfi.c
bitstream.c
bitstream_filter.c
bmp.c
bmpenc.c
c93.c
cabac.c
cavs.c
cavs_parser.c
cavsdec.c
cavsdsp.c
cinepak.c
cljr.c
cook.c
cscd.c
cyuv.c
dca.c
dca_parser.c
dct-test.c
dirac_parser.c
dnxhddata.c
dnxhddec.c
dnxhdenc.c
dpcm.c
dsicinav.c
dsputil.c
dump_extradata_bsf.c
dv.c
dvbsub.c
dvbsub_parser.c
dvbsubdec.c
dvdsub_parser.c
dvdsubdec.c
dvdsubenc.c
dxa.c
eac3dec.c
eacmv.c
eatgv.c
elbg.c
error_resilience.c
escape124.c
eval.c
faandct.c
faanidct.c
fdctref.c
fft-test.c
fft.c
ffv1.c
flac.c
flacenc.c
flashsv.c
flashsvenc.c
flicvideo.c
fraps.c
g726.c
g729dec.c
gif.c
gifdec.c
golomb.c
h261.c
h261_parser.c
h261dec.c
h261enc.c
h263.c
h263_parser.c
h263dec.c
h264.c
h264_mp4toannexb_bsf.c
h264_parser.c
h264dspenc.c
h264enc.c
h264idct.c
h264pred.c
huffman.c
huffyuv.c
idcinvideo.c
imc.c
imgconvert.c
imgresample.c
imx_dump_header_bsf.c
indeo2.c
indeo3.c
interplayvideo.c
intrax8.c
intrax8dsp.c
jfdctfst.c
jfdctint.c
jpegls.c
jpeglsdec.c
jpeglsenc.c
jrevdct.c
kmvc.c
lcldec.c
lclenc.c
liba52.c
libamr.c
libdirac_libschro.c
libdiracdec.c
libdiracenc.c
libfaac.c
libfaad.c
libgsm.c
libmp3lame.c
libschroedinger.c
libschroedingerdec.c
libschroedingerenc.c
libtheoraenc.c
libvorbis.c
libx264.c
libxvid_rc.c
libxvidff.c
ljpegenc.c
loco.c
lowpass.c
lpc.c
lsp.c
lzw.c
lzwenc.c
mace.c
mdct.c
mdec.c
mimic.c
mjpeg.c
mjpeg_parser.c
mjpega_dump_header_bsf.c
mjpegbdec.c
mjpegdec.c
mjpegenc.c
mlp.c
mlp_parser.c
mlpdec.c
mmvideo.c
motion-test.c
motion_est.c
motion_est_template.c
motionpixels.c
movsub_bsf.c
mp3_header_compress_bsf.c
mp3_header_decompress_bsf.c
mpc.c
mpc7.c
mpc8.c
mpeg12.c
mpeg12data.c
mpeg12enc.c
mpeg4audio.c
mpeg4video_parser.c
mpegaudio.c
mpegaudio_parser.c
mpegaudiodata.c
mpegaudiodec.c
mpegaudiodecheader.c
mpegaudioenc.c
mpegvideo.c
mpegvideo_enc.c
mpegvideo_parser.c
msmpeg4.c
msmpeg4data.c
msrle.c
msvideo1.c
nellymoser.c
nellymoserdec.c
noise_bsf.c
nuv.c
opt.c
os2thread.c
parser.c
pcm.c
pcx.c
png.c
pngdec.c
pngenc.c
pnm.c
pnm_parser.c
pnmenc.c
pthread.c
ptx.c
qdm2.c
qdrw.c
qpeg.c
qtrle.c
qtrleenc.c
ra144.c
ra288.c
rangecoder.c
ratecontrol.c
raw.c
rawdec.c
rawenc.c
remove_extradata_bsf.c
resample.c
resample2.c
rl2.c
rle.c
roqaudioenc.c
roqvideo.c
roqvideodec.c
roqvideoenc.c
rpza.c
rtjpeg.c
rv10.c
rv30.c
rv30dsp.c
rv34.c
rv40.c
s3tc.c
sgidec.c
sgienc.c
shorten.c
simple_idct.c
smacker.c
smc.c
snow.c
sonic.c
sp5xdec.c
sunrast.c
svq1.c
svq1dec.c
svq1enc.c
svq3.c
targa.c
targaenc.c
tiertexseqv.c
tiff.c
tiffenc.c
truemotion1.c
truemotion2.c
truespeech.c
tscc.c
tta.c
txd.c
ulti.c
utils.c
vb.c
vc1.c
vc1_parser.c
vc1data.c
vc1dsp.c
vcr1.c
vmdav.c
vmnc.c
vorbis.c
vorbis_data.c
vorbis_dec.c
vorbis_enc.c
vp3.c
vp3_parser.c
vp3dsp.c
vp5.c
vp56.c
vp56data.c
vp6.c
vqavideo.c
w32thread.c
wavpack.c
wma.c
wmadec.c
wmaenc.c
wmv2.c
wmv2dec.c
wmv2enc.c
wnv1.c
ws-snd1.c
xan.c
xiph.c
xl.c
xsubdec.c
xvmcvideo.c
zmbv.c
zmbvenc.c
@@ -0,0 +1,231 @@
/*
* Tiertex Limited SEQ Video Decoder
* Copyright (c) 2006 Gregory Montoir ([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 tiertexseqv.c
* Tiertex Limited SEQ video decoder
*/
#include "avcodec.h"
#define ALT_BITSTREAM_READER_LE
#include "bitstream.h"
typedef struct SeqVideoContext {
AVCodecContext *avctx;
AVFrame frame;
} SeqVideoContext;
static const unsigned char *seq_unpack_rle_block(const unsigned char *src, unsigned char *dst, int dst_size)
{
int i, len, sz;
GetBitContext gb;
int code_table[64];
/* get the rle codes (at most 64 bytes) */
init_get_bits(&gb, src, 64 * 8);
for (i = 0, sz = 0; i < 64 && sz < dst_size; i++) {
code_table[i] = get_sbits(&gb, 4);
sz += FFABS(code_table[i]);
}
src += (get_bits_count(&gb) + 7) / 8;
/* do the rle unpacking */
for (i = 0; i < 64 && dst_size > 0; i++) {
len = code_table[i];
if (len < 0) {
len = -len;
memset(dst, *src++, FFMIN(len, dst_size));
} else {
memcpy(dst, src, FFMIN(len, dst_size));
src += len;
}
dst += len;
dst_size -= len;
}
return src;
}
static const unsigned char *seq_decode_op1(SeqVideoContext *seq, const unsigned char *src, unsigned char *dst)
{
const unsigned char *color_table;
int b, i, len, bits;
GetBitContext gb;
unsigned char block[8 * 8];
len = *src++;
if (len & 0x80) {
switch (len & 3) {
case 1:
src = seq_unpack_rle_block(src, block, sizeof(block));
for (b = 0; b < 8; b++) {
memcpy(dst, &block[b * 8], 8);
dst += seq->frame.linesize[0];
}
break;
case 2:
src = seq_unpack_rle_block(src, block, sizeof(block));
for (i = 0; i < 8; i++) {
for (b = 0; b < 8; b++)
dst[b * seq->frame.linesize[0]] = block[i * 8 + b];
++dst;
}
break;
}
} else {
color_table = src;
src += len;
bits = ff_log2_tab[len - 1] + 1;
init_get_bits(&gb, src, bits * 8 * 8); src += bits * 8;
for (b = 0; b < 8; b++) {
for (i = 0; i < 8; i++)
dst[i] = color_table[get_bits(&gb, bits)];
dst += seq->frame.linesize[0];
}
}
return src;
}
static const unsigned char *seq_decode_op2(SeqVideoContext *seq, const unsigned char *src, unsigned char *dst)
{
int i;
for (i = 0; i < 8; i++) {
memcpy(dst, src, 8);
src += 8;
dst += seq->frame.linesize[0];
}
return src;
}
static const unsigned char *seq_decode_op3(SeqVideoContext *seq, const unsigned char *src, unsigned char *dst)
{
int pos, offset;
do {
pos = *src++;
offset = ((pos >> 3) & 7) * seq->frame.linesize[0] + (pos & 7);
dst[offset] = *src++;
} while (!(pos & 0x80));
return src;
}
static void seqvideo_decode(SeqVideoContext *seq, const unsigned char *data, int data_size)
{
GetBitContext gb;
int flags, i, j, x, y, op;
unsigned char c[3];
unsigned char *dst;
uint32_t *palette;
flags = *data++;
if (flags & 1) {
palette = (uint32_t *)seq->frame.data[1];
for (i = 0; i < 256; i++) {
for (j = 0; j < 3; j++, data++)
c[j] = (*data << 2) | (*data >> 4);
palette[i] = AV_RB24(c);
}
seq->frame.palette_has_changed = 1;
}
if (flags & 2) {
init_get_bits(&gb, data, 128 * 8); data += 128;
for (y = 0; y < 128; y += 8)
for (x = 0; x < 256; x += 8) {
dst = &seq->frame.data[0][y * seq->frame.linesize[0] + x];
op = get_bits(&gb, 2);
switch (op) {
case 1:
data = seq_decode_op1(seq, data, dst);
break;
case 2:
data = seq_decode_op2(seq, data, dst);
break;
case 3:
data = seq_decode_op3(seq, data, dst);
break;
}
}
}
}
static av_cold int seqvideo_decode_init(AVCodecContext *avctx)
{
SeqVideoContext *seq = avctx->priv_data;
seq->avctx = avctx;
avctx->pix_fmt = PIX_FMT_PAL8;
seq->frame.data[0] = NULL;
return 0;
}
static int seqvideo_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
const uint8_t *buf, int buf_size)
{
SeqVideoContext *seq = avctx->priv_data;
seq->frame.reference = 1;
seq->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
if (avctx->reget_buffer(avctx, &seq->frame)) {
av_log(seq->avctx, AV_LOG_ERROR, "tiertexseqvideo: reget_buffer() failed\n");
return -1;
}
seqvideo_decode(seq, buf, buf_size);
*data_size = sizeof(AVFrame);
*(AVFrame *)data = seq->frame;
return buf_size;
}
static av_cold int seqvideo_decode_end(AVCodecContext *avctx)
{
SeqVideoContext *seq = avctx->priv_data;
if (seq->frame.data[0])
avctx->release_buffer(avctx, &seq->frame);
return 0;
}
AVCodec tiertexseqvideo_decoder = {
"tiertexseqvideo",
CODEC_TYPE_VIDEO,
CODEC_ID_TIERTEXSEQVIDEO,
sizeof(SeqVideoContext),
seqvideo_decode_init,
NULL,
seqvideo_decode_end,
seqvideo_decode_frame,
CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("Tiertex Limited SEQ video"),
};
@@ -0,0 +1,500 @@
/*
* TIFF image decoder
* 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
*/
/**
* TIFF image decoder
* @file tiff.c
* @author Konstantin Shishkov
*/
#include "avcodec.h"
#ifdef CONFIG_ZLIB
#include <zlib.h>
#endif
#include "lzw.h"
#include "tiff.h"
typedef struct TiffContext {
AVCodecContext *avctx;
AVFrame picture;
int width, height;
unsigned int bpp;
int le;
int compr;
int invert;
int strips, rps;
int sot;
const uint8_t* stripdata;
const uint8_t* stripsizes;
int stripsize, stripoff;
LZWState *lzw;
} TiffContext;
static int tget_short(const uint8_t **p, int le){
int v = le ? AV_RL16(*p) : AV_RB16(*p);
*p += 2;
return v;
}
static int tget_long(const uint8_t **p, int le){
int v = le ? AV_RL32(*p) : AV_RB32(*p);
*p += 4;
return v;
}
static int tget(const uint8_t **p, int type, int le){
switch(type){
case TIFF_BYTE : return *(*p)++;
case TIFF_SHORT: return tget_short(p, le);
case TIFF_LONG : return tget_long (p, le);
default : return -1;
}
}
static int tiff_unpack_strip(TiffContext *s, uint8_t* dst, int stride, const uint8_t *src, int size, int lines){
int c, line, pixels, code;
const uint8_t *ssrc = src;
int width = s->width * (s->bpp / 8);
#ifdef CONFIG_ZLIB
uint8_t *zbuf; unsigned long outlen;
if(s->compr == TIFF_DEFLATE || s->compr == TIFF_ADOBE_DEFLATE){
outlen = width * lines;
zbuf = av_malloc(outlen);
if(uncompress(zbuf, &outlen, src, size) != Z_OK){
av_log(s->avctx, AV_LOG_ERROR, "Uncompressing failed (%lu of %lu)\n", outlen, (unsigned long)width * lines);
av_free(zbuf);
return -1;
}
src = zbuf;
for(line = 0; line < lines; line++){
memcpy(dst, src, width);
dst += stride;
src += width;
}
av_free(zbuf);
return 0;
}
#endif
if(s->compr == TIFF_LZW){
if(ff_lzw_decode_init(s->lzw, 8, src, size, FF_LZW_TIFF) < 0){
av_log(s->avctx, AV_LOG_ERROR, "Error initializing LZW decoder\n");
return -1;
}
}
for(line = 0; line < lines; line++){
if(src - ssrc > size){
av_log(s->avctx, AV_LOG_ERROR, "Source data overread\n");
return -1;
}
switch(s->compr){
case TIFF_RAW:
memcpy(dst, src, s->width * (s->bpp / 8));
src += s->width * (s->bpp / 8);
break;
case TIFF_PACKBITS:
for(pixels = 0; pixels < width;){
code = (int8_t)*src++;
if(code >= 0){
code++;
if(pixels + code > width){
av_log(s->avctx, AV_LOG_ERROR, "Copy went out of bounds\n");
return -1;
}
memcpy(dst + pixels, src, code);
src += code;
pixels += code;
}else if(code != -128){ // -127..-1
code = (-code) + 1;
if(pixels + code > width){
av_log(s->avctx, AV_LOG_ERROR, "Run went out of bounds\n");
return -1;
}
c = *src++;
memset(dst + pixels, c, code);
pixels += code;
}
}
break;
case TIFF_LZW:
pixels = ff_lzw_decode(s->lzw, dst, width);
if(pixels < width){
av_log(s->avctx, AV_LOG_ERROR, "Decoded only %i bytes of %i\n", pixels, width);
return -1;
}
break;
}
dst += stride;
}
return 0;
}
static int tiff_decode_tag(TiffContext *s, const uint8_t *start, const uint8_t *buf, const uint8_t *end_buf, AVFrame *pic)
{
int tag, type, count, off, value = 0;
const uint8_t *src;
uint8_t *dst;
int i, j, ssize, soff, stride;
uint32_t *pal;
const uint8_t *rp, *gp, *bp;
tag = tget_short(&buf, s->le);
type = tget_short(&buf, s->le);
count = tget_long(&buf, s->le);
off = tget_long(&buf, s->le);
if(count == 1){
switch(type){
case TIFF_BYTE:
case TIFF_SHORT:
buf -= 4;
value = tget(&buf, type, s->le);
buf = NULL;
break;
case TIFF_LONG:
value = off;
buf = NULL;
break;
default:
value = -1;
buf = start + off;
}
}else if(type_sizes[type] * count <= 4){
buf -= 4;
}else{
buf = start + off;
}
if(buf && (buf < start || buf > end_buf)){
av_log(s->avctx, AV_LOG_ERROR, "Tag referencing position outside the image\n");
return -1;
}
switch(tag){
case TIFF_WIDTH:
s->width = value;
break;
case TIFF_HEIGHT:
s->height = value;
break;
case TIFF_BPP:
if(count == 1) s->bpp = value;
else{
switch(type){
case TIFF_BYTE:
s->bpp = (off & 0xFF) + ((off >> 8) & 0xFF) + ((off >> 16) & 0xFF) + ((off >> 24) & 0xFF);
break;
case TIFF_SHORT:
case TIFF_LONG:
s->bpp = 0;
for(i = 0; i < count; i++) s->bpp += tget(&buf, type, s->le);
break;
default:
s->bpp = -1;
}
}
switch(s->bpp){
case 8:
s->avctx->pix_fmt = PIX_FMT_PAL8;
break;
case 24:
s->avctx->pix_fmt = PIX_FMT_RGB24;
break;
case 16:
if(count == 1){
s->avctx->pix_fmt = PIX_FMT_GRAY16BE;
}else{
av_log(s->avctx, AV_LOG_ERROR, "This format is not supported (bpp=%i)\n", s->bpp);
return -1;
}
break;
default:
av_log(s->avctx, AV_LOG_ERROR, "This format is not supported (bpp=%i)\n", s->bpp);
return -1;
}
if(s->width != s->avctx->width || s->height != s->avctx->height){
if(avcodec_check_dimensions(s->avctx, s->width, s->height))
return -1;
avcodec_set_dimensions(s->avctx, s->width, s->height);
}
if(s->picture.data[0])
s->avctx->release_buffer(s->avctx, &s->picture);
if(s->avctx->get_buffer(s->avctx, &s->picture) < 0){
av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
return -1;
}
if(s->bpp == 8){
/* make default grayscale pal */
pal = (uint32_t *) s->picture.data[1];
for(i = 0; i < 256; i++)
pal[i] = i * 0x010101;
}
break;
case TIFF_COMPR:
s->compr = value;
switch(s->compr){
case TIFF_RAW:
case TIFF_PACKBITS:
case TIFF_LZW:
break;
case TIFF_DEFLATE:
case TIFF_ADOBE_DEFLATE:
#ifdef CONFIG_ZLIB
break;
#else
av_log(s->avctx, AV_LOG_ERROR, "Deflate: ZLib not compiled in\n");
return -1;
#endif
case TIFF_G3:
av_log(s->avctx, AV_LOG_ERROR, "CCITT G3 compression is not supported\n");
return -1;
case TIFF_G4:
av_log(s->avctx, AV_LOG_ERROR, "CCITT G4 compression is not supported\n");
return -1;
case TIFF_CCITT_RLE:
av_log(s->avctx, AV_LOG_ERROR, "CCITT RLE compression is not supported\n");
return -1;
case TIFF_JPEG:
case TIFF_NEWJPEG:
av_log(s->avctx, AV_LOG_ERROR, "JPEG compression is not supported\n");
return -1;
default:
av_log(s->avctx, AV_LOG_ERROR, "Unknown compression method %i\n", s->compr);
return -1;
}
break;
case TIFF_ROWSPERSTRIP:
if(value < 1){
av_log(s->avctx, AV_LOG_ERROR, "Incorrect value of rows per strip\n");
return -1;
}
s->rps = value;
break;
case TIFF_STRIP_OFFS:
if(count == 1){
s->stripdata = NULL;
s->stripoff = value;
}else
s->stripdata = start + off;
s->strips = count;
if(s->strips == 1) s->rps = s->height;
s->sot = type;
if(s->stripdata > end_buf){
av_log(s->avctx, AV_LOG_ERROR, "Tag referencing position outside the image\n");
return -1;
}
break;
case TIFF_STRIP_SIZE:
if(count == 1){
s->stripsizes = NULL;
s->stripsize = value;
s->strips = 1;
}else{
s->stripsizes = start + off;
}
s->strips = count;
if(s->stripsizes > end_buf){
av_log(s->avctx, AV_LOG_ERROR, "Tag referencing position outside the image\n");
return -1;
}
if(!pic->data[0]){
av_log(s->avctx, AV_LOG_ERROR, "Picture initialization missing\n");
return -1;
}
/* now we have the data and may start decoding */
stride = pic->linesize[0];
dst = pic->data[0];
for(i = 0; i < s->height; i += s->rps){
if(s->stripsizes)
ssize = tget(&s->stripsizes, type, s->le);
else
ssize = s->stripsize;
if(s->stripdata){
soff = tget(&s->stripdata, s->sot, s->le);
}else
soff = s->stripoff;
src = start + soff;
if(tiff_unpack_strip(s, dst, stride, src, ssize, FFMIN(s->rps, s->height - i)) < 0)
break;
dst += s->rps * stride;
}
break;
case TIFF_PREDICTOR:
if(!pic->data[0]){
av_log(s->avctx, AV_LOG_ERROR, "Picture initialization missing\n");
return -1;
}
if(value == 2){
dst = pic->data[0];
stride = pic->linesize[0];
soff = s->bpp >> 3;
ssize = s->width * soff;
for(i = 0; i < s->height; i++) {
for(j = soff; j < ssize; j++)
dst[j] += dst[j - soff];
dst += stride;
}
}
break;
case TIFF_INVERT:
switch(value){
case 0:
s->invert = 1;
break;
case 1:
s->invert = 0;
break;
case 2:
case 3:
break;
default:
av_log(s->avctx, AV_LOG_ERROR, "Color mode %d is not supported\n", value);
return -1;
}
break;
case TIFF_PAL:
if(s->avctx->pix_fmt != PIX_FMT_PAL8){
av_log(s->avctx, AV_LOG_ERROR, "Palette met but this is not palettized format\n");
return -1;
}
pal = (uint32_t *) s->picture.data[1];
off = type_sizes[type];
rp = buf;
gp = buf + count / 3 * off;
bp = buf + count / 3 * off * 2;
off = (type_sizes[type] - 1) << 3;
for(i = 0; i < count / 3; i++){
j = (tget(&rp, type, s->le) >> off) << 16;
j |= (tget(&gp, type, s->le) >> off) << 8;
j |= tget(&bp, type, s->le) >> off;
pal[i] = j;
}
break;
case TIFF_PLANAR:
if(value == 2){
av_log(s->avctx, AV_LOG_ERROR, "Planar format is not supported\n");
return -1;
}
break;
}
return 0;
}
static int decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
const uint8_t *buf, int buf_size)
{
TiffContext * const s = avctx->priv_data;
AVFrame *picture = data;
AVFrame * const p= (AVFrame*)&s->picture;
const uint8_t *orig_buf = buf, *end_buf = buf + buf_size;
int id, le, off;
int i, entries;
//parse image header
id = AV_RL16(buf); buf += 2;
if(id == 0x4949) le = 1;
else if(id == 0x4D4D) le = 0;
else{
av_log(avctx, AV_LOG_ERROR, "TIFF header not found\n");
return -1;
}
s->le = le;
s->invert = 0;
s->compr = TIFF_RAW;
// As TIFF 6.0 specification puts it "An arbitrary but carefully chosen number
// that further identifies the file as a TIFF file"
if(tget_short(&buf, le) != 42){
av_log(avctx, AV_LOG_ERROR, "The answer to life, universe and everything is not correct!\n");
return -1;
}
/* parse image file directory */
off = tget_long(&buf, le);
if(orig_buf + off + 14 >= end_buf){
av_log(avctx, AV_LOG_ERROR, "IFD offset is greater than image size\n");
return -1;
}
buf = orig_buf + off;
entries = tget_short(&buf, le);
for(i = 0; i < entries; i++){
if(tiff_decode_tag(s, orig_buf, buf, end_buf, p) < 0)
return -1;
buf += 12;
}
if(s->invert){
uint8_t *src;
int j;
src = s->picture.data[0];
for(j = 0; j < s->height; j++){
for(i = 0; i < s->picture.linesize[0]; i++)
src[i] = 255 - src[i];
src += s->picture.linesize[0];
}
}
*picture= *(AVFrame*)&s->picture;
*data_size = sizeof(AVPicture);
return buf_size;
}
static av_cold int tiff_init(AVCodecContext *avctx){
TiffContext *s = avctx->priv_data;
s->width = 0;
s->height = 0;
s->avctx = avctx;
avcodec_get_frame_defaults((AVFrame*)&s->picture);
avctx->coded_frame= (AVFrame*)&s->picture;
s->picture.data[0] = NULL;
ff_lzw_decode_open(&s->lzw);
return 0;
}
static av_cold int tiff_end(AVCodecContext *avctx)
{
TiffContext * const s = avctx->priv_data;
ff_lzw_decode_close(&s->lzw);
if(s->picture.data[0])
avctx->release_buffer(avctx, &s->picture);
return 0;
}
AVCodec tiff_decoder = {
"tiff",
CODEC_TYPE_VIDEO,
CODEC_ID_TIFF,
sizeof(TiffContext),
tiff_init,
NULL,
tiff_end,
decode_frame,
0,
NULL,
.long_name = NULL_IF_CONFIG_SMALL("TIFF image"),
};
@@ -0,0 +1,86 @@
/*
* TIFF tables
* 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
*/
/**
* TIFF tables
* @file tiff.h
* @author Konstantin Shishkov
*/
#ifndef FFMPEG_TIFF_H
#define FFMPEG_TIFF_H
#include <stdint.h>
/** abridged list of TIFF tags */
enum TiffTags{
TIFF_SUBFILE = 0xfe,
TIFF_WIDTH = 0x100,
TIFF_HEIGHT,
TIFF_BPP,
TIFF_COMPR,
TIFF_INVERT = 0x106,
TIFF_STRIP_OFFS = 0x111,
TIFF_SAMPLES_PER_PIXEL = 0x115,
TIFF_ROWSPERSTRIP = 0x116,
TIFF_STRIP_SIZE,
TIFF_XRES = 0x11A,
TIFF_YRES = 0x11B,
TIFF_PLANAR = 0x11C,
TIFF_XPOS = 0x11E,
TIFF_YPOS = 0x11F,
TIFF_RES_UNIT = 0x128,
TIFF_SOFTWARE_NAME = 0x131,
TIFF_PREDICTOR = 0x13D,
TIFF_PAL = 0x140,
TIFF_YCBCR_COEFFICIENTS = 0x211,
TIFF_YCBCR_SUBSAMPLING = 0x212,
TIFF_YCBCR_POSITIONING = 0x213,
TIFF_REFERENCE_BW = 0x214,
};
/** list of TIFF compression types */
enum TiffCompr{
TIFF_RAW = 1,
TIFF_CCITT_RLE,
TIFF_G3,
TIFF_G4,
TIFF_LZW,
TIFF_JPEG,
TIFF_NEWJPEG,
TIFF_ADOBE_DEFLATE,
TIFF_PACKBITS = 0x8005,
TIFF_DEFLATE = 0x80B2
};
enum TiffTypes{
TIFF_BYTE = 1,
TIFF_STRING,
TIFF_SHORT,
TIFF_LONG,
TIFF_RATIONAL,
};
/** sizes of various TIFF field types (string size = 100)*/
static const uint8_t type_sizes[6] = {
0, 1, 100, 2, 4, 8
};
#endif /* FFMPEG_TIFF_H */
@@ -0,0 +1,462 @@
/*
* TIFF image 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
*/
/**
* TIFF image encoder
* @file tiffenc.c
* @author Bartlomiej Wolowiec
*/
#include "avcodec.h"
#ifdef CONFIG_ZLIB
#include <zlib.h>
#endif
#include "bytestream.h"
#include "tiff.h"
#include "rle.h"
#include "lzw.h"
#define TIFF_MAX_ENTRY 32
/** sizes of various TIFF field types (string size = 1)*/
static const uint8_t type_sizes2[6] = {
0, 1, 1, 2, 4, 8
};
typedef struct TiffEncoderContext {
AVCodecContext *avctx;
AVFrame picture;
int width; ///< picture width
int height; ///< picture height
unsigned int bpp; ///< bits per pixel
int compr; ///< compression level
int bpp_tab_size; ///< bpp_tab size
int photometric_interpretation; ///< photometric interpretation
int strips; ///< number of strips
int rps; ///< row per strip
uint8_t entries[TIFF_MAX_ENTRY*12]; ///< entires in header
int num_entries; ///< number of entires
uint8_t **buf; ///< actual position in buffer
uint8_t *buf_start; ///< pointer to first byte in buffer
int buf_size; ///< buffer size
uint16_t subsampling[2]; ///< YUV subsampling factors
struct LZWEncodeState *lzws; ///< LZW Encode state
} TiffEncoderContext;
/**
* Check free space in buffer
* @param s Tiff context
* @param need Needed bytes
* @return 0 - ok, 1 - no free space
*/
inline static int check_size(TiffEncoderContext * s, uint64_t need)
{
if (s->buf_size < *s->buf - s->buf_start + need) {
*s->buf = s->buf_start + s->buf_size + 1;
av_log(s->avctx, AV_LOG_ERROR, "Buffer is too small\n");
return 1;
}
return 0;
}
/**
* Put n values to buffer
*
* @param p Pointer to pointer to output buffer
* @param n Number of values
* @param val Pointer to values
* @param type Type of values
* @param flip =0 - normal copy, >0 - flip
*/
static void tnput(uint8_t ** p, int n, const uint8_t * val, enum TiffTypes type,
int flip)
{
int i;
#ifdef WORDS_BIGENDIAN
flip ^= ((int[]) {0, 0, 0, 1, 3, 3})[type];
#endif
for (i = 0; i < n * type_sizes2[type]; i++)
*(*p)++ = val[i ^ flip];
}
/**
* Add entry to directory in tiff header.
* @param s Tiff context
* @param tag Tag that identifies the entry
* @param type Entry type
* @param count The number of values
* @param ptr_val Pointer to values
*/
static void add_entry(TiffEncoderContext * s,
enum TiffTags tag, enum TiffTypes type, int count,
const void *ptr_val)
{
uint8_t *entries_ptr = s->entries + 12 * s->num_entries;
assert(s->num_entries < TIFF_MAX_ENTRY);
bytestream_put_le16(&entries_ptr, tag);
bytestream_put_le16(&entries_ptr, type);
bytestream_put_le32(&entries_ptr, count);
if (type_sizes[type] * count <= 4) {
tnput(&entries_ptr, count, ptr_val, type, 0);
} else {
bytestream_put_le32(&entries_ptr, *s->buf - s->buf_start);
check_size(s, count * type_sizes2[type]);
tnput(s->buf, count, ptr_val, type, 0);
}
s->num_entries++;
}
static void add_entry1(TiffEncoderContext * s,
enum TiffTags tag, enum TiffTypes type, int val){
uint16_t w = val;
uint32_t dw= val;
add_entry(s, tag, type, 1, type == TIFF_SHORT ? (void *)&w : (void *)&dw);
}
/**
* Encode one strip in tiff file
*
* @param s Tiff context
* @param src Input buffer
* @param dst Output buffer
* @param n Size of input buffer
* @param compr Compression method
* @return Number of output bytes. If an output error is encountered, -1 returned
*/
static int encode_strip(TiffEncoderContext * s, const int8_t * src,
uint8_t * dst, int n, int compr)
{
switch (compr) {
#ifdef CONFIG_ZLIB
case TIFF_DEFLATE:
case TIFF_ADOBE_DEFLATE:
{
unsigned long zlen = s->buf_size - (*s->buf - s->buf_start);
if (compress(dst, &zlen, src, n) != Z_OK) {
av_log(s->avctx, AV_LOG_ERROR, "Compressing failed\n");
return -1;
}
return zlen;
}
#endif
case TIFF_RAW:
if (check_size(s, n))
return -1;
memcpy(dst, src, n);
return n;
case TIFF_PACKBITS:
return ff_rle_encode(dst, s->buf_size - (*s->buf - s->buf_start), src, 1, n, 2, 0xff, -1, 0);
case TIFF_LZW:
return ff_lzw_encode(s->lzws, src, n);
default:
return -1;
}
}
static void pack_yuv(TiffEncoderContext * s, uint8_t * dst, int lnum)
{
AVFrame *p = &s->picture;
int i, j, k;
int w = (s->width - 1) / s->subsampling[0] + 1;
uint8_t *pu = &p->data[1][lnum / s->subsampling[1] * p->linesize[1]];
uint8_t *pv = &p->data[2][lnum / s->subsampling[1] * p->linesize[2]];
for (i = 0; i < w; i++){
for (j = 0; j < s->subsampling[1]; j++)
for (k = 0; k < s->subsampling[0]; k++)
*dst++ = p->data[0][(lnum + j) * p->linesize[0] +
i * s->subsampling[0] + k];
*dst++ = *pu++;
*dst++ = *pv++;
}
}
static int encode_frame(AVCodecContext * avctx, unsigned char *buf,
int buf_size, void *data)
{
TiffEncoderContext *s = avctx->priv_data;
AVFrame *pict = data;
AVFrame *const p = (AVFrame *) & s->picture;
int i;
int n;
uint8_t *ptr = buf;
uint8_t *offset;
uint32_t strips;
uint32_t *strip_sizes = NULL;
uint32_t *strip_offsets = NULL;
int bytes_per_row;
uint32_t res[2] = { 72, 1 }; // image resolution (72/1)
static const uint16_t bpp_tab[] = { 8, 8, 8, 8 };
int ret = -1;
int is_yuv = 0;
uint8_t *yuv_line = NULL;
int shift_h, shift_v;
s->buf_start = buf;
s->buf = &ptr;
s->buf_size = buf_size;
*p = *pict;
p->pict_type = FF_I_TYPE;
p->key_frame = 1;
avctx->coded_frame= &s->picture;
s->compr = TIFF_PACKBITS;
if (avctx->compression_level == 0) {
s->compr = TIFF_RAW;
} else if(avctx->compression_level == 2) {
s->compr = TIFF_LZW;
#ifdef CONFIG_ZLIB
} else if ((avctx->compression_level >= 3)) {
s->compr = TIFF_DEFLATE;
#endif
}
s->width = avctx->width;
s->height = avctx->height;
s->subsampling[0] = 1;
s->subsampling[1] = 1;
switch (avctx->pix_fmt) {
case PIX_FMT_RGB24:
s->bpp = 24;
s->photometric_interpretation = 2;
break;
case PIX_FMT_GRAY8:
s->bpp = 8;
s->photometric_interpretation = 1;
break;
case PIX_FMT_PAL8:
s->bpp = 8;
s->photometric_interpretation = 3;
break;
case PIX_FMT_MONOBLACK:
s->bpp = 1;
s->photometric_interpretation = 1;
break;
case PIX_FMT_MONOWHITE:
s->bpp = 1;
s->photometric_interpretation = 0;
break;
case PIX_FMT_YUV420P:
case PIX_FMT_YUV422P:
case PIX_FMT_YUV444P:
case PIX_FMT_YUV410P:
case PIX_FMT_YUV411P:
s->photometric_interpretation = 6;
avcodec_get_chroma_sub_sample(avctx->pix_fmt,
&shift_h, &shift_v);
s->bpp = 8 + (16 >> (shift_h + shift_v));
s->subsampling[0] = 1 << shift_h;
s->subsampling[1] = 1 << shift_v;
s->bpp_tab_size = 3;
is_yuv = 1;
break;
default:
av_log(s->avctx, AV_LOG_ERROR,
"This colors format is not supported\n");
return -1;
}
if (!is_yuv)
s->bpp_tab_size = (s->bpp >> 3);
if (s->compr == TIFF_DEFLATE || s->compr == TIFF_ADOBE_DEFLATE || s->compr == TIFF_LZW)
//best choose for DEFLATE
s->rps = s->height;
else
s->rps = FFMAX(8192 / (((s->width * s->bpp) >> 3) + 1), 1); // suggest size of strip
s->rps = ((s->rps - 1) / s->subsampling[1] + 1) * s->subsampling[1]; // round rps up
strips = (s->height - 1) / s->rps + 1;
if (check_size(s, 8))
goto fail;
// write header
bytestream_put_le16(&ptr, 0x4949);
bytestream_put_le16(&ptr, 42);
offset = ptr;
bytestream_put_le32(&ptr, 0);
strip_sizes = av_mallocz(sizeof(*strip_sizes) * strips);
strip_offsets = av_mallocz(sizeof(*strip_offsets) * strips);
bytes_per_row = (((s->width - 1)/s->subsampling[0] + 1) * s->bpp
* s->subsampling[0] * s->subsampling[1] + 7) >> 3;
if (is_yuv){
yuv_line = av_malloc(bytes_per_row);
if (yuv_line == NULL){
av_log(s->avctx, AV_LOG_ERROR, "Not enough memory\n");
goto fail;
}
}
#ifdef CONFIG_ZLIB
if (s->compr == TIFF_DEFLATE || s->compr == TIFF_ADOBE_DEFLATE) {
uint8_t *zbuf;
int zlen, zn;
int j;
zlen = bytes_per_row * s->rps;
zbuf = av_malloc(zlen);
strip_offsets[0] = ptr - buf;
zn = 0;
for (j = 0; j < s->rps; j++) {
if (is_yuv){
pack_yuv(s, yuv_line, j);
memcpy(zbuf + zn, yuv_line, bytes_per_row);
j += s->subsampling[1] - 1;
}
else
memcpy(zbuf + j * bytes_per_row,
p->data[0] + j * p->linesize[0], bytes_per_row);
zn += bytes_per_row;
}
n = encode_strip(s, zbuf, ptr, zn, s->compr);
av_free(zbuf);
if (n<0) {
av_log(s->avctx, AV_LOG_ERROR, "Encode strip failed\n");
goto fail;
}
ptr += n;
strip_sizes[0] = ptr - buf - strip_offsets[0];
} else
#endif
{
if(s->compr == TIFF_LZW)
s->lzws = av_malloc(ff_lzw_encode_state_size);
for (i = 0; i < s->height; i++) {
if (strip_sizes[i / s->rps] == 0) {
if(s->compr == TIFF_LZW){
ff_lzw_encode_init(s->lzws, ptr, s->buf_size - (*s->buf - s->buf_start), 12);
}
strip_offsets[i / s->rps] = ptr - buf;
}
if (is_yuv){
pack_yuv(s, yuv_line, i);
n = encode_strip(s, yuv_line, ptr, bytes_per_row, s->compr);
i += s->subsampling[1] - 1;
}
else
n = encode_strip(s, p->data[0] + i * p->linesize[0],
ptr, bytes_per_row, s->compr);
if (n < 0) {
av_log(s->avctx, AV_LOG_ERROR, "Encode strip failed\n");
goto fail;
}
strip_sizes[i / s->rps] += n;
ptr += n;
if(s->compr == TIFF_LZW && (i==s->height-1 || i%s->rps == s->rps-1)){
int ret;
ret = ff_lzw_encode_flush(s->lzws);
strip_sizes[(i / s->rps )] += ret ;
ptr += ret;
}
}
if(s->compr == TIFF_LZW)
av_free(s->lzws);
}
s->num_entries = 0;
add_entry1(s,TIFF_SUBFILE, TIFF_LONG, 0);
add_entry1(s,TIFF_WIDTH, TIFF_LONG, s->width);
add_entry1(s,TIFF_HEIGHT, TIFF_LONG, s->height);
if (s->bpp_tab_size)
add_entry(s, TIFF_BPP, TIFF_SHORT, s->bpp_tab_size, bpp_tab);
add_entry1(s,TIFF_COMPR, TIFF_SHORT, s->compr);
add_entry1(s,TIFF_INVERT, TIFF_SHORT, s->photometric_interpretation);
add_entry(s, TIFF_STRIP_OFFS, TIFF_LONG, strips, strip_offsets);
if (s->bpp_tab_size)
add_entry1(s,TIFF_SAMPLES_PER_PIXEL, TIFF_SHORT, s->bpp_tab_size);
add_entry1(s,TIFF_ROWSPERSTRIP, TIFF_LONG, s->rps);
add_entry(s, TIFF_STRIP_SIZE, TIFF_LONG, strips, strip_sizes);
add_entry(s, TIFF_XRES, TIFF_RATIONAL, 1, res);
add_entry(s, TIFF_YRES, TIFF_RATIONAL, 1, res);
add_entry1(s,TIFF_RES_UNIT, TIFF_SHORT, 2);
if(!(avctx->flags & CODEC_FLAG_BITEXACT))
add_entry(s, TIFF_SOFTWARE_NAME, TIFF_STRING,
strlen(LIBAVCODEC_IDENT) + 1, LIBAVCODEC_IDENT);
if (avctx->pix_fmt == PIX_FMT_PAL8) {
uint16_t pal[256 * 3];
for (i = 0; i < 256; i++) {
uint32_t rgb = *(uint32_t *) (p->data[1] + i * 4);
pal[i] = ((rgb >> 16) & 0xff) * 257;
pal[i + 256] = ((rgb >> 8 ) & 0xff) * 257;
pal[i + 512] = ( rgb & 0xff) * 257;
}
add_entry(s, TIFF_PAL, TIFF_SHORT, 256 * 3, pal);
}
if (is_yuv){
/** according to CCIR Recommendation 601.1 */
uint32_t refbw[12] = {15, 1, 235, 1, 128, 1, 240, 1, 128, 1, 240, 1};
add_entry(s, TIFF_YCBCR_SUBSAMPLING, TIFF_SHORT, 2, s->subsampling);
add_entry(s, TIFF_REFERENCE_BW, TIFF_RATIONAL, 6, refbw);
}
bytestream_put_le32(&offset, ptr - buf); // write offset to dir
if (check_size(s, 6 + s->num_entries * 12))
goto fail;
bytestream_put_le16(&ptr, s->num_entries); // write tag count
bytestream_put_buffer(&ptr, s->entries, s->num_entries * 12);
bytestream_put_le32(&ptr, 0);
ret = ptr - buf;
fail:
av_free(strip_sizes);
av_free(strip_offsets);
av_free(yuv_line);
return ret;
}
AVCodec tiff_encoder = {
"tiff",
CODEC_TYPE_VIDEO,
CODEC_ID_TIFF,
sizeof(TiffEncoderContext),
NULL,
encode_frame,
NULL,
NULL,
0,
NULL,
.pix_fmts =
(enum PixelFormat[]) {PIX_FMT_RGB24, PIX_FMT_PAL8, PIX_FMT_GRAY8,
PIX_FMT_MONOBLACK, PIX_FMT_MONOWHITE,
PIX_FMT_YUV420P, PIX_FMT_YUV422P,
PIX_FMT_YUV444P, PIX_FMT_YUV410P,
PIX_FMT_YUV411P,
PIX_FMT_NONE},
.long_name = NULL_IF_CONFIG_SMALL("TIFF image"),
};
@@ -2,29 +2,31 @@
* Duck TrueMotion 1.0 Decoder * Duck TrueMotion 1.0 Decoder
* Copyright (C) 2003 Alex Beregszaszi & Mike Melanson * Copyright (C) 2003 Alex Beregszaszi & Mike Melanson
* *
* This library is free software; you can redistribute it and/or * 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 * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This library is distributed in the hope that it will be useful, * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
/** /**
* @file truemotion1.c * @file truemotion1.c
* Duck TrueMotion v1 Video Decoder by * Duck TrueMotion v1 Video Decoder by
* Alex Beregszaszi ([email protected]) and * Alex Beregszaszi and
* Mike Melanson ([email protected]) * Mike Melanson ([email protected])
* *
* The TrueMotion v1 decoder presently only decodes 16-bit TM1 data and * The TrueMotion v1 decoder presently only decodes 16-bit TM1 data and
* outputs RGB555 data. 24-bit TM1 data is not supported yet. * outputs RGB555 (or RGB565) data. 24-bit TM1 data is not supported yet.
*/ */
#include <stdio.h> #include <stdio.h>
@@ -32,25 +34,21 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include "common.h"
#include "avcodec.h" #include "avcodec.h"
#include "dsputil.h" #include "dsputil.h"
#include "truemotion1data.h" #include "truemotion1data.h"
#define LE_16(x) ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0])
typedef struct TrueMotion1Context { typedef struct TrueMotion1Context {
AVCodecContext *avctx; AVCodecContext *avctx;
AVFrame frame; AVFrame frame;
AVFrame prev_frame;
unsigned char *buf; const uint8_t *buf;
int size; int size;
unsigned char *mb_change_bits; const uint8_t *mb_change_bits;
int mb_change_bits_row_size; int mb_change_bits_row_size;
unsigned char *index_stream; const uint8_t *index_stream;
int index_stream_size; int index_stream_size;
int flags; int flags;
@@ -58,16 +56,18 @@ typedef struct TrueMotion1Context {
uint32_t y_predictor_table[1024]; uint32_t y_predictor_table[1024];
uint32_t c_predictor_table[1024]; uint32_t c_predictor_table[1024];
uint32_t fat_y_predictor_table[1024];
uint32_t fat_c_predictor_table[1024];
int compression; int compression;
int block_type; int block_type;
int block_width; int block_width;
int block_height; int block_height;
int16_t *ydt; int16_t ydt[8];
int16_t *cdt; int16_t cdt[8];
int16_t *fat_ydt; int16_t fat_ydt[8];
int16_t *fat_cdt; int16_t fat_cdt[8];
int last_deltaset, last_vectable; int last_deltaset, last_vectable;
@@ -111,13 +111,13 @@ struct frame_header {
typedef struct comp_types { typedef struct comp_types {
int algorithm; int algorithm;
int block_width; int block_width; // vres
int block_height; int block_height; // hres
int block_type; int block_type;
} comp_types; } comp_types;
/* { valid for metatype }, algorithm, num of deltas, horiz res, vert res */ /* { valid for metatype }, algorithm, num of deltas, vert res, horiz res */
static comp_types compression_types[17] = { static const comp_types compression_types[17] = {
{ ALGO_NOP, 0, 0, 0 }, { ALGO_NOP, 0, 0, 0 },
{ ALGO_RGB16V, 4, 4, BLOCK_4x4 }, { ALGO_RGB16V, 4, 4, BLOCK_4x4 },
@@ -148,10 +148,10 @@ static void select_delta_tables(TrueMotion1Context *s, int delta_table_index)
if (delta_table_index > 3) if (delta_table_index > 3)
return; return;
s->ydt = ydts[delta_table_index]; memcpy(s->ydt, ydts[delta_table_index], 8 * sizeof(int16_t));
s->cdt = cdts[delta_table_index]; memcpy(s->cdt, cdts[delta_table_index], 8 * sizeof(int16_t));
s->fat_ydt = fat_ydts[delta_table_index]; memcpy(s->fat_ydt, fat_ydts[delta_table_index], 8 * sizeof(int16_t));
s->fat_cdt = fat_cdts[delta_table_index]; memcpy(s->fat_cdt, fat_cdts[delta_table_index], 8 * sizeof(int16_t));
/* Y skinny deltas need to be halved for some reason; maybe the /* Y skinny deltas need to be halved for some reason; maybe the
* skinny Y deltas should be modified */ * skinny Y deltas should be modified */
@@ -165,9 +165,9 @@ static void select_delta_tables(TrueMotion1Context *s, int delta_table_index)
} }
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN
static int make_ydt_entry(int p2, int p1, int16_t *ydt) static int make_ydt15_entry(int p2, int p1, int16_t *ydt)
#else #else
static int make_ydt_entry(int p1, int p2, int16_t *ydt) static int make_ydt15_entry(int p1, int p2, int16_t *ydt)
#endif #endif
{ {
int lo, hi; int lo, hi;
@@ -176,13 +176,13 @@ static int make_ydt_entry(int p1, int p2, int16_t *ydt)
lo += (lo << 5) + (lo << 10); lo += (lo << 5) + (lo << 10);
hi = ydt[p2]; hi = ydt[p2];
hi += (hi << 5) + (hi << 10); hi += (hi << 5) + (hi << 10);
return ((lo + (hi << 16)) << 1); return (lo + (hi << 16)) << 1;
} }
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN
static int make_cdt_entry(int p2, int p1, int16_t *cdt) static int make_cdt15_entry(int p2, int p1, int16_t *cdt)
#else #else
static int make_cdt_entry(int p1, int p2, int16_t *cdt) static int make_cdt15_entry(int p1, int p2, int16_t *cdt)
#endif #endif
{ {
int r, b, lo; int r, b, lo;
@@ -190,10 +190,65 @@ static int make_cdt_entry(int p1, int p2, int16_t *cdt)
b = cdt[p2]; b = cdt[p2];
r = cdt[p1] << 10; r = cdt[p1] << 10;
lo = b + r; lo = b + r;
return ((lo + (lo << 16)) << 1); return (lo + (lo << 16)) << 1;
} }
static void gen_vector_table(TrueMotion1Context *s, uint8_t *sel_vector_table) #ifdef WORDS_BIGENDIAN
static int make_ydt16_entry(int p2, int p1, int16_t *ydt)
#else
static int make_ydt16_entry(int p1, int p2, int16_t *ydt)
#endif
{
int lo, hi;
lo = ydt[p1];
lo += (lo << 6) + (lo << 11);
hi = ydt[p2];
hi += (hi << 6) + (hi << 11);
return (lo + (hi << 16)) << 1;
}
#ifdef WORDS_BIGENDIAN
static int make_cdt16_entry(int p2, int p1, int16_t *cdt)
#else
static int make_cdt16_entry(int p1, int p2, int16_t *cdt)
#endif
{
int r, b, lo;
b = cdt[p2];
r = cdt[p1] << 11;
lo = b + r;
return (lo + (lo << 16)) << 1;
}
#ifdef WORDS_BIGENDIAN
static int make_ydt24_entry(int p2, int p1, int16_t *ydt)
#else
static int make_ydt24_entry(int p1, int p2, int16_t *ydt)
#endif
{
int lo, hi;
lo = ydt[p1];
hi = ydt[p2];
return (lo + (hi << 8) + (hi << 16)) << 1;
}
#ifdef WORDS_BIGENDIAN
static int make_cdt24_entry(int p2, int p1, int16_t *cdt)
#else
static int make_cdt24_entry(int p1, int p2, int16_t *cdt)
#endif
{
int r, b;
b = cdt[p2];
r = cdt[p1]<<16;
return (b+r) << 1;
}
static void gen_vector_table15(TrueMotion1Context *s, const uint8_t *sel_vector_table)
{ {
int len, i, j; int len, i, j;
unsigned char delta_pair; unsigned char delta_pair;
@@ -205,15 +260,63 @@ static void gen_vector_table(TrueMotion1Context *s, uint8_t *sel_vector_table)
{ {
delta_pair = *sel_vector_table++; delta_pair = *sel_vector_table++;
s->y_predictor_table[i+j] = 0xfffffffe & s->y_predictor_table[i+j] = 0xfffffffe &
make_ydt_entry(delta_pair >> 4, delta_pair & 0xf, s->ydt); make_ydt15_entry(delta_pair >> 4, delta_pair & 0xf, s->ydt);
s->c_predictor_table[i+j] = 0xfffffffe & s->c_predictor_table[i+j] = 0xfffffffe &
make_cdt_entry(delta_pair >> 4, delta_pair & 0xf, s->cdt); make_cdt15_entry(delta_pair >> 4, delta_pair & 0xf, s->cdt);
} }
s->y_predictor_table[i+(j-1)] |= 1; s->y_predictor_table[i+(j-1)] |= 1;
s->c_predictor_table[i+(j-1)] |= 1; s->c_predictor_table[i+(j-1)] |= 1;
} }
} }
static void gen_vector_table16(TrueMotion1Context *s, const uint8_t *sel_vector_table)
{
int len, i, j;
unsigned char delta_pair;
for (i = 0; i < 1024; i += 4)
{
len = *sel_vector_table++ / 2;
for (j = 0; j < len; j++)
{
delta_pair = *sel_vector_table++;
s->y_predictor_table[i+j] = 0xfffffffe &
make_ydt16_entry(delta_pair >> 4, delta_pair & 0xf, s->ydt);
s->c_predictor_table[i+j] = 0xfffffffe &
make_cdt16_entry(delta_pair >> 4, delta_pair & 0xf, s->cdt);
}
s->y_predictor_table[i+(j-1)] |= 1;
s->c_predictor_table[i+(j-1)] |= 1;
}
}
static void gen_vector_table24(TrueMotion1Context *s, const uint8_t *sel_vector_table)
{
int len, i, j;
unsigned char delta_pair;
for (i = 0; i < 1024; i += 4)
{
len = *sel_vector_table++ / 2;
for (j = 0; j < len; j++)
{
delta_pair = *sel_vector_table++;
s->y_predictor_table[i+j] = 0xfffffffe &
make_ydt24_entry(delta_pair >> 4, delta_pair & 0xf, s->ydt);
s->c_predictor_table[i+j] = 0xfffffffe &
make_cdt24_entry(delta_pair >> 4, delta_pair & 0xf, s->cdt);
s->fat_y_predictor_table[i+j] = 0xfffffffe &
make_ydt24_entry(delta_pair >> 4, delta_pair & 0xf, s->fat_ydt);
s->fat_c_predictor_table[i+j] = 0xfffffffe &
make_cdt24_entry(delta_pair >> 4, delta_pair & 0xf, s->fat_cdt);
}
s->y_predictor_table[i+(j-1)] |= 1;
s->c_predictor_table[i+(j-1)] |= 1;
s->fat_y_predictor_table[i+(j-1)] |= 1;
s->fat_c_predictor_table[i+(j-1)] |= 1;
}
}
/* Returns the number of bytes consumed from the bytestream. Returns -1 if /* Returns the number of bytes consumed from the bytestream. Returns -1 if
* there was an error while decoding the header */ * there was an error while decoding the header */
static int truemotion1_decode_header(TrueMotion1Context *s) static int truemotion1_decode_header(TrueMotion1Context *s)
@@ -221,7 +324,7 @@ static int truemotion1_decode_header(TrueMotion1Context *s)
int i; int i;
struct frame_header header; struct frame_header header;
uint8_t header_buffer[128]; /* logical maximum size of the header */ uint8_t header_buffer[128]; /* logical maximum size of the header */
uint8_t *sel_vector_table; const uint8_t *sel_vector_table;
/* There is 1 change bit per 4 pixels, so each change byte represents /* There is 1 change bit per 4 pixels, so each change byte represents
* 32 pixels; divide width by 4 to obtain the number of change bits and * 32 pixels; divide width by 4 to obtain the number of change bits and
@@ -231,7 +334,7 @@ static int truemotion1_decode_header(TrueMotion1Context *s)
header.header_size = ((s->buf[0] >> 5) | (s->buf[0] << 3)) & 0x7f; header.header_size = ((s->buf[0] >> 5) | (s->buf[0] << 3)) & 0x7f;
if (s->buf[0] < 0x10) if (s->buf[0] < 0x10)
{ {
printf("invalid header size\n"); av_log(s->avctx, AV_LOG_ERROR, "invalid header size (%d)\n", s->buf[0]);
return -1; return -1;
} }
@@ -239,12 +342,13 @@ static int truemotion1_decode_header(TrueMotion1Context *s)
memset(header_buffer, 0, 128); memset(header_buffer, 0, 128);
for (i = 1; i < header.header_size; i++) for (i = 1; i < header.header_size; i++)
header_buffer[i - 1] = s->buf[i] ^ s->buf[i + 1]; header_buffer[i - 1] = s->buf[i] ^ s->buf[i + 1];
header.compression = header_buffer[0]; header.compression = header_buffer[0];
header.deltaset = header_buffer[1]; header.deltaset = header_buffer[1];
header.vectable = header_buffer[2]; header.vectable = header_buffer[2];
header.ysize = LE_16(&header_buffer[3]); header.ysize = AV_RL16(&header_buffer[3]);
header.xsize = LE_16(&header_buffer[5]); header.xsize = AV_RL16(&header_buffer[5]);
header.checksum = LE_16(&header_buffer[7]); header.checksum = AV_RL16(&header_buffer[7]);
header.version = header_buffer[9]; header.version = header_buffer[9];
header.header_type = header_buffer[10]; header.header_type = header_buffer[10];
header.flags = header_buffer[11]; header.flags = header_buffer[11];
@@ -255,7 +359,7 @@ static int truemotion1_decode_header(TrueMotion1Context *s)
{ {
if (header.header_type > 3) if (header.header_type > 3)
{ {
av_log(s->avctx, AV_LOG_ERROR, "truemotion1: invalid header type\n"); av_log(s->avctx, AV_LOG_ERROR, "invalid header type (%d)\n", header.header_type);
return -1; return -1;
} else if ((header.header_type == 2) || (header.header_type == 3)) { } else if ((header.header_type == 2) || (header.header_type == 3)) {
s->flags = header.flags; s->flags = header.flags;
@@ -267,21 +371,30 @@ static int truemotion1_decode_header(TrueMotion1Context *s)
s->flags = FLAG_KEYFRAME; s->flags = FLAG_KEYFRAME;
if (s->flags & FLAG_SPRITE) { if (s->flags & FLAG_SPRITE) {
av_log(s->avctx, AV_LOG_INFO, "SPRITE frame found, please report the sample to the developers\n");
/* FIXME header.width, height, xoffset and yoffset aren't initialized */
#if 0
s->w = header.width; s->w = header.width;
s->h = header.height; s->h = header.height;
s->x = header.xoffset; s->x = header.xoffset;
s->y = header.yoffset; s->y = header.yoffset;
#else
return -1;
#endif
} else { } else {
s->w = header.xsize; s->w = header.xsize;
s->h = header.ysize; s->h = header.ysize;
if (header.header_type < 2) { if (header.header_type < 2) {
if ((s->w < 213) && (s->h >= 176)) if ((s->w < 213) && (s->h >= 176))
{
s->flags |= FLAG_INTERPOLATED; s->flags |= FLAG_INTERPOLATED;
av_log(s->avctx, AV_LOG_INFO, "INTERPOLATION selected, please report the sample to the developers\n");
}
} }
} }
if (header.compression > 17) { if (header.compression >= 17) {
printf("invalid compression type (%d)\n", header.compression); av_log(s->avctx, AV_LOG_ERROR, "invalid compression type (%d)\n", header.compression);
return -1; return -1;
} }
@@ -295,19 +408,26 @@ static int truemotion1_decode_header(TrueMotion1Context *s)
if (header.vectable < 4) if (header.vectable < 4)
sel_vector_table = tables[header.vectable - 1]; sel_vector_table = tables[header.vectable - 1];
else { else {
printf("invalid vector table id (%d)\n", header.vectable); av_log(s->avctx, AV_LOG_ERROR, "invalid vector table id (%d)\n", header.vectable);
return -1; return -1;
} }
} }
// FIXME: where to place this ?!?!
if (compression_types[header.compression].algorithm == ALGO_RGB24H)
s->avctx->pix_fmt = PIX_FMT_RGB32;
else
s->avctx->pix_fmt = PIX_FMT_RGB555; // RGB565 is supported as well
if ((header.deltaset != s->last_deltaset) || (header.vectable != s->last_vectable)) if ((header.deltaset != s->last_deltaset) || (header.vectable != s->last_vectable))
{ {
if (compression_types[header.compression].algorithm == ALGO_RGB24H) if (compression_types[header.compression].algorithm == ALGO_RGB24H)
{ gen_vector_table24(s, sel_vector_table);
printf("24bit compression not yet supported\n");
}
else else
gen_vector_table(s, sel_vector_table); if (s->avctx->pix_fmt == PIX_FMT_RGB555)
gen_vector_table15(s, sel_vector_table);
else
gen_vector_table16(s, sel_vector_table);
} }
/* set up pointers to the other key data chunks */ /* set up pointers to the other key data chunks */
@@ -329,31 +449,70 @@ static int truemotion1_decode_header(TrueMotion1Context *s)
s->block_height = compression_types[header.compression].block_height; s->block_height = compression_types[header.compression].block_height;
s->block_type = compression_types[header.compression].block_type; s->block_type = compression_types[header.compression].block_type;
if (s->avctx->debug & FF_DEBUG_PICT_INFO)
av_log(s->avctx, AV_LOG_INFO, "tables: %d / %d c:%d %dx%d t:%d %s%s%s%s\n",
s->last_deltaset, s->last_vectable, s->compression, s->block_width,
s->block_height, s->block_type,
s->flags & FLAG_KEYFRAME ? " KEY" : "",
s->flags & FLAG_INTERFRAME ? " INTER" : "",
s->flags & FLAG_SPRITE ? " SPRITE" : "",
s->flags & FLAG_INTERPOLATED ? " INTERPOL" : "");
return header.header_size; return header.header_size;
} }
static int truemotion1_decode_init(AVCodecContext *avctx) static av_cold int truemotion1_decode_init(AVCodecContext *avctx)
{ {
TrueMotion1Context *s = (TrueMotion1Context *)avctx->priv_data; TrueMotion1Context *s = avctx->priv_data;
s->avctx = avctx; s->avctx = avctx;
avctx->pix_fmt = PIX_FMT_RGB555; // FIXME: it may change ?
avctx->has_b_frames = 0; // if (avctx->bits_per_sample == 24)
s->frame.data[0] = s->prev_frame.data[0] = NULL; // avctx->pix_fmt = PIX_FMT_RGB24;
// else
// avctx->pix_fmt = PIX_FMT_RGB555;
s->frame.data[0] = NULL;
/* there is a vertical predictor for each pixel in a line; each vertical /* there is a vertical predictor for each pixel in a line; each vertical
* predictor is 0 to start with */ * predictor is 0 to start with */
s->vert_pred = s->vert_pred =
(unsigned int *)av_malloc(s->avctx->width * sizeof(unsigned short)); (unsigned int *)av_malloc(s->avctx->width * sizeof(unsigned int));
return 0; return 0;
} }
/*
Block decoding order:
dxi: Y-Y
dxic: Y-C-Y
dxic2: Y-C-Y-C
hres,vres,i,i%vres (0 < i < 4)
2x2 0: 0 dxic2
2x2 1: 1 dxi
2x2 2: 0 dxic2
2x2 3: 1 dxi
2x4 0: 0 dxic2
2x4 1: 1 dxi
2x4 2: 2 dxi
2x4 3: 3 dxi
4x2 0: 0 dxic
4x2 1: 1 dxi
4x2 2: 0 dxic
4x2 3: 1 dxi
4x4 0: 0 dxic
4x4 1: 1 dxi
4x4 2: 2 dxi
4x4 3: 3 dxi
*/
#define GET_NEXT_INDEX() \ #define GET_NEXT_INDEX() \
{\ {\
if (index_stream_index >= s->index_stream_size) { \ if (index_stream_index >= s->index_stream_size) { \
printf (" help! truemotion1 decoder went out of bounds\n"); \ av_log(s->avctx, AV_LOG_INFO, " help! truemotion1 decoder went out of bounds\n"); \
return; \ return; \
} \ } \
index = s->index_stream[index_stream_index++] * 4; \ index = s->index_stream[index_stream_index++] * 4; \
@@ -376,6 +535,24 @@ static int truemotion1_decode_init(AVCodecContext *avctx)
} else \ } else \
index++; index++;
#define APPLY_C_PREDICTOR_24() \
predictor_pair = s->c_predictor_table[index]; \
horiz_pred += (predictor_pair >> 1); \
if (predictor_pair & 1) { \
GET_NEXT_INDEX() \
if (!index) { \
GET_NEXT_INDEX() \
predictor_pair = s->fat_c_predictor_table[index]; \
horiz_pred += (predictor_pair >> 1); \
if (predictor_pair & 1) \
GET_NEXT_INDEX() \
else \
index++; \
} \
} else \
index++;
#define APPLY_Y_PREDICTOR() \ #define APPLY_Y_PREDICTOR() \
predictor_pair = s->y_predictor_table[index]; \ predictor_pair = s->y_predictor_table[index]; \
horiz_pred += (predictor_pair >> 1); \ horiz_pred += (predictor_pair >> 1); \
@@ -393,10 +570,26 @@ static int truemotion1_decode_init(AVCodecContext *avctx)
} else \ } else \
index++; index++;
#define APPLY_Y_PREDICTOR_24() \
predictor_pair = s->y_predictor_table[index]; \
horiz_pred += (predictor_pair >> 1); \
if (predictor_pair & 1) { \
GET_NEXT_INDEX() \
if (!index) { \
GET_NEXT_INDEX() \
predictor_pair = s->fat_y_predictor_table[index]; \
horiz_pred += (predictor_pair >> 1); \
if (predictor_pair & 1) \
GET_NEXT_INDEX() \
else \
index++; \
} \
} else \
index++;
#define OUTPUT_PIXEL_PAIR() \ #define OUTPUT_PIXEL_PAIR() \
*current_pixel_pair = *vert_pred + horiz_pred; \ *current_pixel_pair = *vert_pred + horiz_pred; \
*vert_pred++ = *current_pixel_pair++; \ *vert_pred++ = *current_pixel_pair++;
prev_pixel_pair++;
static void truemotion1_decode_16bit(TrueMotion1Context *s) static void truemotion1_decode_16bit(TrueMotion1Context *s)
{ {
@@ -406,13 +599,11 @@ static void truemotion1_decode_16bit(TrueMotion1Context *s)
unsigned int horiz_pred; unsigned int horiz_pred;
unsigned int *vert_pred; unsigned int *vert_pred;
unsigned int *current_pixel_pair; unsigned int *current_pixel_pair;
unsigned int *prev_pixel_pair;
unsigned char *current_line = s->frame.data[0]; unsigned char *current_line = s->frame.data[0];
unsigned char *prev_line = s->prev_frame.data[0];
int keyframe = s->flags & FLAG_KEYFRAME; int keyframe = s->flags & FLAG_KEYFRAME;
/* these variables are for managing the stream of macroblock change bits */ /* these variables are for managing the stream of macroblock change bits */
unsigned char *mb_change_bits = s->mb_change_bits; const unsigned char *mb_change_bits = s->mb_change_bits;
unsigned char mb_change_byte; unsigned char mb_change_byte;
unsigned char mb_change_byte_mask; unsigned char mb_change_byte_mask;
int mb_change_index; int mb_change_index;
@@ -422,7 +613,7 @@ static void truemotion1_decode_16bit(TrueMotion1Context *s)
int index; int index;
/* clean out the line buffer */ /* clean out the line buffer */
memset(s->vert_pred, 0, s->avctx->width * sizeof(unsigned short)); memset(s->vert_pred, 0, s->avctx->width * sizeof(unsigned int));
GET_NEXT_INDEX(); GET_NEXT_INDEX();
@@ -431,7 +622,6 @@ static void truemotion1_decode_16bit(TrueMotion1Context *s)
/* re-init variables for the next line iteration */ /* re-init variables for the next line iteration */
horiz_pred = 0; horiz_pred = 0;
current_pixel_pair = (unsigned int *)current_line; current_pixel_pair = (unsigned int *)current_line;
prev_pixel_pair = (unsigned int *)prev_line;
vert_pred = s->vert_pred; vert_pred = s->vert_pred;
mb_change_index = 0; mb_change_index = 0;
mb_change_byte = mb_change_bits[mb_change_index++]; mb_change_byte = mb_change_bits[mb_change_index++];
@@ -500,9 +690,7 @@ static void truemotion1_decode_16bit(TrueMotion1Context *s)
/* skip (copy) four pixels, but reassign the horizontal /* skip (copy) four pixels, but reassign the horizontal
* predictor */ * predictor */
*current_pixel_pair = *prev_pixel_pair++;
*vert_pred++ = *current_pixel_pair++; *vert_pred++ = *current_pixel_pair++;
*current_pixel_pair = *prev_pixel_pair++;
horiz_pred = *current_pixel_pair - *vert_pred; horiz_pred = *current_pixel_pair - *vert_pred;
*vert_pred++ = *current_pixel_pair++; *vert_pred++ = *current_pixel_pair++;
@@ -526,50 +714,161 @@ static void truemotion1_decode_16bit(TrueMotion1Context *s)
mb_change_bits += s->mb_change_bits_row_size; mb_change_bits += s->mb_change_bits_row_size;
current_line += s->frame.linesize[0]; current_line += s->frame.linesize[0];
prev_line += s->prev_frame.linesize[0];
} }
} }
static void truemotion1_decode_24bit(TrueMotion1Context *s)
{
int y;
int pixels_left; /* remaining pixels on this line */
unsigned int predictor_pair;
unsigned int horiz_pred;
unsigned int *vert_pred;
unsigned int *current_pixel_pair;
unsigned char *current_line = s->frame.data[0];
int keyframe = s->flags & FLAG_KEYFRAME;
/* these variables are for managing the stream of macroblock change bits */
const unsigned char *mb_change_bits = s->mb_change_bits;
unsigned char mb_change_byte;
unsigned char mb_change_byte_mask;
int mb_change_index;
/* these variables are for managing the main index stream */
int index_stream_index = 0; /* yes, the index into the index stream */
int index;
/* clean out the line buffer */
memset(s->vert_pred, 0, s->avctx->width * sizeof(unsigned int));
GET_NEXT_INDEX();
for (y = 0; y < s->avctx->height; y++) {
/* re-init variables for the next line iteration */
horiz_pred = 0;
current_pixel_pair = (unsigned int *)current_line;
vert_pred = s->vert_pred;
mb_change_index = 0;
mb_change_byte = mb_change_bits[mb_change_index++];
mb_change_byte_mask = 0x01;
pixels_left = s->avctx->width;
while (pixels_left > 0) {
if (keyframe || ((mb_change_byte & mb_change_byte_mask) == 0)) {
switch (y & 3) {
case 0:
/* if macroblock width is 2, apply C-Y-C-Y; else
* apply C-Y-Y */
if (s->block_width == 2) {
APPLY_C_PREDICTOR_24();
APPLY_Y_PREDICTOR_24();
OUTPUT_PIXEL_PAIR();
APPLY_C_PREDICTOR_24();
APPLY_Y_PREDICTOR_24();
OUTPUT_PIXEL_PAIR();
} else {
APPLY_C_PREDICTOR_24();
APPLY_Y_PREDICTOR_24();
OUTPUT_PIXEL_PAIR();
APPLY_Y_PREDICTOR_24();
OUTPUT_PIXEL_PAIR();
}
break;
case 1:
case 3:
/* always apply 2 Y predictors on these iterations */
APPLY_Y_PREDICTOR_24();
OUTPUT_PIXEL_PAIR();
APPLY_Y_PREDICTOR_24();
OUTPUT_PIXEL_PAIR();
break;
case 2:
/* this iteration might be C-Y-C-Y, Y-Y, or C-Y-Y
* depending on the macroblock type */
if (s->block_type == BLOCK_2x2) {
APPLY_C_PREDICTOR_24();
APPLY_Y_PREDICTOR_24();
OUTPUT_PIXEL_PAIR();
APPLY_C_PREDICTOR_24();
APPLY_Y_PREDICTOR_24();
OUTPUT_PIXEL_PAIR();
} else if (s->block_type == BLOCK_4x2) {
APPLY_C_PREDICTOR_24();
APPLY_Y_PREDICTOR_24();
OUTPUT_PIXEL_PAIR();
APPLY_Y_PREDICTOR_24();
OUTPUT_PIXEL_PAIR();
} else {
APPLY_Y_PREDICTOR_24();
OUTPUT_PIXEL_PAIR();
APPLY_Y_PREDICTOR_24();
OUTPUT_PIXEL_PAIR();
}
break;
}
} else {
/* skip (copy) four pixels, but reassign the horizontal
* predictor */
*vert_pred++ = *current_pixel_pair++;
horiz_pred = *current_pixel_pair - *vert_pred;
*vert_pred++ = *current_pixel_pair++;
}
if (!keyframe) {
mb_change_byte_mask <<= 1;
/* next byte */
if (!mb_change_byte_mask) {
mb_change_byte = mb_change_bits[mb_change_index++];
mb_change_byte_mask = 0x01;
}
}
pixels_left -= 4;
}
/* next change row */
if (((y + 1) & 3) == 0)
mb_change_bits += s->mb_change_bits_row_size;
current_line += s->frame.linesize[0];
}
}
static int truemotion1_decode_frame(AVCodecContext *avctx, static int truemotion1_decode_frame(AVCodecContext *avctx,
void *data, int *data_size, void *data, int *data_size,
uint8_t *buf, int buf_size) const uint8_t *buf, int buf_size)
{ {
TrueMotion1Context *s = (TrueMotion1Context *)avctx->priv_data; TrueMotion1Context *s = avctx->priv_data;
s->buf = buf; s->buf = buf;
s->size = buf_size; s->size = buf_size;
s->frame.reference = 1;
if (avctx->get_buffer(avctx, &s->frame) < 0) {
fprintf(stderr, "truemotion1: get_buffer() failed\n");
return -1;
}
/* no supplementary picture */
if (buf_size == 0)
return 0;
*data_size = 0;
if (truemotion1_decode_header(s) == -1) if (truemotion1_decode_header(s) == -1)
return -1; return -1;
/* check for a do-nothing frame and copy the previous frame */ s->frame.reference = 1;
if (compression_types[s->compression].algorithm == ALGO_NOP) s->frame.buffer_hints = FF_BUFFER_HINTS_VALID |
{ FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
memcpy(s->frame.data[0], s->prev_frame.data[0], if (avctx->reget_buffer(avctx, &s->frame) < 0) {
s->frame.linesize[0] * s->avctx->height); av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
} else if (compression_types[s->compression].algorithm == ALGO_RGB24H) { return -1;
printf (" 24-bit Duck TrueMotion decoding not yet implemented\n");
} else {
truemotion1_decode_16bit(s);
} }
if (s->prev_frame.data[0]) if (compression_types[s->compression].algorithm == ALGO_RGB24H) {
avctx->release_buffer(avctx, &s->prev_frame); truemotion1_decode_24bit(s);
} else if (compression_types[s->compression].algorithm != ALGO_NOP) {
/* shuffle frames */ truemotion1_decode_16bit(s);
s->prev_frame = s->frame; }
*data_size = sizeof(AVFrame); *data_size = sizeof(AVFrame);
*(AVFrame*)data = s->frame; *(AVFrame*)data = s->frame;
@@ -578,13 +877,12 @@ static int truemotion1_decode_frame(AVCodecContext *avctx,
return buf_size; return buf_size;
} }
static int truemotion1_decode_end(AVCodecContext *avctx) static av_cold int truemotion1_decode_end(AVCodecContext *avctx)
{ {
TrueMotion1Context *s = (TrueMotion1Context *)avctx->priv_data; TrueMotion1Context *s = avctx->priv_data;
/* release the last frame */ if (s->frame.data[0])
if (s->prev_frame.data[0]) avctx->release_buffer(avctx, &s->frame);
avctx->release_buffer(avctx, &s->prev_frame);
av_free(s->vert_pred); av_free(s->vert_pred);
@@ -601,4 +899,5 @@ AVCodec truemotion1_decoder = {
truemotion1_decode_end, truemotion1_decode_end,
truemotion1_decode_frame, truemotion1_decode_frame,
CODEC_CAP_DR1, CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("Duck TrueMotion 1.0"),
}; };
@@ -5,34 +5,53 @@
* distributed under the GNU GPL. It is redistributed with ffmpeg under the * distributed under the GNU GPL. It is redistributed with ffmpeg under the
* GNU LGPL using the common understanding that data tables necessary for * GNU LGPL using the common understanding that data tables necessary for
* decoding algorithms are not necessarily licensable. * decoding algorithms are not necessarily licensable.
*
* 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 TRUEMOTION1DATA_H #ifndef FFMPEG_TRUEMOTION1DATA_H
#define TRUEMOTION1DATA_H #define FFMPEG_TRUEMOTION1DATA_H
#include <stdint.h>
#include <stdlib.h>
/* Y delta tables, skinny and fat */ /* Y delta tables, skinny and fat */
static int16_t ydt1[8] = { 0, -2, 2, -6, 6, -12, 12, -12 }; static const int16_t ydt1[8] = { 0, -2, 2, -6, 6, -12, 12, -12 };
static int16_t ydt2[8] = { 0, -2, 2, -6, 6, -12, 12, -12 }; static const int16_t ydt2[8] = { 0, -2, 4, -6, 8, -12, 12, -12 };
static int16_t ydt3[8] = { 4, -6, 20, -20, 46, -46, 94, -94 }; static const int16_t ydt3[8] = { 4, -6, 20, -20, 46, -46, 94, -94 };
static int16_t fat_ydt3[8] = { 0, -15, 50, -50, 115, -115, 235, -235 }; static const int16_t fat_ydt3[8] = { 0, -15, 50, -50, 115, -115, 235, -235 };
static int16_t ydt4[8] = { 0, -4, 4, -16, 16, -36, 36, -80 }; static const int16_t ydt4[8] = { 0, -4, 4, -16, 16, -36, 36, -80 };
static int16_t fat_ydt4[8] = { 0, 40, 80, -76, 160, -154, 236, -236 }; static const int16_t fat_ydt4[8] = { 0, 40, 80, -76, 160, -154, 236, -236 };
/* C delta tables, skinny and fat */ /* C delta tables, skinny and fat */
static int16_t cdt1[8] = { 0, -1, 1, -2, 3, -4, 5, -4 }; static const int16_t cdt1[8] = { 0, -1, 1, -2, 3, -4, 5, -4 };
static int16_t cdt2[8] = { 0, -4, 3, -16, 20, -32, 36, -32 }; static const int16_t cdt2[8] = { 0, -4, 3, -16, 20, -32, 36, -32 };
static int16_t fat_cdt2[8] = { 0, -20, 15, -80, 100, -160, 180, -160 }; static const int16_t fat_cdt2[8] = { 0, -20, 15, -80, 100, -160, 180, -160 };
static int16_t cdt3[8] = { 0, -2, 2, -8, 8, -18, 18, -40 }; static const int16_t cdt3[8] = { 0, -2, 2, -8, 8, -18, 18, -40 };
/* NOTE: This table breaks the [+,-] pattern that the rest of the /* NOTE: This table breaks the [+,-] pattern that the rest of the
* tables maintain. Is this intentional? */ * tables maintain. Is this intentional? */
static int16_t fat_cdt3[8] = { 0, 40, 80, -76, 160, -154, 236, -236 }; static const int16_t fat_cdt3[8] = { 0, 40, 80, -76, 160, -154, 236, -236 };
/* all the delta tables to choose from, at all 4 delta levels */ /* all the delta tables to choose from, at all 4 delta levels */
static int16_t *ydts[] = { ydt1, ydt2, ydt3, ydt4, NULL }; static const int16_t * const ydts[] = { ydt1, ydt2, ydt3, ydt4, NULL };
static int16_t *fat_ydts[] = { fat_ydt3, fat_ydt3, fat_ydt3, fat_ydt4, NULL }; static const int16_t * const fat_ydts[] = { fat_ydt3, fat_ydt3, fat_ydt3, fat_ydt4, NULL };
static int16_t *cdts[] = { cdt1, cdt2, cdt3, cdt3, NULL }; static const int16_t * const cdts[] = { cdt1, cdt1, cdt2, cdt3, NULL };
static int16_t *fat_cdts[] = { fat_cdt2, fat_cdt2, fat_cdt2, fat_cdt3, NULL }; static const int16_t * const fat_cdts[] = { fat_cdt2, fat_cdt2, fat_cdt2, fat_cdt3, NULL };
static uint8_t pc_tbl2[] = { static const uint8_t pc_tbl2[] = {
0x8,0x00,0x00,0x00,0x00, 0x8,0x00,0x00,0x00,0x00,
0x8,0x00,0x00,0x00,0x00, 0x8,0x00,0x00,0x00,0x00,
0x8,0x10,0x00,0x00,0x00, 0x8,0x10,0x00,0x00,0x00,
@@ -291,7 +310,7 @@ static uint8_t pc_tbl2[] = {
0x2,0x66 0x2,0x66
}; };
static uint8_t pc_tbl3[] = { static const uint8_t pc_tbl3[] = {
0x6,0x00,0x00,0x00, 0x6,0x00,0x00,0x00,
0x6,0x00,0x00,0x00, 0x6,0x00,0x00,0x00,
0x6,0x00,0x00,0x01, 0x6,0x00,0x00,0x01,
@@ -550,7 +569,7 @@ static uint8_t pc_tbl3[] = {
0x2,0x77 0x2,0x77
}; };
static uint8_t pc_tbl4[] = { static const uint8_t pc_tbl4[] = {
0x8,0x00,0x00,0x00,0x00, 0x8,0x00,0x00,0x00,0x00,
0x8,0x00,0x00,0x00,0x00, 0x8,0x00,0x00,0x00,0x00,
0x8,0x20,0x00,0x00,0x00, 0x8,0x20,0x00,0x00,0x00,
@@ -809,5 +828,6 @@ static uint8_t pc_tbl4[] = {
0x2,0x77 0x2,0x77
}; };
static uint8_t *tables[] = { pc_tbl2, pc_tbl3, pc_tbl4 }; static const uint8_t * const tables[] = { pc_tbl2, pc_tbl3, pc_tbl4 };
#endif
#endif /* FFMPEG_TRUEMOTION1DATA_H */
@@ -0,0 +1,891 @@
/*
* Duck/ON2 TrueMotion 2 Decoder
* 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 truemotion2.c
* Duck TrueMotion2 decoder.
*/
#include "avcodec.h"
#include "bitstream.h"
#include "dsputil.h"
#define TM2_ESCAPE 0x80000000
#define TM2_DELTAS 64
/* Huffman-coded streams of different types of blocks */
enum TM2_STREAMS{ TM2_C_HI = 0, TM2_C_LO, TM2_L_HI, TM2_L_LO,
TM2_UPD, TM2_MOT, TM2_TYPE, TM2_NUM_STREAMS};
/* Block types */
enum TM2_BLOCKS{ TM2_HI_RES = 0, TM2_MED_RES, TM2_LOW_RES, TM2_NULL_RES,
TM2_UPDATE, TM2_STILL, TM2_MOTION};
typedef struct TM2Context{
AVCodecContext *avctx;
AVFrame pic;
GetBitContext gb;
DSPContext dsp;
/* TM2 streams */
int *tokens[TM2_NUM_STREAMS];
int tok_lens[TM2_NUM_STREAMS];
int tok_ptrs[TM2_NUM_STREAMS];
int deltas[TM2_NUM_STREAMS][TM2_DELTAS];
/* for blocks decoding */
int D[4];
int CD[4];
int *last;
int *clast;
/* data for current and previous frame */
int *Y1, *U1, *V1, *Y2, *U2, *V2;
int cur;
} TM2Context;
/**
* Huffman codes for each of streams
*/
typedef struct TM2Codes{
VLC vlc; ///< table for FFmpeg bitstream reader
int bits;
int *recode; ///< table for converting from code indexes to values
int length;
} TM2Codes;
/**
* structure for gathering Huffman codes information
*/
typedef struct TM2Huff{
int val_bits; ///< length of literal
int max_bits; ///< maximum length of code
int min_bits; ///< minimum length of code
int nodes; ///< total number of nodes in tree
int num; ///< current number filled
int max_num; ///< total number of codes
int *nums; ///< literals
uint32_t *bits; ///< codes
int *lens; ///< codelengths
} TM2Huff;
static int tm2_read_tree(TM2Context *ctx, uint32_t prefix, int length, TM2Huff *huff)
{
if(length > huff->max_bits) {
av_log(ctx->avctx, AV_LOG_ERROR, "Tree exceeded its given depth (%i)\n", huff->max_bits);
return -1;
}
if(!get_bits1(&ctx->gb)) { /* literal */
if (length == 0) {
length = 1;
}
if(huff->num >= huff->max_num) {
av_log(ctx->avctx, AV_LOG_DEBUG, "Too many literals\n");
return -1;
}
huff->nums[huff->num] = get_bits_long(&ctx->gb, huff->val_bits);
huff->bits[huff->num] = prefix;
huff->lens[huff->num] = length;
huff->num++;
return 0;
} else { /* non-terminal node */
if(tm2_read_tree(ctx, prefix << 1, length + 1, huff) == -1)
return -1;
if(tm2_read_tree(ctx, (prefix << 1) | 1, length + 1, huff) == -1)
return -1;
}
return 0;
}
static int tm2_build_huff_table(TM2Context *ctx, TM2Codes *code)
{
TM2Huff huff;
int res = 0;
huff.val_bits = get_bits(&ctx->gb, 5);
huff.max_bits = get_bits(&ctx->gb, 5);
huff.min_bits = get_bits(&ctx->gb, 5);
huff.nodes = get_bits_long(&ctx->gb, 17);
huff.num = 0;
/* check for correct codes parameters */
if((huff.val_bits < 1) || (huff.val_bits > 32) ||
(huff.max_bits < 0) || (huff.max_bits > 32)) {
av_log(ctx->avctx, AV_LOG_ERROR, "Incorrect tree parameters - literal length: %i, max code length: %i\n",
huff.val_bits, huff.max_bits);
return -1;
}
if((huff.nodes < 0) || (huff.nodes > 0x10000)) {
av_log(ctx->avctx, AV_LOG_ERROR, "Incorrect number of Huffman tree nodes: %i\n", huff.nodes);
return -1;
}
/* one-node tree */
if(huff.max_bits == 0)
huff.max_bits = 1;
/* allocate space for codes - it is exactly ceil(nodes / 2) entries */
huff.max_num = (huff.nodes + 1) >> 1;
huff.nums = av_mallocz(huff.max_num * sizeof(int));
huff.bits = av_mallocz(huff.max_num * sizeof(uint32_t));
huff.lens = av_mallocz(huff.max_num * sizeof(int));
if(tm2_read_tree(ctx, 0, 0, &huff) == -1)
res = -1;
if(huff.num != huff.max_num) {
av_log(ctx->avctx, AV_LOG_ERROR, "Got less codes than expected: %i of %i\n",
huff.num, huff.max_num);
res = -1;
}
/* convert codes to vlc_table */
if(res != -1) {
int i;
res = init_vlc(&code->vlc, huff.max_bits, huff.max_num,
huff.lens, sizeof(int), sizeof(int),
huff.bits, sizeof(uint32_t), sizeof(uint32_t), 0);
if(res < 0) {
av_log(ctx->avctx, AV_LOG_ERROR, "Cannot build VLC table\n");
res = -1;
} else
res = 0;
if(res != -1) {
code->bits = huff.max_bits;
code->length = huff.max_num;
code->recode = av_malloc(code->length * sizeof(int));
for(i = 0; i < code->length; i++)
code->recode[i] = huff.nums[i];
}
}
/* free allocated memory */
av_free(huff.nums);
av_free(huff.bits);
av_free(huff.lens);
return res;
}
static void tm2_free_codes(TM2Codes *code)
{
if(code->recode)
av_free(code->recode);
if(code->vlc.table)
free_vlc(&code->vlc);
}
static inline int tm2_get_token(GetBitContext *gb, TM2Codes *code)
{
int val;
val = get_vlc2(gb, code->vlc.table, code->bits, 1);
return code->recode[val];
}
static inline int tm2_read_header(TM2Context *ctx, const uint8_t *buf)
{
uint32_t magic;
const uint8_t *obuf;
int length;
obuf = buf;
magic = AV_RL32(buf);
buf += 4;
if(magic == 0x00000100) { /* old header */
/* av_log (ctx->avctx, AV_LOG_ERROR, "TM2 old header: not implemented (yet)\n"); */
return 40;
} else if(magic == 0x00000101) { /* new header */
int w, h, size, flags, xr, yr;
length = AV_RL32(buf);
buf += 4;
init_get_bits(&ctx->gb, buf, 32 * 8);
size = get_bits_long(&ctx->gb, 31);
h = get_bits(&ctx->gb, 15);
w = get_bits(&ctx->gb, 15);
flags = get_bits_long(&ctx->gb, 31);
yr = get_bits(&ctx->gb, 9);
xr = get_bits(&ctx->gb, 9);
return 40;
} else {
av_log (ctx->avctx, AV_LOG_ERROR, "Not a TM2 header: 0x%08X\n", magic);
return -1;
}
return buf - obuf;
}
static int tm2_read_deltas(TM2Context *ctx, int stream_id) {
int d, mb;
int i, v;
d = get_bits(&ctx->gb, 9);
mb = get_bits(&ctx->gb, 5);
if((d < 1) || (d > TM2_DELTAS) || (mb < 1) || (mb > 32)) {
av_log(ctx->avctx, AV_LOG_ERROR, "Incorrect delta table: %i deltas x %i bits\n", d, mb);
return -1;
}
for(i = 0; i < d; i++) {
v = get_bits_long(&ctx->gb, mb);
if(v & (1 << (mb - 1)))
ctx->deltas[stream_id][i] = v - (1 << mb);
else
ctx->deltas[stream_id][i] = v;
}
for(; i < TM2_DELTAS; i++)
ctx->deltas[stream_id][i] = 0;
return 0;
}
static int tm2_read_stream(TM2Context *ctx, const uint8_t *buf, int stream_id) {
int i;
int cur = 0;
int skip = 0;
int len, toks;
TM2Codes codes;
/* get stream length in dwords */
len = AV_RB32(buf); buf += 4; cur += 4;
skip = len * 4 + 4;
if(len == 0)
return 4;
toks = AV_RB32(buf); buf += 4; cur += 4;
if(toks & 1) {
len = AV_RB32(buf); buf += 4; cur += 4;
if(len == TM2_ESCAPE) {
len = AV_RB32(buf); buf += 4; cur += 4;
}
if(len > 0) {
init_get_bits(&ctx->gb, buf, (skip - cur) * 8);
if(tm2_read_deltas(ctx, stream_id) == -1)
return -1;
buf += ((get_bits_count(&ctx->gb) + 31) >> 5) << 2;
cur += ((get_bits_count(&ctx->gb) + 31) >> 5) << 2;
}
}
/* skip unused fields */
if(AV_RB32(buf) == TM2_ESCAPE) {
buf += 4; cur += 4; /* some unknown length - could be escaped too */
}
buf += 4; cur += 4;
buf += 4; cur += 4; /* unused by decoder */
init_get_bits(&ctx->gb, buf, (skip - cur) * 8);
if(tm2_build_huff_table(ctx, &codes) == -1)
return -1;
buf += ((get_bits_count(&ctx->gb) + 31) >> 5) << 2;
cur += ((get_bits_count(&ctx->gb) + 31) >> 5) << 2;
toks >>= 1;
/* check if we have sane number of tokens */
if((toks < 0) || (toks > 0xFFFFFF)){
av_log(ctx->avctx, AV_LOG_ERROR, "Incorrect number of tokens: %i\n", toks);
tm2_free_codes(&codes);
return -1;
}
ctx->tokens[stream_id] = av_realloc(ctx->tokens[stream_id], toks * sizeof(int));
ctx->tok_lens[stream_id] = toks;
len = AV_RB32(buf); buf += 4; cur += 4;
if(len > 0) {
init_get_bits(&ctx->gb, buf, (skip - cur) * 8);
for(i = 0; i < toks; i++)
ctx->tokens[stream_id][i] = tm2_get_token(&ctx->gb, &codes);
} else {
for(i = 0; i < toks; i++)
ctx->tokens[stream_id][i] = codes.recode[0];
}
tm2_free_codes(&codes);
return skip;
}
static inline int GET_TOK(TM2Context *ctx,int type) {
if(ctx->tok_ptrs[type] >= ctx->tok_lens[type]) {
av_log(ctx->avctx, AV_LOG_ERROR, "Read token from stream %i out of bounds (%i>=%i)\n", type, ctx->tok_ptrs[type], ctx->tok_lens[type]);
return 0;
}
if(type <= TM2_MOT)
return ctx->deltas[type][ctx->tokens[type][ctx->tok_ptrs[type]++]];
return ctx->tokens[type][ctx->tok_ptrs[type]++];
}
/* blocks decoding routines */
/* common Y, U, V pointers initialisation */
#define TM2_INIT_POINTERS() \
int *last, *clast; \
int *Y, *U, *V;\
int Ystride, Ustride, Vstride;\
\
Ystride = ctx->avctx->width;\
Vstride = (ctx->avctx->width + 1) >> 1;\
Ustride = (ctx->avctx->width + 1) >> 1;\
Y = (ctx->cur?ctx->Y2:ctx->Y1) + by * 4 * Ystride + bx * 4;\
V = (ctx->cur?ctx->V2:ctx->V1) + by * 2 * Vstride + bx * 2;\
U = (ctx->cur?ctx->U2:ctx->U1) + by * 2 * Ustride + bx * 2;\
last = ctx->last + bx * 4;\
clast = ctx->clast + bx * 4;
#define TM2_INIT_POINTERS_2() \
int *Yo, *Uo, *Vo;\
int oYstride, oUstride, oVstride;\
\
TM2_INIT_POINTERS();\
oYstride = Ystride;\
oVstride = Vstride;\
oUstride = Ustride;\
Yo = (ctx->cur?ctx->Y1:ctx->Y2) + by * 4 * oYstride + bx * 4;\
Vo = (ctx->cur?ctx->V1:ctx->V2) + by * 2 * oVstride + bx * 2;\
Uo = (ctx->cur?ctx->U1:ctx->U2) + by * 2 * oUstride + bx * 2;
/* recalculate last and delta values for next blocks */
#define TM2_RECALC_BLOCK(CHR, stride, last, CD) {\
CD[0] = (CHR[1] - 128) - last[1];\
CD[1] = (int)CHR[stride + 1] - (int)CHR[1];\
last[0] = (int)CHR[stride + 0] - 128;\
last[1] = (int)CHR[stride + 1] - 128;}
/* common operations - add deltas to 4x4 block of luma or 2x2 blocks of chroma */
static inline void tm2_apply_deltas(TM2Context *ctx, int* Y, int stride, int *deltas, int *last)
{
int ct, d;
int i, j;
for(j = 0; j < 4; j++){
ct = ctx->D[j];
for(i = 0; i < 4; i++){
d = deltas[i + j * 4];
ct += d;
last[i] += ct;
Y[i] = av_clip_uint8(last[i]);
}
Y += stride;
ctx->D[j] = ct;
}
}
static inline void tm2_high_chroma(int *data, int stride, int *last, int *CD, int *deltas)
{
int i, j;
for(j = 0; j < 2; j++){
for(i = 0; i < 2; i++){
CD[j] += deltas[i + j * 2];
last[i] += CD[j];
data[i] = last[i] + 128;
}
data += stride;
}
}
static inline void tm2_low_chroma(int *data, int stride, int *clast, int *CD, int *deltas, int bx)
{
int t;
int l;
int prev;
if(bx > 0)
prev = clast[-3];
else
prev = 0;
t = (CD[0] + CD[1]) >> 1;
l = (prev - CD[0] - CD[1] + clast[1]) >> 1;
CD[1] = CD[0] + CD[1] - t;
CD[0] = t;
clast[0] = l;
tm2_high_chroma(data, stride, clast, CD, deltas);
}
static inline void tm2_hi_res_block(TM2Context *ctx, AVFrame *pic, int bx, int by)
{
int i;
int deltas[16];
TM2_INIT_POINTERS();
/* hi-res chroma */
for(i = 0; i < 4; i++) {
deltas[i] = GET_TOK(ctx, TM2_C_HI);
deltas[i + 4] = GET_TOK(ctx, TM2_C_HI);
}
tm2_high_chroma(U, Ustride, clast, ctx->CD, deltas);
tm2_high_chroma(V, Vstride, clast + 2, ctx->CD + 2, deltas + 4);
/* hi-res luma */
for(i = 0; i < 16; i++)
deltas[i] = GET_TOK(ctx, TM2_L_HI);
tm2_apply_deltas(ctx, Y, Ystride, deltas, last);
}
static inline void tm2_med_res_block(TM2Context *ctx, AVFrame *pic, int bx, int by)
{
int i;
int deltas[16];
TM2_INIT_POINTERS();
/* low-res chroma */
deltas[0] = GET_TOK(ctx, TM2_C_LO);
deltas[1] = deltas[2] = deltas[3] = 0;
tm2_low_chroma(U, Ustride, clast, ctx->CD, deltas, bx);
deltas[0] = GET_TOK(ctx, TM2_C_LO);
deltas[1] = deltas[2] = deltas[3] = 0;
tm2_low_chroma(V, Vstride, clast + 2, ctx->CD + 2, deltas, bx);
/* hi-res luma */
for(i = 0; i < 16; i++)
deltas[i] = GET_TOK(ctx, TM2_L_HI);
tm2_apply_deltas(ctx, Y, Ystride, deltas, last);
}
static inline void tm2_low_res_block(TM2Context *ctx, AVFrame *pic, int bx, int by)
{
int i;
int t1, t2;
int deltas[16];
TM2_INIT_POINTERS();
/* low-res chroma */
deltas[0] = GET_TOK(ctx, TM2_C_LO);
deltas[1] = deltas[2] = deltas[3] = 0;
tm2_low_chroma(U, Ustride, clast, ctx->CD, deltas, bx);
deltas[0] = GET_TOK(ctx, TM2_C_LO);
deltas[1] = deltas[2] = deltas[3] = 0;
tm2_low_chroma(V, Vstride, clast + 2, ctx->CD + 2, deltas, bx);
/* low-res luma */
for(i = 0; i < 16; i++)
deltas[i] = 0;
deltas[ 0] = GET_TOK(ctx, TM2_L_LO);
deltas[ 2] = GET_TOK(ctx, TM2_L_LO);
deltas[ 8] = GET_TOK(ctx, TM2_L_LO);
deltas[10] = GET_TOK(ctx, TM2_L_LO);
if(bx > 0)
last[0] = (last[-1] - ctx->D[0] - ctx->D[1] - ctx->D[2] - ctx->D[3] + last[1]) >> 1;
else
last[0] = (last[1] - ctx->D[0] - ctx->D[1] - ctx->D[2] - ctx->D[3])>> 1;
last[2] = (last[1] + last[3]) >> 1;
t1 = ctx->D[0] + ctx->D[1];
ctx->D[0] = t1 >> 1;
ctx->D[1] = t1 - (t1 >> 1);
t2 = ctx->D[2] + ctx->D[3];
ctx->D[2] = t2 >> 1;
ctx->D[3] = t2 - (t2 >> 1);
tm2_apply_deltas(ctx, Y, Ystride, deltas, last);
}
static inline void tm2_null_res_block(TM2Context *ctx, AVFrame *pic, int bx, int by)
{
int i;
int ct;
int left, right, diff;
int deltas[16];
TM2_INIT_POINTERS();
/* null chroma */
deltas[0] = deltas[1] = deltas[2] = deltas[3] = 0;
tm2_low_chroma(U, Ustride, clast, ctx->CD, deltas, bx);
deltas[0] = deltas[1] = deltas[2] = deltas[3] = 0;
tm2_low_chroma(V, Vstride, clast + 2, ctx->CD + 2, deltas, bx);
/* null luma */
for(i = 0; i < 16; i++)
deltas[i] = 0;
ct = ctx->D[0] + ctx->D[1] + ctx->D[2] + ctx->D[3];
if(bx > 0)
left = last[-1] - ct;
else
left = 0;
right = last[3];
diff = right - left;
last[0] = left + (diff >> 2);
last[1] = left + (diff >> 1);
last[2] = right - (diff >> 2);
last[3] = right;
{
int tp = left;
ctx->D[0] = (tp + (ct >> 2)) - left;
left += ctx->D[0];
ctx->D[1] = (tp + (ct >> 1)) - left;
left += ctx->D[1];
ctx->D[2] = ((tp + ct) - (ct >> 2)) - left;
left += ctx->D[2];
ctx->D[3] = (tp + ct) - left;
}
tm2_apply_deltas(ctx, Y, Ystride, deltas, last);
}
static inline void tm2_still_block(TM2Context *ctx, AVFrame *pic, int bx, int by)
{
int i, j;
TM2_INIT_POINTERS_2();
/* update chroma */
for(j = 0; j < 2; j++){
for(i = 0; i < 2; i++){
U[i] = Uo[i];
V[i] = Vo[i];
}
U += Ustride; V += Vstride;
Uo += oUstride; Vo += oVstride;
}
U -= Ustride * 2;
V -= Vstride * 2;
TM2_RECALC_BLOCK(U, Ustride, clast, ctx->CD);
TM2_RECALC_BLOCK(V, Vstride, (clast + 2), (ctx->CD + 2));
/* update deltas */
ctx->D[0] = Yo[3] - last[3];
ctx->D[1] = Yo[3 + oYstride] - Yo[3];
ctx->D[2] = Yo[3 + oYstride * 2] - Yo[3 + oYstride];
ctx->D[3] = Yo[3 + oYstride * 3] - Yo[3 + oYstride * 2];
for(j = 0; j < 4; j++){
for(i = 0; i < 4; i++){
Y[i] = Yo[i];
last[i] = Yo[i];
}
Y += Ystride;
Yo += oYstride;
}
}
static inline void tm2_update_block(TM2Context *ctx, AVFrame *pic, int bx, int by)
{
int i, j;
int d;
TM2_INIT_POINTERS_2();
/* update chroma */
for(j = 0; j < 2; j++){
for(i = 0; i < 2; i++){
U[i] = Uo[i] + GET_TOK(ctx, TM2_UPD);
V[i] = Vo[i] + GET_TOK(ctx, TM2_UPD);
}
U += Ustride; V += Vstride;
Uo += oUstride; Vo += oVstride;
}
U -= Ustride * 2;
V -= Vstride * 2;
TM2_RECALC_BLOCK(U, Ustride, clast, ctx->CD);
TM2_RECALC_BLOCK(V, Vstride, (clast + 2), (ctx->CD + 2));
/* update deltas */
ctx->D[0] = Yo[3] - last[3];
ctx->D[1] = Yo[3 + oYstride] - Yo[3];
ctx->D[2] = Yo[3 + oYstride * 2] - Yo[3 + oYstride];
ctx->D[3] = Yo[3 + oYstride * 3] - Yo[3 + oYstride * 2];
for(j = 0; j < 4; j++){
d = last[3];
for(i = 0; i < 4; i++){
Y[i] = Yo[i] + GET_TOK(ctx, TM2_UPD);
last[i] = Y[i];
}
ctx->D[j] = last[3] - d;
Y += Ystride;
Yo += oYstride;
}
}
static inline void tm2_motion_block(TM2Context *ctx, AVFrame *pic, int bx, int by)
{
int i, j;
int mx, my;
TM2_INIT_POINTERS_2();
mx = GET_TOK(ctx, TM2_MOT);
my = GET_TOK(ctx, TM2_MOT);
Yo += my * oYstride + mx;
Uo += (my >> 1) * oUstride + (mx >> 1);
Vo += (my >> 1) * oVstride + (mx >> 1);
/* copy chroma */
for(j = 0; j < 2; j++){
for(i = 0; i < 2; i++){
U[i] = Uo[i];
V[i] = Vo[i];
}
U += Ustride; V += Vstride;
Uo += oUstride; Vo += oVstride;
}
U -= Ustride * 2;
V -= Vstride * 2;
TM2_RECALC_BLOCK(U, Ustride, clast, ctx->CD);
TM2_RECALC_BLOCK(V, Vstride, (clast + 2), (ctx->CD + 2));
/* copy luma */
for(j = 0; j < 4; j++){
for(i = 0; i < 4; i++){
Y[i] = Yo[i];
}
Y += Ystride;
Yo += oYstride;
}
/* calculate deltas */
Y -= Ystride * 4;
ctx->D[0] = Y[3] - last[3];
ctx->D[1] = Y[3 + Ystride] - Y[3];
ctx->D[2] = Y[3 + Ystride * 2] - Y[3 + Ystride];
ctx->D[3] = Y[3 + Ystride * 3] - Y[3 + Ystride * 2];
for(i = 0; i < 4; i++)
last[i] = Y[i + Ystride * 3];
}
static int tm2_decode_blocks(TM2Context *ctx, AVFrame *p)
{
int i, j;
int bw, bh;
int type;
int keyframe = 1;
uint8_t *Y, *U, *V;
int *src;
bw = ctx->avctx->width >> 2;
bh = ctx->avctx->height >> 2;
for(i = 0; i < TM2_NUM_STREAMS; i++)
ctx->tok_ptrs[i] = 0;
if (ctx->tok_lens[TM2_TYPE]<bw*bh){
av_log(ctx->avctx,AV_LOG_ERROR,"Got %i tokens for %i blocks\n",ctx->tok_lens[TM2_TYPE],bw*bh);
return -1;
}
memset(ctx->last, 0, 4 * bw * sizeof(int));
memset(ctx->clast, 0, 4 * bw * sizeof(int));
for(j = 0; j < bh; j++) {
memset(ctx->D, 0, 4 * sizeof(int));
memset(ctx->CD, 0, 4 * sizeof(int));
for(i = 0; i < bw; i++) {
type = GET_TOK(ctx, TM2_TYPE);
switch(type) {
case TM2_HI_RES:
tm2_hi_res_block(ctx, p, i, j);
break;
case TM2_MED_RES:
tm2_med_res_block(ctx, p, i, j);
break;
case TM2_LOW_RES:
tm2_low_res_block(ctx, p, i, j);
break;
case TM2_NULL_RES:
tm2_null_res_block(ctx, p, i, j);
break;
case TM2_UPDATE:
tm2_update_block(ctx, p, i, j);
keyframe = 0;
break;
case TM2_STILL:
tm2_still_block(ctx, p, i, j);
keyframe = 0;
break;
case TM2_MOTION:
tm2_motion_block(ctx, p, i, j);
keyframe = 0;
break;
default:
av_log(ctx->avctx, AV_LOG_ERROR, "Skipping unknown block type %i\n", type);
}
}
}
/* copy data from our buffer to AVFrame */
Y = p->data[0];
src = (ctx->cur?ctx->Y2:ctx->Y1);
for(j = 0; j < ctx->avctx->height; j++){
for(i = 0; i < ctx->avctx->width; i++){
Y[i] = av_clip_uint8(*src++);
}
Y += p->linesize[0];
}
U = p->data[2];
src = (ctx->cur?ctx->U2:ctx->U1);
for(j = 0; j < (ctx->avctx->height + 1) >> 1; j++){
for(i = 0; i < (ctx->avctx->width + 1) >> 1; i++){
U[i] = av_clip_uint8(*src++);
}
U += p->linesize[2];
}
V = p->data[1];
src = (ctx->cur?ctx->V2:ctx->V1);
for(j = 0; j < (ctx->avctx->height + 1) >> 1; j++){
for(i = 0; i < (ctx->avctx->width + 1) >> 1; i++){
V[i] = av_clip_uint8(*src++);
}
V += p->linesize[1];
}
return keyframe;
}
static int decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
const uint8_t *buf, int buf_size)
{
TM2Context * const l = avctx->priv_data;
AVFrame * const p= (AVFrame*)&l->pic;
int skip, t;
p->reference = 1;
p->buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
if(avctx->reget_buffer(avctx, p) < 0){
av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
return -1;
}
l->dsp.bswap_buf((uint32_t*)buf, (const uint32_t*)buf, buf_size >> 2); //FIXME SERIOUS BUG
skip = tm2_read_header(l, buf);
if(skip == -1)
return -1;
t = tm2_read_stream(l, buf + skip, TM2_C_HI);
if(t == -1)
return -1;
skip += t;
t = tm2_read_stream(l, buf + skip, TM2_C_LO);
if(t == -1)
return -1;
skip += t;
t = tm2_read_stream(l, buf + skip, TM2_L_HI);
if(t == -1)
return -1;
skip += t;
t = tm2_read_stream(l, buf + skip, TM2_L_LO);
if(t == -1)
return -1;
skip += t;
t = tm2_read_stream(l, buf + skip, TM2_UPD);
if(t == -1)
return -1;
skip += t;
t = tm2_read_stream(l, buf + skip, TM2_MOT);
if(t == -1)
return -1;
skip += t;
t = tm2_read_stream(l, buf + skip, TM2_TYPE);
if(t == -1)
return -1;
p->key_frame = tm2_decode_blocks(l, p);
if(p->key_frame)
p->pict_type = FF_I_TYPE;
else
p->pict_type = FF_P_TYPE;
l->cur = !l->cur;
*data_size = sizeof(AVFrame);
*(AVFrame*)data = l->pic;
return buf_size;
}
static av_cold int decode_init(AVCodecContext *avctx){
TM2Context * const l = avctx->priv_data;
int i;
if (avcodec_check_dimensions(avctx, avctx->width, avctx->height) < 0) {
return -1;
}
if((avctx->width & 3) || (avctx->height & 3)){
av_log(avctx, AV_LOG_ERROR, "Width and height must be multiple of 4\n");
return -1;
}
l->avctx = avctx;
l->pic.data[0]=NULL;
avctx->pix_fmt = PIX_FMT_YUV420P;
dsputil_init(&l->dsp, avctx);
l->last = av_malloc(4 * sizeof(int) * (avctx->width >> 2));
l->clast = av_malloc(4 * sizeof(int) * (avctx->width >> 2));
for(i = 0; i < TM2_NUM_STREAMS; i++) {
l->tokens[i] = NULL;
l->tok_lens[i] = 0;
}
l->Y1 = av_malloc(sizeof(int) * avctx->width * avctx->height);
l->U1 = av_malloc(sizeof(int) * ((avctx->width + 1) >> 1) * ((avctx->height + 1) >> 1));
l->V1 = av_malloc(sizeof(int) * ((avctx->width + 1) >> 1) * ((avctx->height + 1) >> 1));
l->Y2 = av_malloc(sizeof(int) * avctx->width * avctx->height);
l->U2 = av_malloc(sizeof(int) * ((avctx->width + 1) >> 1) * ((avctx->height + 1) >> 1));
l->V2 = av_malloc(sizeof(int) * ((avctx->width + 1) >> 1) * ((avctx->height + 1) >> 1));
l->cur = 0;
return 0;
}
static av_cold int decode_end(AVCodecContext *avctx){
TM2Context * const l = avctx->priv_data;
int i;
if(l->last)
av_free(l->last);
if(l->clast)
av_free(l->clast);
for(i = 0; i < TM2_NUM_STREAMS; i++)
if(l->tokens[i])
av_free(l->tokens[i]);
if(l->Y1){
av_free(l->Y1);
av_free(l->U1);
av_free(l->V1);
av_free(l->Y2);
av_free(l->U2);
av_free(l->V2);
}
return 0;
}
AVCodec truemotion2_decoder = {
"truemotion2",
CODEC_TYPE_VIDEO,
CODEC_ID_TRUEMOTION2,
sizeof(TM2Context),
decode_init,
NULL,
decode_end,
decode_frame,
CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("Duck TrueMotion 2.0"),
};
@@ -0,0 +1,385 @@
/*
* DSP Group TrueSpeech compatible decoder
* 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
*/
#include "avcodec.h"
#include "truespeech_data.h"
/**
* @file truespeech.c
* TrueSpeech decoder.
*/
/**
* TrueSpeech decoder context
*/
typedef struct {
/* input data */
int16_t vector[8]; //< input vector: 5/5/4/4/4/3/3/3
int offset1[2]; //< 8-bit value, used in one copying offset
int offset2[4]; //< 7-bit value, encodes offsets for copying and for two-point filter
int pulseoff[4]; //< 4-bit offset of pulse values block
int pulsepos[4]; //< 27-bit variable, encodes 7 pulse positions
int pulseval[4]; //< 7x2-bit pulse values
int flag; //< 1-bit flag, shows how to choose filters
/* temporary data */
int filtbuf[146]; // some big vector used for storing filters
int prevfilt[8]; // filter from previous frame
int16_t tmp1[8]; // coefficients for adding to out
int16_t tmp2[8]; // coefficients for adding to out
int16_t tmp3[8]; // coefficients for adding to out
int16_t cvector[8]; // correlated input vector
int filtval; // gain value for one function
int16_t newvec[60]; // tmp vector
int16_t filters[32]; // filters for every subframe
} TSContext;
static av_cold int truespeech_decode_init(AVCodecContext * avctx)
{
// TSContext *c = avctx->priv_data;
avctx->sample_fmt = SAMPLE_FMT_S16;
return 0;
}
static void truespeech_read_frame(TSContext *dec, const uint8_t *input)
{
uint32_t t;
/* first dword */
t = AV_RL32(input);
input += 4;
dec->flag = t & 1;
dec->vector[0] = ts_codebook[0][(t >> 1) & 0x1F];
dec->vector[1] = ts_codebook[1][(t >> 6) & 0x1F];
dec->vector[2] = ts_codebook[2][(t >> 11) & 0xF];
dec->vector[3] = ts_codebook[3][(t >> 15) & 0xF];
dec->vector[4] = ts_codebook[4][(t >> 19) & 0xF];
dec->vector[5] = ts_codebook[5][(t >> 23) & 0x7];
dec->vector[6] = ts_codebook[6][(t >> 26) & 0x7];
dec->vector[7] = ts_codebook[7][(t >> 29) & 0x7];
/* second dword */
t = AV_RL32(input);
input += 4;
dec->offset2[0] = (t >> 0) & 0x7F;
dec->offset2[1] = (t >> 7) & 0x7F;
dec->offset2[2] = (t >> 14) & 0x7F;
dec->offset2[3] = (t >> 21) & 0x7F;
dec->offset1[0] = ((t >> 28) & 0xF) << 4;
/* third dword */
t = AV_RL32(input);
input += 4;
dec->pulseval[0] = (t >> 0) & 0x3FFF;
dec->pulseval[1] = (t >> 14) & 0x3FFF;
dec->offset1[1] = (t >> 28) & 0x0F;
/* fourth dword */
t = AV_RL32(input);
input += 4;
dec->pulseval[2] = (t >> 0) & 0x3FFF;
dec->pulseval[3] = (t >> 14) & 0x3FFF;
dec->offset1[1] |= ((t >> 28) & 0x0F) << 4;
/* fifth dword */
t = AV_RL32(input);
input += 4;
dec->pulsepos[0] = (t >> 4) & 0x7FFFFFF;
dec->pulseoff[0] = (t >> 0) & 0xF;
dec->offset1[0] |= (t >> 31) & 1;
/* sixth dword */
t = AV_RL32(input);
input += 4;
dec->pulsepos[1] = (t >> 4) & 0x7FFFFFF;
dec->pulseoff[1] = (t >> 0) & 0xF;
dec->offset1[0] |= ((t >> 31) & 1) << 1;
/* seventh dword */
t = AV_RL32(input);
input += 4;
dec->pulsepos[2] = (t >> 4) & 0x7FFFFFF;
dec->pulseoff[2] = (t >> 0) & 0xF;
dec->offset1[0] |= ((t >> 31) & 1) << 2;
/* eighth dword */
t = AV_RL32(input);
input += 4;
dec->pulsepos[3] = (t >> 4) & 0x7FFFFFF;
dec->pulseoff[3] = (t >> 0) & 0xF;
dec->offset1[0] |= ((t >> 31) & 1) << 3;
}
static void truespeech_correlate_filter(TSContext *dec)
{
int16_t tmp[8];
int i, j;
for(i = 0; i < 8; i++){
if(i > 0){
memcpy(tmp, dec->cvector, i * 2);
for(j = 0; j < i; j++)
dec->cvector[j] = ((tmp[i - j - 1] * dec->vector[i]) +
(dec->cvector[j] << 15) + 0x4000) >> 15;
}
dec->cvector[i] = (8 - dec->vector[i]) >> 3;
}
for(i = 0; i < 8; i++)
dec->cvector[i] = (dec->cvector[i] * ts_230[i]) >> 15;
dec->filtval = dec->vector[0];
}
static void truespeech_filters_merge(TSContext *dec)
{
int i;
if(!dec->flag){
for(i = 0; i < 8; i++){
dec->filters[i + 0] = dec->prevfilt[i];
dec->filters[i + 8] = dec->prevfilt[i];
}
}else{
for(i = 0; i < 8; i++){
dec->filters[i + 0]=(dec->cvector[i] * 21846 + dec->prevfilt[i] * 10923 + 16384) >> 15;
dec->filters[i + 8]=(dec->cvector[i] * 10923 + dec->prevfilt[i] * 21846 + 16384) >> 15;
}
}
for(i = 0; i < 8; i++){
dec->filters[i + 16] = dec->cvector[i];
dec->filters[i + 24] = dec->cvector[i];
}
}
static void truespeech_apply_twopoint_filter(TSContext *dec, int quart)
{
int16_t tmp[146 + 60], *ptr0, *ptr1;
const int16_t *filter;
int i, t, off;
t = dec->offset2[quart];
if(t == 127){
memset(dec->newvec, 0, 60 * 2);
return;
}
for(i = 0; i < 146; i++)
tmp[i] = dec->filtbuf[i];
off = (t / 25) + dec->offset1[quart >> 1] + 18;
ptr0 = tmp + 145 - off;
ptr1 = tmp + 146;
filter = (const int16_t*)ts_240 + (t % 25) * 2;
for(i = 0; i < 60; i++){
t = (ptr0[0] * filter[0] + ptr0[1] * filter[1] + 0x2000) >> 14;
ptr0++;
dec->newvec[i] = t;
ptr1[i] = t;
}
}
static void truespeech_place_pulses(TSContext *dec, int16_t *out, int quart)
{
int16_t tmp[7];
int i, j, t;
const int16_t *ptr1;
int16_t *ptr2;
int coef;
memset(out, 0, 60 * 2);
for(i = 0; i < 7; i++) {
t = dec->pulseval[quart] & 3;
dec->pulseval[quart] >>= 2;
tmp[6 - i] = ts_562[dec->pulseoff[quart] * 4 + t];
}
coef = dec->pulsepos[quart] >> 15;
ptr1 = (const int16_t*)ts_140 + 30;
ptr2 = tmp;
for(i = 0, j = 3; (i < 30) && (j > 0); i++){
t = *ptr1++;
if(coef >= t)
coef -= t;
else{
out[i] = *ptr2++;
ptr1 += 30;
j--;
}
}
coef = dec->pulsepos[quart] & 0x7FFF;
ptr1 = (const int16_t*)ts_140;
for(i = 30, j = 4; (i < 60) && (j > 0); i++){
t = *ptr1++;
if(coef >= t)
coef -= t;
else{
out[i] = *ptr2++;
ptr1 += 30;
j--;
}
}
}
static void truespeech_update_filters(TSContext *dec, int16_t *out, int quart)
{
int i;
for(i = 0; i < 86; i++)
dec->filtbuf[i] = dec->filtbuf[i + 60];
for(i = 0; i < 60; i++){
dec->filtbuf[i + 86] = out[i] + dec->newvec[i] - (dec->newvec[i] >> 3);
out[i] += dec->newvec[i];
}
}
static void truespeech_synth(TSContext *dec, int16_t *out, int quart)
{
int i,k;
int t[8];
int16_t *ptr0, *ptr1;
ptr0 = dec->tmp1;
ptr1 = dec->filters + quart * 8;
for(i = 0; i < 60; i++){
int sum = 0;
for(k = 0; k < 8; k++)
sum += ptr0[k] * ptr1[k];
sum = (sum + (out[i] << 12) + 0x800) >> 12;
out[i] = av_clip(sum, -0x7FFE, 0x7FFE);
for(k = 7; k > 0; k--)
ptr0[k] = ptr0[k - 1];
ptr0[0] = out[i];
}
for(i = 0; i < 8; i++)
t[i] = (ts_5E2[i] * ptr1[i]) >> 15;
ptr0 = dec->tmp2;
for(i = 0; i < 60; i++){
int sum = 0;
for(k = 0; k < 8; k++)
sum += ptr0[k] * t[k];
for(k = 7; k > 0; k--)
ptr0[k] = ptr0[k - 1];
ptr0[0] = out[i];
out[i] = ((out[i] << 12) - sum) >> 12;
}
for(i = 0; i < 8; i++)
t[i] = (ts_5F2[i] * ptr1[i]) >> 15;
ptr0 = dec->tmp3;
for(i = 0; i < 60; i++){
int sum = out[i] << 12;
for(k = 0; k < 8; k++)
sum += ptr0[k] * t[k];
for(k = 7; k > 0; k--)
ptr0[k] = ptr0[k - 1];
ptr0[0] = av_clip((sum + 0x800) >> 12, -0x7FFE, 0x7FFE);
sum = ((ptr0[1] * (dec->filtval - (dec->filtval >> 2))) >> 4) + sum;
sum = sum - (sum >> 3);
out[i] = av_clip((sum + 0x800) >> 12, -0x7FFE, 0x7FFE);
}
}
static void truespeech_save_prevvec(TSContext *c)
{
int i;
for(i = 0; i < 8; i++)
c->prevfilt[i] = c->cvector[i];
}
static int truespeech_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
const uint8_t *buf, int buf_size)
{
TSContext *c = avctx->priv_data;
int i, j;
short *samples = data;
int consumed = 0;
int16_t out_buf[240];
int iterations;
if (!buf_size)
return 0;
iterations = FFMIN(buf_size / 32, *data_size / 480);
for(j = 0; j < iterations; j++) {
truespeech_read_frame(c, buf + consumed);
consumed += 32;
truespeech_correlate_filter(c);
truespeech_filters_merge(c);
memset(out_buf, 0, 240 * 2);
for(i = 0; i < 4; i++) {
truespeech_apply_twopoint_filter(c, i);
truespeech_place_pulses(c, out_buf + i * 60, i);
truespeech_update_filters(c, out_buf + i * 60, i);
truespeech_synth(c, out_buf + i * 60, i);
}
truespeech_save_prevvec(c);
/* finally output decoded frame */
for(i = 0; i < 240; i++)
*samples++ = out_buf[i];
}
*data_size = consumed * 15;
return consumed;
}
AVCodec truespeech_decoder = {
"truespeech",
CODEC_TYPE_AUDIO,
CODEC_ID_TRUESPEECH,
sizeof(TSContext),
truespeech_decode_init,
NULL,
NULL,
truespeech_decode_frame,
.long_name = NULL_IF_CONFIG_SMALL("DSP Group TrueSpeech"),
};
@@ -0,0 +1,159 @@
/*
* DSP Group TrueSpeech compatible decoder
* 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
*/
#ifndef FFMPEG_TRUESPEECH_DATA_H
#define FFMPEG_TRUESPEECH_DATA_H
#include <stdint.h>
/* codebooks fo expanding input filter */
static const int16_t ts_cb_0[32] = {
0x8240, 0x8364, 0x84CE, 0x865D, 0x8805, 0x89DE, 0x8BD7, 0x8DF4,
0x9051, 0x92E2, 0x95DE, 0x990F, 0x9C81, 0xA079, 0xA54C, 0xAAD2,
0xB18A, 0xB90A, 0xC124, 0xC9CC, 0xD339, 0xDDD3, 0xE9D6, 0xF893,
0x096F, 0x1ACA, 0x29EC, 0x381F, 0x45F9, 0x546A, 0x63C3, 0x73B5,
};
static const int16_t ts_cb_1[32] = {
0x9F65, 0xB56B, 0xC583, 0xD371, 0xE018, 0xEBB4, 0xF61C, 0xFF59,
0x085B, 0x1106, 0x1952, 0x214A, 0x28C9, 0x2FF8, 0x36E6, 0x3D92,
0x43DF, 0x49BB, 0x4F46, 0x5467, 0x5930, 0x5DA3, 0x61EC, 0x65F9,
0x69D4, 0x6D5A, 0x709E, 0x73AD, 0x766B, 0x78F0, 0x7B5A, 0x7DA5,
};
static const int16_t ts_cb_2[16] = {
0x96F8, 0xA3B4, 0xAF45, 0xBA53, 0xC4B1, 0xCECC, 0xD86F, 0xE21E,
0xEBF3, 0xF640, 0x00F7, 0x0C20, 0x1881, 0x269A, 0x376B, 0x4D60,
};
static const int16_t ts_cb_3[16] = {
0xC654, 0xDEF2, 0xEFAA, 0xFD94, 0x096A, 0x143F, 0x1E7B, 0x282C,
0x3176, 0x3A89, 0x439F, 0x4CA2, 0x557F, 0x5E50, 0x6718, 0x6F8D,
};
static const int16_t ts_cb_4[16] = {
0xABE7, 0xBBA8, 0xC81C, 0xD326, 0xDD0E, 0xE5D4, 0xEE22, 0xF618,
0xFE28, 0x064F, 0x0EB7, 0x17B8, 0x21AA, 0x2D8B, 0x3BA2, 0x4DF9,
};
static const int16_t ts_cb_5[8] = {
0xD51B, 0xF12E, 0x042E, 0x13C7, 0x2260, 0x311B, 0x40DE, 0x5385,
};
static const int16_t ts_cb_6[8] = {
0xB550, 0xC825, 0xD980, 0xE997, 0xF883, 0x0752, 0x1811, 0x2E18,
};
static const int16_t ts_cb_7[8] = {
0xCEF0, 0xE4F9, 0xF6BB, 0x0646, 0x14F5, 0x23FF, 0x356F, 0x4A8D,
};
static const int16_t * const ts_codebook[8] = {
ts_cb_0, ts_cb_1, ts_cb_2, ts_cb_3, ts_cb_4, ts_cb_5, ts_cb_6, ts_cb_7
};
/* table used for decoding pulse positions */
static const int16_t ts_140[120] = {
0x0E46, 0x0CCC, 0x0B6D, 0x0A28, 0x08FC, 0x07E8, 0x06EB, 0x0604,
0x0532, 0x0474, 0x03C9, 0x0330, 0x02A8, 0x0230, 0x01C7, 0x016C,
0x011E, 0x00DC, 0x00A5, 0x0078, 0x0054, 0x0038, 0x0023, 0x0014,
0x000A, 0x0004, 0x0001, 0x0000, 0x0000, 0x0000,
0x0196, 0x017A, 0x015F, 0x0145, 0x012C, 0x0114, 0x00FD, 0x00E7,
0x00D2, 0x00BE, 0x00AB, 0x0099, 0x0088, 0x0078, 0x0069, 0x005B,
0x004E, 0x0042, 0x0037, 0x002D, 0x0024, 0x001C, 0x0015, 0x000F,
0x000A, 0x0006, 0x0003, 0x0001, 0x0000, 0x0000,
0x001D, 0x001C, 0x001B, 0x001A, 0x0019, 0x0018, 0x0017, 0x0016,
0x0015, 0x0014, 0x0013, 0x0012, 0x0011, 0x0010, 0x000F, 0x000E,
0x000D, 0x000C, 0x000B, 0x000A, 0x0009, 0x0008, 0x0007, 0x0006,
0x0005, 0x0004, 0x0003, 0x0002, 0x0001, 0x0000,
0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001
};
/* filter for correlated input filter */
static const int16_t ts_230[8] =
{ 0x7F3B, 0x7E78, 0x7DB6, 0x7CF5, 0x7C35, 0x7B76, 0x7AB8, 0x79FC };
/* two-point filters table */
static const int16_t ts_240[25 * 2] = {
0xED2F, 0x5239,
0x54F1, 0xE4A9,
0x2620, 0xEE3E,
0x09D6, 0x2C40,
0xEFB5, 0x2BE0,
0x3FE1, 0x3339,
0x442F, 0xE6FE,
0x4458, 0xF9DF,
0xF231, 0x43DB,
0x3DB0, 0xF705,
0x4F7B, 0xFEFB,
0x26AD, 0x0CDC,
0x33C2, 0x0739,
0x12BE, 0x43A2,
0x1BDF, 0x1F3E,
0x0211, 0x0796,
0x2AEB, 0x163F,
0x050D, 0x3A38,
0x0D1E, 0x0D78,
0x150F, 0x3346,
0x38A4, 0x0B7D,
0x2D5D, 0x1FDF,
0x19B7, 0x2822,
0x0D99, 0x1F12,
0x194C, 0x0CE6
};
/* possible pulse values */
static const int16_t ts_562[64] = {
0x0002, 0x0006, 0xFFFE, 0xFFFA,
0x0004, 0x000C, 0xFFFC, 0xFFF4,
0x0006, 0x0012, 0xFFFA, 0xFFEE,
0x000A, 0x001E, 0xFFF6, 0xFFE2,
0x0010, 0x0030, 0xFFF0, 0xFFD0,
0x0019, 0x004B, 0xFFE7, 0xFFB5,
0x0028, 0x0078, 0xFFD8, 0xFF88,
0x0040, 0x00C0, 0xFFC0, 0xFF40,
0x0065, 0x012F, 0xFF9B, 0xFED1,
0x00A1, 0x01E3, 0xFF5F, 0xFE1D,
0x0100, 0x0300, 0xFF00, 0xFD00,
0x0196, 0x04C2, 0xFE6A, 0xFB3E,
0x0285, 0x078F, 0xFD7B, 0xF871,
0x0400, 0x0C00, 0xFC00, 0xF400,
0x0659, 0x130B, 0xF9A7, 0xECF5,
0x0A14, 0x1E3C, 0xF5EC, 0xE1C4
};
/* filters used in final output calculations */
static const int16_t ts_5E2[8] =
{ 0x4666, 0x26B8, 0x154C, 0x0BB6, 0x0671, 0x038B, 0x01F3, 0x0112 };
static const int16_t ts_5F2[8] =
{ 0x6000, 0x4800, 0x3600, 0x2880, 0x1E60, 0x16C8, 0x1116, 0x0CD1 };
#endif /* FFMPEG_TRUESPEECH_DATA_H */
@@ -0,0 +1,346 @@
/*
* TechSmith Camtasia decoder
* Copyright (c) 2004 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 tscc.c
* TechSmith Camtasia decoder
*
* Fourcc: TSCC
*
* Codec is very simple:
* it codes picture (picture difference, really)
* with algorithm almost identical to Windows RLE8,
* only without padding and with greater pixel sizes,
* then this coded picture is packed with ZLib
*
* Supports: BGR8,BGR555,BGR24 - only BGR8 and BGR555 tested
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "avcodec.h"
#ifdef CONFIG_ZLIB
#include <zlib.h>
#endif
/*
* Decoder context
*/
typedef struct TsccContext {
AVCodecContext *avctx;
AVFrame pic;
// Bits per pixel
int bpp;
// Decompressed data size
unsigned int decomp_size;
// Decompression buffer
unsigned char* decomp_buf;
int height;
#ifdef CONFIG_ZLIB
z_stream zstream;
#endif
} CamtasiaContext;
/*
*
* Decode RLE - almost identical to Windows BMP RLE8
* and enhanced to bigger color depths
*
*/
static int decode_rle(CamtasiaContext *c, unsigned int srcsize)
{
unsigned char *src = c->decomp_buf;
unsigned char *output, *output_end;
int p1, p2, line=c->height, pos=0, i;
uint16_t pix16;
uint32_t pix32;
output = c->pic.data[0] + (c->height - 1) * c->pic.linesize[0];
output_end = c->pic.data[0] + (c->height) * c->pic.linesize[0];
while(src < c->decomp_buf + srcsize) {
p1 = *src++;
if(p1 == 0) { //Escape code
p2 = *src++;
if(p2 == 0) { //End-of-line
output = c->pic.data[0] + (--line) * c->pic.linesize[0];
if (line < 0)
return -1;
pos = 0;
continue;
} else if(p2 == 1) { //End-of-picture
return 0;
} else if(p2 == 2) { //Skip
p1 = *src++;
p2 = *src++;
line -= p2;
if (line < 0)
return -1;
pos += p1;
output = c->pic.data[0] + line * c->pic.linesize[0] + pos * (c->bpp / 8);
continue;
}
// Copy data
if (output + p2 * (c->bpp / 8) > output_end) {
src += p2 * (c->bpp / 8);
continue;
}
if ((c->bpp == 8) || (c->bpp == 24)) {
for(i = 0; i < p2 * (c->bpp / 8); i++) {
*output++ = *src++;
}
// RLE8 copy is actually padded - and runs are not!
if(c->bpp == 8 && (p2 & 1)) {
src++;
}
} else if (c->bpp == 16) {
for(i = 0; i < p2; i++) {
pix16 = AV_RL16(src);
src += 2;
*(uint16_t*)output = pix16;
output += 2;
}
} else if (c->bpp == 32) {
for(i = 0; i < p2; i++) {
pix32 = AV_RL32(src);
src += 4;
*(uint32_t*)output = pix32;
output += 4;
}
}
pos += p2;
} else { //Run of pixels
int pix[4]; //original pixel
switch(c->bpp){
case 8: pix[0] = *src++;
break;
case 16: pix16 = AV_RL16(src);
src += 2;
*(uint16_t*)pix = pix16;
break;
case 24: pix[0] = *src++;
pix[1] = *src++;
pix[2] = *src++;
break;
case 32: pix32 = AV_RL32(src);
src += 4;
*(uint32_t*)pix = pix32;
break;
}
if (output + p1 * (c->bpp / 8) > output_end)
continue;
for(i = 0; i < p1; i++) {
switch(c->bpp){
case 8: *output++ = pix[0];
break;
case 16: *(uint16_t*)output = pix16;
output += 2;
break;
case 24: *output++ = pix[0];
*output++ = pix[1];
*output++ = pix[2];
break;
case 32: *(uint32_t*)output = pix32;
output += 4;
break;
}
}
pos += p1;
}
}
av_log(c->avctx, AV_LOG_ERROR, "Camtasia warning: no End-of-picture code\n");
return 1;
}
/*
*
* Decode a frame
*
*/
static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, const uint8_t *buf, int buf_size)
{
CamtasiaContext * const c = avctx->priv_data;
const unsigned char *encoded = buf;
unsigned char *outptr;
#ifdef CONFIG_ZLIB
int zret; // Zlib return code
#endif
int len = buf_size;
if(c->pic.data[0])
avctx->release_buffer(avctx, &c->pic);
c->pic.reference = 1;
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
#ifdef CONFIG_ZLIB
zret = inflateReset(&(c->zstream));
if (zret != Z_OK) {
av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", zret);
return -1;
}
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);
// Z_DATA_ERROR means empty picture
if ((zret != Z_OK) && (zret != Z_STREAM_END) && (zret != Z_DATA_ERROR)) {
av_log(avctx, AV_LOG_ERROR, "Inflate error: %d\n", zret);
return -1;
}
if(zret != Z_DATA_ERROR)
decode_rle(c, c->zstream.avail_out);
/* make the palette available on the way out */
if (c->avctx->pix_fmt == PIX_FMT_PAL8) {
memcpy(c->pic.data[1], c->avctx->palctrl->palette, AVPALETTE_SIZE);
if (c->avctx->palctrl->palette_changed) {
c->pic.palette_has_changed = 1;
c->avctx->palctrl->palette_changed = 0;
}
}
#else
av_log(avctx, AV_LOG_ERROR, "BUG! Zlib support not compiled in frame decoder.\n");
return -1;
#endif
*data_size = sizeof(AVFrame);
*(AVFrame*)data = c->pic;
/* always report that the buffer was completely consumed */
return buf_size;
}
/*
*
* Init tscc decoder
*
*/
static av_cold int decode_init(AVCodecContext *avctx)
{
CamtasiaContext * const c = avctx->priv_data;
int zret; // Zlib return code
c->avctx = avctx;
c->pic.data[0] = NULL;
c->height = avctx->height;
if (avcodec_check_dimensions(avctx, avctx->width, avctx->height) < 0) {
return 1;
}
#ifdef CONFIG_ZLIB
// Needed if zlib unused or init aborted before inflateInit
memset(&(c->zstream), 0, sizeof(z_stream));
#else
av_log(avctx, AV_LOG_ERROR, "Zlib support not compiled.\n");
return 1;
#endif
switch(avctx->bits_per_sample){
case 8: avctx->pix_fmt = PIX_FMT_PAL8; break;
case 16: avctx->pix_fmt = PIX_FMT_RGB555; break;
case 24:
avctx->pix_fmt = PIX_FMT_BGR24;
break;
case 32: avctx->pix_fmt = PIX_FMT_RGB32; break;
default: av_log(avctx, AV_LOG_ERROR, "Camtasia error: unknown depth %i bpp\n", avctx->bits_per_sample);
return -1;
}
c->bpp = avctx->bits_per_sample;
c->decomp_size = (avctx->width * c->bpp + (avctx->width + 254) / 255 + 2) * avctx->height + 2;//RLE in the 'best' case
/* Allocate decompression buffer */
if (c->decomp_size) {
if ((c->decomp_buf = av_malloc(c->decomp_size)) == NULL) {
av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n");
return 1;
}
}
#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;
}
#endif
return 0;
}
/*
*
* Uninit tscc decoder
*
*/
static av_cold int decode_end(AVCodecContext *avctx)
{
CamtasiaContext * const c = avctx->priv_data;
av_freep(&c->decomp_buf);
if (c->pic.data[0])
avctx->release_buffer(avctx, &c->pic);
#ifdef CONFIG_ZLIB
inflateEnd(&(c->zstream));
#endif
return 0;
}
AVCodec tscc_decoder = {
"camtasia",
CODEC_TYPE_VIDEO,
CODEC_ID_TSCC,
sizeof(CamtasiaContext),
decode_init,
NULL,
decode_end,
decode_frame,
CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("TechSmith Screen Capture Codec"),
};
@@ -0,0 +1,447 @@
/*
* TTA (The Lossless True Audio) decoder
* Copyright (c) 2006 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 tta.c
* TTA (The Lossless True Audio) decoder
* (www.true-audio.com or tta.corecodec.org)
* @author Alex Beregszaszi
*
*/
#define ALT_BITSTREAM_READER_LE
//#define DEBUG
#include <limits.h>
#include "avcodec.h"
#include "bitstream.h"
#define FORMAT_INT 1
#define FORMAT_FLOAT 3
typedef struct TTAContext {
AVCodecContext *avctx;
GetBitContext gb;
int flags, channels, bps, is_float, data_length;
int frame_length, last_frame_length, total_frames;
int32_t *decode_buffer;
} TTAContext;
#if 0
static inline int shift_1(int i)
{
if (i < 32)
return 1 << i;
else
return 0x80000000; // 16 << 31
}
static inline int shift_16(int i)
{
if (i < 28)
return 16 << i;
else
return 0x80000000; // 16 << 27
}
#else
static const uint32_t shift_1[] = {
0x00000001, 0x00000002, 0x00000004, 0x00000008,
0x00000010, 0x00000020, 0x00000040, 0x00000080,
0x00000100, 0x00000200, 0x00000400, 0x00000800,
0x00001000, 0x00002000, 0x00004000, 0x00008000,
0x00010000, 0x00020000, 0x00040000, 0x00080000,
0x00100000, 0x00200000, 0x00400000, 0x00800000,
0x01000000, 0x02000000, 0x04000000, 0x08000000,
0x10000000, 0x20000000, 0x40000000, 0x80000000,
0x80000000, 0x80000000, 0x80000000, 0x80000000,
0x80000000, 0x80000000, 0x80000000, 0x80000000
};
static const uint32_t * const shift_16 = shift_1 + 4;
#endif
#define MAX_ORDER 16
typedef struct TTAFilter {
int32_t shift, round, error, mode;
int32_t qm[MAX_ORDER];
int32_t dx[MAX_ORDER];
int32_t dl[MAX_ORDER];
} TTAFilter;
static const int32_t ttafilter_configs[4][2] = {
{10, 1},
{9, 1},
{10, 1},
{12, 0}
};
static void ttafilter_init(TTAFilter *c, int32_t shift, int32_t mode) {
memset(c, 0, sizeof(TTAFilter));
c->shift = shift;
c->round = shift_1[shift-1];
// c->round = 1 << (shift - 1);
c->mode = mode;
}
// FIXME: copy paste from original
static inline void memshl(register int32_t *a, register int32_t *b) {
*a++ = *b++;
*a++ = *b++;
*a++ = *b++;
*a++ = *b++;
*a++ = *b++;
*a++ = *b++;
*a++ = *b++;
*a = *b;
}
// FIXME: copy paste from original
// mode=1 encoder, mode=0 decoder
static inline void ttafilter_process(TTAFilter *c, int32_t *in, int32_t mode) {
register int32_t *dl = c->dl, *qm = c->qm, *dx = c->dx, sum = c->round;
if (!c->error) {
sum += *dl++ * *qm, qm++;
sum += *dl++ * *qm, qm++;
sum += *dl++ * *qm, qm++;
sum += *dl++ * *qm, qm++;
sum += *dl++ * *qm, qm++;
sum += *dl++ * *qm, qm++;
sum += *dl++ * *qm, qm++;
sum += *dl++ * *qm, qm++;
dx += 8;
} else if(c->error < 0) {
sum += *dl++ * (*qm -= *dx++), qm++;
sum += *dl++ * (*qm -= *dx++), qm++;
sum += *dl++ * (*qm -= *dx++), qm++;
sum += *dl++ * (*qm -= *dx++), qm++;
sum += *dl++ * (*qm -= *dx++), qm++;
sum += *dl++ * (*qm -= *dx++), qm++;
sum += *dl++ * (*qm -= *dx++), qm++;
sum += *dl++ * (*qm -= *dx++), qm++;
} else {
sum += *dl++ * (*qm += *dx++), qm++;
sum += *dl++ * (*qm += *dx++), qm++;
sum += *dl++ * (*qm += *dx++), qm++;
sum += *dl++ * (*qm += *dx++), qm++;
sum += *dl++ * (*qm += *dx++), qm++;
sum += *dl++ * (*qm += *dx++), qm++;
sum += *dl++ * (*qm += *dx++), qm++;
sum += *dl++ * (*qm += *dx++), qm++;
}
*(dx-0) = ((*(dl-1) >> 30) | 1) << 2;
*(dx-1) = ((*(dl-2) >> 30) | 1) << 1;
*(dx-2) = ((*(dl-3) >> 30) | 1) << 1;
*(dx-3) = ((*(dl-4) >> 30) | 1);
// compress
if (mode) {
*dl = *in;
*in -= (sum >> c->shift);
c->error = *in;
} else {
c->error = *in;
*in += (sum >> c->shift);
*dl = *in;
}
if (c->mode) {
*(dl-1) = *dl - *(dl-1);
*(dl-2) = *(dl-1) - *(dl-2);
*(dl-3) = *(dl-2) - *(dl-3);
}
memshl(c->dl, c->dl + 1);
memshl(c->dx, c->dx + 1);
}
typedef struct TTARice {
uint32_t k0, k1, sum0, sum1;
} TTARice;
static void rice_init(TTARice *c, uint32_t k0, uint32_t k1)
{
c->k0 = k0;
c->k1 = k1;
c->sum0 = shift_16[k0];
c->sum1 = shift_16[k1];
}
static int tta_get_unary(GetBitContext *gb)
{
int ret = 0;
// count ones
while(get_bits1(gb))
ret++;
return ret;
}
static av_cold int tta_decode_init(AVCodecContext * avctx)
{
TTAContext *s = avctx->priv_data;
int i;
s->avctx = avctx;
// 30bytes includes a seektable with one frame
if (avctx->extradata_size < 30)
return -1;
init_get_bits(&s->gb, avctx->extradata, avctx->extradata_size);
if (show_bits_long(&s->gb, 32) == ff_get_fourcc("TTA1"))
{
/* signature */
skip_bits(&s->gb, 32);
// if (get_bits_long(&s->gb, 32) != bswap_32(ff_get_fourcc("TTA1"))) {
// av_log(s->avctx, AV_LOG_ERROR, "Missing magic\n");
// return -1;
// }
s->flags = get_bits(&s->gb, 16);
if (s->flags != 1 && s->flags != 3)
{
av_log(s->avctx, AV_LOG_ERROR, "Invalid flags\n");
return -1;
}
s->is_float = (s->flags == FORMAT_FLOAT);
avctx->channels = s->channels = get_bits(&s->gb, 16);
avctx->bits_per_sample = get_bits(&s->gb, 16);
s->bps = (avctx->bits_per_sample + 7) / 8;
avctx->sample_rate = get_bits_long(&s->gb, 32);
if(avctx->sample_rate > 1000000){ //prevent FRAME_TIME * avctx->sample_rate from overflowing and sanity check
av_log(avctx, AV_LOG_ERROR, "sample_rate too large\n");
return -1;
}
s->data_length = get_bits_long(&s->gb, 32);
skip_bits(&s->gb, 32); // CRC32 of header
if (s->is_float)
{
avctx->sample_fmt = SAMPLE_FMT_FLT;
av_log(s->avctx, AV_LOG_ERROR, "Unsupported sample format. Please contact the developers.\n");
return -1;
}
else switch(s->bps) {
// case 1: avctx->sample_fmt = SAMPLE_FMT_U8; break;
case 2: avctx->sample_fmt = SAMPLE_FMT_S16; break;
// case 3: avctx->sample_fmt = SAMPLE_FMT_S24; break;
case 4: avctx->sample_fmt = SAMPLE_FMT_S32; break;
default:
av_log(s->avctx, AV_LOG_ERROR, "Invalid/unsupported sample format. Please contact the developers.\n");
return -1;
}
// FIXME: horribly broken, but directly from reference source
#define FRAME_TIME 1.04489795918367346939
s->frame_length = (int)(FRAME_TIME * avctx->sample_rate);
s->last_frame_length = s->data_length % s->frame_length;
s->total_frames = s->data_length / s->frame_length +
(s->last_frame_length ? 1 : 0);
av_log(s->avctx, AV_LOG_DEBUG, "flags: %x chans: %d bps: %d rate: %d block: %d\n",
s->flags, avctx->channels, avctx->bits_per_sample, avctx->sample_rate,
avctx->block_align);
av_log(s->avctx, AV_LOG_DEBUG, "data_length: %d frame_length: %d last: %d total: %d\n",
s->data_length, s->frame_length, s->last_frame_length, s->total_frames);
// FIXME: seek table
for (i = 0; i < s->total_frames; i++)
skip_bits(&s->gb, 32);
skip_bits(&s->gb, 32); // CRC32 of seektable
if(s->frame_length >= UINT_MAX / (s->channels * sizeof(int32_t))){
av_log(avctx, AV_LOG_ERROR, "frame_length too large\n");
return -1;
}
s->decode_buffer = av_mallocz(sizeof(int32_t)*s->frame_length*s->channels);
} else {
av_log(avctx, AV_LOG_ERROR, "Wrong extradata present\n");
return -1;
}
return 0;
}
static int tta_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
const uint8_t *buf, int buf_size)
{
TTAContext *s = avctx->priv_data;
int i;
init_get_bits(&s->gb, buf, buf_size*8);
{
int32_t predictors[s->channels];
TTAFilter filters[s->channels];
TTARice rices[s->channels];
int cur_chan = 0, framelen = s->frame_length;
int32_t *p;
// FIXME: seeking
s->total_frames--;
if (!s->total_frames && s->last_frame_length)
framelen = s->last_frame_length;
// init per channel states
for (i = 0; i < s->channels; i++) {
predictors[i] = 0;
ttafilter_init(&(filters[i]), ttafilter_configs[s->bps-1][0], ttafilter_configs[s->bps-1][1]);
rice_init(&(rices[i]), 10, 10);
}
for (p = s->decode_buffer; p < s->decode_buffer + (framelen * s->channels); p++) {
int32_t *predictor = &(predictors[cur_chan]);
TTAFilter *filter = &(filters[cur_chan]);
TTARice *rice = &(rices[cur_chan]);
uint32_t unary, depth, k;
int32_t value;
unary = tta_get_unary(&s->gb);
if (unary == 0) {
depth = 0;
k = rice->k0;
} else {
depth = 1;
k = rice->k1;
unary--;
}
if (k)
value = (unary << k) + get_bits(&s->gb, k);
else
value = unary;
// FIXME: copy paste from original
switch (depth) {
case 1:
rice->sum1 += value - (rice->sum1 >> 4);
if (rice->k1 > 0 && rice->sum1 < shift_16[rice->k1])
rice->k1--;
else if(rice->sum1 > shift_16[rice->k1 + 1])
rice->k1++;
value += shift_1[rice->k0];
default:
rice->sum0 += value - (rice->sum0 >> 4);
if (rice->k0 > 0 && rice->sum0 < shift_16[rice->k0])
rice->k0--;
else if(rice->sum0 > shift_16[rice->k0 + 1])
rice->k0++;
}
// extract coded value
#define UNFOLD(x) (((x)&1) ? (++(x)>>1) : (-(x)>>1))
*p = UNFOLD(value);
// run hybrid filter
ttafilter_process(filter, p, 0);
// fixed order prediction
#define PRED(x, k) (int32_t)((((uint64_t)x << k) - x) >> k)
switch (s->bps) {
case 1: *p += PRED(*predictor, 4); break;
case 2:
case 3: *p += PRED(*predictor, 5); break;
case 4: *p += *predictor; break;
}
*predictor = *p;
#if 0
// extract 32bit float from last two int samples
if (s->is_float && ((p - data) & 1)) {
uint32_t neg = *p & 0x80000000;
uint32_t hi = *(p - 1);
uint32_t lo = abs(*p) - 1;
hi += (hi || lo) ? 0x3f80 : 0;
// SWAP16: swap all the 16 bits
*(p - 1) = (hi << 16) | SWAP16(lo) | neg;
}
#endif
/*if ((get_bits_count(&s->gb)+7)/8 > buf_size)
{
av_log(NULL, AV_LOG_INFO, "overread!!\n");
break;
}*/
// flip channels
if (cur_chan < (s->channels-1))
cur_chan++;
else {
// decorrelate in case of stereo integer
if (!s->is_float && (s->channels > 1)) {
int32_t *r = p - 1;
for (*p += *r / 2; r > p - s->channels; r--)
*r = *(r + 1) - *r;
}
cur_chan = 0;
}
}
skip_bits(&s->gb, 32); // frame crc
// convert to output buffer
switch(s->bps) {
case 2: {
uint16_t *samples = data;
for (p = s->decode_buffer; p < s->decode_buffer + (framelen * s->channels); p++) {
// *samples++ = (unsigned char)*p;
// *samples++ = (unsigned char)(*p >> 8);
*samples++ = *p;
}
*data_size = (uint8_t *)samples - (uint8_t *)data;
break;
}
default:
av_log(s->avctx, AV_LOG_ERROR, "Error, only 16bit samples supported!\n");
}
}
// return get_bits_count(&s->gb)+7)/8;
return buf_size;
}
static av_cold int tta_decode_close(AVCodecContext *avctx) {
TTAContext *s = avctx->priv_data;
if (s->decode_buffer)
av_free(s->decode_buffer);
return 0;
}
AVCodec tta_decoder = {
"tta",
CODEC_TYPE_AUDIO,
CODEC_ID_TTA,
sizeof(TTAContext),
tta_decode_init,
NULL,
tta_decode_close,
tta_decode_frame,
.long_name = NULL_IF_CONFIG_SMALL("True Audio"),
};
@@ -0,0 +1,167 @@
/*
* Renderware TeXture Dictionary (.txd) image decoder
* Copyright (c) 2007 Ivo van Poorten
*
* See also: http://wiki.multimedia.cx/index.php?title=TXD
*
* 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 "s3tc.h"
typedef struct TXDContext {
AVFrame picture;
} TXDContext;
static av_cold int txd_init(AVCodecContext *avctx) {
TXDContext *s = avctx->priv_data;
avcodec_get_frame_defaults(&s->picture);
avctx->coded_frame = &s->picture;
return 0;
}
static int txd_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
const uint8_t *buf, int buf_size) {
TXDContext * const s = avctx->priv_data;
AVFrame *picture = data;
AVFrame * const p = &s->picture;
unsigned int version, w, h, d3d_format, depth, stride, mipmap_count, flags;
unsigned int y, v;
uint8_t *ptr;
const uint8_t *cur = buf;
const uint32_t *palette = (const uint32_t *)(cur + 88);
uint32_t *pal;
version = AV_RL32(cur);
d3d_format = AV_RL32(cur+76);
w = AV_RL16(cur+80);
h = AV_RL16(cur+82);
depth = AV_RL8 (cur+84);
mipmap_count = AV_RL8 (cur+85);
flags = AV_RL8 (cur+87);
cur += 92;
if (version < 8 || version > 9) {
av_log(avctx, AV_LOG_ERROR, "texture data version %i is unsupported\n",
version);
return -1;
}
if (depth == 8) {
avctx->pix_fmt = PIX_FMT_PAL8;
cur += 1024;
} else if (depth == 16 || depth == 32)
avctx->pix_fmt = PIX_FMT_RGB32;
else {
av_log(avctx, AV_LOG_ERROR, "depth of %i is unsupported\n", depth);
return -1;
}
if (p->data[0])
avctx->release_buffer(avctx, p);
if (avcodec_check_dimensions(avctx, w, h))
return -1;
if (w != avctx->width || h != avctx->height)
avcodec_set_dimensions(avctx, w, h);
if (avctx->get_buffer(avctx, p) < 0) {
av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
return -1;
}
p->pict_type = FF_I_TYPE;
ptr = p->data[0];
stride = p->linesize[0];
if (depth == 8) {
pal = (uint32_t *) p->data[1];
for (y=0; y<256; y++) {
v = AV_RB32(palette+y);
pal[y] = (v>>8) + (v<<24);
}
for (y=0; y<h; y++) {
memcpy(ptr, cur, w);
ptr += stride;
cur += w;
}
} else if (depth == 16) {
switch (d3d_format) {
case 0:
if (!flags&1) goto unsupported;
case FF_S3TC_DXT1:
ff_decode_dxt1(cur, ptr, w, h, stride);
break;
case FF_S3TC_DXT3:
ff_decode_dxt3(cur, ptr, w, h, stride);
break;
default:
goto unsupported;
}
} else if (depth == 32) {
switch (d3d_format) {
case 0x15:
case 0x16:
for (y=0; y<h; y++) {
memcpy(ptr, cur, w*4);
ptr += stride;
cur += w*4;
}
break;
default:
goto unsupported;
}
}
for (; mipmap_count > 1; mipmap_count--)
cur += AV_RL32(cur) + 4;
*picture = s->picture;
*data_size = sizeof(AVPicture);
return cur - buf;
unsupported:
av_log(avctx, AV_LOG_ERROR, "unsupported d3d format (%08x)\n", d3d_format);
return -1;
}
static av_cold int txd_end(AVCodecContext *avctx) {
TXDContext *s = avctx->priv_data;
if (s->picture.data[0])
avctx->release_buffer(avctx, &s->picture);
return 0;
}
AVCodec txd_decoder = {
"txd",
CODEC_TYPE_VIDEO,
CODEC_ID_TXD,
sizeof(TXDContext),
txd_init,
NULL,
txd_end,
txd_decode_frame,
0,
NULL,
.long_name = NULL_IF_CONFIG_SMALL("Renderware TXD (TeXture Dictionary) image"),
};