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:
@@ -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,43 +34,41 @@
|
|||||||
#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;
|
||||||
int x, y, w, h;
|
int x, y, w, h;
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
unsigned int *vert_pred;
|
unsigned int *vert_pred;
|
||||||
@@ -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,63 +165,166 @@ 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;
|
||||||
|
|
||||||
lo = ydt[p1];
|
lo = ydt[p1];
|
||||||
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;
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
for (i = 0; i < 1024; i += 4)
|
for (i = 0; i < 1024; i += 4)
|
||||||
{
|
{
|
||||||
len = *sel_vector_table++ / 2;
|
len = *sel_vector_table++ / 2;
|
||||||
for (j = 0; j < len; j++)
|
for (j = 0; j < len; j++)
|
||||||
{
|
{
|
||||||
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)
|
||||||
{
|
{
|
||||||
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,20 +334,21 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* unscramble the header bytes with a XOR operation */
|
/* unscramble the header bytes with a XOR operation */
|
||||||
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;
|
||||||
@@ -265,27 +369,36 @@ static int truemotion1_decode_header(TrueMotion1Context *s)
|
|||||||
s->flags = FLAG_KEYFRAME;
|
s->flags = FLAG_KEYFRAME;
|
||||||
} else /* Version 1 */
|
} else /* Version 1 */
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((header.deltaset != s->last_deltaset) ||
|
if ((header.deltaset != s->last_deltaset) ||
|
||||||
(header.vectable != s->last_vectable))
|
(header.vectable != s->last_vectable))
|
||||||
select_delta_tables(s, header.deltaset);
|
select_delta_tables(s, header.deltaset);
|
||||||
|
|
||||||
@@ -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 */
|
||||||
@@ -317,7 +437,7 @@ static int truemotion1_decode_header(TrueMotion1Context *s)
|
|||||||
s->index_stream = s->mb_change_bits;
|
s->index_stream = s->mb_change_bits;
|
||||||
} else {
|
} else {
|
||||||
/* one change bit per 4x4 block */
|
/* one change bit per 4x4 block */
|
||||||
s->index_stream = s->mb_change_bits +
|
s->index_stream = s->mb_change_bits +
|
||||||
(s->mb_change_bits_row_size * (s->avctx->height >> 2));
|
(s->mb_change_bits_row_size * (s->avctx->height >> 2));
|
||||||
}
|
}
|
||||||
s->index_stream_size = s->size - (s->index_stream - s->buf);
|
s->index_stream_size = s->size - (s->index_stream - s->buf);
|
||||||
@@ -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;
|
||||||
|
|
||||||
return header.header_size;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
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++];
|
||||||
@@ -444,7 +634,7 @@ static void truemotion1_decode_16bit(TrueMotion1Context *s)
|
|||||||
|
|
||||||
switch (y & 3) {
|
switch (y & 3) {
|
||||||
case 0:
|
case 0:
|
||||||
/* if macroblock width is 2, apply C-Y-C-Y; else
|
/* if macroblock width is 2, apply C-Y-C-Y; else
|
||||||
* apply C-Y-Y */
|
* apply C-Y-Y */
|
||||||
if (s->block_width == 2) {
|
if (s->block_width == 2) {
|
||||||
APPLY_C_PREDICTOR();
|
APPLY_C_PREDICTOR();
|
||||||
@@ -472,7 +662,7 @@ static void truemotion1_decode_16bit(TrueMotion1Context *s)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
/* this iteration might be C-Y-C-Y, Y-Y, or C-Y-Y
|
/* this iteration might be C-Y-C-Y, Y-Y, or C-Y-Y
|
||||||
* depending on the macroblock type */
|
* depending on the macroblock type */
|
||||||
if (s->block_type == BLOCK_2x2) {
|
if (s->block_type == BLOCK_2x2) {
|
||||||
APPLY_C_PREDICTOR();
|
APPLY_C_PREDICTOR();
|
||||||
@@ -498,14 +688,12 @@ static void truemotion1_decode_16bit(TrueMotion1Context *s)
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* 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++;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!keyframe) {
|
if (!keyframe) {
|
||||||
@@ -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"),
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user