diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/targa.c b/src/add-ons/media/plugins/avcodec/libavcodec/targa.c new file mode 100644 index 0000000000..f9bc343997 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/targa.c @@ -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"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/targaenc.c b/src/add-ons/media/plugins/avcodec/libavcodec/targaenc.c new file mode 100644 index 0000000000..958ae50553 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/targaenc.c @@ -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"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/test b/src/add-ons/media/plugins/avcodec/libavcodec/test new file mode 100644 index 0000000000..9b92d94767 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/test @@ -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 diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/tiertexseqv.c b/src/add-ons/media/plugins/avcodec/libavcodec/tiertexseqv.c new file mode 100644 index 0000000000..3ff353555d --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/tiertexseqv.c @@ -0,0 +1,231 @@ +/* + * Tiertex Limited SEQ Video Decoder + * Copyright (c) 2006 Gregory Montoir (cyx@users.sourceforge.net) + * + * 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"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/tiff.c b/src/add-ons/media/plugins/avcodec/libavcodec/tiff.c new file mode 100644 index 0000000000..7e42aabcbd --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/tiff.c @@ -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 +#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"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/tiff.h b/src/add-ons/media/plugins/avcodec/libavcodec/tiff.h new file mode 100644 index 0000000000..c5687d7df6 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/tiff.h @@ -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 + +/** 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 */ diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/tiffenc.c b/src/add-ons/media/plugins/avcodec/libavcodec/tiffenc.c new file mode 100644 index 0000000000..c44045435b --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/tiffenc.c @@ -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 +#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"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/truemotion1.c b/src/add-ons/media/plugins/avcodec/libavcodec/truemotion1.c index ebd0ad5229..10b17df601 100644 --- a/src/add-ons/media/plugins/avcodec/libavcodec/truemotion1.c +++ b/src/add-ons/media/plugins/avcodec/libavcodec/truemotion1.c @@ -2,29 +2,31 @@ * Duck TrueMotion 1.0 Decoder * 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 * 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 * 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 this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file truemotion1.c - * Duck TrueMotion v1 Video Decoder by - * Alex Beregszaszi (alex@fsn.hu) and + * Duck TrueMotion v1 Video Decoder by + * Alex Beregszaszi and * Mike Melanson (melanson@pcisys.net) * * 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 @@ -32,43 +34,41 @@ #include #include -#include "common.h" #include "avcodec.h" #include "dsputil.h" #include "truemotion1data.h" -#define LE_16(x) ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0]) - typedef struct TrueMotion1Context { AVCodecContext *avctx; AVFrame frame; - AVFrame prev_frame; - unsigned char *buf; + const uint8_t *buf; int size; - unsigned char *mb_change_bits; + const uint8_t *mb_change_bits; int mb_change_bits_row_size; - unsigned char *index_stream; + const uint8_t *index_stream; int index_stream_size; int flags; int x, y, w, h; - + uint32_t y_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 block_type; int block_width; int block_height; - int16_t *ydt; - int16_t *cdt; - int16_t *fat_ydt; - int16_t *fat_cdt; - + int16_t ydt[8]; + int16_t cdt[8]; + int16_t fat_ydt[8]; + int16_t fat_cdt[8]; + int last_deltaset, last_vectable; unsigned int *vert_pred; @@ -111,13 +111,13 @@ struct frame_header { typedef struct comp_types { int algorithm; - int block_width; - int block_height; + int block_width; // vres + int block_height; // hres int block_type; } comp_types; -/* { valid for metatype }, algorithm, num of deltas, horiz res, vert res */ -static comp_types compression_types[17] = { +/* { valid for metatype }, algorithm, num of deltas, vert res, horiz res */ +static const comp_types compression_types[17] = { { ALGO_NOP, 0, 0, 0 }, { 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) return; - s->ydt = ydts[delta_table_index]; - s->cdt = cdts[delta_table_index]; - s->fat_ydt = fat_ydts[delta_table_index]; - s->fat_cdt = fat_cdts[delta_table_index]; + memcpy(s->ydt, ydts[delta_table_index], 8 * sizeof(int16_t)); + memcpy(s->cdt, cdts[delta_table_index], 8 * sizeof(int16_t)); + memcpy(s->fat_ydt, fat_ydts[delta_table_index], 8 * sizeof(int16_t)); + 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 * skinny Y deltas should be modified */ @@ -165,63 +165,166 @@ static void select_delta_tables(TrueMotion1Context *s, int delta_table_index) } #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 -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 { int lo, hi; - + lo = ydt[p1]; lo += (lo << 5) + (lo << 10); hi = ydt[p2]; hi += (hi << 5) + (hi << 10); - return ((lo + (hi << 16)) << 1); + return (lo + (hi << 16)) << 1; } #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 -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 { int r, b, lo; - + b = cdt[p2]; r = cdt[p1] << 10; 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; 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_ydt_entry(delta_pair >> 4, delta_pair & 0xf, s->ydt); - s->c_predictor_table[i+j] = 0xfffffffe & - make_cdt_entry(delta_pair >> 4, delta_pair & 0xf, s->cdt); + s->y_predictor_table[i+j] = 0xfffffffe & + make_ydt15_entry(delta_pair >> 4, delta_pair & 0xf, s->ydt); + s->c_predictor_table[i+j] = 0xfffffffe & + make_cdt15_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_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 - * there was an error while decoding the header */ + * there was an error while decoding the header */ static int truemotion1_decode_header(TrueMotion1Context *s) { int i; struct frame_header 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 * 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; 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; } /* unscramble the header bytes with a XOR operation */ memset(header_buffer, 0, 128); 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.deltaset = header_buffer[1]; header.vectable = header_buffer[2]; - header.ysize = LE_16(&header_buffer[3]); - header.xsize = LE_16(&header_buffer[5]); - header.checksum = LE_16(&header_buffer[7]); + header.ysize = AV_RL16(&header_buffer[3]); + header.xsize = AV_RL16(&header_buffer[5]); + header.checksum = AV_RL16(&header_buffer[7]); header.version = header_buffer[9]; header.header_type = header_buffer[10]; header.flags = header_buffer[11]; @@ -255,7 +359,7 @@ static int truemotion1_decode_header(TrueMotion1Context *s) { 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; } else if ((header.header_type == 2) || (header.header_type == 3)) { s->flags = header.flags; @@ -265,27 +369,36 @@ static int truemotion1_decode_header(TrueMotion1Context *s) s->flags = FLAG_KEYFRAME; } else /* Version 1 */ s->flags = FLAG_KEYFRAME; - + 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->h = header.height; s->x = header.xoffset; s->y = header.yoffset; +#else + return -1; +#endif } else { s->w = header.xsize; s->h = header.ysize; if (header.header_type < 2) { if ((s->w < 213) && (s->h >= 176)) + { 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) { - printf("invalid compression type (%d)\n", header.compression); + if (header.compression >= 17) { + av_log(s->avctx, AV_LOG_ERROR, "invalid compression type (%d)\n", header.compression); return -1; } - - if ((header.deltaset != s->last_deltaset) || + + if ((header.deltaset != s->last_deltaset) || (header.vectable != s->last_vectable)) select_delta_tables(s, header.deltaset); @@ -295,19 +408,26 @@ static int truemotion1_decode_header(TrueMotion1Context *s) if (header.vectable < 4) sel_vector_table = tables[header.vectable - 1]; 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; } } + // 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 (compression_types[header.compression].algorithm == ALGO_RGB24H) - { - printf("24bit compression not yet supported\n"); - } + gen_vector_table24(s, sel_vector_table); 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 */ @@ -317,7 +437,7 @@ static int truemotion1_decode_header(TrueMotion1Context *s) s->index_stream = s->mb_change_bits; } else { /* 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->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_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; - avctx->pix_fmt = PIX_FMT_RGB555; - avctx->has_b_frames = 0; - s->frame.data[0] = s->prev_frame.data[0] = NULL; + // FIXME: it may change ? +// if (avctx->bits_per_sample == 24) +// 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 * predictor is 0 to start with */ - s->vert_pred = - (unsigned int *)av_malloc(s->avctx->width * sizeof(unsigned short)); + s->vert_pred = + (unsigned int *)av_malloc(s->avctx->width * sizeof(unsigned int)); 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() \ {\ 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; \ } \ index = s->index_stream[index_stream_index++] * 4; \ @@ -376,6 +535,24 @@ static int truemotion1_decode_init(AVCodecContext *avctx) } else \ 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() \ predictor_pair = s->y_predictor_table[index]; \ horiz_pred += (predictor_pair >> 1); \ @@ -393,10 +570,26 @@ static int truemotion1_decode_init(AVCodecContext *avctx) } else \ 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() \ *current_pixel_pair = *vert_pred + horiz_pred; \ - *vert_pred++ = *current_pixel_pair++; \ - prev_pixel_pair++; + *vert_pred++ = *current_pixel_pair++; static void truemotion1_decode_16bit(TrueMotion1Context *s) { @@ -406,13 +599,11 @@ static void truemotion1_decode_16bit(TrueMotion1Context *s) unsigned int horiz_pred; unsigned int *vert_pred; unsigned int *current_pixel_pair; - unsigned int *prev_pixel_pair; unsigned char *current_line = s->frame.data[0]; - unsigned char *prev_line = s->prev_frame.data[0]; int keyframe = s->flags & FLAG_KEYFRAME; /* 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_mask; int mb_change_index; @@ -422,7 +613,7 @@ static void truemotion1_decode_16bit(TrueMotion1Context *s) int index; /* 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(); @@ -431,7 +622,6 @@ static void truemotion1_decode_16bit(TrueMotion1Context *s) /* re-init variables for the next line iteration */ horiz_pred = 0; current_pixel_pair = (unsigned int *)current_line; - prev_pixel_pair = (unsigned int *)prev_line; vert_pred = s->vert_pred; mb_change_index = 0; mb_change_byte = mb_change_bits[mb_change_index++]; @@ -444,7 +634,7 @@ static void truemotion1_decode_16bit(TrueMotion1Context *s) switch (y & 3) { 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 */ if (s->block_width == 2) { APPLY_C_PREDICTOR(); @@ -472,7 +662,7 @@ static void truemotion1_decode_16bit(TrueMotion1Context *s) break; 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 */ if (s->block_type == BLOCK_2x2) { APPLY_C_PREDICTOR(); @@ -498,14 +688,12 @@ static void truemotion1_decode_16bit(TrueMotion1Context *s) } else { - /* skip (copy) four pixels, but reassign the horizontal + /* skip (copy) four pixels, but reassign the horizontal * predictor */ - *current_pixel_pair = *prev_pixel_pair++; *vert_pred++ = *current_pixel_pair++; - *current_pixel_pair = *prev_pixel_pair++; horiz_pred = *current_pixel_pair - *vert_pred; *vert_pred++ = *current_pixel_pair++; - + } if (!keyframe) { @@ -526,50 +714,161 @@ static void truemotion1_decode_16bit(TrueMotion1Context *s) mb_change_bits += s->mb_change_bits_row_size; 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, 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->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) return -1; - /* check for a do-nothing frame and copy the previous frame */ - if (compression_types[s->compression].algorithm == ALGO_NOP) - { - memcpy(s->frame.data[0], s->prev_frame.data[0], - s->frame.linesize[0] * s->avctx->height); - } else if (compression_types[s->compression].algorithm == ALGO_RGB24H) { - printf (" 24-bit Duck TrueMotion decoding not yet implemented\n"); - } else { - truemotion1_decode_16bit(s); + s->frame.reference = 1; + s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | + FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; + if (avctx->reget_buffer(avctx, &s->frame) < 0) { + av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n"); + return -1; } - if (s->prev_frame.data[0]) - avctx->release_buffer(avctx, &s->prev_frame); - - /* shuffle frames */ - s->prev_frame = s->frame; + if (compression_types[s->compression].algorithm == ALGO_RGB24H) { + truemotion1_decode_24bit(s); + } else if (compression_types[s->compression].algorithm != ALGO_NOP) { + truemotion1_decode_16bit(s); + } *data_size = sizeof(AVFrame); *(AVFrame*)data = s->frame; @@ -578,13 +877,12 @@ static int truemotion1_decode_frame(AVCodecContext *avctx, 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->prev_frame.data[0]) - avctx->release_buffer(avctx, &s->prev_frame); + if (s->frame.data[0]) + avctx->release_buffer(avctx, &s->frame); av_free(s->vert_pred); @@ -601,4 +899,5 @@ AVCodec truemotion1_decoder = { truemotion1_decode_end, truemotion1_decode_frame, CODEC_CAP_DR1, + .long_name = NULL_IF_CONFIG_SMALL("Duck TrueMotion 1.0"), }; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/truemotion1data.h b/src/add-ons/media/plugins/avcodec/libavcodec/truemotion1data.h index d56e015a4f..033e25e059 100644 --- a/src/add-ons/media/plugins/avcodec/libavcodec/truemotion1data.h +++ b/src/add-ons/media/plugins/avcodec/libavcodec/truemotion1data.h @@ -5,34 +5,53 @@ * distributed under the GNU GPL. It is redistributed with ffmpeg under the * GNU LGPL using the common understanding that data tables necessary for * 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 -#define TRUEMOTION1DATA_H +#ifndef FFMPEG_TRUEMOTION1DATA_H +#define FFMPEG_TRUEMOTION1DATA_H + +#include +#include /* Y delta tables, skinny and fat */ -static 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 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 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 ydt1[8] = { 0, -2, 2, -6, 6, -12, 12, -12 }; +static const int16_t ydt2[8] = { 0, -2, 4, -6, 8, -12, 12, -12 }; +static const int16_t ydt3[8] = { 4, -6, 20, -20, 46, -46, 94, -94 }; +static const int16_t fat_ydt3[8] = { 0, -15, 50, -50, 115, -115, 235, -235 }; +static const int16_t ydt4[8] = { 0, -4, 4, -16, 16, -36, 36, -80 }; +static const int16_t fat_ydt4[8] = { 0, 40, 80, -76, 160, -154, 236, -236 }; /* C delta tables, skinny and fat */ -static 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 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 cdt1[8] = { 0, -1, 1, -2, 3, -4, 5, -4 }; +static const int16_t cdt2[8] = { 0, -4, 3, -16, 20, -32, 36, -32 }; +static const int16_t fat_cdt2[8] = { 0, -20, 15, -80, 100, -160, 180, -160 }; +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 * 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 */ -static int16_t *ydts[] = { ydt1, ydt2, ydt3, ydt4, NULL }; -static int16_t *fat_ydts[] = { fat_ydt3, fat_ydt3, fat_ydt3, fat_ydt4, NULL }; -static int16_t *cdts[] = { cdt1, cdt2, cdt3, cdt3, NULL }; -static int16_t *fat_cdts[] = { fat_cdt2, fat_cdt2, fat_cdt2, fat_cdt3, NULL }; +static const int16_t * const ydts[] = { ydt1, ydt2, ydt3, ydt4, NULL }; +static const int16_t * const fat_ydts[] = { fat_ydt3, fat_ydt3, fat_ydt3, fat_ydt4, NULL }; +static const int16_t * const cdts[] = { cdt1, cdt1, cdt2, 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,0x10,0x00,0x00,0x00, @@ -291,7 +310,7 @@ static uint8_t pc_tbl2[] = { 0x2,0x66 }; -static uint8_t pc_tbl3[] = { +static const uint8_t pc_tbl3[] = { 0x6,0x00,0x00,0x00, 0x6,0x00,0x00,0x00, 0x6,0x00,0x00,0x01, @@ -550,7 +569,7 @@ static uint8_t pc_tbl3[] = { 0x2,0x77 }; -static uint8_t pc_tbl4[] = { +static const uint8_t pc_tbl4[] = { 0x8,0x00,0x00,0x00,0x00, 0x8,0x00,0x00,0x00,0x00, 0x8,0x20,0x00,0x00,0x00, @@ -809,5 +828,6 @@ static uint8_t pc_tbl4[] = { 0x2,0x77 }; -static uint8_t *tables[] = { pc_tbl2, pc_tbl3, pc_tbl4 }; -#endif +static const uint8_t * const tables[] = { pc_tbl2, pc_tbl3, pc_tbl4 }; + +#endif /* FFMPEG_TRUEMOTION1DATA_H */ diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/truemotion2.c b/src/add-ons/media/plugins/avcodec/libavcodec/truemotion2.c new file mode 100644 index 0000000000..d1d3f71133 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/truemotion2.c @@ -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]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"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/truespeech.c b/src/add-ons/media/plugins/avcodec/libavcodec/truespeech.c new file mode 100644 index 0000000000..3df71cb7f2 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/truespeech.c @@ -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"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/truespeech_data.h b/src/add-ons/media/plugins/avcodec/libavcodec/truespeech_data.h new file mode 100644 index 0000000000..572387cd7a --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/truespeech_data.h @@ -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 + +/* 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 */ diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/tscc.c b/src/add-ons/media/plugins/avcodec/libavcodec/tscc.c new file mode 100644 index 0000000000..3c9adc0690 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/tscc.c @@ -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 +#include + +#include "avcodec.h" + +#ifdef CONFIG_ZLIB +#include +#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"), +}; + diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/tta.c b/src/add-ons/media/plugins/avcodec/libavcodec/tta.c new file mode 100644 index 0000000000..45efdaecb0 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/tta.c @@ -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 +#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"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/txd.c b/src/add-ons/media/plugins/avcodec/libavcodec/txd.c new file mode 100644 index 0000000000..284b00d2de --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/txd.c @@ -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 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"), +};