Update avcodec to 20080825

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27561 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
David McPaul
2008-09-15 14:11:26 +00:00
parent eaa51ccd98
commit c17be5fb78
24 changed files with 10402 additions and 1330 deletions
@@ -0,0 +1,96 @@
/*
* S3 Texture Compression (S3TC) decoding functions
* Copyright (c) 2007 by Ivo van Poorten
*
* see also: http://wiki.multimedia.cx/index.php?title=S3TC
*
* 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"
static inline void dxt1_decode_pixels(const uint8_t *s, uint32_t *d,
unsigned int qstride, unsigned int flag,
uint64_t alpha) {
unsigned int x, y, c0, c1, a = (!flag * 255) << 24;
unsigned int rb0, rb1, rb2, rb3, g0, g1, g2, g3;
uint32_t colors[4], pixels;
c0 = AV_RL16(s);
c1 = AV_RL16(s+2);
rb0 = (c0<<3 | c0<<8) & 0xf800f8;
rb1 = (c1<<3 | c1<<8) & 0xf800f8;
rb0 += (rb0>>5) & 0x070007;
rb1 += (rb1>>5) & 0x070007;
g0 = (c0 <<5) & 0x00fc00;
g1 = (c1 <<5) & 0x00fc00;
g0 += (g0 >>6) & 0x000300;
g1 += (g1 >>6) & 0x000300;
colors[0] = rb0 + g0 + a;
colors[1] = rb1 + g1 + a;
if (c0 > c1 || flag) {
rb2 = (((2*rb0+rb1) * 21) >> 6) & 0xff00ff;
rb3 = (((2*rb1+rb0) * 21) >> 6) & 0xff00ff;
g2 = (((2*g0 +g1 ) * 21) >> 6) & 0x00ff00;
g3 = (((2*g1 +g0 ) * 21) >> 6) & 0x00ff00;
colors[3] = rb3 + g3 + a;
} else {
rb2 = ((rb0+rb1) >> 1) & 0xff00ff;
g2 = ((g0 +g1 ) >> 1) & 0x00ff00;
colors[3] = 0;
}
colors[2] = rb2 + g2 + a;
pixels = AV_RL32(s+4);
for (y=0; y<4; y++) {
for (x=0; x<4; x++) {
a = (alpha & 0x0f) << 28;
a += a >> 4;
d[x] = a + colors[pixels&3];
pixels >>= 2;
alpha >>= 4;
}
d += qstride;
}
}
void ff_decode_dxt1(const uint8_t *s, uint8_t *dst,
const unsigned int w, const unsigned int h,
const unsigned int stride) {
unsigned int bx, by, qstride = stride/4;
uint32_t *d = (uint32_t *) dst;
for (by=0; by < h/4; by++, d += stride-w)
for (bx=0; bx < w/4; bx++, s+=8, d+=4)
dxt1_decode_pixels(s, d, qstride, 0, 0LL);
}
void ff_decode_dxt3(const uint8_t *s, uint8_t *dst,
const unsigned int w, const unsigned int h,
const unsigned int stride) {
unsigned int bx, by, qstride = stride/4;
uint32_t *d = (uint32_t *) dst;
for (by=0; by < h/4; by++, d += stride-w)
for (bx=0; bx < w/4; bx++, s+=16, d+=4)
dxt1_decode_pixels(s+8, d, qstride, 1, AV_RL64(s));
}
@@ -0,0 +1,53 @@
/*
* S3 Texture Compression (S3TC) decoding functions
* Copyright (c) 2007 by Ivo van Poorten
*
* 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_S3TC_H
#define FFMPEG_S3TC_H
#include <stdint.h>
#define FF_S3TC_DXT1 0x31545844
#define FF_S3TC_DXT3 0x33545844
/**
* Decode DXT1 encoded data to RGB32
* @param *src source buffer, has to be aligned on a 4-byte boundary
* @param *dst destination buffer
* @param w width of output image
* @param h height of output image
* @param stride line size of output image
*/
void ff_decode_dxt1(const uint8_t *src, uint8_t *dst,
const unsigned int w, const unsigned int h,
const unsigned int stride);
/**
* Decode DXT3 encoded data to RGB32
* @param *src source buffer, has to be aligned on a 4-byte boundary
* @param *dst destination buffer
* @param w width of output image
* @param h height of output image
* @param stride line size of output image
*/
void ff_decode_dxt3(const uint8_t *src, uint8_t *dst,
const unsigned int w, const unsigned int h,
const unsigned int stride);
#endif /* FFMPEG_S3TC_H */
@@ -0,0 +1,36 @@
/*
* SGI image encoder
* Xiaohui Sun <[email protected]>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FFMPEG_SGI_H
#define FFMPEG_SGI_H
/**
* SGI image file signature
*/
#define SGI_MAGIC 474
#define SGI_HEADER_SIZE 512
#define SGI_GRAYSCALE 1
#define SGI_RGB 3
#define SGI_RGBA 4
#endif /* FFMPEG_SGI_H */
@@ -0,0 +1,268 @@
/*
* SGI image decoder
* Todd Kirby <[email protected]>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avcodec.h"
#include "bytestream.h"
#include "sgi.h"
typedef struct SgiState {
AVFrame picture;
unsigned int width;
unsigned int height;
unsigned int depth;
int linesize;
} SgiState;
/**
* Expand an RLE row into a channel.
* @param in_buf input buffer
* @param in_end end of input buffer
* @param out_buf Points to one line after the output buffer.
* @param out_end end of line in output buffer
* @param pixelstride pixel stride of input buffer
* @return size of output in bytes, -1 if buffer overflows
*/
static int expand_rle_row(const uint8_t *in_buf, const uint8_t* in_end,
unsigned char *out_buf, uint8_t* out_end, int pixelstride)
{
unsigned char pixel, count;
unsigned char *orig = out_buf;
while (1) {
if(in_buf + 1 > in_end) return -1;
pixel = bytestream_get_byte(&in_buf);
if (!(count = (pixel & 0x7f))) {
return (out_buf - orig) / pixelstride;
}
/* Check for buffer overflow. */
if(out_buf + pixelstride * count >= out_end) return -1;
if (pixel & 0x80) {
while (count--) {
*out_buf = bytestream_get_byte(&in_buf);
out_buf += pixelstride;
}
} else {
pixel = bytestream_get_byte(&in_buf);
while (count--) {
*out_buf = pixel;
out_buf += pixelstride;
}
}
}
}
/**
* Read a run length encoded SGI image.
* @param out_buf output buffer
* @param in_buf input buffer
* @param in_end end of input buffer
* @param s the current image state
* @return 0 if no error, else return error number.
*/
static int read_rle_sgi(unsigned char* out_buf, const uint8_t *in_buf,
const uint8_t *in_end, SgiState* s)
{
uint8_t *dest_row;
unsigned int len = s->height * s->depth * 4;
const uint8_t *start_table = in_buf;
unsigned int y, z;
unsigned int start_offset;
/* size of RLE offset and length tables */
if(len * 2 > in_end - in_buf) {
return AVERROR_INVALIDDATA;
}
in_buf -= SGI_HEADER_SIZE;
for (z = 0; z < s->depth; z++) {
dest_row = out_buf;
for (y = 0; y < s->height; y++) {
dest_row -= s->linesize;
start_offset = bytestream_get_be32(&start_table);
if(start_offset > in_end - in_buf) {
return AVERROR_INVALIDDATA;
}
if (expand_rle_row(in_buf + start_offset, in_end, dest_row + z,
dest_row + FFABS(s->linesize), s->depth) != s->width)
return AVERROR_INVALIDDATA;
}
}
return 0;
}
/**
* Read an uncompressed SGI image.
* @param out_buf output buffer
* @param out_end end ofoutput buffer
* @param in_buf input buffer
* @param in_end end of input buffer
* @param s the current image state
* @return 0 if read success, otherwise return -1.
*/
static int read_uncompressed_sgi(unsigned char* out_buf, uint8_t* out_end,
const uint8_t *in_buf, const uint8_t *in_end, SgiState* s)
{
int x, y, z;
const uint8_t *ptr;
unsigned int offset = s->height * s->width;
/* Test buffer size. */
if (offset * s->depth > in_end - in_buf) {
return -1;
}
for (y = s->height - 1; y >= 0; y--) {
out_end = out_buf + (y * s->linesize);
for (x = s->width; x > 0; x--) {
ptr = in_buf++;
for(z = 0; z < s->depth; z ++) {
bytestream_put_byte(&out_end, *ptr);
ptr += offset;
}
}
}
return 0;
}
static int decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
const uint8_t *in_buf, int buf_size)
{
SgiState *s = avctx->priv_data;
AVFrame *picture = data;
AVFrame *p = &s->picture;
const uint8_t *in_end = in_buf + buf_size;
unsigned int dimension, bytes_per_channel, rle;
int ret = 0;
uint8_t *out_buf, *out_end;
if (buf_size < SGI_HEADER_SIZE){
av_log(avctx, AV_LOG_ERROR, "buf_size too small (%d)\n", buf_size);
return -1;
}
/* Test for SGI magic. */
if (bytestream_get_be16(&in_buf) != SGI_MAGIC) {
av_log(avctx, AV_LOG_ERROR, "bad magic number\n");
return -1;
}
rle = bytestream_get_byte(&in_buf);
bytes_per_channel = bytestream_get_byte(&in_buf);
dimension = bytestream_get_be16(&in_buf);
s->width = bytestream_get_be16(&in_buf);
s->height = bytestream_get_be16(&in_buf);
s->depth = bytestream_get_be16(&in_buf);
if (bytes_per_channel != 1) {
av_log(avctx, AV_LOG_ERROR, "wrong channel number\n");
return -1;
}
/* Check for supported image dimensions. */
if (dimension != 2 && dimension != 3) {
av_log(avctx, AV_LOG_ERROR, "wrong dimension number\n");
return -1;
}
if (s->depth == SGI_GRAYSCALE) {
avctx->pix_fmt = PIX_FMT_GRAY8;
} else if (s->depth == SGI_RGB) {
avctx->pix_fmt = PIX_FMT_RGB24;
} else if (s->depth == SGI_RGBA) {
avctx->pix_fmt = PIX_FMT_RGBA;
} else {
av_log(avctx, AV_LOG_ERROR, "wrong picture format\n");
return -1;
}
if (avcodec_check_dimensions(avctx, s->width, s->height))
return -1;
avcodec_set_dimensions(avctx, s->width, s->height);
if (p->data[0])
avctx->release_buffer(avctx, p);
p->reference = 0;
if (avctx->get_buffer(avctx, p) < 0) {
av_log(avctx, AV_LOG_ERROR, "get_buffer() failed.\n");
return -1;
}
p->pict_type = FF_I_TYPE;
p->key_frame = 1;
out_buf = p->data[0];
out_end = out_buf + p->linesize[0] * s->height;
s->linesize = p->linesize[0];
/* Skip header. */
in_buf += SGI_HEADER_SIZE - 12;
if (rle) {
ret = read_rle_sgi(out_end, in_buf, in_end, s);
} else {
ret = read_uncompressed_sgi(out_buf, out_end, in_buf, in_end, s);
}
if (ret == 0) {
*picture = s->picture;
*data_size = sizeof(AVPicture);
return buf_size;
} else {
return -1;
}
}
static av_cold int sgi_init(AVCodecContext *avctx){
SgiState *s = avctx->priv_data;
avcodec_get_frame_defaults(&s->picture);
avctx->coded_frame = &s->picture;
return 0;
}
static av_cold int sgi_end(AVCodecContext *avctx)
{
SgiState * const s = avctx->priv_data;
if (s->picture.data[0])
avctx->release_buffer(avctx, &s->picture);
return 0;
}
AVCodec sgi_decoder = {
"sgi",
CODEC_TYPE_VIDEO,
CODEC_ID_SGI,
sizeof(SgiState),
sgi_init,
NULL,
sgi_end,
decode_frame,
.long_name = NULL_IF_CONFIG_SMALL("SGI image"),
};
@@ -0,0 +1,157 @@
/*
* SGI image encoder
* Todd Kirby <[email protected]>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avcodec.h"
#include "bytestream.h"
#include "sgi.h"
#include "rle.h"
#define SGI_SINGLE_CHAN 2
#define SGI_MULTI_CHAN 3
typedef struct SgiContext {
AVFrame picture;
} SgiContext;
static av_cold int encode_init(AVCodecContext *avctx){
SgiContext *s = avctx->priv_data;
avcodec_get_frame_defaults(&s->picture);
avctx->coded_frame = &s->picture;
return 0;
}
static int encode_frame(AVCodecContext *avctx, unsigned char *buf,
int buf_size, void *data) {
SgiContext *s = avctx->priv_data;
AVFrame * const p = &s->picture;
uint8_t *offsettab, *lengthtab, *in_buf, *encode_buf;
int x, y, z, length, tablesize;
unsigned int width, height, depth, dimension;
unsigned char *orig_buf = buf, *end_buf = buf + buf_size;
*p = *(AVFrame*)data;
p->pict_type = FF_I_TYPE;
p->key_frame = 1;
width = avctx->width;
height = avctx->height;
switch (avctx->pix_fmt) {
case PIX_FMT_GRAY8:
dimension = SGI_SINGLE_CHAN;
depth = SGI_GRAYSCALE;
break;
case PIX_FMT_RGB24:
dimension = SGI_MULTI_CHAN;
depth = SGI_RGB;
break;
case PIX_FMT_RGBA:
dimension = SGI_MULTI_CHAN;
depth = SGI_RGBA;
break;
default:
return AVERROR_INVALIDDATA;
}
tablesize = depth * height * 4;
length = tablesize * 2 + SGI_HEADER_SIZE;
if (buf_size < length) {
av_log(avctx, AV_LOG_ERROR, "buf_size too small(need %d, got %d)\n", length, buf_size);
return -1;
}
/* Encode header. */
bytestream_put_be16(&buf, SGI_MAGIC);
bytestream_put_byte(&buf, 1); /* RLE */
bytestream_put_byte(&buf, 1); /* bytes_per_channel */
bytestream_put_be16(&buf, dimension);
bytestream_put_be16(&buf, width);
bytestream_put_be16(&buf, height);
bytestream_put_be16(&buf, depth);
/* The rest are constant in this implementation. */
bytestream_put_be32(&buf, 0L); /* pixmin */
bytestream_put_be32(&buf, 255L); /* pixmax */
bytestream_put_be32(&buf, 0L); /* dummy */
/* name */
memset(buf, 0, SGI_HEADER_SIZE);
buf += 80;
/* colormap */
bytestream_put_be32(&buf, 0L);
/* The rest of the 512 byte header is unused. */
buf += 404;
offsettab = buf;
/* Skip RLE offset table. */
buf += tablesize;
lengthtab = buf;
/* Skip RLE length table. */
buf += tablesize;
/* Make an intermediate consecutive buffer. */
if ((encode_buf = av_malloc(width)) == NULL)
return -1;
for (z = 0; z < depth; z++) {
in_buf = p->data[0] + p->linesize[0] * (height - 1) + z;
for (y = 0; y < height; y++) {
bytestream_put_be32(&offsettab, buf - orig_buf);
for (x = 0; x < width; x++)
encode_buf[x] = in_buf[depth * x];
if((length = ff_rle_encode(buf, end_buf - buf - 1, encode_buf, 1, width, 0, 0, 0x80, 0)) < 1) {
av_free(encode_buf);
return -1;
}
buf += length;
bytestream_put_byte(&buf, 0);
bytestream_put_be32(&lengthtab, length + 1);
in_buf -= p->linesize[0];
}
}
av_free(encode_buf);
/* total length */
return buf - orig_buf;
}
AVCodec sgi_encoder = {
"sgi",
CODEC_TYPE_VIDEO,
CODEC_ID_SGI,
sizeof(SgiContext),
encode_init,
encode_frame,
NULL,
.pix_fmts= (enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGBA, PIX_FMT_PAL8, PIX_FMT_GRAY8, PIX_FMT_NONE},
.long_name= NULL_IF_CONFIG_SMALL("SGI image"),
};
@@ -0,0 +1,537 @@
/*
* Shorten decoder
* Copyright (c) 2005 Jeff Muizelaar
*
* 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 shorten.c
* Shorten decoder
* @author Jeff Muizelaar
*
*/
#define DEBUG
#include <limits.h>
#include "avcodec.h"
#include "bitstream.h"
#include "golomb.h"
#define MAX_CHANNELS 8
#define MAX_BLOCKSIZE 65535
#define OUT_BUFFER_SIZE 16384
#define ULONGSIZE 2
#define WAVE_FORMAT_PCM 0x0001
#define DEFAULT_BLOCK_SIZE 256
#define TYPESIZE 4
#define CHANSIZE 0
#define LPCQSIZE 2
#define ENERGYSIZE 3
#define BITSHIFTSIZE 2
#define TYPE_S16HL 3
#define TYPE_S16LH 5
#define NWRAP 3
#define NSKIPSIZE 1
#define LPCQUANT 5
#define V2LPCQOFFSET (1 << LPCQUANT)
#define FNSIZE 2
#define FN_DIFF0 0
#define FN_DIFF1 1
#define FN_DIFF2 2
#define FN_DIFF3 3
#define FN_QUIT 4
#define FN_BLOCKSIZE 5
#define FN_BITSHIFT 6
#define FN_QLPC 7
#define FN_ZERO 8
#define FN_VERBATIM 9
#define VERBATIM_CKSIZE_SIZE 5
#define VERBATIM_BYTE_SIZE 8
#define CANONICAL_HEADER_SIZE 44
typedef struct ShortenContext {
AVCodecContext *avctx;
GetBitContext gb;
int min_framesize, max_framesize;
int channels;
int32_t *decoded[MAX_CHANNELS];
int32_t *offset[MAX_CHANNELS];
uint8_t *bitstream;
int bitstream_size;
int bitstream_index;
unsigned int allocated_bitstream_size;
int header_size;
uint8_t header[OUT_BUFFER_SIZE];
int version;
int cur_chan;
int bitshift;
int nmean;
int internal_ftype;
int nwrap;
int blocksize;
int bitindex;
int32_t lpcqoffset;
} ShortenContext;
static av_cold int shorten_decode_init(AVCodecContext * avctx)
{
ShortenContext *s = avctx->priv_data;
s->avctx = avctx;
avctx->sample_fmt = SAMPLE_FMT_S16;
return 0;
}
static int allocate_buffers(ShortenContext *s)
{
int i, chan;
for (chan=0; chan<s->channels; chan++) {
if(FFMAX(1, s->nmean) >= UINT_MAX/sizeof(int32_t)){
av_log(s->avctx, AV_LOG_ERROR, "nmean too large\n");
return -1;
}
if(s->blocksize + s->nwrap >= UINT_MAX/sizeof(int32_t) || s->blocksize + s->nwrap <= (unsigned)s->nwrap){
av_log(s->avctx, AV_LOG_ERROR, "s->blocksize + s->nwrap too large\n");
return -1;
}
s->offset[chan] = av_realloc(s->offset[chan], sizeof(int32_t)*FFMAX(1, s->nmean));
s->decoded[chan] = av_realloc(s->decoded[chan], sizeof(int32_t)*(s->blocksize + s->nwrap));
for (i=0; i<s->nwrap; i++)
s->decoded[chan][i] = 0;
s->decoded[chan] += s->nwrap;
}
return 0;
}
static inline unsigned int get_uint(ShortenContext *s, int k)
{
if (s->version != 0)
k = get_ur_golomb_shorten(&s->gb, ULONGSIZE);
return get_ur_golomb_shorten(&s->gb, k);
}
static void fix_bitshift(ShortenContext *s, int32_t *buffer)
{
int i;
if (s->bitshift != 0)
for (i = 0; i < s->blocksize; i++)
buffer[s->nwrap + i] <<= s->bitshift;
}
static void init_offset(ShortenContext *s)
{
int32_t mean = 0;
int chan, i;
int nblock = FFMAX(1, s->nmean);
/* initialise offset */
switch (s->internal_ftype)
{
case TYPE_S16HL:
case TYPE_S16LH:
mean = 0;
break;
default:
av_log(s->avctx, AV_LOG_ERROR, "unknown audio type");
abort();
}
for (chan = 0; chan < s->channels; chan++)
for (i = 0; i < nblock; i++)
s->offset[chan][i] = mean;
}
static inline int get_le32(GetBitContext *gb)
{
return bswap_32(get_bits_long(gb, 32));
}
static inline short get_le16(GetBitContext *gb)
{
return bswap_16(get_bits_long(gb, 16));
}
static int decode_wave_header(AVCodecContext *avctx, uint8_t *header, int header_size)
{
GetBitContext hb;
int len;
int chunk_size;
short wave_format;
init_get_bits(&hb, header, header_size*8);
if (get_le32(&hb) != MKTAG('R','I','F','F')) {
av_log(avctx, AV_LOG_ERROR, "missing RIFF tag\n");
return -1;
}
chunk_size = get_le32(&hb);
if (get_le32(&hb) != MKTAG('W','A','V','E')) {
av_log(avctx, AV_LOG_ERROR, "missing WAVE tag\n");
return -1;
}
while (get_le32(&hb) != MKTAG('f','m','t',' ')) {
len = get_le32(&hb);
skip_bits(&hb, 8*len);
}
len = get_le32(&hb);
if (len < 16) {
av_log(avctx, AV_LOG_ERROR, "fmt chunk was too short\n");
return -1;
}
wave_format = get_le16(&hb);
switch (wave_format) {
case WAVE_FORMAT_PCM:
break;
default:
av_log(avctx, AV_LOG_ERROR, "unsupported wave format\n");
return -1;
}
avctx->channels = get_le16(&hb);
avctx->sample_rate = get_le32(&hb);
avctx->bit_rate = get_le32(&hb) * 8;
avctx->block_align = get_le16(&hb);
avctx->bits_per_sample = get_le16(&hb);
if (avctx->bits_per_sample != 16) {
av_log(avctx, AV_LOG_ERROR, "unsupported number of bits per sample\n");
return -1;
}
len -= 16;
if (len > 0)
av_log(avctx, AV_LOG_INFO, "%d header bytes unparsed\n", len);
return 0;
}
static int16_t * interleave_buffer(int16_t *samples, int nchan, int blocksize, int32_t **buffer) {
int i, chan;
for (i=0; i<blocksize; i++)
for (chan=0; chan < nchan; chan++)
*samples++ = FFMIN(buffer[chan][i], 32768);
return samples;
}
static void decode_subframe_lpc(ShortenContext *s, int channel, int residual_size, int pred_order)
{
int sum, i, j;
int coeffs[pred_order];
for (i=0; i<pred_order; i++)
coeffs[i] = get_sr_golomb_shorten(&s->gb, LPCQUANT);
for (i=0; i < s->blocksize; i++) {
sum = s->lpcqoffset;
for (j=0; j<pred_order; j++)
sum += coeffs[j] * s->decoded[channel][i-j-1];
s->decoded[channel][i] = get_sr_golomb_shorten(&s->gb, residual_size) + (sum >> LPCQUANT);
}
}
static int shorten_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
const uint8_t *buf, int buf_size)
{
ShortenContext *s = avctx->priv_data;
int i, input_buf_size = 0;
int16_t *samples = data;
if(s->max_framesize == 0){
s->max_framesize= 1024; // should hopefully be enough for the first header
s->bitstream= av_fast_realloc(s->bitstream, &s->allocated_bitstream_size, s->max_framesize);
}
if(1 && s->max_framesize){//FIXME truncated
buf_size= FFMIN(buf_size, s->max_framesize - s->bitstream_size);
input_buf_size= buf_size;
if(s->bitstream_index + s->bitstream_size + buf_size > s->allocated_bitstream_size){
// printf("memmove\n");
memmove(s->bitstream, &s->bitstream[s->bitstream_index], s->bitstream_size);
s->bitstream_index=0;
}
memcpy(&s->bitstream[s->bitstream_index + s->bitstream_size], buf, buf_size);
buf= &s->bitstream[s->bitstream_index];
buf_size += s->bitstream_size;
s->bitstream_size= buf_size;
if(buf_size < s->max_framesize){
//dprintf(avctx, "wanna more data ... %d\n", buf_size);
*data_size = 0;
return input_buf_size;
}
}
init_get_bits(&s->gb, buf, buf_size*8);
skip_bits(&s->gb, s->bitindex);
if (!s->blocksize)
{
int maxnlpc = 0;
/* shorten signature */
if (get_bits_long(&s->gb, 32) != bswap_32(ff_get_fourcc("ajkg"))) {
av_log(s->avctx, AV_LOG_ERROR, "missing shorten magic 'ajkg'\n");
return -1;
}
s->lpcqoffset = 0;
s->blocksize = DEFAULT_BLOCK_SIZE;
s->channels = 1;
s->nmean = -1;
s->version = get_bits(&s->gb, 8);
s->internal_ftype = get_uint(s, TYPESIZE);
s->channels = get_uint(s, CHANSIZE);
if (s->channels > MAX_CHANNELS) {
av_log(s->avctx, AV_LOG_ERROR, "too many channels: %d\n", s->channels);
return -1;
}
/* get blocksize if version > 0 */
if (s->version > 0) {
int skip_bytes;
s->blocksize = get_uint(s, av_log2(DEFAULT_BLOCK_SIZE));
maxnlpc = get_uint(s, LPCQSIZE);
s->nmean = get_uint(s, 0);
skip_bytes = get_uint(s, NSKIPSIZE);
for (i=0; i<skip_bytes; i++) {
skip_bits(&s->gb, 8);
}
}
s->nwrap = FFMAX(NWRAP, maxnlpc);
if (allocate_buffers(s))
return -1;
init_offset(s);
if (s->version > 1)
s->lpcqoffset = V2LPCQOFFSET;
if (get_ur_golomb_shorten(&s->gb, FNSIZE) != FN_VERBATIM) {
av_log(s->avctx, AV_LOG_ERROR, "missing verbatim section at beginning of stream\n");
return -1;
}
s->header_size = get_ur_golomb_shorten(&s->gb, VERBATIM_CKSIZE_SIZE);
if (s->header_size >= OUT_BUFFER_SIZE || s->header_size < CANONICAL_HEADER_SIZE) {
av_log(s->avctx, AV_LOG_ERROR, "header is wrong size: %d\n", s->header_size);
return -1;
}
for (i=0; i<s->header_size; i++)
s->header[i] = (char)get_ur_golomb_shorten(&s->gb, VERBATIM_BYTE_SIZE);
if (decode_wave_header(avctx, s->header, s->header_size) < 0)
return -1;
s->cur_chan = 0;
s->bitshift = 0;
}
else
{
int cmd;
int len;
cmd = get_ur_golomb_shorten(&s->gb, FNSIZE);
switch (cmd) {
case FN_ZERO:
case FN_DIFF0:
case FN_DIFF1:
case FN_DIFF2:
case FN_DIFF3:
case FN_QLPC:
{
int residual_size = 0;
int channel = s->cur_chan;
int32_t coffset;
if (cmd != FN_ZERO) {
residual_size = get_ur_golomb_shorten(&s->gb, ENERGYSIZE);
/* this is a hack as version 0 differed in defintion of get_sr_golomb_shorten */
if (s->version == 0)
residual_size--;
}
if (s->nmean == 0)
coffset = s->offset[channel][0];
else {
int32_t sum = (s->version < 2) ? 0 : s->nmean / 2;
for (i=0; i<s->nmean; i++)
sum += s->offset[channel][i];
coffset = sum / s->nmean;
if (s->version >= 2)
coffset >>= FFMIN(1, s->bitshift);
}
switch (cmd) {
case FN_ZERO:
for (i=0; i<s->blocksize; i++)
s->decoded[channel][i] = 0;
break;
case FN_DIFF0:
for (i=0; i<s->blocksize; i++)
s->decoded[channel][i] = get_sr_golomb_shorten(&s->gb, residual_size) + coffset;
break;
case FN_DIFF1:
for (i=0; i<s->blocksize; i++)
s->decoded[channel][i] = get_sr_golomb_shorten(&s->gb, residual_size) + s->decoded[channel][i - 1];
break;
case FN_DIFF2:
for (i=0; i<s->blocksize; i++)
s->decoded[channel][i] = get_sr_golomb_shorten(&s->gb, residual_size) + 2*s->decoded[channel][i-1]
- s->decoded[channel][i-2];
break;
case FN_DIFF3:
for (i=0; i<s->blocksize; i++)
s->decoded[channel][i] = get_sr_golomb_shorten(&s->gb, residual_size) + 3*s->decoded[channel][i-1]
- 3*s->decoded[channel][i-2]
+ s->decoded[channel][i-3];
break;
case FN_QLPC:
{
int pred_order = get_ur_golomb_shorten(&s->gb, LPCQSIZE);
for (i=0; i<pred_order; i++)
s->decoded[channel][i - pred_order] -= coffset;
decode_subframe_lpc(s, channel, residual_size, pred_order);
if (coffset != 0)
for (i=0; i < s->blocksize; i++)
s->decoded[channel][i] += coffset;
}
}
if (s->nmean > 0) {
int32_t sum = (s->version < 2) ? 0 : s->blocksize / 2;
for (i=0; i<s->blocksize; i++)
sum += s->decoded[channel][i];
for (i=1; i<s->nmean; i++)
s->offset[channel][i-1] = s->offset[channel][i];
if (s->version < 2)
s->offset[channel][s->nmean - 1] = sum / s->blocksize;
else
s->offset[channel][s->nmean - 1] = (sum / s->blocksize) << s->bitshift;
}
for (i=-s->nwrap; i<0; i++)
s->decoded[channel][i] = s->decoded[channel][i + s->blocksize];
fix_bitshift(s, s->decoded[channel]);
s->cur_chan++;
if (s->cur_chan == s->channels) {
samples = interleave_buffer(samples, s->channels, s->blocksize, s->decoded);
s->cur_chan = 0;
goto frame_done;
}
break;
}
break;
case FN_VERBATIM:
len = get_ur_golomb_shorten(&s->gb, VERBATIM_CKSIZE_SIZE);
while (len--) {
get_ur_golomb_shorten(&s->gb, VERBATIM_BYTE_SIZE);
}
break;
case FN_BITSHIFT:
s->bitshift = get_ur_golomb_shorten(&s->gb, BITSHIFTSIZE);
break;
case FN_BLOCKSIZE:
s->blocksize = get_uint(s, av_log2(s->blocksize));
break;
case FN_QUIT:
*data_size = 0;
return buf_size;
break;
default:
av_log(avctx, AV_LOG_ERROR, "unknown shorten function %d\n", cmd);
return -1;
break;
}
}
frame_done:
*data_size = (int8_t *)samples - (int8_t *)data;
// s->last_blocksize = s->blocksize;
s->bitindex = get_bits_count(&s->gb) - 8*((get_bits_count(&s->gb))/8);
i= (get_bits_count(&s->gb))/8;
if (i > buf_size) {
av_log(s->avctx, AV_LOG_ERROR, "overread: %d\n", i - buf_size);
s->bitstream_size=0;
s->bitstream_index=0;
return -1;
}
if (s->bitstream_size) {
s->bitstream_index += i;
s->bitstream_size -= i;
return input_buf_size;
} else
return i;
}
static av_cold int shorten_decode_close(AVCodecContext *avctx)
{
ShortenContext *s = avctx->priv_data;
int i;
for (i = 0; i < s->channels; i++) {
s->decoded[i] -= s->nwrap;
av_freep(&s->decoded[i]);
av_freep(&s->offset[i]);
}
av_freep(&s->bitstream);
return 0;
}
static void shorten_flush(AVCodecContext *avctx){
ShortenContext *s = avctx->priv_data;
s->bitstream_size=
s->bitstream_index= 0;
}
AVCodec shorten_decoder = {
"shorten",
CODEC_TYPE_AUDIO,
CODEC_ID_SHORTEN,
sizeof(ShortenContext),
shorten_decode_init,
NULL,
shorten_decode_close,
shorten_decode_frame,
.flush= shorten_flush,
.long_name= NULL_IF_CONFIG_SMALL("Shorten"),
};
@@ -3,19 +3,21 @@
* *
* Copyright (c) 2001 Michael Niedermayer <[email protected]> * Copyright (c) 2001 Michael Niedermayer <[email protected]>
* *
* This library is free software; you can redistribute it and/or * This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This library is distributed in the hope that it will be useful, * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
/** /**
@@ -75,14 +77,14 @@
static inline void idctRowCondDC (DCTELEM * row) static inline void idctRowCondDC (DCTELEM * row)
{ {
int a0, a1, a2, a3, b0, b1, b2, b3; int a0, a1, a2, a3, b0, b1, b2, b3;
#ifdef FAST_64BIT #ifdef HAVE_FAST_64BIT
uint64_t temp; uint64_t temp;
#else #else
uint32_t temp; uint32_t temp;
#endif #endif
#ifdef FAST_64BIT #ifdef HAVE_FAST_64BIT
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN
#define ROW0_MASK 0xffff000000000000LL #define ROW0_MASK 0xffff000000000000LL
#else #else
@@ -97,7 +99,7 @@ static inline void idctRowCondDC (DCTELEM * row)
((uint64_t *)row)[0] = temp; ((uint64_t *)row)[0] = temp;
((uint64_t *)row)[1] = temp; ((uint64_t *)row)[1] = temp;
return; return;
} }
}else{ }else{
if (!(row[1]|row[2]|row[3]|row[4]|row[5]|row[6]|row[7])) { if (!(row[1]|row[2]|row[3]|row[4]|row[5]|row[6]|row[7])) {
row[0]=row[1]=row[2]=row[3]=row[4]=row[5]=row[6]=row[7]= row[0] << 3; row[0]=row[1]=row[2]=row[3]=row[4]=row[5]=row[6]=row[7]= row[0] << 3;
@@ -125,9 +127,9 @@ static inline void idctRowCondDC (DCTELEM * row)
#endif #endif
a0 = (W4 * row[0]) + (1 << (ROW_SHIFT - 1)); a0 = (W4 * row[0]) + (1 << (ROW_SHIFT - 1));
a1 = a0; a1 = a0;
a2 = a0; a2 = a0;
a3 = a0; a3 = a0;
/* no need to optimize : gcc does it */ /* no need to optimize : gcc does it */
a0 += W2 * row[2]; a0 += W2 * row[2];
@@ -144,12 +146,12 @@ static inline void idctRowCondDC (DCTELEM * row)
MUL16(b3, W7, row[1]); MUL16(b3, W7, row[1]);
MAC16(b3, -W5, row[3]); MAC16(b3, -W5, row[3]);
#ifdef FAST_64BIT #ifdef HAVE_FAST_64BIT
temp = ((uint64_t*)row)[1]; temp = ((uint64_t*)row)[1];
#else #else
temp = ((uint32_t*)row)[2] | ((uint32_t*)row)[3]; temp = ((uint32_t*)row)[2] | ((uint32_t*)row)[3];
#endif #endif
if (temp != 0) { if (temp != 0) {
a0 += W4*row[4] + W6*row[6]; a0 += W4*row[4] + W6*row[6];
a1 += - W4*row[4] - W2*row[6]; a1 += - W4*row[4] - W2*row[6];
a2 += - W4*row[4] + W2*row[6]; a2 += - W4*row[4] + W2*row[6];
@@ -166,29 +168,29 @@ static inline void idctRowCondDC (DCTELEM * row)
MAC16(b3, W3, row[5]); MAC16(b3, W3, row[5]);
MAC16(b3, -W1, row[7]); MAC16(b3, -W1, row[7]);
} }
row[0] = (a0 + b0) >> ROW_SHIFT; row[0] = (a0 + b0) >> ROW_SHIFT;
row[7] = (a0 - b0) >> ROW_SHIFT; row[7] = (a0 - b0) >> ROW_SHIFT;
row[1] = (a1 + b1) >> ROW_SHIFT; row[1] = (a1 + b1) >> ROW_SHIFT;
row[6] = (a1 - b1) >> ROW_SHIFT; row[6] = (a1 - b1) >> ROW_SHIFT;
row[2] = (a2 + b2) >> ROW_SHIFT; row[2] = (a2 + b2) >> ROW_SHIFT;
row[5] = (a2 - b2) >> ROW_SHIFT; row[5] = (a2 - b2) >> ROW_SHIFT;
row[3] = (a3 + b3) >> ROW_SHIFT; row[3] = (a3 + b3) >> ROW_SHIFT;
row[4] = (a3 - b3) >> ROW_SHIFT; row[4] = (a3 - b3) >> ROW_SHIFT;
} }
static inline void idctSparseColPut (uint8_t *dest, int line_size, static inline void idctSparseColPut (uint8_t *dest, int line_size,
DCTELEM * col) DCTELEM * col)
{ {
int a0, a1, a2, a3, b0, b1, b2, b3; int a0, a1, a2, a3, b0, b1, b2, b3;
uint8_t *cm = cropTbl + MAX_NEG_CROP; uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
/* XXX: I did that only to give same values as previous code */ /* XXX: I did that only to give same values as previous code */
a0 = W4 * (col[8*0] + ((1<<(COL_SHIFT-1))/W4)); a0 = W4 * (col[8*0] + ((1<<(COL_SHIFT-1))/W4));
a1 = a0; a1 = a0;
a2 = a0; a2 = a0;
a3 = a0; a3 = a0;
a0 += + W2*col[8*2]; a0 += + W2*col[8*2];
a1 += + W6*col[8*2]; a1 += + W6*col[8*2];
@@ -205,33 +207,33 @@ static inline void idctSparseColPut (uint8_t *dest, int line_size,
MAC16(b2, - W1, col[8*3]); MAC16(b2, - W1, col[8*3]);
MAC16(b3, - W5, col[8*3]); MAC16(b3, - W5, col[8*3]);
if(col[8*4]){ if(col[8*4]){
a0 += + W4*col[8*4]; a0 += + W4*col[8*4];
a1 += - W4*col[8*4]; a1 += - W4*col[8*4];
a2 += - W4*col[8*4]; a2 += - W4*col[8*4];
a3 += + W4*col[8*4]; a3 += + W4*col[8*4];
} }
if (col[8*5]) { if (col[8*5]) {
MAC16(b0, + W5, col[8*5]); MAC16(b0, + W5, col[8*5]);
MAC16(b1, - W1, col[8*5]); MAC16(b1, - W1, col[8*5]);
MAC16(b2, + W7, col[8*5]); MAC16(b2, + W7, col[8*5]);
MAC16(b3, + W3, col[8*5]); MAC16(b3, + W3, col[8*5]);
} }
if(col[8*6]){ if(col[8*6]){
a0 += + W6*col[8*6]; a0 += + W6*col[8*6];
a1 += - W2*col[8*6]; a1 += - W2*col[8*6];
a2 += + W2*col[8*6]; a2 += + W2*col[8*6];
a3 += - W6*col[8*6]; a3 += - W6*col[8*6];
} }
if (col[8*7]) { if (col[8*7]) {
MAC16(b0, + W7, col[8*7]); MAC16(b0, + W7, col[8*7]);
MAC16(b1, - W5, col[8*7]); MAC16(b1, - W5, col[8*7]);
MAC16(b2, + W3, col[8*7]); MAC16(b2, + W3, col[8*7]);
MAC16(b3, - W1, col[8*7]); MAC16(b3, - W1, col[8*7]);
} }
dest[0] = cm[(a0 + b0) >> COL_SHIFT]; dest[0] = cm[(a0 + b0) >> COL_SHIFT];
dest += line_size; dest += line_size;
@@ -253,14 +255,14 @@ static inline void idctSparseColPut (uint8_t *dest, int line_size,
static inline void idctSparseColAdd (uint8_t *dest, int line_size, static inline void idctSparseColAdd (uint8_t *dest, int line_size,
DCTELEM * col) DCTELEM * col)
{ {
int a0, a1, a2, a3, b0, b1, b2, b3; int a0, a1, a2, a3, b0, b1, b2, b3;
uint8_t *cm = cropTbl + MAX_NEG_CROP; uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
/* XXX: I did that only to give same values as previous code */ /* XXX: I did that only to give same values as previous code */
a0 = W4 * (col[8*0] + ((1<<(COL_SHIFT-1))/W4)); a0 = W4 * (col[8*0] + ((1<<(COL_SHIFT-1))/W4));
a1 = a0; a1 = a0;
a2 = a0; a2 = a0;
a3 = a0; a3 = a0;
a0 += + W2*col[8*2]; a0 += + W2*col[8*2];
a1 += + W6*col[8*2]; a1 += + W6*col[8*2];
@@ -277,33 +279,33 @@ static inline void idctSparseColAdd (uint8_t *dest, int line_size,
MAC16(b2, - W1, col[8*3]); MAC16(b2, - W1, col[8*3]);
MAC16(b3, - W5, col[8*3]); MAC16(b3, - W5, col[8*3]);
if(col[8*4]){ if(col[8*4]){
a0 += + W4*col[8*4]; a0 += + W4*col[8*4];
a1 += - W4*col[8*4]; a1 += - W4*col[8*4];
a2 += - W4*col[8*4]; a2 += - W4*col[8*4];
a3 += + W4*col[8*4]; a3 += + W4*col[8*4];
} }
if (col[8*5]) { if (col[8*5]) {
MAC16(b0, + W5, col[8*5]); MAC16(b0, + W5, col[8*5]);
MAC16(b1, - W1, col[8*5]); MAC16(b1, - W1, col[8*5]);
MAC16(b2, + W7, col[8*5]); MAC16(b2, + W7, col[8*5]);
MAC16(b3, + W3, col[8*5]); MAC16(b3, + W3, col[8*5]);
} }
if(col[8*6]){ if(col[8*6]){
a0 += + W6*col[8*6]; a0 += + W6*col[8*6];
a1 += - W2*col[8*6]; a1 += - W2*col[8*6];
a2 += + W2*col[8*6]; a2 += + W2*col[8*6];
a3 += - W6*col[8*6]; a3 += - W6*col[8*6];
} }
if (col[8*7]) { if (col[8*7]) {
MAC16(b0, + W7, col[8*7]); MAC16(b0, + W7, col[8*7]);
MAC16(b1, - W5, col[8*7]); MAC16(b1, - W5, col[8*7]);
MAC16(b2, + W3, col[8*7]); MAC16(b2, + W3, col[8*7]);
MAC16(b3, - W1, col[8*7]); MAC16(b3, - W1, col[8*7]);
} }
dest[0] = cm[dest[0] + ((a0 + b0) >> COL_SHIFT)]; dest[0] = cm[dest[0] + ((a0 + b0) >> COL_SHIFT)];
dest += line_size; dest += line_size;
@@ -324,13 +326,13 @@ static inline void idctSparseColAdd (uint8_t *dest, int line_size,
static inline void idctSparseCol (DCTELEM * col) static inline void idctSparseCol (DCTELEM * col)
{ {
int a0, a1, a2, a3, b0, b1, b2, b3; int a0, a1, a2, a3, b0, b1, b2, b3;
/* XXX: I did that only to give same values as previous code */ /* XXX: I did that only to give same values as previous code */
a0 = W4 * (col[8*0] + ((1<<(COL_SHIFT-1))/W4)); a0 = W4 * (col[8*0] + ((1<<(COL_SHIFT-1))/W4));
a1 = a0; a1 = a0;
a2 = a0; a2 = a0;
a3 = a0; a3 = a0;
a0 += + W2*col[8*2]; a0 += + W2*col[8*2];
a1 += + W6*col[8*2]; a1 += + W6*col[8*2];
@@ -347,33 +349,33 @@ static inline void idctSparseCol (DCTELEM * col)
MAC16(b2, - W1, col[8*3]); MAC16(b2, - W1, col[8*3]);
MAC16(b3, - W5, col[8*3]); MAC16(b3, - W5, col[8*3]);
if(col[8*4]){ if(col[8*4]){
a0 += + W4*col[8*4]; a0 += + W4*col[8*4];
a1 += - W4*col[8*4]; a1 += - W4*col[8*4];
a2 += - W4*col[8*4]; a2 += - W4*col[8*4];
a3 += + W4*col[8*4]; a3 += + W4*col[8*4];
} }
if (col[8*5]) { if (col[8*5]) {
MAC16(b0, + W5, col[8*5]); MAC16(b0, + W5, col[8*5]);
MAC16(b1, - W1, col[8*5]); MAC16(b1, - W1, col[8*5]);
MAC16(b2, + W7, col[8*5]); MAC16(b2, + W7, col[8*5]);
MAC16(b3, + W3, col[8*5]); MAC16(b3, + W3, col[8*5]);
} }
if(col[8*6]){ if(col[8*6]){
a0 += + W6*col[8*6]; a0 += + W6*col[8*6];
a1 += - W2*col[8*6]; a1 += - W2*col[8*6];
a2 += + W2*col[8*6]; a2 += + W2*col[8*6];
a3 += - W6*col[8*6]; a3 += - W6*col[8*6];
} }
if (col[8*7]) { if (col[8*7]) {
MAC16(b0, + W7, col[8*7]); MAC16(b0, + W7, col[8*7]);
MAC16(b1, - W5, col[8*7]); MAC16(b1, - W5, col[8*7]);
MAC16(b2, + W3, col[8*7]); MAC16(b2, + W3, col[8*7]);
MAC16(b3, - W1, col[8*7]); MAC16(b3, - W1, col[8*7]);
} }
col[0 ] = ((a0 + b0) >> COL_SHIFT); col[0 ] = ((a0 + b0) >> COL_SHIFT);
col[8 ] = ((a1 + b1) >> COL_SHIFT); col[8 ] = ((a1 + b1) >> COL_SHIFT);
@@ -385,7 +387,7 @@ static inline void idctSparseCol (DCTELEM * col)
col[56] = ((a0 - b0) >> COL_SHIFT); col[56] = ((a0 - b0) >> COL_SHIFT);
} }
void simple_idct_put(uint8_t *dest, int line_size, DCTELEM *block) void ff_simple_idct_put(uint8_t *dest, int line_size, DCTELEM *block)
{ {
int i; int i;
for(i=0; i<8; i++) for(i=0; i<8; i++)
@@ -395,7 +397,7 @@ void simple_idct_put(uint8_t *dest, int line_size, DCTELEM *block)
idctSparseColPut(dest + i, line_size, block + i); idctSparseColPut(dest + i, line_size, block + i);
} }
void simple_idct_add(uint8_t *dest, int line_size, DCTELEM *block) void ff_simple_idct_add(uint8_t *dest, int line_size, DCTELEM *block)
{ {
int i; int i;
for(i=0; i<8; i++) for(i=0; i<8; i++)
@@ -405,7 +407,7 @@ void simple_idct_add(uint8_t *dest, int line_size, DCTELEM *block)
idctSparseColAdd(dest + i, line_size, block + i); idctSparseColAdd(dest + i, line_size, block + i);
} }
void simple_idct(DCTELEM *block) void ff_simple_idct(DCTELEM *block)
{ {
int i; int i;
for(i=0; i<8; i++) for(i=0; i<8; i++)
@@ -426,10 +428,10 @@ void simple_idct(DCTELEM *block)
and the butterfly must be multiplied by 0.5 * sqrt(2.0) */ and the butterfly must be multiplied by 0.5 * sqrt(2.0) */
#define C_SHIFT (4+1+12) #define C_SHIFT (4+1+12)
static inline void idct4col(uint8_t *dest, int line_size, const DCTELEM *col) static inline void idct4col_put(uint8_t *dest, int line_size, const DCTELEM *col)
{ {
int c0, c1, c2, c3, a0, a1, a2, a3; int c0, c1, c2, c3, a0, a1, a2, a3;
const uint8_t *cm = cropTbl + MAX_NEG_CROP; const uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
a0 = col[8*0]; a0 = col[8*0];
a1 = col[8*2]; a1 = col[8*2];
@@ -463,7 +465,7 @@ static inline void idct4col(uint8_t *dest, int line_size, const DCTELEM *col)
/* XXX: I think a 1.0/sqrt(2) normalization should be needed to /* XXX: I think a 1.0/sqrt(2) normalization should be needed to
compensate the extra butterfly stage - I don't have the full DV compensate the extra butterfly stage - I don't have the full DV
specification */ specification */
void simple_idct248_put(uint8_t *dest, int line_size, DCTELEM *block) void ff_simple_idct248_put(uint8_t *dest, int line_size, DCTELEM *block)
{ {
int i; int i;
DCTELEM *ptr; DCTELEM *ptr;
@@ -489,8 +491,8 @@ void simple_idct248_put(uint8_t *dest, int line_size, DCTELEM *block)
/* IDCT4 and store */ /* IDCT4 and store */
for(i=0;i<8;i++) { for(i=0;i<8;i++) {
idct4col(dest + i, 2 * line_size, block + i); idct4col_put(dest + i, 2 * line_size, block + i);
idct4col(dest + line_size + i, 2 * line_size, block + 8 + i); idct4col_put(dest + line_size + i, 2 * line_size, block + 8 + i);
} }
} }
@@ -509,7 +511,7 @@ void simple_idct248_put(uint8_t *dest, int line_size, DCTELEM *block)
static inline void idct4col_add(uint8_t *dest, int line_size, const DCTELEM *col) static inline void idct4col_add(uint8_t *dest, int line_size, const DCTELEM *col)
{ {
int c0, c1, c2, c3, a0, a1, a2, a3; int c0, c1, c2, c3, a0, a1, a2, a3;
const uint8_t *cm = cropTbl + MAX_NEG_CROP; const uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
a0 = col[8*0]; a0 = col[8*0];
a1 = col[8*1]; a1 = col[8*1];
@@ -537,7 +539,7 @@ static inline void idct4col_add(uint8_t *dest, int line_size, const DCTELEM *col
static inline void idct4row(DCTELEM *row) static inline void idct4row(DCTELEM *row)
{ {
int c0, c1, c2, c3, a0, a1, a2, a3; int c0, c1, c2, c3, a0, a1, a2, a3;
//const uint8_t *cm = cropTbl + MAX_NEG_CROP; //const uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
a0 = row[0]; a0 = row[0];
a1 = row[1]; a1 = row[1];
@@ -553,7 +555,7 @@ static inline void idct4row(DCTELEM *row)
row[3]= (c0 - c1) >> R_SHIFT; row[3]= (c0 - c1) >> R_SHIFT;
} }
void simple_idct84_add(uint8_t *dest, int line_size, DCTELEM *block) void ff_simple_idct84_add(uint8_t *dest, int line_size, DCTELEM *block)
{ {
int i; int i;
@@ -568,7 +570,7 @@ void simple_idct84_add(uint8_t *dest, int line_size, DCTELEM *block)
} }
} }
void simple_idct48_add(uint8_t *dest, int line_size, DCTELEM *block) void ff_simple_idct48_add(uint8_t *dest, int line_size, DCTELEM *block)
{ {
int i; int i;
@@ -583,3 +585,17 @@ void simple_idct48_add(uint8_t *dest, int line_size, DCTELEM *block)
} }
} }
void ff_simple_idct44_add(uint8_t *dest, int line_size, DCTELEM *block)
{
int i;
/* IDCT4 on each line */
for(i=0; i<4; i++) {
idct4row(block + i*8);
}
/* IDCT4 and store */
for(i=0; i<4; i++){
idct4col_add(dest + i, line_size, block + i);
}
}
@@ -3,19 +3,21 @@
* *
* Copyright (c) 2001 Michael Niedermayer <[email protected]> * Copyright (c) 2001 Michael Niedermayer <[email protected]>
* *
* This library is free software; you can redistribute it and/or * This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This library is distributed in the hope that it will be useful, * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
/** /**
@@ -23,14 +25,23 @@
* simple idct header. * simple idct header.
*/ */
void simple_idct_put(uint8_t *dest, int line_size, DCTELEM *block); #ifndef FFMPEG_SIMPLE_IDCT_H
void simple_idct_add(uint8_t *dest, int line_size, DCTELEM *block); #define FFMPEG_SIMPLE_IDCT_H
#include <stdint.h>
#include "dsputil.h"
void ff_simple_idct_put(uint8_t *dest, int line_size, DCTELEM *block);
void ff_simple_idct_add(uint8_t *dest, int line_size, DCTELEM *block);
void ff_simple_idct_mmx(int16_t *block); void ff_simple_idct_mmx(int16_t *block);
void ff_simple_idct_add_mmx(uint8_t *dest, int line_size, int16_t *block); void ff_simple_idct_add_mmx(uint8_t *dest, int line_size, int16_t *block);
void ff_simple_idct_put_mmx(uint8_t *dest, int line_size, int16_t *block); void ff_simple_idct_put_mmx(uint8_t *dest, int line_size, int16_t *block);
void simple_idct(DCTELEM *block); void ff_simple_idct(DCTELEM *block);
void simple_idct248_put(uint8_t *dest, int line_size, DCTELEM *block); void ff_simple_idct248_put(uint8_t *dest, int line_size, DCTELEM *block);
void simple_idct84_add(uint8_t *dest, int line_size, DCTELEM *block); void ff_simple_idct84_add(uint8_t *dest, int line_size, DCTELEM *block);
void simple_idct48_add(uint8_t *dest, int line_size, DCTELEM *block); void ff_simple_idct48_add(uint8_t *dest, int line_size, DCTELEM *block);
void ff_simple_idct44_add(uint8_t *dest, int line_size, DCTELEM *block);
#endif /* FFMPEG_SIMPLE_IDCT_H */
@@ -0,0 +1,716 @@
/*
* Smacker 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
*/
/**
* @file smacker.c
* Smacker decoder
*/
/*
* Based on http://wiki.multimedia.cx/index.php?title=Smacker
*/
#include <stdio.h>
#include <stdlib.h>
#include "avcodec.h"
#define ALT_BITSTREAM_READER_LE
#include "bitstream.h"
#include "bytestream.h"
#define SMKTREE_BITS 9
#define SMK_NODE 0x80000000
/*
* Decoder context
*/
typedef struct SmackVContext {
AVCodecContext *avctx;
AVFrame pic;
int *mmap_tbl, *mclr_tbl, *full_tbl, *type_tbl;
int mmap_last[3], mclr_last[3], full_last[3], type_last[3];
} SmackVContext;
/**
* Context used for code reconstructing
*/
typedef struct HuffContext {
int length;
int maxlength;
int current;
uint32_t *bits;
int *lengths;
int *values;
} HuffContext;
/* common parameters used for decode_bigtree */
typedef struct DBCtx {
VLC *v1, *v2;
int *recode1, *recode2;
int escapes[3];
int *last;
int lcur;
} DBCtx;
/* possible runs of blocks */
static const int block_runs[64] = {
1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 52, 53, 54, 55, 56,
57, 58, 59, 128, 256, 512, 1024, 2048 };
enum SmkBlockTypes {
SMK_BLK_MONO = 0,
SMK_BLK_FULL = 1,
SMK_BLK_SKIP = 2,
SMK_BLK_FILL = 3 };
/**
* Decode local frame tree
*/
static int smacker_decode_tree(GetBitContext *gb, HuffContext *hc, uint32_t prefix, int length)
{
if(!get_bits1(gb)){ //Leaf
if(hc->current >= 256){
av_log(NULL, AV_LOG_ERROR, "Tree size exceeded!\n");
return -1;
}
if(length){
hc->bits[hc->current] = prefix;
hc->lengths[hc->current] = length;
} else {
hc->bits[hc->current] = 0;
hc->lengths[hc->current] = 0;
}
hc->values[hc->current] = get_bits(gb, 8);
hc->current++;
if(hc->maxlength < length)
hc->maxlength = length;
return 0;
} else { //Node
int r;
length++;
r = smacker_decode_tree(gb, hc, prefix, length);
if(r)
return r;
return smacker_decode_tree(gb, hc, prefix | (1 << (length - 1)), length);
}
}
/**
* Decode header tree
*/
static int smacker_decode_bigtree(GetBitContext *gb, HuffContext *hc, DBCtx *ctx)
{
if(!get_bits1(gb)){ //Leaf
int val, i1, i2, b1, b2;
if(hc->current >= hc->length){
av_log(NULL, AV_LOG_ERROR, "Tree size exceeded!\n");
return -1;
}
b1 = get_bits_count(gb);
i1 = get_vlc2(gb, ctx->v1->table, SMKTREE_BITS, 3);
b1 = get_bits_count(gb) - b1;
b2 = get_bits_count(gb);
i2 = get_vlc2(gb, ctx->v2->table, SMKTREE_BITS, 3);
b2 = get_bits_count(gb) - b2;
val = ctx->recode1[i1] | (ctx->recode2[i2] << 8);
if(val == ctx->escapes[0]) {
ctx->last[0] = hc->current;
val = 0;
} else if(val == ctx->escapes[1]) {
ctx->last[1] = hc->current;
val = 0;
} else if(val == ctx->escapes[2]) {
ctx->last[2] = hc->current;
val = 0;
}
hc->values[hc->current++] = val;
return 1;
} else { //Node
int r = 0, t;
t = hc->current++;
r = smacker_decode_bigtree(gb, hc, ctx);
if(r < 0)
return r;
hc->values[t] = SMK_NODE | r;
r++;
r += smacker_decode_bigtree(gb, hc, ctx);
return r;
}
}
/**
* Store large tree as FFmpeg's vlc codes
*/
static int smacker_decode_header_tree(SmackVContext *smk, GetBitContext *gb, int **recodes, int *last, int size)
{
int res;
HuffContext huff;
HuffContext tmp1, tmp2;
VLC vlc[2];
int escapes[3];
DBCtx ctx;
if(size >= UINT_MAX>>4){ // (((size + 3) >> 2) + 3) << 2 must not overflow
av_log(smk->avctx, AV_LOG_ERROR, "size too large\n");
return -1;
}
tmp1.length = 256;
tmp1.maxlength = 0;
tmp1.current = 0;
tmp1.bits = av_mallocz(256 * 4);
tmp1.lengths = av_mallocz(256 * sizeof(int));
tmp1.values = av_mallocz(256 * sizeof(int));
tmp2.length = 256;
tmp2.maxlength = 0;
tmp2.current = 0;
tmp2.bits = av_mallocz(256 * 4);
tmp2.lengths = av_mallocz(256 * sizeof(int));
tmp2.values = av_mallocz(256 * sizeof(int));
memset(&vlc[0], 0, sizeof(VLC));
memset(&vlc[1], 0, sizeof(VLC));
if(get_bits1(gb)) {
smacker_decode_tree(gb, &tmp1, 0, 0);
skip_bits1(gb);
res = init_vlc(&vlc[0], SMKTREE_BITS, tmp1.length,
tmp1.lengths, sizeof(int), sizeof(int),
tmp1.bits, sizeof(uint32_t), sizeof(uint32_t), INIT_VLC_LE);
if(res < 0) {
av_log(smk->avctx, AV_LOG_ERROR, "Cannot build VLC table\n");
return -1;
}
} else {
av_log(smk->avctx, AV_LOG_ERROR, "Skipping low bytes tree\n");
}
if(get_bits1(gb)){
smacker_decode_tree(gb, &tmp2, 0, 0);
skip_bits1(gb);
res = init_vlc(&vlc[1], SMKTREE_BITS, tmp2.length,
tmp2.lengths, sizeof(int), sizeof(int),
tmp2.bits, sizeof(uint32_t), sizeof(uint32_t), INIT_VLC_LE);
if(res < 0) {
av_log(smk->avctx, AV_LOG_ERROR, "Cannot build VLC table\n");
return -1;
}
} else {
av_log(smk->avctx, AV_LOG_ERROR, "Skipping high bytes tree\n");
}
escapes[0] = get_bits(gb, 8);
escapes[0] |= get_bits(gb, 8) << 8;
escapes[1] = get_bits(gb, 8);
escapes[1] |= get_bits(gb, 8) << 8;
escapes[2] = get_bits(gb, 8);
escapes[2] |= get_bits(gb, 8) << 8;
last[0] = last[1] = last[2] = -1;
ctx.escapes[0] = escapes[0];
ctx.escapes[1] = escapes[1];
ctx.escapes[2] = escapes[2];
ctx.v1 = &vlc[0];
ctx.v2 = &vlc[1];
ctx.recode1 = tmp1.values;
ctx.recode2 = tmp2.values;
ctx.last = last;
huff.length = ((size + 3) >> 2) + 3;
huff.maxlength = 0;
huff.current = 0;
huff.values = av_mallocz(huff.length * sizeof(int));
smacker_decode_bigtree(gb, &huff, &ctx);
skip_bits1(gb);
if(ctx.last[0] == -1) ctx.last[0] = huff.current++;
if(ctx.last[1] == -1) ctx.last[1] = huff.current++;
if(ctx.last[2] == -1) ctx.last[2] = huff.current++;
*recodes = huff.values;
if(vlc[0].table)
free_vlc(&vlc[0]);
if(vlc[1].table)
free_vlc(&vlc[1]);
av_free(tmp1.bits);
av_free(tmp1.lengths);
av_free(tmp1.values);
av_free(tmp2.bits);
av_free(tmp2.lengths);
av_free(tmp2.values);
return 0;
}
static int decode_header_trees(SmackVContext *smk) {
GetBitContext gb;
int mmap_size, mclr_size, full_size, type_size;
mmap_size = AV_RL32(smk->avctx->extradata);
mclr_size = AV_RL32(smk->avctx->extradata + 4);
full_size = AV_RL32(smk->avctx->extradata + 8);
type_size = AV_RL32(smk->avctx->extradata + 12);
init_get_bits(&gb, smk->avctx->extradata + 16, (smk->avctx->extradata_size - 16) * 8);
if(!get_bits1(&gb)) {
av_log(smk->avctx, AV_LOG_INFO, "Skipping MMAP tree\n");
smk->mmap_tbl = av_malloc(sizeof(int) * 2);
smk->mmap_tbl[0] = 0;
smk->mmap_last[0] = smk->mmap_last[1] = smk->mmap_last[2] = 1;
} else {
smacker_decode_header_tree(smk, &gb, &smk->mmap_tbl, smk->mmap_last, mmap_size);
}
if(!get_bits1(&gb)) {
av_log(smk->avctx, AV_LOG_INFO, "Skipping MCLR tree\n");
smk->mclr_tbl = av_malloc(sizeof(int) * 2);
smk->mclr_tbl[0] = 0;
smk->mclr_last[0] = smk->mclr_last[1] = smk->mclr_last[2] = 1;
} else {
smacker_decode_header_tree(smk, &gb, &smk->mclr_tbl, smk->mclr_last, mclr_size);
}
if(!get_bits1(&gb)) {
av_log(smk->avctx, AV_LOG_INFO, "Skipping FULL tree\n");
smk->full_tbl = av_malloc(sizeof(int) * 2);
smk->full_tbl[0] = 0;
smk->full_last[0] = smk->full_last[1] = smk->full_last[2] = 1;
} else {
smacker_decode_header_tree(smk, &gb, &smk->full_tbl, smk->full_last, full_size);
}
if(!get_bits1(&gb)) {
av_log(smk->avctx, AV_LOG_INFO, "Skipping TYPE tree\n");
smk->type_tbl = av_malloc(sizeof(int) * 2);
smk->type_tbl[0] = 0;
smk->type_last[0] = smk->type_last[1] = smk->type_last[2] = 1;
} else {
smacker_decode_header_tree(smk, &gb, &smk->type_tbl, smk->type_last, type_size);
}
return 0;
}
static av_always_inline void last_reset(int *recode, int *last) {
recode[last[0]] = recode[last[1]] = recode[last[2]] = 0;
}
/* get code and update history */
static av_always_inline int smk_get_code(GetBitContext *gb, int *recode, int *last) {
register int *table = recode;
int v, b;
b = get_bits_count(gb);
while(*table & SMK_NODE) {
if(get_bits1(gb))
table += (*table) & (~SMK_NODE);
table++;
}
v = *table;
b = get_bits_count(gb) - b;
if(v != recode[last[0]]) {
recode[last[2]] = recode[last[1]];
recode[last[1]] = recode[last[0]];
recode[last[0]] = v;
}
return v;
}
static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, const uint8_t *buf, int buf_size)
{
SmackVContext * const smk = avctx->priv_data;
uint8_t *out;
uint32_t *pal;
GetBitContext gb;
int blocks, blk, bw, bh;
int i;
int stride;
if(buf_size <= 769)
return 0;
if(smk->pic.data[0])
avctx->release_buffer(avctx, &smk->pic);
smk->pic.reference = 1;
smk->pic.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
if(avctx->reget_buffer(avctx, &smk->pic) < 0){
av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
return -1;
}
/* make the palette available on the way out */
pal = (uint32_t*)smk->pic.data[1];
smk->pic.palette_has_changed = buf[0] & 1;
smk->pic.key_frame = !!(buf[0] & 2);
if(smk->pic.key_frame)
smk->pic.pict_type = FF_I_TYPE;
else
smk->pic.pict_type = FF_P_TYPE;
buf++;
for(i = 0; i < 256; i++)
*pal++ = bytestream_get_be24(&buf);
buf_size -= 769;
last_reset(smk->mmap_tbl, smk->mmap_last);
last_reset(smk->mclr_tbl, smk->mclr_last);
last_reset(smk->full_tbl, smk->full_last);
last_reset(smk->type_tbl, smk->type_last);
init_get_bits(&gb, buf, buf_size * 8);
blk = 0;
bw = avctx->width >> 2;
bh = avctx->height >> 2;
blocks = bw * bh;
out = smk->pic.data[0];
stride = smk->pic.linesize[0];
while(blk < blocks) {
int type, run, mode;
uint16_t pix;
type = smk_get_code(&gb, smk->type_tbl, smk->type_last);
run = block_runs[(type >> 2) & 0x3F];
switch(type & 3){
case SMK_BLK_MONO:
while(run-- && blk < blocks){
int clr, map;
int hi, lo;
clr = smk_get_code(&gb, smk->mclr_tbl, smk->mclr_last);
map = smk_get_code(&gb, smk->mmap_tbl, smk->mmap_last);
out = smk->pic.data[0] + (blk / bw) * (stride * 4) + (blk % bw) * 4;
hi = clr >> 8;
lo = clr & 0xFF;
for(i = 0; i < 4; i++) {
if(map & 1) out[0] = hi; else out[0] = lo;
if(map & 2) out[1] = hi; else out[1] = lo;
if(map & 4) out[2] = hi; else out[2] = lo;
if(map & 8) out[3] = hi; else out[3] = lo;
map >>= 4;
out += stride;
}
blk++;
}
break;
case SMK_BLK_FULL:
mode = 0;
if(avctx->codec_tag == MKTAG('S', 'M', 'K', '4')) { // In case of Smacker v4 we have three modes
if(get_bits1(&gb)) mode = 1;
else if(get_bits1(&gb)) mode = 2;
}
while(run-- && blk < blocks){
out = smk->pic.data[0] + (blk / bw) * (stride * 4) + (blk % bw) * 4;
switch(mode){
case 0:
for(i = 0; i < 4; i++) {
pix = smk_get_code(&gb, smk->full_tbl, smk->full_last);
AV_WL16(out+2,pix);
pix = smk_get_code(&gb, smk->full_tbl, smk->full_last);
AV_WL16(out,pix);
out += stride;
}
break;
case 1:
pix = smk_get_code(&gb, smk->full_tbl, smk->full_last);
out[0] = out[1] = pix & 0xFF;
out[2] = out[3] = pix >> 8;
out += stride;
out[0] = out[1] = pix & 0xFF;
out[2] = out[3] = pix >> 8;
out += stride;
pix = smk_get_code(&gb, smk->full_tbl, smk->full_last);
out[0] = out[1] = pix & 0xFF;
out[2] = out[3] = pix >> 8;
out += stride;
out[0] = out[1] = pix & 0xFF;
out[2] = out[3] = pix >> 8;
out += stride;
break;
case 2:
for(i = 0; i < 2; i++) {
uint16_t pix1, pix2;
pix1 = smk_get_code(&gb, smk->full_tbl, smk->full_last);
pix2 = smk_get_code(&gb, smk->full_tbl, smk->full_last);
AV_WL16(out,pix1);
AV_WL16(out+2,pix2);
out += stride;
AV_WL16(out,pix1);
AV_WL16(out+2,pix2);
out += stride;
}
break;
}
blk++;
}
break;
case SMK_BLK_SKIP:
while(run-- && blk < blocks)
blk++;
break;
case SMK_BLK_FILL:
mode = type >> 8;
while(run-- && blk < blocks){
uint32_t col;
out = smk->pic.data[0] + (blk / bw) * (stride * 4) + (blk % bw) * 4;
col = mode * 0x01010101;
for(i = 0; i < 4; i++) {
*((uint32_t*)out) = col;
out += stride;
}
blk++;
}
break;
}
}
*data_size = sizeof(AVFrame);
*(AVFrame*)data = smk->pic;
/* always report that the buffer was completely consumed */
return buf_size;
}
/*
*
* Init smacker decoder
*
*/
static av_cold int decode_init(AVCodecContext *avctx)
{
SmackVContext * const c = avctx->priv_data;
c->avctx = avctx;
c->pic.data[0] = NULL;
if (avcodec_check_dimensions(avctx, avctx->width, avctx->height) < 0) {
return 1;
}
avctx->pix_fmt = PIX_FMT_PAL8;
/* decode huffman trees from extradata */
if(avctx->extradata_size < 16){
av_log(avctx, AV_LOG_ERROR, "Extradata missing!\n");
return -1;
}
decode_header_trees(c);
return 0;
}
/*
*
* Uninit smacker decoder
*
*/
static av_cold int decode_end(AVCodecContext *avctx)
{
SmackVContext * const smk = avctx->priv_data;
av_freep(&smk->mmap_tbl);
av_freep(&smk->mclr_tbl);
av_freep(&smk->full_tbl);
av_freep(&smk->type_tbl);
if (smk->pic.data[0])
avctx->release_buffer(avctx, &smk->pic);
return 0;
}
static av_cold int smka_decode_init(AVCodecContext *avctx)
{
avctx->sample_fmt = SAMPLE_FMT_S16;
return 0;
}
/**
* Decode Smacker audio data
*/
static int smka_decode_frame(AVCodecContext *avctx, void *data, int *data_size, const uint8_t *buf, int buf_size)
{
GetBitContext gb;
HuffContext h[4];
VLC vlc[4];
int16_t *samples = data;
int val;
int i, res;
int unp_size;
int bits, stereo;
int pred[2] = {0, 0};
unp_size = AV_RL32(buf);
init_get_bits(&gb, buf + 4, (buf_size - 4) * 8);
if(!get_bits1(&gb)){
av_log(avctx, AV_LOG_INFO, "Sound: no data\n");
*data_size = 0;
return 1;
}
stereo = get_bits1(&gb);
bits = get_bits1(&gb);
if (unp_size & 0xC0000000 || (unp_size << !bits) > *data_size) {
av_log(avctx, AV_LOG_ERROR, "Frame is too large to fit in buffer\n");
return -1;
}
memset(vlc, 0, sizeof(VLC) * 4);
memset(h, 0, sizeof(HuffContext) * 4);
// Initialize
for(i = 0; i < (1 << (bits + stereo)); i++) {
h[i].length = 256;
h[i].maxlength = 0;
h[i].current = 0;
h[i].bits = av_mallocz(256 * 4);
h[i].lengths = av_mallocz(256 * sizeof(int));
h[i].values = av_mallocz(256 * sizeof(int));
skip_bits1(&gb);
smacker_decode_tree(&gb, &h[i], 0, 0);
skip_bits1(&gb);
if(h[i].current > 1) {
res = init_vlc(&vlc[i], SMKTREE_BITS, h[i].length,
h[i].lengths, sizeof(int), sizeof(int),
h[i].bits, sizeof(uint32_t), sizeof(uint32_t), INIT_VLC_LE);
if(res < 0) {
av_log(avctx, AV_LOG_ERROR, "Cannot build VLC table\n");
return -1;
}
}
}
if(bits) { //decode 16-bit data
for(i = stereo; i >= 0; i--)
pred[i] = bswap_16(get_bits(&gb, 16));
for(i = 0; i < stereo; i++)
*samples++ = pred[i];
for(i = 0; i < unp_size / 2; i++) {
if(i & stereo) {
if(vlc[2].table)
res = get_vlc2(&gb, vlc[2].table, SMKTREE_BITS, 3);
else
res = 0;
val = h[2].values[res];
if(vlc[3].table)
res = get_vlc2(&gb, vlc[3].table, SMKTREE_BITS, 3);
else
res = 0;
val |= h[3].values[res] << 8;
pred[1] += (int16_t)val;
*samples++ = pred[1];
} else {
if(vlc[0].table)
res = get_vlc2(&gb, vlc[0].table, SMKTREE_BITS, 3);
else
res = 0;
val = h[0].values[res];
if(vlc[1].table)
res = get_vlc2(&gb, vlc[1].table, SMKTREE_BITS, 3);
else
res = 0;
val |= h[1].values[res] << 8;
pred[0] += val;
*samples++ = pred[0];
}
}
} else { //8-bit data
for(i = stereo; i >= 0; i--)
pred[i] = get_bits(&gb, 8);
for(i = 0; i < stereo; i++)
*samples++ = (pred[i] - 0x80) << 8;
for(i = 0; i < unp_size; i++) {
if(i & stereo){
if(vlc[1].table)
res = get_vlc2(&gb, vlc[1].table, SMKTREE_BITS, 3);
else
res = 0;
pred[1] += (int8_t)h[1].values[res];
*samples++ = (pred[1] - 0x80) << 8;
} else {
if(vlc[0].table)
res = get_vlc2(&gb, vlc[0].table, SMKTREE_BITS, 3);
else
res = 0;
pred[0] += (int8_t)h[0].values[res];
*samples++ = (pred[0] - 0x80) << 8;
}
}
unp_size *= 2;
}
for(i = 0; i < 4; i++) {
if(vlc[i].table)
free_vlc(&vlc[i]);
if(h[i].bits)
av_free(h[i].bits);
if(h[i].lengths)
av_free(h[i].lengths);
if(h[i].values)
av_free(h[i].values);
}
*data_size = unp_size;
return buf_size;
}
AVCodec smacker_decoder = {
"smackvid",
CODEC_TYPE_VIDEO,
CODEC_ID_SMACKVIDEO,
sizeof(SmackVContext),
decode_init,
NULL,
decode_end,
decode_frame,
.long_name = NULL_IF_CONFIG_SMALL("Smacker video"),
};
AVCodec smackaud_decoder = {
"smackaud",
CODEC_TYPE_AUDIO,
CODEC_ID_SMACKAUDIO,
0,
smka_decode_init,
NULL,
NULL,
smka_decode_frame,
.long_name = NULL_IF_CONFIG_SMALL("Smacker audio"),
};
@@ -2,20 +2,21 @@
* Quicktime Graphics (SMC) Video Decoder * Quicktime Graphics (SMC) Video Decoder
* Copyright (C) 2003 the ffmpeg project * Copyright (C) 2003 the ffmpeg project
* *
* This library is free software; you can redistribute it and/or * This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This library is distributed in the hope that it will be useful, * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/ */
/** /**
@@ -32,9 +33,7 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include "common.h"
#include "avcodec.h" #include "avcodec.h"
#include "dsputil.h"
#define CPAIR 2 #define CPAIR 2
#define CQUAD 4 #define CQUAD 4
@@ -45,10 +44,9 @@
typedef struct SmcContext { typedef struct SmcContext {
AVCodecContext *avctx; AVCodecContext *avctx;
DSPContext dsp;
AVFrame frame; AVFrame frame;
unsigned char *buf; const unsigned char *buf;
int size; int size;
/* SMC color tables */ /* SMC color tables */
@@ -58,11 +56,6 @@ typedef struct SmcContext {
} SmcContext; } SmcContext;
#define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1])
#define BE_32(x) ((((uint8_t*)(x))[0] << 24) | \
(((uint8_t*)(x))[1] << 16) | \
(((uint8_t*)(x))[2] << 8) | \
((uint8_t*)(x))[3])
#define GET_BLOCK_COUNT() \ #define GET_BLOCK_COUNT() \
(opcode & 0x10) ? (1 + s->buf[stream_ptr++]) : 1 + (opcode & 0x0F); (opcode & 0x10) ? (1 + s->buf[stream_ptr++]) : 1 + (opcode & 0x0F);
@@ -77,7 +70,7 @@ typedef struct SmcContext {
total_blocks--; \ total_blocks--; \
if (total_blocks < 0) \ if (total_blocks < 0) \
{ \ { \
printf("warning: block counter just went negative (this should not happen)\n"); \ av_log(s->avctx, AV_LOG_INFO, "warning: block counter just went negative (this should not happen)\n"); \
return; \ return; \
} \ } \
} }
@@ -123,27 +116,27 @@ static void smc_decode_stream(SmcContext *s)
s->avctx->palctrl->palette_changed = 0; s->avctx->palctrl->palette_changed = 0;
} }
chunk_size = BE_32(&s->buf[stream_ptr]) & 0x00FFFFFF; chunk_size = AV_RB32(&s->buf[stream_ptr]) & 0x00FFFFFF;
stream_ptr += 4; stream_ptr += 4;
if (chunk_size != s->size) if (chunk_size != s->size)
printf("warning: MOV chunk size != encoded chunk size (%d != %d); using MOV chunk size\n", av_log(s->avctx, AV_LOG_INFO, "warning: MOV chunk size != encoded chunk size (%d != %d); using MOV chunk size\n",
chunk_size, s->size); chunk_size, s->size);
chunk_size = s->size; chunk_size = s->size;
total_blocks = (s->avctx->width * s->avctx->height) / (4 * 4); total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4);
/* traverse through the blocks */ /* traverse through the blocks */
while (total_blocks) { while (total_blocks) {
/* sanity checks */ /* sanity checks */
/* make sure stream ptr hasn't gone out of bounds */ /* make sure stream ptr hasn't gone out of bounds */
if (stream_ptr > chunk_size) { if (stream_ptr > chunk_size) {
printf("SMC decoder just went out of bounds (stream ptr = %d, chunk size = %d)\n", av_log(s->avctx, AV_LOG_INFO, "SMC decoder just went out of bounds (stream ptr = %d, chunk size = %d)\n",
stream_ptr, chunk_size); stream_ptr, chunk_size);
return; return;
} }
/* make sure the row pointer hasn't gone wild */ /* make sure the row pointer hasn't gone wild */
if (row_ptr >= image_size) { if (row_ptr >= image_size) {
printf("SMC decoder just went out of bounds (row ptr = %d, height = %d)\n", av_log(s->avctx, AV_LOG_INFO, "SMC decoder just went out of bounds (row ptr = %d, height = %d)\n",
row_ptr, image_size); row_ptr, image_size);
return; return;
} }
@@ -166,7 +159,7 @@ static void smc_decode_stream(SmcContext *s)
/* sanity check */ /* sanity check */
if ((row_ptr == 0) && (pixel_ptr == 0)) { if ((row_ptr == 0) && (pixel_ptr == 0)) {
printf("encountered repeat block opcode (%02X) but no blocks rendered yet\n", av_log(s->avctx, AV_LOG_INFO, "encountered repeat block opcode (%02X) but no blocks rendered yet\n",
opcode & 0xF0); opcode & 0xF0);
break; break;
} }
@@ -200,7 +193,7 @@ static void smc_decode_stream(SmcContext *s)
/* sanity check */ /* sanity check */
if ((row_ptr == 0) && (pixel_ptr < 2 * 4)) { if ((row_ptr == 0) && (pixel_ptr < 2 * 4)) {
printf("encountered repeat block opcode (%02X) but not enough blocks rendered yet\n", av_log(s->avctx, AV_LOG_INFO, "encountered repeat block opcode (%02X) but not enough blocks rendered yet\n",
opcode & 0xF0); opcode & 0xF0);
break; break;
} }
@@ -281,7 +274,7 @@ static void smc_decode_stream(SmcContext *s)
color_table_index = CPAIR * s->buf[stream_ptr++]; color_table_index = CPAIR * s->buf[stream_ptr++];
while (n_blocks--) { while (n_blocks--) {
color_flags = BE_16(&s->buf[stream_ptr]); color_flags = AV_RB16(&s->buf[stream_ptr]);
stream_ptr += 2; stream_ptr += 2;
flag_mask = 0x8000; flag_mask = 0x8000;
block_ptr = row_ptr + pixel_ptr; block_ptr = row_ptr + pixel_ptr;
@@ -324,7 +317,7 @@ static void smc_decode_stream(SmcContext *s)
color_table_index = CQUAD * s->buf[stream_ptr++]; color_table_index = CQUAD * s->buf[stream_ptr++];
while (n_blocks--) { while (n_blocks--) {
color_flags = BE_32(&s->buf[stream_ptr]); color_flags = AV_RB32(&s->buf[stream_ptr]);
stream_ptr += 4; stream_ptr += 4;
/* flag mask actually acts as a bit shift count here */ /* flag mask actually acts as a bit shift count here */
flag_mask = 30; flag_mask = 30;
@@ -427,20 +420,18 @@ static void smc_decode_stream(SmcContext *s)
break; break;
case 0xF0: case 0xF0:
printf("0xF0 opcode seen in SMC chunk (xine developers would like to know)\n"); av_log(s->avctx, AV_LOG_INFO, "0xF0 opcode seen in SMC chunk (contact the developers)\n");
break; break;
} }
} }
} }
static int smc_decode_init(AVCodecContext *avctx) static av_cold int smc_decode_init(AVCodecContext *avctx)
{ {
SmcContext *s = (SmcContext *)avctx->priv_data; SmcContext *s = avctx->priv_data;
s->avctx = avctx; s->avctx = avctx;
avctx->pix_fmt = PIX_FMT_PAL8; avctx->pix_fmt = PIX_FMT_PAL8;
avctx->has_b_frames = 0;
dsputil_init(&s->dsp, avctx);
s->frame.data[0] = NULL; s->frame.data[0] = NULL;
@@ -449,13 +440,9 @@ static int smc_decode_init(AVCodecContext *avctx)
static int smc_decode_frame(AVCodecContext *avctx, static int smc_decode_frame(AVCodecContext *avctx,
void *data, int *data_size, void *data, int *data_size,
uint8_t *buf, int buf_size) const uint8_t *buf, int buf_size)
{ {
SmcContext *s = (SmcContext *)avctx->priv_data; SmcContext *s = avctx->priv_data;
/* no supplementary picture */
if (buf_size == 0)
return 0;
s->buf = buf; s->buf = buf;
s->size = buf_size; s->size = buf_size;
@@ -464,7 +451,7 @@ static int smc_decode_frame(AVCodecContext *avctx,
s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE |
FF_BUFFER_HINTS_REUSABLE | FF_BUFFER_HINTS_READABLE; FF_BUFFER_HINTS_REUSABLE | FF_BUFFER_HINTS_READABLE;
if (avctx->reget_buffer(avctx, &s->frame)) { if (avctx->reget_buffer(avctx, &s->frame)) {
printf ("reget_buffer() failed\n"); av_log(s->avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
return -1; return -1;
} }
@@ -477,9 +464,9 @@ static int smc_decode_frame(AVCodecContext *avctx,
return buf_size; return buf_size;
} }
static int smc_decode_end(AVCodecContext *avctx) static av_cold int smc_decode_end(AVCodecContext *avctx)
{ {
SmcContext *s = (SmcContext *)avctx->priv_data; SmcContext *s = avctx->priv_data;
if (s->frame.data[0]) if (s->frame.data[0])
avctx->release_buffer(avctx, &s->frame); avctx->release_buffer(avctx, &s->frame);
@@ -497,4 +484,5 @@ AVCodec smc_decoder = {
smc_decode_end, smc_decode_end,
smc_decode_frame, smc_decode_frame,
CODEC_CAP_DR1, CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("QuickTime Graphics (SMC)"),
}; };
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,174 @@
/*
* Copyright (C) 2004 Michael Niedermayer <michaelni@gmx.at>
* Copyright (C) 2006 Robert Edele <yartrebo@earthlink.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
*/
#ifndef FFMPEG_SNOW_H
#define FFMPEG_SNOW_H
#include "dsputil.h"
#define MID_STATE 128
#define MAX_DECOMPOSITIONS 8
#define MAX_PLANES 4
#define QSHIFT 5
#define QROOT (1<<QSHIFT)
#define LOSSLESS_QLOG -128
#define FRAC_BITS 4
#define MAX_REF_FRAMES 8
#define LOG2_OBMC_MAX 8
#define OBMC_MAX (1<<(LOG2_OBMC_MAX))
#define DWT_97 0
#define DWT_53 1
/** Used to minimize the amount of memory used in order to optimize cache performance. **/
struct slice_buffer_s {
IDWTELEM * * line; ///< For use by idwt and predict_slices.
IDWTELEM * * data_stack; ///< Used for internal purposes.
int data_stack_top;
int line_count;
int line_width;
int data_count;
IDWTELEM * base_buffer; ///< Buffer that this structure is caching.
};
#define liftS lift
#if 1
#define W_AM 3
#define W_AO 0
#define W_AS 1
#undef liftS
#define W_BM 1
#define W_BO 8
#define W_BS 4
#define W_CM 1
#define W_CO 0
#define W_CS 0
#define W_DM 3
#define W_DO 4
#define W_DS 3
#elif 0
#define W_AM 55
#define W_AO 16
#define W_AS 5
#define W_BM 3
#define W_BO 32
#define W_BS 6
#define W_CM 127
#define W_CO 64
#define W_CS 7
#define W_DM 7
#define W_DO 8
#define W_DS 4
#elif 0
#define W_AM 97
#define W_AO 32
#define W_AS 6
#define W_BM 63
#define W_BO 512
#define W_BS 10
#define W_CM 13
#define W_CO 8
#define W_CS 4
#define W_DM 15
#define W_DO 16
#define W_DS 5
#else
#define W_AM 203
#define W_AO 64
#define W_AS 7
#define W_BM 217
#define W_BO 2048
#define W_BS 12
#define W_CM 113
#define W_CO 64
#define W_CS 7
#define W_DM 227
#define W_DO 128
#define W_DS 9
#endif
extern void ff_snow_vertical_compose97i(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, IDWTELEM *b3, IDWTELEM *b4, IDWTELEM *b5, int width);
extern void ff_snow_horizontal_compose97i(IDWTELEM *b, int width);
extern void ff_snow_inner_add_yblock(const uint8_t *obmc, const int obmc_stride, uint8_t * * block, int b_w, int b_h, int src_x, int src_y, int src_stride, slice_buffer * sb, int add, uint8_t * dst8);
#ifdef CONFIG_SNOW_ENCODER
int w53_32_c(void *v, uint8_t * pix1, uint8_t * pix2, int line_size, int h);
int w97_32_c(void *v, uint8_t * pix1, uint8_t * pix2, int line_size, int h);
#else
static int w53_32_c(void *v, uint8_t * pix1, uint8_t * pix2, int line_size, int h) {assert (0);}
static int w97_32_c(void *v, uint8_t * pix1, uint8_t * pix2, int line_size, int h) {assert (0);}
#endif
/* C bits used by mmx/sse2/altivec */
static av_always_inline void snow_interleave_line_header(int * i, int width, IDWTELEM * low, IDWTELEM * high){
(*i) = (width) - 2;
if (width & 1){
low[(*i)+1] = low[((*i)+1)>>1];
(*i)--;
}
}
static av_always_inline void snow_interleave_line_footer(int * i, IDWTELEM * low, IDWTELEM * high){
for (; (*i)>=0; (*i)-=2){
low[(*i)+1] = high[(*i)>>1];
low[*i] = low[(*i)>>1];
}
}
static av_always_inline void snow_horizontal_compose_lift_lead_out(int i, IDWTELEM * dst, IDWTELEM * src, IDWTELEM * ref, int width, int w, int lift_high, int mul, int add, int shift){
for(; i<w; i++){
dst[i] = src[i] - ((mul * (ref[i] + ref[i + 1]) + add) >> shift);
}
if((width^lift_high)&1){
dst[w] = src[w] - ((mul * 2 * ref[w] + add) >> shift);
}
}
static av_always_inline void snow_horizontal_compose_liftS_lead_out(int i, IDWTELEM * dst, IDWTELEM * src, IDWTELEM * ref, int width, int w){
for(; i<w; i++){
dst[i] = src[i] + ((ref[i] + ref[(i+1)]+W_BO + 4 * src[i]) >> W_BS);
}
if(width&1){
dst[w] = src[w] + ((2 * ref[w] + W_BO + 4 * src[w]) >> W_BS);
}
}
#endif /* FFMPEG_SNOW_H */
@@ -0,0 +1,978 @@
/*
* Simple free lossless/lossy audio codec
* Copyright (c) 2004 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
*/
#include "avcodec.h"
#include "bitstream.h"
#include "golomb.h"
/**
* @file sonic.c
* Simple free lossless/lossy audio codec
* Based on Paul Francis Harrison's Bonk (http://www.logarithmic.net/pfh/bonk)
* Written and designed by Alex Beregszaszi
*
* TODO:
* - CABAC put/get_symbol
* - independent quantizer for channels
* - >2 channels support
* - more decorrelation types
* - more tap_quant tests
* - selectable intlist writers/readers (bonk-style, golomb, cabac)
*/
#define MAX_CHANNELS 2
#define MID_SIDE 0
#define LEFT_SIDE 1
#define RIGHT_SIDE 2
typedef struct SonicContext {
int lossless, decorrelation;
int num_taps, downsampling;
double quantization;
int channels, samplerate, block_align, frame_size;
int *tap_quant;
int *int_samples;
int *coded_samples[MAX_CHANNELS];
// for encoding
int *tail;
int tail_size;
int *window;
int window_size;
// for decoding
int *predictor_k;
int *predictor_state[MAX_CHANNELS];
} SonicContext;
#define LATTICE_SHIFT 10
#define SAMPLE_SHIFT 4
#define LATTICE_FACTOR (1 << LATTICE_SHIFT)
#define SAMPLE_FACTOR (1 << SAMPLE_SHIFT)
#define BASE_QUANT 0.6
#define RATE_VARIATION 3.0
static inline int divide(int a, int b)
{
if (a < 0)
return -( (-a + b/2)/b );
else
return (a + b/2)/b;
}
static inline int shift(int a,int b)
{
return (a+(1<<(b-1))) >> b;
}
static inline int shift_down(int a,int b)
{
return (a>>b)+((a<0)?1:0);
}
#if 1
static inline int intlist_write(PutBitContext *pb, int *buf, int entries, int base_2_part)
{
int i;
for (i = 0; i < entries; i++)
set_se_golomb(pb, buf[i]);
return 1;
}
static inline int intlist_read(GetBitContext *gb, int *buf, int entries, int base_2_part)
{
int i;
for (i = 0; i < entries; i++)
buf[i] = get_se_golomb(gb);
return 1;
}
#else
#define ADAPT_LEVEL 8
static int bits_to_store(uint64_t x)
{
int res = 0;
while(x)
{
res++;
x >>= 1;
}
return res;
}
static void write_uint_max(PutBitContext *pb, unsigned int value, unsigned int max)
{
int i, bits;
if (!max)
return;
bits = bits_to_store(max);
for (i = 0; i < bits-1; i++)
put_bits(pb, 1, value & (1 << i));
if ( (value | (1 << (bits-1))) <= max)
put_bits(pb, 1, value & (1 << (bits-1)));
}
static unsigned int read_uint_max(GetBitContext *gb, int max)
{
int i, bits, value = 0;
if (!max)
return 0;
bits = bits_to_store(max);
for (i = 0; i < bits-1; i++)
if (get_bits1(gb))
value += 1 << i;
if ( (value | (1<<(bits-1))) <= max)
if (get_bits1(gb))
value += 1 << (bits-1);
return value;
}
static int intlist_write(PutBitContext *pb, int *buf, int entries, int base_2_part)
{
int i, j, x = 0, low_bits = 0, max = 0;
int step = 256, pos = 0, dominant = 0, any = 0;
int *copy, *bits;
copy = av_mallocz(4* entries);
if (!copy)
return -1;
if (base_2_part)
{
int energy = 0;
for (i = 0; i < entries; i++)
energy += abs(buf[i]);
low_bits = bits_to_store(energy / (entries * 2));
if (low_bits > 15)
low_bits = 15;
put_bits(pb, 4, low_bits);
}
for (i = 0; i < entries; i++)
{
put_bits(pb, low_bits, abs(buf[i]));
copy[i] = abs(buf[i]) >> low_bits;
if (copy[i] > max)
max = abs(copy[i]);
}
bits = av_mallocz(4* entries*max);
if (!bits)
{
// av_free(copy);
return -1;
}
for (i = 0; i <= max; i++)
{
for (j = 0; j < entries; j++)
if (copy[j] >= i)
bits[x++] = copy[j] > i;
}
// store bitstream
while (pos < x)
{
int steplet = step >> 8;
if (pos + steplet > x)
steplet = x - pos;
for (i = 0; i < steplet; i++)
if (bits[i+pos] != dominant)
any = 1;
put_bits(pb, 1, any);
if (!any)
{
pos += steplet;
step += step / ADAPT_LEVEL;
}
else
{
int interloper = 0;
while (((pos + interloper) < x) && (bits[pos + interloper] == dominant))
interloper++;
// note change
write_uint_max(pb, interloper, (step >> 8) - 1);
pos += interloper + 1;
step -= step / ADAPT_LEVEL;
}
if (step < 256)
{
step = 65536 / step;
dominant = !dominant;
}
}
// store signs
for (i = 0; i < entries; i++)
if (buf[i])
put_bits(pb, 1, buf[i] < 0);
// av_free(bits);
// av_free(copy);
return 0;
}
static int intlist_read(GetBitContext *gb, int *buf, int entries, int base_2_part)
{
int i, low_bits = 0, x = 0;
int n_zeros = 0, step = 256, dominant = 0;
int pos = 0, level = 0;
int *bits = av_mallocz(4* entries);
if (!bits)
return -1;
if (base_2_part)
{
low_bits = get_bits(gb, 4);
if (low_bits)
for (i = 0; i < entries; i++)
buf[i] = get_bits(gb, low_bits);
}
// av_log(NULL, AV_LOG_INFO, "entries: %d, low bits: %d\n", entries, low_bits);
while (n_zeros < entries)
{
int steplet = step >> 8;
if (!get_bits1(gb))
{
for (i = 0; i < steplet; i++)
bits[x++] = dominant;
if (!dominant)
n_zeros += steplet;
step += step / ADAPT_LEVEL;
}
else
{
int actual_run = read_uint_max(gb, steplet-1);
// av_log(NULL, AV_LOG_INFO, "actual run: %d\n", actual_run);
for (i = 0; i < actual_run; i++)
bits[x++] = dominant;
bits[x++] = !dominant;
if (!dominant)
n_zeros += actual_run;
else
n_zeros++;
step -= step / ADAPT_LEVEL;
}
if (step < 256)
{
step = 65536 / step;
dominant = !dominant;
}
}
// reconstruct unsigned values
n_zeros = 0;
for (i = 0; n_zeros < entries; i++)
{
while(1)
{
if (pos >= entries)
{
pos = 0;
level += 1 << low_bits;
}
if (buf[pos] >= level)
break;
pos++;
}
if (bits[i])
buf[pos] += 1 << low_bits;
else
n_zeros++;
pos++;
}
// av_free(bits);
// read signs
for (i = 0; i < entries; i++)
if (buf[i] && get_bits1(gb))
buf[i] = -buf[i];
// av_log(NULL, AV_LOG_INFO, "zeros: %d pos: %d\n", n_zeros, pos);
return 0;
}
#endif
static void predictor_init_state(int *k, int *state, int order)
{
int i;
for (i = order-2; i >= 0; i--)
{
int j, p, x = state[i];
for (j = 0, p = i+1; p < order; j++,p++)
{
int tmp = x + shift_down(k[j] * state[p], LATTICE_SHIFT);
state[p] += shift_down(k[j]*x, LATTICE_SHIFT);
x = tmp;
}
}
}
static int predictor_calc_error(int *k, int *state, int order, int error)
{
int i, x = error - shift_down(k[order-1] * state[order-1], LATTICE_SHIFT);
#if 1
int *k_ptr = &(k[order-2]),
*state_ptr = &(state[order-2]);
for (i = order-2; i >= 0; i--, k_ptr--, state_ptr--)
{
int k_value = *k_ptr, state_value = *state_ptr;
x -= shift_down(k_value * state_value, LATTICE_SHIFT);
state_ptr[1] = state_value + shift_down(k_value * x, LATTICE_SHIFT);
}
#else
for (i = order-2; i >= 0; i--)
{
x -= shift_down(k[i] * state[i], LATTICE_SHIFT);
state[i+1] = state[i] + shift_down(k[i] * x, LATTICE_SHIFT);
}
#endif
// don't drift too far, to avoid overflows
if (x > (SAMPLE_FACTOR<<16)) x = (SAMPLE_FACTOR<<16);
if (x < -(SAMPLE_FACTOR<<16)) x = -(SAMPLE_FACTOR<<16);
state[0] = x;
return x;
}
#ifdef CONFIG_ENCODERS
// Heavily modified Levinson-Durbin algorithm which
// copes better with quantization, and calculates the
// actual whitened result as it goes.
static void modified_levinson_durbin(int *window, int window_entries,
int *out, int out_entries, int channels, int *tap_quant)
{
int i;
int *state = av_mallocz(4* window_entries);
memcpy(state, window, 4* window_entries);
for (i = 0; i < out_entries; i++)
{
int step = (i+1)*channels, k, j;
double xx = 0.0, xy = 0.0;
#if 1
int *x_ptr = &(window[step]), *state_ptr = &(state[0]);
j = window_entries - step;
for (;j>=0;j--,x_ptr++,state_ptr++)
{
double x_value = *x_ptr, state_value = *state_ptr;
xx += state_value*state_value;
xy += x_value*state_value;
}
#else
for (j = 0; j <= (window_entries - step); j++);
{
double stepval = window[step+j], stateval = window[j];
// xx += (double)window[j]*(double)window[j];
// xy += (double)window[step+j]*(double)window[j];
xx += stateval*stateval;
xy += stepval*stateval;
}
#endif
if (xx == 0.0)
k = 0;
else
k = (int)(floor(-xy/xx * (double)LATTICE_FACTOR / (double)(tap_quant[i]) + 0.5));
if (k > (LATTICE_FACTOR/tap_quant[i]))
k = LATTICE_FACTOR/tap_quant[i];
if (-k > (LATTICE_FACTOR/tap_quant[i]))
k = -(LATTICE_FACTOR/tap_quant[i]);
out[i] = k;
k *= tap_quant[i];
#if 1
x_ptr = &(window[step]);
state_ptr = &(state[0]);
j = window_entries - step;
for (;j>=0;j--,x_ptr++,state_ptr++)
{
int x_value = *x_ptr, state_value = *state_ptr;
*x_ptr = x_value + shift_down(k*state_value,LATTICE_SHIFT);
*state_ptr = state_value + shift_down(k*x_value, LATTICE_SHIFT);
}
#else
for (j=0; j <= (window_entries - step); j++)
{
int stepval = window[step+j], stateval=state[j];
window[step+j] += shift_down(k * stateval, LATTICE_SHIFT);
state[j] += shift_down(k * stepval, LATTICE_SHIFT);
}
#endif
}
av_free(state);
}
#endif /* CONFIG_ENCODERS */
static const int samplerate_table[] =
{ 44100, 22050, 11025, 96000, 48000, 32000, 24000, 16000, 8000 };
#ifdef CONFIG_ENCODERS
static inline int code_samplerate(int samplerate)
{
switch (samplerate)
{
case 44100: return 0;
case 22050: return 1;
case 11025: return 2;
case 96000: return 3;
case 48000: return 4;
case 32000: return 5;
case 24000: return 6;
case 16000: return 7;
case 8000: return 8;
}
return -1;
}
static av_cold int sonic_encode_init(AVCodecContext *avctx)
{
SonicContext *s = avctx->priv_data;
PutBitContext pb;
int i, version = 0;
if (avctx->channels > MAX_CHANNELS)
{
av_log(avctx, AV_LOG_ERROR, "Only mono and stereo streams are supported by now\n");
return -1; /* only stereo or mono for now */
}
if (avctx->channels == 2)
s->decorrelation = MID_SIDE;
if (avctx->codec->id == CODEC_ID_SONIC_LS)
{
s->lossless = 1;
s->num_taps = 32;
s->downsampling = 1;
s->quantization = 0.0;
}
else
{
s->num_taps = 128;
s->downsampling = 2;
s->quantization = 1.0;
}
// max tap 2048
if ((s->num_taps < 32) || (s->num_taps > 1024) ||
((s->num_taps>>5)<<5 != s->num_taps))
{
av_log(avctx, AV_LOG_ERROR, "Invalid number of taps\n");
return -1;
}
// generate taps
s->tap_quant = av_mallocz(4* s->num_taps);
for (i = 0; i < s->num_taps; i++)
s->tap_quant[i] = (int)(sqrt(i+1));
s->channels = avctx->channels;
s->samplerate = avctx->sample_rate;
s->block_align = (int)(2048.0*s->samplerate/44100)/s->downsampling;
s->frame_size = s->channels*s->block_align*s->downsampling;
s->tail = av_mallocz(4* s->num_taps*s->channels);
if (!s->tail)
return -1;
s->tail_size = s->num_taps*s->channels;
s->predictor_k = av_mallocz(4 * s->num_taps);
if (!s->predictor_k)
return -1;
for (i = 0; i < s->channels; i++)
{
s->coded_samples[i] = av_mallocz(4* s->block_align);
if (!s->coded_samples[i])
return -1;
}
s->int_samples = av_mallocz(4* s->frame_size);
s->window_size = ((2*s->tail_size)+s->frame_size);
s->window = av_mallocz(4* s->window_size);
if (!s->window)
return -1;
avctx->extradata = av_mallocz(16);
if (!avctx->extradata)
return -1;
init_put_bits(&pb, avctx->extradata, 16*8);
put_bits(&pb, 2, version); // version
if (version == 1)
{
put_bits(&pb, 2, s->channels);
put_bits(&pb, 4, code_samplerate(s->samplerate));
}
put_bits(&pb, 1, s->lossless);
if (!s->lossless)
put_bits(&pb, 3, SAMPLE_SHIFT); // XXX FIXME: sample precision
put_bits(&pb, 2, s->decorrelation);
put_bits(&pb, 2, s->downsampling);
put_bits(&pb, 5, (s->num_taps >> 5)-1); // 32..1024
put_bits(&pb, 1, 0); // XXX FIXME: no custom tap quant table
flush_put_bits(&pb);
avctx->extradata_size = put_bits_count(&pb)/8;
av_log(avctx, AV_LOG_INFO, "Sonic: ver: %d ls: %d dr: %d taps: %d block: %d frame: %d downsamp: %d\n",
version, s->lossless, s->decorrelation, s->num_taps, s->block_align, s->frame_size, s->downsampling);
avctx->coded_frame = avcodec_alloc_frame();
if (!avctx->coded_frame)
return AVERROR(ENOMEM);
avctx->coded_frame->key_frame = 1;
avctx->frame_size = s->block_align*s->downsampling;
return 0;
}
static av_cold int sonic_encode_close(AVCodecContext *avctx)
{
SonicContext *s = avctx->priv_data;
int i;
av_freep(&avctx->coded_frame);
for (i = 0; i < s->channels; i++)
av_free(s->coded_samples[i]);
av_free(s->predictor_k);
av_free(s->tail);
av_free(s->tap_quant);
av_free(s->window);
av_free(s->int_samples);
return 0;
}
static int sonic_encode_frame(AVCodecContext *avctx,
uint8_t *buf, int buf_size, void *data)
{
SonicContext *s = avctx->priv_data;
PutBitContext pb;
int i, j, ch, quant = 0, x = 0;
short *samples = data;
init_put_bits(&pb, buf, buf_size*8);
// short -> internal
for (i = 0; i < s->frame_size; i++)
s->int_samples[i] = samples[i];
if (!s->lossless)
for (i = 0; i < s->frame_size; i++)
s->int_samples[i] = s->int_samples[i] << SAMPLE_SHIFT;
switch(s->decorrelation)
{
case MID_SIDE:
for (i = 0; i < s->frame_size; i += s->channels)
{
s->int_samples[i] += s->int_samples[i+1];
s->int_samples[i+1] -= shift(s->int_samples[i], 1);
}
break;
case LEFT_SIDE:
for (i = 0; i < s->frame_size; i += s->channels)
s->int_samples[i+1] -= s->int_samples[i];
break;
case RIGHT_SIDE:
for (i = 0; i < s->frame_size; i += s->channels)
s->int_samples[i] -= s->int_samples[i+1];
break;
}
memset(s->window, 0, 4* s->window_size);
for (i = 0; i < s->tail_size; i++)
s->window[x++] = s->tail[i];
for (i = 0; i < s->frame_size; i++)
s->window[x++] = s->int_samples[i];
for (i = 0; i < s->tail_size; i++)
s->window[x++] = 0;
for (i = 0; i < s->tail_size; i++)
s->tail[i] = s->int_samples[s->frame_size - s->tail_size + i];
// generate taps
modified_levinson_durbin(s->window, s->window_size,
s->predictor_k, s->num_taps, s->channels, s->tap_quant);
if (intlist_write(&pb, s->predictor_k, s->num_taps, 0) < 0)
return -1;
for (ch = 0; ch < s->channels; ch++)
{
x = s->tail_size+ch;
for (i = 0; i < s->block_align; i++)
{
int sum = 0;
for (j = 0; j < s->downsampling; j++, x += s->channels)
sum += s->window[x];
s->coded_samples[ch][i] = sum;
}
}
// simple rate control code
if (!s->lossless)
{
double energy1 = 0.0, energy2 = 0.0;
for (ch = 0; ch < s->channels; ch++)
{
for (i = 0; i < s->block_align; i++)
{
double sample = s->coded_samples[ch][i];
energy2 += sample*sample;
energy1 += fabs(sample);
}
}
energy2 = sqrt(energy2/(s->channels*s->block_align));
energy1 = sqrt(2.0)*energy1/(s->channels*s->block_align);
// increase bitrate when samples are like a gaussian distribution
// reduce bitrate when samples are like a two-tailed exponential distribution
if (energy2 > energy1)
energy2 += (energy2-energy1)*RATE_VARIATION;
quant = (int)(BASE_QUANT*s->quantization*energy2/SAMPLE_FACTOR);
// av_log(avctx, AV_LOG_DEBUG, "quant: %d energy: %f / %f\n", quant, energy1, energy2);
if (quant < 1)
quant = 1;
if (quant > 65535)
quant = 65535;
set_ue_golomb(&pb, quant);
quant *= SAMPLE_FACTOR;
}
// write out coded samples
for (ch = 0; ch < s->channels; ch++)
{
if (!s->lossless)
for (i = 0; i < s->block_align; i++)
s->coded_samples[ch][i] = divide(s->coded_samples[ch][i], quant);
if (intlist_write(&pb, s->coded_samples[ch], s->block_align, 1) < 0)
return -1;
}
// av_log(avctx, AV_LOG_DEBUG, "used bytes: %d\n", (put_bits_count(&pb)+7)/8);
flush_put_bits(&pb);
return (put_bits_count(&pb)+7)/8;
}
#endif //CONFIG_ENCODERS
#ifdef CONFIG_DECODERS
static av_cold int sonic_decode_init(AVCodecContext *avctx)
{
SonicContext *s = avctx->priv_data;
GetBitContext gb;
int i, version;
s->channels = avctx->channels;
s->samplerate = avctx->sample_rate;
if (!avctx->extradata)
{
av_log(avctx, AV_LOG_ERROR, "No mandatory headers present\n");
return -1;
}
init_get_bits(&gb, avctx->extradata, avctx->extradata_size);
version = get_bits(&gb, 2);
if (version > 1)
{
av_log(avctx, AV_LOG_ERROR, "Unsupported Sonic version, please report\n");
return -1;
}
if (version == 1)
{
s->channels = get_bits(&gb, 2);
s->samplerate = samplerate_table[get_bits(&gb, 4)];
av_log(avctx, AV_LOG_INFO, "Sonicv2 chans: %d samprate: %d\n",
s->channels, s->samplerate);
}
if (s->channels > MAX_CHANNELS)
{
av_log(avctx, AV_LOG_ERROR, "Only mono and stereo streams are supported by now\n");
return -1;
}
s->lossless = get_bits1(&gb);
if (!s->lossless)
skip_bits(&gb, 3); // XXX FIXME
s->decorrelation = get_bits(&gb, 2);
s->downsampling = get_bits(&gb, 2);
s->num_taps = (get_bits(&gb, 5)+1)<<5;
if (get_bits1(&gb)) // XXX FIXME
av_log(avctx, AV_LOG_INFO, "Custom quant table\n");
s->block_align = (int)(2048.0*(s->samplerate/44100))/s->downsampling;
s->frame_size = s->channels*s->block_align*s->downsampling;
// avctx->frame_size = s->block_align;
av_log(avctx, AV_LOG_INFO, "Sonic: ver: %d ls: %d dr: %d taps: %d block: %d frame: %d downsamp: %d\n",
version, s->lossless, s->decorrelation, s->num_taps, s->block_align, s->frame_size, s->downsampling);
// generate taps
s->tap_quant = av_mallocz(4* s->num_taps);
for (i = 0; i < s->num_taps; i++)
s->tap_quant[i] = (int)(sqrt(i+1));
s->predictor_k = av_mallocz(4* s->num_taps);
for (i = 0; i < s->channels; i++)
{
s->predictor_state[i] = av_mallocz(4* s->num_taps);
if (!s->predictor_state[i])
return -1;
}
for (i = 0; i < s->channels; i++)
{
s->coded_samples[i] = av_mallocz(4* s->block_align);
if (!s->coded_samples[i])
return -1;
}
s->int_samples = av_mallocz(4* s->frame_size);
avctx->sample_fmt = SAMPLE_FMT_S16;
return 0;
}
static av_cold int sonic_decode_close(AVCodecContext *avctx)
{
SonicContext *s = avctx->priv_data;
int i;
av_free(s->int_samples);
av_free(s->tap_quant);
av_free(s->predictor_k);
for (i = 0; i < s->channels; i++)
{
av_free(s->predictor_state[i]);
av_free(s->coded_samples[i]);
}
return 0;
}
static int sonic_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
const uint8_t *buf, int buf_size)
{
SonicContext *s = avctx->priv_data;
GetBitContext gb;
int i, quant, ch, j;
short *samples = data;
if (buf_size == 0) return 0;
// av_log(NULL, AV_LOG_INFO, "buf_size: %d\n", buf_size);
init_get_bits(&gb, buf, buf_size*8);
intlist_read(&gb, s->predictor_k, s->num_taps, 0);
// dequantize
for (i = 0; i < s->num_taps; i++)
s->predictor_k[i] *= s->tap_quant[i];
if (s->lossless)
quant = 1;
else
quant = get_ue_golomb(&gb) * SAMPLE_FACTOR;
// av_log(NULL, AV_LOG_INFO, "quant: %d\n", quant);
for (ch = 0; ch < s->channels; ch++)
{
int x = ch;
predictor_init_state(s->predictor_k, s->predictor_state[ch], s->num_taps);
intlist_read(&gb, s->coded_samples[ch], s->block_align, 1);
for (i = 0; i < s->block_align; i++)
{
for (j = 0; j < s->downsampling - 1; j++)
{
s->int_samples[x] = predictor_calc_error(s->predictor_k, s->predictor_state[ch], s->num_taps, 0);
x += s->channels;
}
s->int_samples[x] = predictor_calc_error(s->predictor_k, s->predictor_state[ch], s->num_taps, s->coded_samples[ch][i] * quant);
x += s->channels;
}
for (i = 0; i < s->num_taps; i++)
s->predictor_state[ch][i] = s->int_samples[s->frame_size - s->channels + ch - i*s->channels];
}
switch(s->decorrelation)
{
case MID_SIDE:
for (i = 0; i < s->frame_size; i += s->channels)
{
s->int_samples[i+1] += shift(s->int_samples[i], 1);
s->int_samples[i] -= s->int_samples[i+1];
}
break;
case LEFT_SIDE:
for (i = 0; i < s->frame_size; i += s->channels)
s->int_samples[i+1] += s->int_samples[i];
break;
case RIGHT_SIDE:
for (i = 0; i < s->frame_size; i += s->channels)
s->int_samples[i] += s->int_samples[i+1];
break;
}
if (!s->lossless)
for (i = 0; i < s->frame_size; i++)
s->int_samples[i] = shift(s->int_samples[i], SAMPLE_SHIFT);
// internal -> short
for (i = 0; i < s->frame_size; i++)
samples[i] = av_clip_int16(s->int_samples[i]);
align_get_bits(&gb);
*data_size = s->frame_size * 2;
return (get_bits_count(&gb)+7)/8;
}
#endif
#ifdef CONFIG_ENCODERS
AVCodec sonic_encoder = {
"sonic",
CODEC_TYPE_AUDIO,
CODEC_ID_SONIC,
sizeof(SonicContext),
sonic_encode_init,
sonic_encode_frame,
sonic_encode_close,
NULL,
.long_name = NULL_IF_CONFIG_SMALL("Sonic"),
};
AVCodec sonic_ls_encoder = {
"sonicls",
CODEC_TYPE_AUDIO,
CODEC_ID_SONIC_LS,
sizeof(SonicContext),
sonic_encode_init,
sonic_encode_frame,
sonic_encode_close,
NULL,
.long_name = NULL_IF_CONFIG_SMALL("Sonic lossless"),
};
#endif
#ifdef CONFIG_DECODERS
AVCodec sonic_decoder = {
"sonic",
CODEC_TYPE_AUDIO,
CODEC_ID_SONIC,
sizeof(SonicContext),
sonic_decode_init,
NULL,
sonic_decode_close,
sonic_decode_frame,
.long_name = NULL_IF_CONFIG_SMALL("Sonic"),
};
#endif
@@ -2,51 +2,55 @@
* Sunplus JPEG tables * Sunplus JPEG tables
* Copyright (c) 2003 the ffmpeg project * Copyright (c) 2003 the ffmpeg project
* *
* This library is free software; you can redistribute it and/or * This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This library is distributed in the hope that it will be useful, * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef SP5X_H #ifndef FFMPEG_SP5X_H
#define SP5X_H #define FFMPEG_SP5X_H
static uint8_t sp5x_data_sof[] = #include <stdint.h>
static const uint8_t sp5x_data_sof[] =
{ {
0xFF, 0xC0, /* SOF */ 0xFF, 0xC0, /* SOF */
0x00, 0x11, /* len */ 0x00, 0x11, /* len */
0x08, /* bits */ 0x08, /* bits */
0x00, 0xf0, /* height (default: 240) */ 0x00, 0xf0, /* height (default: 240) */
0x01, 0x40, /* width (default: 240) */ 0x01, 0x40, /* width (default: 240) */
0x03, /* nb components */ 0x03, /* nb components */
0x01, 0x22, 0x00, /* 21 vs 22 ? */ 0x01, 0x22, 0x00, /* 21 vs 22 ? */
0x02, 0x11, 0x01, 0x02, 0x11, 0x01,
0x03, 0x11, 0x01 0x03, 0x11, 0x01
}; };
static uint8_t sp5x_data_sos[] = static const uint8_t sp5x_data_sos[] =
{ {
0xFF, 0xDA, /* SOS */ 0xFF, 0xDA, /* SOS */
0x00, 0x0C, /* len */ 0x00, 0x0C, /* len */
0x03, /* nb components */ 0x03, /* nb components */
0x01, 0x00, 0x01, 0x00,
0x02, 0x11, 0x02, 0x11,
0x03, 0x11, 0x03, 0x11,
0x00, /* Ss */ 0x00, /* Ss */
0x3F, /* Se */ 0x3F, /* Se */
0x00 /* Ah/Al */ 0x00 /* Ah/Al */
}; };
static uint8_t sp5x_data_dqt[] = static const uint8_t sp5x_data_dqt[] =
{ {
0xFF, 0xDB, /* DQT */ 0xFF, 0xDB, /* DQT */
0x00, 0x84, /* len */ 0x00, 0x84, /* len */
@@ -70,9 +74,9 @@ static uint8_t sp5x_data_dqt[] =
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22
}; };
static uint8_t sp5x_data_dht[] = { static const uint8_t sp5x_data_dht[] = {
0xFF, 0xC4, /* DHT */ 0xFF, 0xC4, /* DHT */
0x01, 0xA2, /* len */ 0x01, 0xA2, /* len */
0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
@@ -128,7 +132,7 @@ static uint8_t sp5x_data_dht[] = {
}; };
static uint8_t sp5x_quant_table[20][64]= static const uint8_t sp5x_quant_table[20][64]=
{ {
/* index 0, Q50 */ /* index 0, Q50 */
{ 16, 11, 12, 14, 12, 10, 16, 14, 13, 14, 18, 17, 16, 19, 24, 40, { 16, 11, 12, 14, 12, 10, 16, 14, 13, 14, 18, 17, 16, 19, 24, 40,
@@ -233,7 +237,7 @@ static uint8_t sp5x_quant_table[20][64]=
#if 0 #if 0
/* 4NF-M, not ZigZag */ /* 4NF-M, not ZigZag */
static uint8_t sp5x_quant_table_orig[18][64] = static const uint8_t sp5x_quant_table_orig[18][64] =
{ {
/* index 0, Q50 */ /* index 0, Q50 */
{ 16, 11, 10, 16, 24, 40, 51, 61, 12, 12, 14, 19, 26, 58, 60, 55, { 16, 11, 10, 16, 24, 40, 51, 61, 12, 12, 14, 19, 26, 58, 60, 55,
@@ -257,7 +261,7 @@ static uint8_t sp5x_quant_table_orig[18][64] =
/* index 2, Q80 */ /* index 2, Q80 */
{ 6, 4, 4, 6, 10, 16, 20, 24, 5, 5, 6, 8, 10, 23, 24, 22, { 6, 4, 4, 6, 10, 16, 20, 24, 5, 5, 6, 8, 10, 23, 24, 22,
6, 5, 6, 10, 16, 23, 28, 22, 6, 7, 9, 12, 20, 35, 32, 25, 6, 5, 6, 10, 16, 23, 28, 22, 6, 7, 9, 12, 20, 35, 32, 25,
7, 9, 15, 22, 27, 44, 41, 31, 10, 14, 22, 26, 32, 42, 45, 37, 7, 9, 15, 22, 27, 44, 41, 31, 10, 14, 22, 26, 32, 42, 45, 37,
20, 26, 31, 35, 41, 48, 48, 40, 29, 37, 38, 39, 45, 40, 41, 40 }, 20, 26, 31, 35, 41, 48, 48, 40, 29, 37, 38, 39, 45, 40, 41, 40 },
{ 7, 7, 10, 19, 40, 40, 40, 40, 7, 8, 10, 26, 40, 40, 40, 40, { 7, 7, 10, 19, 40, 40, 40, 40, 7, 8, 10, 26, 40, 40, 40, 40,
@@ -267,7 +271,7 @@ static uint8_t sp5x_quant_table_orig[18][64] =
/* index 3, Q85 */ /* index 3, Q85 */
{ 5, 3, 3, 5, 7, 12, 15, 18, 4, 4, 4, 6, 8, 17, 18, 17, { 5, 3, 3, 5, 7, 12, 15, 18, 4, 4, 4, 6, 8, 17, 18, 17,
4, 4, 5, 7, 12, 17, 21, 17, 4, 5, 7, 9, 15, 26, 24, 19, 4, 4, 5, 7, 12, 17, 21, 17, 4, 5, 7, 9, 15, 26, 24, 19,
5, 7, 11, 17, 20, 33, 31, 23, 7, 11, 17, 19, 24, 31, 34, 28, 5, 7, 11, 17, 20, 33, 31, 23, 7, 11, 17, 19, 24, 31, 34, 28,
15, 19, 23, 26, 31, 36, 36, 30, 22, 28, 29, 29, 34, 30, 31, 30 }, 15, 19, 23, 26, 31, 36, 36, 30, 22, 28, 29, 29, 34, 30, 31, 30 },
{ 5, 5, 7, 14, 30, 30, 30, 30, 5, 6, 8, 20, 30, 30, 30, 30, { 5, 5, 7, 14, 30, 30, 30, 30, 5, 6, 8, 20, 30, 30, 30, 30,
@@ -327,4 +331,4 @@ static uint8_t sp5x_quant_table_orig[18][64] =
}; };
#endif #endif
#endif /* SP5X_H */ #endif /* FFMPEG_SP5X_H */
@@ -0,0 +1,215 @@
/*
* Sunplus JPEG decoder (SP5X)
* Copyright (c) 2003 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 sp5xdec.c
* Sunplus JPEG decoder (SP5X).
*/
#include "avcodec.h"
#include "mjpeg.h"
#include "mjpegdec.h"
#include "sp5x.h"
static int sp5x_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
const uint8_t *buf, int buf_size)
{
#if 0
MJpegDecodeContext *s = avctx->priv_data;
#endif
const int qscale = 5;
const uint8_t *buf_ptr, *buf_end;
uint8_t *recoded;
int i = 0, j = 0;
if (!avctx->width || !avctx->height)
return -1;
buf_ptr = buf;
buf_end = buf + buf_size;
#if 1
recoded = av_mallocz(buf_size + 1024);
if (!recoded)
return -1;
/* SOI */
recoded[j++] = 0xFF;
recoded[j++] = 0xD8;
memcpy(recoded+j, &sp5x_data_dqt[0], sizeof(sp5x_data_dqt));
memcpy(recoded+j+5, &sp5x_quant_table[qscale * 2], 64);
memcpy(recoded+j+70, &sp5x_quant_table[(qscale * 2) + 1], 64);
j += sizeof(sp5x_data_dqt);
memcpy(recoded+j, &sp5x_data_dht[0], sizeof(sp5x_data_dht));
j += sizeof(sp5x_data_dht);
memcpy(recoded+j, &sp5x_data_sof[0], sizeof(sp5x_data_sof));
AV_WB16(recoded+j+5, avctx->coded_height);
AV_WB16(recoded+j+7, avctx->coded_width);
j += sizeof(sp5x_data_sof);
memcpy(recoded+j, &sp5x_data_sos[0], sizeof(sp5x_data_sos));
j += sizeof(sp5x_data_sos);
if(avctx->codec_id==CODEC_ID_AMV)
for (i = 2; i < buf_size-2 && j < buf_size+1024-2; i++)
recoded[j++] = buf[i];
else
for (i = 14; i < buf_size && j < buf_size+1024-2; i++)
{
recoded[j++] = buf[i];
if (buf[i] == 0xff)
recoded[j++] = 0;
}
/* EOI */
recoded[j++] = 0xFF;
recoded[j++] = 0xD9;
avctx->flags &= ~CODEC_FLAG_EMU_EDGE;
i = ff_mjpeg_decode_frame(avctx, data, data_size, recoded, j);
av_free(recoded);
#else
/* SOF */
s->bits = 8;
s->width = avctx->coded_width;
s->height = avctx->coded_height;
s->nb_components = 3;
s->component_id[0] = 0;
s->h_count[0] = 2;
s->v_count[0] = 2;
s->quant_index[0] = 0;
s->component_id[1] = 1;
s->h_count[1] = 1;
s->v_count[1] = 1;
s->quant_index[1] = 1;
s->component_id[2] = 2;
s->h_count[2] = 1;
s->v_count[2] = 1;
s->quant_index[2] = 1;
s->h_max = 2;
s->v_max = 2;
s->qscale_table = av_mallocz((s->width+15)/16);
avctx->pix_fmt = s->cs_itu601 ? PIX_FMT_YUV420P : PIX_FMT_YUVJ420;
s->interlaced = 0;
s->picture.reference = 0;
if (avctx->get_buffer(avctx, &s->picture) < 0)
{
av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
return -1;
}
s->picture.pict_type = FF_I_TYPE;
s->picture.key_frame = 1;
for (i = 0; i < 3; i++)
s->linesize[i] = s->picture.linesize[i] << s->interlaced;
/* DQT */
for (i = 0; i < 64; i++)
{
j = s->scantable.permutated[i];
s->quant_matrixes[0][j] = sp5x_quant_table[(qscale * 2) + i];
}
s->qscale[0] = FFMAX(
s->quant_matrixes[0][s->scantable.permutated[1]],
s->quant_matrixes[0][s->scantable.permutated[8]]) >> 1;
for (i = 0; i < 64; i++)
{
j = s->scantable.permutated[i];
s->quant_matrixes[1][j] = sp5x_quant_table[(qscale * 2) + 1 + i];
}
s->qscale[1] = FFMAX(
s->quant_matrixes[1][s->scantable.permutated[1]],
s->quant_matrixes[1][s->scantable.permutated[8]]) >> 1;
/* DHT */
/* SOS */
s->comp_index[0] = 0;
s->nb_blocks[0] = s->h_count[0] * s->v_count[0];
s->h_scount[0] = s->h_count[0];
s->v_scount[0] = s->v_count[0];
s->dc_index[0] = 0;
s->ac_index[0] = 0;
s->comp_index[1] = 1;
s->nb_blocks[1] = s->h_count[1] * s->v_count[1];
s->h_scount[1] = s->h_count[1];
s->v_scount[1] = s->v_count[1];
s->dc_index[1] = 1;
s->ac_index[1] = 1;
s->comp_index[2] = 2;
s->nb_blocks[2] = s->h_count[2] * s->v_count[2];
s->h_scount[2] = s->h_count[2];
s->v_scount[2] = s->v_count[2];
s->dc_index[2] = 1;
s->ac_index[2] = 1;
for (i = 0; i < 3; i++)
s->last_dc[i] = 1024;
s->mb_width = (s->width * s->h_max * 8 -1) / (s->h_max * 8);
s->mb_height = (s->height * s->v_max * 8 -1) / (s->v_max * 8);
init_get_bits(&s->gb, buf+14, (buf_size-14)*8);
return mjpeg_decode_scan(s);
#endif
return i;
}
AVCodec sp5x_decoder = {
"sp5x",
CODEC_TYPE_VIDEO,
CODEC_ID_SP5X,
sizeof(MJpegDecodeContext),
ff_mjpeg_decode_init,
NULL,
ff_mjpeg_decode_end,
sp5x_decode_frame,
CODEC_CAP_DR1,
NULL,
.long_name = NULL_IF_CONFIG_SMALL("Sunplus JPEG (SP5X)"),
};
AVCodec amv_decoder = {
"amv",
CODEC_TYPE_VIDEO,
CODEC_ID_AMV,
sizeof(MJpegDecodeContext),
ff_mjpeg_decode_init,
NULL,
ff_mjpeg_decode_end,
sp5x_decode_frame,
.long_name = NULL_IF_CONFIG_SMALL("AMV Video"),
};
@@ -0,0 +1,196 @@
/*
* Sun Rasterfile (.sun/.ras/im{1,8,24}/.sunras) image decoder
* Copyright (c) 2007, 2008 Ivo van Poorten
*
* 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"
#define RT_OLD 0
#define RT_STANDARD 1
#define RT_BYTE_ENCODED 2
#define RT_FORMAT_RGB 3
#define RT_FORMAT_TIFF 4
#define RT_FORMAT_IFF 5
typedef struct SUNRASTContext {
AVFrame picture;
} SUNRASTContext;
static av_cold int sunrast_init(AVCodecContext *avctx) {
SUNRASTContext *s = avctx->priv_data;
avcodec_get_frame_defaults(&s->picture);
avctx->coded_frame= &s->picture;
return 0;
}
static int sunrast_decode_frame(AVCodecContext *avctx, void *data,
int *data_size, const uint8_t *buf, int buf_size) {
SUNRASTContext * const s = avctx->priv_data;
AVFrame *picture = data;
AVFrame * const p = &s->picture;
unsigned int w, h, depth, type, maptype, maplength, stride, x, y, len, alen;
uint8_t *ptr;
const uint8_t *bufstart = buf;
if (AV_RB32(buf) != 0x59a66a95) {
av_log(avctx, AV_LOG_ERROR, "this is not sunras encoded data\n");
return -1;
}
w = AV_RB32(buf+4);
h = AV_RB32(buf+8);
depth = AV_RB32(buf+12);
type = AV_RB32(buf+20);
maptype = AV_RB32(buf+24);
maplength = AV_RB32(buf+28);
if (type > RT_BYTE_ENCODED && type <= RT_FORMAT_IFF) {
av_log(avctx, AV_LOG_ERROR, "unsupported (compression) type\n");
return -1;
}
if (type > RT_FORMAT_IFF) {
av_log(avctx, AV_LOG_ERROR, "invalid (compression) type\n");
return -1;
}
if (maptype & ~1) {
av_log(avctx, AV_LOG_ERROR, "invalid colormap type\n");
return -1;
}
buf += 32;
switch (depth) {
case 1:
avctx->pix_fmt = PIX_FMT_MONOWHITE;
break;
case 8:
avctx->pix_fmt = PIX_FMT_PAL8;
break;
case 24:
avctx->pix_fmt = PIX_FMT_BGR24;
break;
default:
av_log(avctx, AV_LOG_ERROR, "invalid depth\n");
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;
if (depth != 8 && maplength) {
av_log(avctx, AV_LOG_WARNING, "useless colormap found or file is corrupted, trying to recover\n");
} else if (depth == 8) {
unsigned int len = maplength / 3;
if (!maplength) {
av_log(avctx, AV_LOG_ERROR, "colormap expected\n");
return -1;
}
if (maplength % 3 || maplength > 768) {
av_log(avctx, AV_LOG_WARNING, "invalid colormap length\n");
return -1;
}
ptr = p->data[1];
for (x=0; x<len; x++, ptr+=4)
*(uint32_t *)ptr = (buf[x]<<16) + (buf[len+x]<<8) + buf[len+len+x];
}
buf += maplength;
ptr = p->data[0];
stride = p->linesize[0];
/* scanlines are aligned on 16 bit boundaries */
len = (depth * w + 7) >> 3;
alen = len + (len&1);
if (type == RT_BYTE_ENCODED) {
int value, run;
uint8_t *end = ptr + h*stride;
x = 0;
while (ptr != end) {
run = 1;
if ((value = *buf++) == 0x80) {
run = *buf++ + 1;
if (run != 1)
value = *buf++;
}
while (run--) {
if (x < len)
ptr[x] = value;
if (++x >= alen) {
x = 0;
ptr += stride;
if (ptr == end)
break;
}
}
}
} else {
for (y=0; y<h; y++) {
memcpy(ptr, buf, len);
ptr += stride;
buf += alen;
}
}
*picture = s->picture;
*data_size = sizeof(AVFrame);
return buf - bufstart;
}
static av_cold int sunrast_end(AVCodecContext *avctx) {
SUNRASTContext *s = avctx->priv_data;
if(s->picture.data[0])
avctx->release_buffer(avctx, &s->picture);
return 0;
}
AVCodec sunrast_decoder = {
"sunrast",
CODEC_TYPE_VIDEO,
CODEC_ID_SUNRAST,
sizeof(SUNRASTContext),
sunrast_init,
NULL,
sunrast_end,
sunrast_decode_frame,
0,
NULL,
.long_name = NULL_IF_CONFIG_SMALL("Sun Rasterfile image"),
};
@@ -1,841 +1,43 @@
/* /*
* SVQ1 decoder
* ported to MPlayer by Arpi <arpi@thot.banki.hu>
* ported to libavcodec by Nick Kurshev <nickols_k@mail.ru>
* *
* Copyright (C) 2002 the xine project * Copyright (C) 2002 the xine project
* Copyright (C) 2002 the ffmpeg project * Copyright (C) 2002 the ffmpeg project
* *
* This library is free software; you can redistribute it and/or * SVQ1 Encoder (c) 2004 Mike Melanson <melanson@pcisys.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 * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This library is distributed in the hope that it will be useful, * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Ported to mplayer by Arpi <arpi@thot.banki.hu>
* Ported to libavcodec by Nick Kurshev <nickols_k@mail.ru>
*
*/ */
/** /**
* @file svq1.c * @file svq1.c
* Sorenson Vector Quantizer #1 (SVQ1) video decoder. * Sorenson Vector Quantizer #1 (SVQ1) video codec.
* For more information of the SVQ1 algorithm, visit:
* http://www.pcisys.net/~melanson/codecs/
*/ */
#include "svq1.h"
//#define DEBUG_SVQ1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "common.h"
#include "avcodec.h"
#include "dsputil.h"
#include "mpegvideo.h"
#include "bswap.h"
static VLC svq1_block_type;
static VLC svq1_motion_component;
static VLC svq1_intra_multistage[6];
static VLC svq1_inter_multistage[6];
static VLC svq1_intra_mean;
static VLC svq1_inter_mean;
#define MEDIAN(a,b,c) (((a < b) != (b >= c)) ? b : (((a < c) != (c > b)) ? c : a))
#define SVQ1_BLOCK_SKIP 0
#define SVQ1_BLOCK_INTER 1
#define SVQ1_BLOCK_INTER_4V 2
#define SVQ1_BLOCK_INTRA 3
/* motion vector (prediction) */
typedef struct svq1_pmv_s {
int x;
int y;
} svq1_pmv_t;
#include "svq1_cb.h" #include "svq1_cb.h"
#include "svq1_vlc.h" #include "svq1_vlc.h"
static const uint16_t checksum_table[256] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
};
static const uint8_t string_table[256] = {
0x00, 0xD5, 0x7F, 0xAA, 0xFE, 0x2B, 0x81, 0x54,
0x29, 0xFC, 0x56, 0x83, 0xD7, 0x02, 0xA8, 0x7D,
0x52, 0x87, 0x2D, 0xF8, 0xAC, 0x79, 0xD3, 0x06,
0x7B, 0xAE, 0x04, 0xD1, 0x85, 0x50, 0xFA, 0x2F,
0xA4, 0x71, 0xDB, 0x0E, 0x5A, 0x8F, 0x25, 0xF0,
0x8D, 0x58, 0xF2, 0x27, 0x73, 0xA6, 0x0C, 0xD9,
0xF6, 0x23, 0x89, 0x5C, 0x08, 0xDD, 0x77, 0xA2,
0xDF, 0x0A, 0xA0, 0x75, 0x21, 0xF4, 0x5E, 0x8B,
0x9D, 0x48, 0xE2, 0x37, 0x63, 0xB6, 0x1C, 0xC9,
0xB4, 0x61, 0xCB, 0x1E, 0x4A, 0x9F, 0x35, 0xE0,
0xCF, 0x1A, 0xB0, 0x65, 0x31, 0xE4, 0x4E, 0x9B,
0xE6, 0x33, 0x99, 0x4C, 0x18, 0xCD, 0x67, 0xB2,
0x39, 0xEC, 0x46, 0x93, 0xC7, 0x12, 0xB8, 0x6D,
0x10, 0xC5, 0x6F, 0xBA, 0xEE, 0x3B, 0x91, 0x44,
0x6B, 0xBE, 0x14, 0xC1, 0x95, 0x40, 0xEA, 0x3F,
0x42, 0x97, 0x3D, 0xE8, 0xBC, 0x69, 0xC3, 0x16,
0xEF, 0x3A, 0x90, 0x45, 0x11, 0xC4, 0x6E, 0xBB,
0xC6, 0x13, 0xB9, 0x6C, 0x38, 0xED, 0x47, 0x92,
0xBD, 0x68, 0xC2, 0x17, 0x43, 0x96, 0x3C, 0xE9,
0x94, 0x41, 0xEB, 0x3E, 0x6A, 0xBF, 0x15, 0xC0,
0x4B, 0x9E, 0x34, 0xE1, 0xB5, 0x60, 0xCA, 0x1F,
0x62, 0xB7, 0x1D, 0xC8, 0x9C, 0x49, 0xE3, 0x36,
0x19, 0xCC, 0x66, 0xB3, 0xE7, 0x32, 0x98, 0x4D,
0x30, 0xE5, 0x4F, 0x9A, 0xCE, 0x1B, 0xB1, 0x64,
0x72, 0xA7, 0x0D, 0xD8, 0x8C, 0x59, 0xF3, 0x26,
0x5B, 0x8E, 0x24, 0xF1, 0xA5, 0x70, 0xDA, 0x0F,
0x20, 0xF5, 0x5F, 0x8A, 0xDE, 0x0B, 0xA1, 0x74,
0x09, 0xDC, 0x76, 0xA3, 0xF7, 0x22, 0x88, 0x5D,
0xD6, 0x03, 0xA9, 0x7C, 0x28, 0xFD, 0x57, 0x82,
0xFF, 0x2A, 0x80, 0x55, 0x01, 0xD4, 0x7E, 0xAB,
0x84, 0x51, 0xFB, 0x2E, 0x7A, 0xAF, 0x05, 0xD0,
0xAD, 0x78, 0xD2, 0x07, 0x53, 0x86, 0x2C, 0xF9
};
#define SVQ1_PROCESS_VECTOR()\
for (; level > 0; i++) {\
/* process next depth */\
if (i == m) {\
m = n;\
if (--level == 0)\
break;\
}\
/* divide block if next bit set */\
if (get_bits (bitbuf, 1) == 0)\
break;\
/* add child nodes */\
list[n++] = list[i];\
list[n++] = list[i] + (((level & 1) ? pitch : 1) << ((level / 2) + 1));\
}
#define SVQ1_ADD_CODEBOOK()\
/* add codebook entries to vector */\
for (j=0; j < stages; j++) {\
n3 = codebook[entries[j]] ^ 0x80808080;\
n1 += ((n3 & 0xFF00FF00) >> 8);\
n2 += (n3 & 0x00FF00FF);\
}\
\
/* clip to [0..255] */\
if (n1 & 0xFF00FF00) {\
n3 = ((( n1 >> 15) & 0x00010001) | 0x01000100) - 0x00010001;\
n1 += 0x7F007F00;\
n1 |= (((~n1 >> 15) & 0x00010001) | 0x01000100) - 0x00010001;\
n1 &= (n3 & 0x00FF00FF);\
}\
\
if (n2 & 0xFF00FF00) {\
n3 = ((( n2 >> 15) & 0x00010001) | 0x01000100) - 0x00010001;\
n2 += 0x7F007F00;\
n2 |= (((~n2 >> 15) & 0x00010001) | 0x01000100) - 0x00010001;\
n2 &= (n3 & 0x00FF00FF);\
}
#define SVQ1_DO_CODEBOOK_INTRA()\
for (y=0; y < height; y++) {\
for (x=0; x < (width / 4); x++, codebook++) {\
n1 = n4;\
n2 = n4;\
SVQ1_ADD_CODEBOOK()\
/* store result */\
dst[x] = (n1 << 8) | n2;\
}\
dst += (pitch / 4);\
}
#define SVQ1_DO_CODEBOOK_NONINTRA()\
for (y=0; y < height; y++) {\
for (x=0; x < (width / 4); x++, codebook++) {\
n3 = dst[x];\
/* add mean value to vector */\
n1 = ((n3 & 0xFF00FF00) >> 8) + n4;\
n2 = (n3 & 0x00FF00FF) + n4;\
SVQ1_ADD_CODEBOOK()\
/* store result */\
dst[x] = (n1 << 8) | n2;\
}\
dst += (pitch / 4);\
}
#define SVQ1_CALC_CODEBOOK_ENTRIES(cbook)\
codebook = (const uint32_t *) cbook[level];\
bit_cache = get_bits (bitbuf, 4*stages);\
/* calculate codebook entries for this vector */\
for (j=0; j < stages; j++) {\
entries[j] = (((bit_cache >> (4*(stages - j - 1))) & 0xF) + 16*j) << (level + 1);\
}\
mean -= (stages * 128);\
n4 = ((mean + (mean >> 31)) << 16) | (mean & 0xFFFF);
static int svq1_decode_block_intra (GetBitContext *bitbuf, uint8_t *pixels, int pitch ) {
uint32_t bit_cache;
uint8_t *list[63];
uint32_t *dst;
const uint32_t *codebook;
int entries[6];
int i, j, m, n;
int mean, stages;
unsigned x, y, width, height, level;
uint32_t n1, n2, n3, n4;
/* initialize list for breadth first processing of vectors */
list[0] = pixels;
/* recursively process vector */
for (i=0, m=1, n=1, level=5; i < n; i++) {
SVQ1_PROCESS_VECTOR();
/* destination address and vector size */
dst = (uint32_t *) list[i];
width = 1 << ((4 + level) /2);
height = 1 << ((3 + level) /2);
/* get number of stages (-1 skips vector, 0 for mean only) */
stages = get_vlc2(bitbuf, svq1_intra_multistage[level].table, 3, 3) - 1;
if (stages == -1) {
for (y=0; y < height; y++) {
memset (&dst[y*(pitch / 4)], 0, width);
}
continue; /* skip vector */
}
if ((stages > 0) && (level >= 4)) {
#ifdef DEBUG_SVQ1
printf("Error (svq1_decode_block_intra): invalid vector: stages=%i level=%i\n",stages,level);
#endif
return -1; /* invalid vector */
}
mean = get_vlc2(bitbuf, svq1_intra_mean.table, 8, 3);
if (stages == 0) {
for (y=0; y < height; y++) {
memset (&dst[y*(pitch / 4)], mean, width);
}
} else {
SVQ1_CALC_CODEBOOK_ENTRIES(svq1_intra_codebooks);
SVQ1_DO_CODEBOOK_INTRA()
}
}
return 0;
}
static int svq1_decode_block_non_intra (GetBitContext *bitbuf, uint8_t *pixels, int pitch ) {
uint32_t bit_cache;
uint8_t *list[63];
uint32_t *dst;
const uint32_t *codebook;
int entries[6];
int i, j, m, n;
int mean, stages;
int x, y, width, height, level;
uint32_t n1, n2, n3, n4;
/* initialize list for breadth first processing of vectors */
list[0] = pixels;
/* recursively process vector */
for (i=0, m=1, n=1, level=5; i < n; i++) {
SVQ1_PROCESS_VECTOR();
/* destination address and vector size */
dst = (uint32_t *) list[i];
width = 1 << ((4 + level) /2);
height = 1 << ((3 + level) /2);
/* get number of stages (-1 skips vector, 0 for mean only) */
stages = get_vlc2(bitbuf, svq1_inter_multistage[level].table, 3, 2) - 1;
if (stages == -1) continue; /* skip vector */
if ((stages > 0) && (level >= 4)) {
#ifdef DEBUG_SVQ1
printf("Error (svq1_decode_block_non_intra): invalid vector: stages=%i level=%i\n",stages,level);
#endif
return -1; /* invalid vector */
}
mean = get_vlc2(bitbuf, svq1_inter_mean.table, 9, 3) - 256;
SVQ1_CALC_CODEBOOK_ENTRIES(svq1_inter_codebooks);
SVQ1_DO_CODEBOOK_NONINTRA()
}
return 0;
}
static int svq1_decode_motion_vector (GetBitContext *bitbuf, svq1_pmv_t *mv, svq1_pmv_t **pmv) {
int diff;
int i;
for (i=0; i < 2; i++) {
/* get motion code */
diff = get_vlc2(bitbuf, svq1_motion_component.table, 7, 2) - 32;
/* add median of motion vector predictors and clip result */
if (i == 1)
mv->y = ((diff + MEDIAN(pmv[0]->y, pmv[1]->y, pmv[2]->y)) << 26) >> 26;
else
mv->x = ((diff + MEDIAN(pmv[0]->x, pmv[1]->x, pmv[2]->x)) << 26) >> 26;
}
return 0;
}
static void svq1_skip_block (uint8_t *current, uint8_t *previous, int pitch, int x, int y) {
uint8_t *src;
uint8_t *dst;
int i;
src = &previous[x + y*pitch];
dst = current;
for (i=0; i < 16; i++) {
memcpy (dst, src, 16);
src += pitch;
dst += pitch;
}
}
static int svq1_motion_inter_block (MpegEncContext *s, GetBitContext *bitbuf,
uint8_t *current, uint8_t *previous, int pitch,
svq1_pmv_t *motion, int x, int y) {
uint8_t *src;
uint8_t *dst;
svq1_pmv_t mv;
svq1_pmv_t *pmv[3];
int result;
/* predict and decode motion vector */
pmv[0] = &motion[0];
if (y == 0) {
pmv[1] =
pmv[2] = pmv[0];
}
else {
pmv[1] = &motion[(x / 8) + 2];
pmv[2] = &motion[(x / 8) + 4];
}
result = svq1_decode_motion_vector (bitbuf, &mv, pmv);
if (result != 0)
return result;
motion[0].x =
motion[(x / 8) + 2].x =
motion[(x / 8) + 3].x = mv.x;
motion[0].y =
motion[(x / 8) + 2].y =
motion[(x / 8) + 3].y = mv.y;
if(y + (mv.y >> 1)<0)
mv.y= 0;
if(x + (mv.x >> 1)<0)
mv.x= 0;
#if 0
int w= (s->width+15)&~15;
int h= (s->height+15)&~15;
if(x + (mv.x >> 1)<0 || y + (mv.y >> 1)<0 || x + (mv.x >> 1) + 16 > w || y + (mv.y >> 1) + 16> h)
printf("%d %d %d %d\n", x, y, x + (mv.x >> 1), y + (mv.y >> 1));
#endif
src = &previous[(x + (mv.x >> 1)) + (y + (mv.y >> 1))*pitch];
dst = current;
s->dsp.put_pixels_tab[0][((mv.y & 1) << 1) | (mv.x & 1)](dst,src,pitch,16);
return 0;
}
static int svq1_motion_inter_4v_block (MpegEncContext *s, GetBitContext *bitbuf,
uint8_t *current, uint8_t *previous, int pitch,
svq1_pmv_t *motion,int x, int y) {
uint8_t *src;
uint8_t *dst;
svq1_pmv_t mv;
svq1_pmv_t *pmv[4];
int i, result;
/* predict and decode motion vector (0) */
pmv[0] = &motion[0];
if (y == 0) {
pmv[1] =
pmv[2] = pmv[0];
}
else {
pmv[1] = &motion[(x / 8) + 2];
pmv[2] = &motion[(x / 8) + 4];
}
result = svq1_decode_motion_vector (bitbuf, &mv, pmv);
if (result != 0)
return result;
/* predict and decode motion vector (1) */
pmv[0] = &mv;
if (y == 0) {
pmv[1] =
pmv[2] = pmv[0];
}
else {
pmv[1] = &motion[(x / 8) + 3];
}
result = svq1_decode_motion_vector (bitbuf, &motion[0], pmv);
if (result != 0)
return result;
/* predict and decode motion vector (2) */
pmv[1] = &motion[0];
pmv[2] = &motion[(x / 8) + 1];
result = svq1_decode_motion_vector (bitbuf, &motion[(x / 8) + 2], pmv);
if (result != 0)
return result;
/* predict and decode motion vector (3) */
pmv[2] = &motion[(x / 8) + 2];
pmv[3] = &motion[(x / 8) + 3];
result = svq1_decode_motion_vector (bitbuf, pmv[3], pmv);
if (result != 0)
return result;
/* form predictions */
for (i=0; i < 4; i++) {
int mvx= pmv[i]->x + (i&1)*16;
int mvy= pmv[i]->y + (i>>1)*16;
///XXX /FIXME cliping or padding?
if(y + (mvy >> 1)<0)
mvy= 0;
if(x + (mvx >> 1)<0)
mvx= 0;
#if 0
int w= (s->width+15)&~15;
int h= (s->height+15)&~15;
if(x + (mvx >> 1)<0 || y + (mvy >> 1)<0 || x + (mvx >> 1) + 8 > w || y + (mvy >> 1) + 8> h)
printf("%d %d %d %d\n", x, y, x + (mvx >> 1), y + (mvy >> 1));
#endif
src = &previous[(x + (mvx >> 1)) + (y + (mvy >> 1))*pitch];
dst = current;
s->dsp.put_pixels_tab[1][((mvy & 1) << 1) | (mvx & 1)](dst,src,pitch,8);
/* select next block */
if (i & 1) {
current += 8*(pitch - 1);
} else {
current += 8;
}
}
return 0;
}
static int svq1_decode_delta_block (MpegEncContext *s, GetBitContext *bitbuf,
uint8_t *current, uint8_t *previous, int pitch,
svq1_pmv_t *motion, int x, int y) {
uint32_t block_type;
int result = 0;
/* get block type */
block_type = get_vlc2(bitbuf, svq1_block_type.table, 2, 2);
/* reset motion vectors */
if (block_type == SVQ1_BLOCK_SKIP || block_type == SVQ1_BLOCK_INTRA) {
motion[0].x =
motion[0].y =
motion[(x / 8) + 2].x =
motion[(x / 8) + 2].y =
motion[(x / 8) + 3].x =
motion[(x / 8) + 3].y = 0;
}
switch (block_type) {
case SVQ1_BLOCK_SKIP:
svq1_skip_block (current, previous, pitch, x, y);
break;
case SVQ1_BLOCK_INTER:
result = svq1_motion_inter_block (s, bitbuf, current, previous, pitch, motion, x, y);
if (result != 0)
{
#ifdef DEBUG_SVQ1
printf("Error in svq1_motion_inter_block %i\n",result);
#endif
break;
}
result = svq1_decode_block_non_intra (bitbuf, current, pitch);
break;
case SVQ1_BLOCK_INTER_4V:
result = svq1_motion_inter_4v_block (s, bitbuf, current, previous, pitch, motion, x, y);
if (result != 0)
{
#ifdef DEBUG_SVQ1
printf("Error in svq1_motion_inter_4v_block %i\n",result);
#endif
break;
}
result = svq1_decode_block_non_intra (bitbuf, current, pitch);
break;
case SVQ1_BLOCK_INTRA:
result = svq1_decode_block_intra (bitbuf, current, pitch);
break;
}
return result;
}
/* standard video sizes */ /* standard video sizes */
static struct { int width; int height; } svq1_frame_size_table[8] = { const svq1_frame_size_t ff_svq1_frame_size_table[8] = {
{ 160, 120 }, { 128, 96 }, { 176, 144 }, { 352, 288 }, { 160, 120 }, { 128, 96 }, { 176, 144 }, { 352, 288 },
{ 704, 576 }, { 240, 180 }, { 320, 240 }, { -1, -1 } { 704, 576 }, { 240, 180 }, { 320, 240 }, { -1, -1 }
}; };
static uint16_t svq1_packet_checksum (uint8_t *data, int length, int value) {
int i;
for (i=0; i < length; i++) {
value = checksum_table[data[i] ^ (value >> 8)] ^ ((value & 0xFF) << 8);
}
return value;
}
static uint16_t svq1_component_checksum (uint16_t *pixels, int pitch,
int width, int height, int value) {
int x, y;
for (y=0; y < height; y++) {
for (x=0; x < width; x++) {
value = checksum_table[pixels[x] ^ (value >> 8)] ^ ((value & 0xFF) << 8);
}
pixels += pitch;
}
return value;
}
static void svq1_parse_string (GetBitContext *bitbuf, uint8_t *out) {
uint8_t seed;
int i;
out[0] = get_bits (bitbuf, 8);
seed = string_table[out[0]];
for (i=1; i <= out[0]; i++) {
out[i] = get_bits (bitbuf, 8) ^ seed;
seed = string_table[out[i] ^ seed];
}
}
static int svq1_decode_frame_header (GetBitContext *bitbuf,MpegEncContext *s) {
int frame_size_code;
int temporal_reference;
temporal_reference = get_bits (bitbuf, 8);
/* frame type */
s->pict_type= get_bits (bitbuf, 2)+1;
if(s->pict_type==4)
return -1;
if (s->pict_type == I_TYPE) {
/* unknown fields */
if (s->f_code == 0x50 || s->f_code == 0x60) {
int csum = get_bits (bitbuf, 16);
csum = svq1_packet_checksum ((uint8_t *)bitbuf->buffer, bitbuf->size_in_bits>>3, csum);
// printf ("%s checksum (%02x) for packet data\n",
// (csum == 0) ? "correct" : "incorrect", csum);
}
if ((s->f_code ^ 0x10) >= 0x50) {
char msg[256];
svq1_parse_string (bitbuf, (char *) msg);
av_log(s->avctx, AV_LOG_INFO, "embedded message: \"%s\"\n", (char *) msg);
}
skip_bits (bitbuf, 2);
skip_bits (bitbuf, 2);
skip_bits1 (bitbuf);
/* load frame size */
frame_size_code = get_bits (bitbuf, 3);
if (frame_size_code == 7) {
/* load width, height (12 bits each) */
s->width = get_bits (bitbuf, 12);
s->height = get_bits (bitbuf, 12);
if (!s->width || !s->height)
return -1;
} else {
/* get width, height from table */
s->width = svq1_frame_size_table[frame_size_code].width;
s->height = svq1_frame_size_table[frame_size_code].height;
}
}
/* unknown fields */
if (get_bits (bitbuf, 1) == 1) {
skip_bits1 (bitbuf); /* use packet checksum if (1) */
skip_bits1 (bitbuf); /* component checksums after image data if (1) */
if (get_bits (bitbuf, 2) != 0)
return -1;
}
if (get_bits (bitbuf, 1) == 1) {
skip_bits1 (bitbuf);
skip_bits (bitbuf, 4);
skip_bits1 (bitbuf);
skip_bits (bitbuf, 2);
while (get_bits (bitbuf, 1) == 1) {
skip_bits (bitbuf, 8);
}
}
return 0;
}
static int svq1_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
uint8_t *buf, int buf_size)
{
MpegEncContext *s=avctx->priv_data;
uint8_t *current, *previous;
int result, i, x, y, width, height;
AVFrame *pict = data;
/* initialize bit buffer */
init_get_bits(&s->gb,buf,buf_size*8);
/* decode frame header */
s->f_code = get_bits (&s->gb, 22);
if ((s->f_code & ~0x70) || !(s->f_code & 0x60))
return -1;
/* swap some header bytes (why?) */
if (s->f_code != 0x20) {
uint32_t *src = (uint32_t *) (buf + 4);
for (i=0; i < 4; i++) {
src[i] = ((src[i] << 16) | (src[i] >> 16)) ^ src[7 - i];
}
}
result = svq1_decode_frame_header (&s->gb, s);
if (result != 0)
{
#ifdef DEBUG_SVQ1
printf("Error in svq1_decode_frame_header %i\n",result);
#endif
return result;
}
//FIXME this avoids some confusion for "B frames" without 2 references
//this should be removed after libavcodec can handle more flaxible picture types & ordering
if(s->pict_type==B_TYPE && s->last_picture_ptr==NULL) return buf_size;
if(avctx->hurry_up && s->pict_type==B_TYPE) return buf_size;
if(MPV_frame_start(s, avctx) < 0)
return -1;
/* decode y, u and v components */
for (i=0; i < 3; i++) {
int linesize;
if (i == 0) {
width = (s->width+15)&~15;
height = (s->height+15)&~15;
linesize= s->linesize;
} else {
if(s->flags&CODEC_FLAG_GRAY) break;
width = (s->width/4+15)&~15;
height = (s->height/4+15)&~15;
linesize= s->uvlinesize;
}
current = s->current_picture.data[i];
if(s->pict_type==B_TYPE){
previous = s->next_picture.data[i];
}else{
previous = s->last_picture.data[i];
}
if (s->pict_type == I_TYPE) {
/* keyframe */
for (y=0; y < height; y+=16) {
for (x=0; x < width; x+=16) {
result = svq1_decode_block_intra (&s->gb, &current[x], linesize);
if (result != 0)
{
#ifdef DEBUG_SVQ1
printf("Error in svq1_decode_block %i (keyframe)\n",result);
#endif
return result;
}
}
current += 16*linesize;
}
} else {
svq1_pmv_t pmv[width/8+3];
/* delta frame */
memset (pmv, 0, ((width / 8) + 3) * sizeof(svq1_pmv_t));
for (y=0; y < height; y+=16) {
for (x=0; x < width; x+=16) {
result = svq1_decode_delta_block (s, &s->gb, &current[x], previous,
linesize, pmv, x, y);
if (result != 0)
{
#ifdef DEBUG_SVQ1
printf("Error in svq1_decode_delta_block %i\n",result);
#endif
return result;
}
}
pmv[0].x =
pmv[0].y = 0;
current += 16*linesize;
}
}
}
*pict = *(AVFrame*)&s->current_picture;
MPV_frame_end(s);
*data_size=sizeof(AVFrame);
return buf_size;
}
static int svq1_decode_init(AVCodecContext *avctx)
{
MpegEncContext *s = avctx->priv_data;
int i;
s->avctx = avctx;
s->width = (avctx->width+3)&~3;
s->height = (avctx->height+3)&~3;
s->codec_id= avctx->codec->id;
avctx->pix_fmt = PIX_FMT_YUV410P;
avctx->has_b_frames= 1; // not true, but DP frames and these behave like unidirectional b frames
if (MPV_common_init(s) < 0) return -1;
init_vlc(&svq1_block_type, 2, 4,
&svq1_block_type_vlc[0][1], 2, 1,
&svq1_block_type_vlc[0][0], 2, 1);
init_vlc(&svq1_motion_component, 7, 65,
&svq1_motion_component_vlc[0][1], 4, 2,
&svq1_motion_component_vlc[0][0], 4, 2);
for (i = 0; i < 6; i++) {
init_vlc(&svq1_intra_multistage[i], 3, 8,
&svq1_intra_multistage_vlc[i][0][1], 2, 1,
&svq1_intra_multistage_vlc[i][0][0], 2, 1);
init_vlc(&svq1_inter_multistage[i], 3, 8,
&svq1_inter_multistage_vlc[i][0][1], 2, 1,
&svq1_inter_multistage_vlc[i][0][0], 2, 1);
}
init_vlc(&svq1_intra_mean, 8, 256,
&svq1_intra_mean_vlc[0][1], 4, 2,
&svq1_intra_mean_vlc[0][0], 4, 2);
init_vlc(&svq1_inter_mean, 9, 512,
&svq1_inter_mean_vlc[0][1], 4, 2,
&svq1_inter_mean_vlc[0][0], 4, 2);
return 0;
}
static int svq1_decode_end(AVCodecContext *avctx)
{
MpegEncContext *s = avctx->priv_data;
MPV_common_end(s);
return 0;
}
AVCodec svq1_decoder = {
"svq1",
CODEC_TYPE_VIDEO,
CODEC_ID_SVQ1,
sizeof(MpegEncContext),
svq1_decode_init,
NULL,
svq1_decode_end,
svq1_decode_frame,
CODEC_CAP_DR1,
.flush= ff_mpeg_flush,
};
@@ -0,0 +1,61 @@
/*
* SVQ1 decoder
* ported to MPlayer by Arpi <arpi@thot.banki.hu>
* ported to libavcodec by Nick Kurshev <nickols_k@mail.ru>
*
* Copyright (C) 2002 the xine project
* Copyright (C) 2002 the ffmpeg project
*
* SVQ1 Encoder (c) 2004 Mike Melanson <melanson@pcisys.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 svq1.h
* Sorenson Vector Quantizer #1 (SVQ1) video codec.
* For more information of the SVQ1 algorithm, visit:
* http://www.pcisys.net/~melanson/codecs/
*/
#ifndef FFMPEG_SVQ1_H
#define FFMPEG_SVQ1_H
#include <stdint.h>
#define SVQ1_BLOCK_SKIP 0
#define SVQ1_BLOCK_INTER 1
#define SVQ1_BLOCK_INTER_4V 2
#define SVQ1_BLOCK_INTRA 3
typedef struct {
int width;
int height;
} svq1_frame_size_t;
extern const int8_t* const ff_svq1_inter_codebooks[6];
extern const int8_t* const ff_svq1_intra_codebooks[6];
extern const uint8_t ff_svq1_block_type_vlc[4][2];
extern const uint8_t ff_svq1_intra_multistage_vlc[6][8][2];
extern const uint8_t ff_svq1_inter_multistage_vlc[6][8][2];
extern const uint16_t ff_svq1_intra_mean_vlc[256][2];
extern const uint16_t ff_svq1_inter_mean_vlc[512][2];
extern const svq1_frame_size_t ff_svq1_frame_size_table[8];
#endif /* FFMPEG_SVQ1_H */
@@ -1,25 +1,26 @@
/* /*
* SVQ1 decoder
* ported to MPlayer by Arpi <arpi@thot.banki.hu>
* ported to libavcodec by Nick Kurshev <nickols_k@mail.ru>
* *
* Copyright (C) 2002 the xine project * Copyright (C) 2002 the xine project
* Copyright (C) 2002 the ffmpeg project * Copyright (C) 2002 the ffmpeg project
* *
* This library is free software; you can redistribute it and/or * This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This library is distributed in the hope that it will be useful, * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Ported to mplayer by Arpi <arpi@thot.banki.hu>
* Ported to libavcodec by Nick Kurshev <nickols_k@mail.ru>
*
*/ */
/** /**
@@ -27,6 +28,12 @@
* svq1 code books. * svq1 code books.
*/ */
#ifndef FFMPEG_SVQ1_CB_H
#define FFMPEG_SVQ1_CB_H
#include <stdint.h>
#include <stdlib.h>
/* 6x16-entry codebook for inter-coded 4x2 vectors */ /* 6x16-entry codebook for inter-coded 4x2 vectors */
static const int8_t svq1_inter_codebook_4x2[768] = { static const int8_t svq1_inter_codebook_4x2[768] = {
7, 2, -6, -7, 7, 3, -3, -4, -7, -2, 7, 8, -8, -4, 3, 4, 7, 2, -6, -7, 7, 3, -3, -4, -7, -2, 7, 8, -8, -4, 3, 4,
@@ -764,9 +771,10 @@ static const int8_t svq1_inter_codebook_8x8[6144] = {
}; };
/* list of codebooks for inter-coded vectors */ /* list of codebooks for inter-coded vectors */
static const uint8_t* const svq1_inter_codebooks[4] = { const int8_t* const ff_svq1_inter_codebooks[6] = {
svq1_inter_codebook_4x2, svq1_inter_codebook_4x4, svq1_inter_codebook_4x2, svq1_inter_codebook_4x4,
svq1_inter_codebook_8x4, svq1_inter_codebook_8x8 svq1_inter_codebook_8x4, svq1_inter_codebook_8x8,
NULL, NULL,
}; };
/* 6x16-entry codebook for intra-coded 4x2 vectors */ /* 6x16-entry codebook for intra-coded 4x2 vectors */
@@ -1506,7 +1514,10 @@ static const int8_t svq1_intra_codebook_8x8[6144] = {
}; };
/* list of codebooks for intra-coded vectors */ /* list of codebooks for intra-coded vectors */
static const uint8_t* const svq1_intra_codebooks[4] = { const int8_t* const ff_svq1_intra_codebooks[6] = {
svq1_intra_codebook_4x2, svq1_intra_codebook_4x4, svq1_intra_codebook_4x2, svq1_intra_codebook_4x4,
svq1_intra_codebook_8x4, svq1_intra_codebook_8x8 svq1_intra_codebook_8x4, svq1_intra_codebook_8x8,
NULL, NULL,
}; };
#endif /* FFMPEG_SVQ1_CB_H */
@@ -1,37 +1,37 @@
#ifndef SVQ1_VLC_H /*
#define SVQ1_VLC_H * copyright (C) 2003 the ffmpeg project
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FFMPEG_SVQ1_VLC_H
#define FFMPEG_SVQ1_VLC_H
#include <stdint.h>
/* values in this table range from 0..3; adjust retrieved value by +0 */ /* values in this table range from 0..3; adjust retrieved value by +0 */
static const uint8_t svq1_block_type_vlc[4][2] = { const uint8_t ff_svq1_block_type_vlc[4][2] = {
/* { code, length } */ /* { code, length } */
{ 0x1, 1 }, { 0x1, 2 }, { 0x1, 3 }, { 0x0, 3 } { 0x1, 1 }, { 0x1, 2 }, { 0x1, 3 }, { 0x0, 3 }
}; };
/* values in this table range from -32..32; adjust retrieved value by -32 */
static const uint16_t svq1_motion_component_vlc[65][2] = {
/* { code, length } */
{ 0x5, 13 }, { 0x7, 13 }, { 0x5, 12 }, { 0x7, 12 },
{ 0x9, 12 }, { 0xB, 12 }, { 0xD, 12 }, { 0xF, 12 },
{ 0x9, 11 }, { 0xB, 11 }, { 0xD, 11 }, { 0xF, 11 },
{ 0x11, 11 }, { 0x13, 11 }, { 0x15, 11 }, { 0x17, 11 },
{ 0x19, 11 }, { 0x1B, 11 }, { 0x1D, 11 }, { 0x1F, 11 },
{ 0x21, 11 }, { 0x23, 11 }, { 0x13, 10 }, { 0x15, 10 },
{ 0x17, 10 }, { 0x7, 8 }, { 0x9, 8 }, { 0xB, 8 },
{ 0x7, 7 }, { 0x3, 5 }, { 0x3, 4 }, { 0x3, 3 },
{ 0x1, 1 }, { 0x2, 3 }, { 0x2, 4 }, { 0x2, 5 },
{ 0x6, 7 }, { 0xA, 8 }, { 0x8, 8 }, { 0x6, 8 },
{ 0x16, 10 }, { 0x14, 10 }, { 0x12, 10 }, { 0x22, 11 },
{ 0x20, 11 }, { 0x1E, 11 }, { 0x1C, 11 }, { 0x1A, 11 },
{ 0x18, 11 }, { 0x16, 11 }, { 0x14, 11 }, { 0x12, 11 },
{ 0x10, 11 }, { 0xE, 11 }, { 0xC, 11 }, { 0xA, 11 },
{ 0x8, 11 }, { 0xE, 12 }, { 0xC, 12 }, { 0xA, 12 },
{ 0x8, 12 }, { 0x6, 12 }, { 0x4, 12 }, { 0x6, 13 },
{ 0x4, 13 }
};
/* values in this table range from -1..6; adjust retrieved value by -1 */ /* values in this table range from -1..6; adjust retrieved value by -1 */
static const uint8_t svq1_intra_multistage_vlc[6][8][2] = { const uint8_t ff_svq1_intra_multistage_vlc[6][8][2] = {
/* { code, length } */ /* { code, length } */
{ {
{ 0x1, 5 }, { 0x1, 1 }, { 0x3, 3 }, { 0x2, 3 }, { 0x1, 5 }, { 0x1, 1 }, { 0x3, 3 }, { 0x2, 3 },
@@ -55,7 +55,7 @@ static const uint8_t svq1_intra_multistage_vlc[6][8][2] = {
}; };
/* values in this table range from -1..6; adjust retrieved value by -1 */ /* values in this table range from -1..6; adjust retrieved value by -1 */
static const uint8_t svq1_inter_multistage_vlc[6][8][2] = { const uint8_t ff_svq1_inter_multistage_vlc[6][8][2] = {
/* { code, length } */ /* { code, length } */
{ {
{ 0x3, 2 }, { 0x5, 3 }, { 0x4, 3 }, { 0x3, 3 }, { 0x3, 2 }, { 0x5, 3 }, { 0x4, 3 }, { 0x3, 3 },
@@ -79,7 +79,7 @@ static const uint8_t svq1_inter_multistage_vlc[6][8][2] = {
}; };
/* values in this table range from 0..255; adjust retrieved value by +0 */ /* values in this table range from 0..255; adjust retrieved value by +0 */
static const uint16_t svq1_intra_mean_vlc[256][2] = { const uint16_t ff_svq1_intra_mean_vlc[256][2] = {
/* { code, length } */ /* { code, length } */
{ 0x37, 6 }, { 0x56, 7 }, { 0x1, 17 }, { 0x1, 20 }, { 0x37, 6 }, { 0x56, 7 }, { 0x1, 17 }, { 0x1, 20 },
{ 0x2, 20 }, { 0x3, 20 }, { 0x0, 20 }, { 0x4, 20 }, { 0x2, 20 }, { 0x3, 20 }, { 0x0, 20 }, { 0x4, 20 },
@@ -148,7 +148,7 @@ static const uint16_t svq1_intra_mean_vlc[256][2] = {
}; };
/* values in this table range from -256..255; adjust retrieved value by -256 */ /* values in this table range from -256..255; adjust retrieved value by -256 */
static const uint16_t svq1_inter_mean_vlc[512][2] = { const uint16_t ff_svq1_inter_mean_vlc[512][2] = {
/* { code, length } */ /* { code, length } */
{ 0x5A, 22 }, { 0xD4, 22 }, { 0xD5, 22 }, { 0xD6, 22 }, { 0x5A, 22 }, { 0xD4, 22 }, { 0xD5, 22 }, { 0xD6, 22 },
{ 0xD7, 22 }, { 0xD8, 22 }, { 0xD9, 22 }, { 0xDA, 22 }, { 0xD7, 22 }, { 0xD8, 22 }, { 0xD9, 22 }, { 0xDA, 22 },
@@ -280,4 +280,4 @@ static const uint16_t svq1_inter_mean_vlc[512][2] = {
{ 0x3, 22 }, { 0x2, 22 }, { 0x1, 22 }, { 0x0, 22 } { 0x3, 22 }, { 0x2, 22 }, { 0x1, 22 }, { 0x0, 22 }
}; };
#endif #endif /* FFMPEG_SVQ1_VLC_H */
@@ -0,0 +1,830 @@
/*
* SVQ1 decoder
* ported to MPlayer by Arpi <arpi@thot.banki.hu>
* ported to libavcodec by Nick Kurshev <nickols_k@mail.ru>
*
* Copyright (C) 2002 the xine project
* Copyright (C) 2002 the ffmpeg project
*
* SVQ1 Encoder (c) 2004 Mike Melanson <melanson@pcisys.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 svq1.c
* Sorenson Vector Quantizer #1 (SVQ1) video codec.
* For more information of the SVQ1 algorithm, visit:
* http://www.pcisys.net/~melanson/codecs/
*/
//#define DEBUG_SVQ1
#include "avcodec.h"
#include "dsputil.h"
#include "mpegvideo.h"
#include "svq1.h"
#undef NDEBUG
#include <assert.h>
extern const uint8_t mvtab[33][2];
static VLC svq1_block_type;
static VLC svq1_motion_component;
static VLC svq1_intra_multistage[6];
static VLC svq1_inter_multistage[6];
static VLC svq1_intra_mean;
static VLC svq1_inter_mean;
/* motion vector (prediction) */
typedef struct svq1_pmv_s {
int x;
int y;
} svq1_pmv_t;
static const uint16_t checksum_table[256] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
};
static const uint8_t string_table[256] = {
0x00, 0xD5, 0x7F, 0xAA, 0xFE, 0x2B, 0x81, 0x54,
0x29, 0xFC, 0x56, 0x83, 0xD7, 0x02, 0xA8, 0x7D,
0x52, 0x87, 0x2D, 0xF8, 0xAC, 0x79, 0xD3, 0x06,
0x7B, 0xAE, 0x04, 0xD1, 0x85, 0x50, 0xFA, 0x2F,
0xA4, 0x71, 0xDB, 0x0E, 0x5A, 0x8F, 0x25, 0xF0,
0x8D, 0x58, 0xF2, 0x27, 0x73, 0xA6, 0x0C, 0xD9,
0xF6, 0x23, 0x89, 0x5C, 0x08, 0xDD, 0x77, 0xA2,
0xDF, 0x0A, 0xA0, 0x75, 0x21, 0xF4, 0x5E, 0x8B,
0x9D, 0x48, 0xE2, 0x37, 0x63, 0xB6, 0x1C, 0xC9,
0xB4, 0x61, 0xCB, 0x1E, 0x4A, 0x9F, 0x35, 0xE0,
0xCF, 0x1A, 0xB0, 0x65, 0x31, 0xE4, 0x4E, 0x9B,
0xE6, 0x33, 0x99, 0x4C, 0x18, 0xCD, 0x67, 0xB2,
0x39, 0xEC, 0x46, 0x93, 0xC7, 0x12, 0xB8, 0x6D,
0x10, 0xC5, 0x6F, 0xBA, 0xEE, 0x3B, 0x91, 0x44,
0x6B, 0xBE, 0x14, 0xC1, 0x95, 0x40, 0xEA, 0x3F,
0x42, 0x97, 0x3D, 0xE8, 0xBC, 0x69, 0xC3, 0x16,
0xEF, 0x3A, 0x90, 0x45, 0x11, 0xC4, 0x6E, 0xBB,
0xC6, 0x13, 0xB9, 0x6C, 0x38, 0xED, 0x47, 0x92,
0xBD, 0x68, 0xC2, 0x17, 0x43, 0x96, 0x3C, 0xE9,
0x94, 0x41, 0xEB, 0x3E, 0x6A, 0xBF, 0x15, 0xC0,
0x4B, 0x9E, 0x34, 0xE1, 0xB5, 0x60, 0xCA, 0x1F,
0x62, 0xB7, 0x1D, 0xC8, 0x9C, 0x49, 0xE3, 0x36,
0x19, 0xCC, 0x66, 0xB3, 0xE7, 0x32, 0x98, 0x4D,
0x30, 0xE5, 0x4F, 0x9A, 0xCE, 0x1B, 0xB1, 0x64,
0x72, 0xA7, 0x0D, 0xD8, 0x8C, 0x59, 0xF3, 0x26,
0x5B, 0x8E, 0x24, 0xF1, 0xA5, 0x70, 0xDA, 0x0F,
0x20, 0xF5, 0x5F, 0x8A, 0xDE, 0x0B, 0xA1, 0x74,
0x09, 0xDC, 0x76, 0xA3, 0xF7, 0x22, 0x88, 0x5D,
0xD6, 0x03, 0xA9, 0x7C, 0x28, 0xFD, 0x57, 0x82,
0xFF, 0x2A, 0x80, 0x55, 0x01, 0xD4, 0x7E, 0xAB,
0x84, 0x51, 0xFB, 0x2E, 0x7A, 0xAF, 0x05, 0xD0,
0xAD, 0x78, 0xD2, 0x07, 0x53, 0x86, 0x2C, 0xF9
};
#define SVQ1_PROCESS_VECTOR()\
for (; level > 0; i++) {\
/* process next depth */\
if (i == m) {\
m = n;\
if (--level == 0)\
break;\
}\
/* divide block if next bit set */\
if (get_bits1 (bitbuf) == 0)\
break;\
/* add child nodes */\
list[n++] = list[i];\
list[n++] = list[i] + (((level & 1) ? pitch : 1) << ((level / 2) + 1));\
}
#define SVQ1_ADD_CODEBOOK()\
/* add codebook entries to vector */\
for (j=0; j < stages; j++) {\
n3 = codebook[entries[j]] ^ 0x80808080;\
n1 += ((n3 & 0xFF00FF00) >> 8);\
n2 += (n3 & 0x00FF00FF);\
}\
\
/* clip to [0..255] */\
if (n1 & 0xFF00FF00) {\
n3 = ((( n1 >> 15) & 0x00010001) | 0x01000100) - 0x00010001;\
n1 += 0x7F007F00;\
n1 |= (((~n1 >> 15) & 0x00010001) | 0x01000100) - 0x00010001;\
n1 &= (n3 & 0x00FF00FF);\
}\
\
if (n2 & 0xFF00FF00) {\
n3 = ((( n2 >> 15) & 0x00010001) | 0x01000100) - 0x00010001;\
n2 += 0x7F007F00;\
n2 |= (((~n2 >> 15) & 0x00010001) | 0x01000100) - 0x00010001;\
n2 &= (n3 & 0x00FF00FF);\
}
#define SVQ1_DO_CODEBOOK_INTRA()\
for (y=0; y < height; y++) {\
for (x=0; x < (width / 4); x++, codebook++) {\
n1 = n4;\
n2 = n4;\
SVQ1_ADD_CODEBOOK()\
/* store result */\
dst[x] = (n1 << 8) | n2;\
}\
dst += (pitch / 4);\
}
#define SVQ1_DO_CODEBOOK_NONINTRA()\
for (y=0; y < height; y++) {\
for (x=0; x < (width / 4); x++, codebook++) {\
n3 = dst[x];\
/* add mean value to vector */\
n1 = ((n3 & 0xFF00FF00) >> 8) + n4;\
n2 = (n3 & 0x00FF00FF) + n4;\
SVQ1_ADD_CODEBOOK()\
/* store result */\
dst[x] = (n1 << 8) | n2;\
}\
dst += (pitch / 4);\
}
#define SVQ1_CALC_CODEBOOK_ENTRIES(cbook)\
codebook = (const uint32_t *) cbook[level];\
bit_cache = get_bits (bitbuf, 4*stages);\
/* calculate codebook entries for this vector */\
for (j=0; j < stages; j++) {\
entries[j] = (((bit_cache >> (4*(stages - j - 1))) & 0xF) + 16*j) << (level + 1);\
}\
mean -= (stages * 128);\
n4 = ((mean + (mean >> 31)) << 16) | (mean & 0xFFFF);
static int svq1_decode_block_intra (GetBitContext *bitbuf, uint8_t *pixels, int pitch ) {
uint32_t bit_cache;
uint8_t *list[63];
uint32_t *dst;
const uint32_t *codebook;
int entries[6];
int i, j, m, n;
int mean, stages;
unsigned x, y, width, height, level;
uint32_t n1, n2, n3, n4;
/* initialize list for breadth first processing of vectors */
list[0] = pixels;
/* recursively process vector */
for (i=0, m=1, n=1, level=5; i < n; i++) {
SVQ1_PROCESS_VECTOR();
/* destination address and vector size */
dst = (uint32_t *) list[i];
width = 1 << ((4 + level) /2);
height = 1 << ((3 + level) /2);
/* get number of stages (-1 skips vector, 0 for mean only) */
stages = get_vlc2(bitbuf, svq1_intra_multistage[level].table, 3, 3) - 1;
if (stages == -1) {
for (y=0; y < height; y++) {
memset (&dst[y*(pitch / 4)], 0, width);
}
continue; /* skip vector */
}
if ((stages > 0) && (level >= 4)) {
#ifdef DEBUG_SVQ1
av_log(s->avctx, AV_LOG_INFO, "Error (svq1_decode_block_intra): invalid vector: stages=%i level=%i\n",stages,level);
#endif
return -1; /* invalid vector */
}
mean = get_vlc2(bitbuf, svq1_intra_mean.table, 8, 3);
if (stages == 0) {
for (y=0; y < height; y++) {
memset (&dst[y*(pitch / 4)], mean, width);
}
} else {
SVQ1_CALC_CODEBOOK_ENTRIES(ff_svq1_intra_codebooks);
SVQ1_DO_CODEBOOK_INTRA()
}
}
return 0;
}
static int svq1_decode_block_non_intra (GetBitContext *bitbuf, uint8_t *pixels, int pitch ) {
uint32_t bit_cache;
uint8_t *list[63];
uint32_t *dst;
const uint32_t *codebook;
int entries[6];
int i, j, m, n;
int mean, stages;
int x, y, width, height, level;
uint32_t n1, n2, n3, n4;
/* initialize list for breadth first processing of vectors */
list[0] = pixels;
/* recursively process vector */
for (i=0, m=1, n=1, level=5; i < n; i++) {
SVQ1_PROCESS_VECTOR();
/* destination address and vector size */
dst = (uint32_t *) list[i];
width = 1 << ((4 + level) /2);
height = 1 << ((3 + level) /2);
/* get number of stages (-1 skips vector, 0 for mean only) */
stages = get_vlc2(bitbuf, svq1_inter_multistage[level].table, 3, 2) - 1;
if (stages == -1) continue; /* skip vector */
if ((stages > 0) && (level >= 4)) {
#ifdef DEBUG_SVQ1
av_log(s->avctx, AV_LOG_INFO, "Error (svq1_decode_block_non_intra): invalid vector: stages=%i level=%i\n",stages,level);
#endif
return -1; /* invalid vector */
}
mean = get_vlc2(bitbuf, svq1_inter_mean.table, 9, 3) - 256;
SVQ1_CALC_CODEBOOK_ENTRIES(ff_svq1_inter_codebooks);
SVQ1_DO_CODEBOOK_NONINTRA()
}
return 0;
}
static int svq1_decode_motion_vector (GetBitContext *bitbuf, svq1_pmv_t *mv, svq1_pmv_t **pmv) {
int diff;
int i;
for (i=0; i < 2; i++) {
/* get motion code */
diff = get_vlc2(bitbuf, svq1_motion_component.table, 7, 2);
if(diff<0)
return -1;
else if(diff){
if(get_bits1(bitbuf)) diff= -diff;
}
/* add median of motion vector predictors and clip result */
if (i == 1)
mv->y = ((diff + mid_pred(pmv[0]->y, pmv[1]->y, pmv[2]->y)) << 26) >> 26;
else
mv->x = ((diff + mid_pred(pmv[0]->x, pmv[1]->x, pmv[2]->x)) << 26) >> 26;
}
return 0;
}
static void svq1_skip_block (uint8_t *current, uint8_t *previous, int pitch, int x, int y) {
uint8_t *src;
uint8_t *dst;
int i;
src = &previous[x + y*pitch];
dst = current;
for (i=0; i < 16; i++) {
memcpy (dst, src, 16);
src += pitch;
dst += pitch;
}
}
static int svq1_motion_inter_block (MpegEncContext *s, GetBitContext *bitbuf,
uint8_t *current, uint8_t *previous, int pitch,
svq1_pmv_t *motion, int x, int y) {
uint8_t *src;
uint8_t *dst;
svq1_pmv_t mv;
svq1_pmv_t *pmv[3];
int result;
/* predict and decode motion vector */
pmv[0] = &motion[0];
if (y == 0) {
pmv[1] =
pmv[2] = pmv[0];
}
else {
pmv[1] = &motion[(x / 8) + 2];
pmv[2] = &motion[(x / 8) + 4];
}
result = svq1_decode_motion_vector (bitbuf, &mv, pmv);
if (result != 0)
return result;
motion[0].x =
motion[(x / 8) + 2].x =
motion[(x / 8) + 3].x = mv.x;
motion[0].y =
motion[(x / 8) + 2].y =
motion[(x / 8) + 3].y = mv.y;
if(y + (mv.y >> 1)<0)
mv.y= 0;
if(x + (mv.x >> 1)<0)
mv.x= 0;
#if 0
int w= (s->width+15)&~15;
int h= (s->height+15)&~15;
if(x + (mv.x >> 1)<0 || y + (mv.y >> 1)<0 || x + (mv.x >> 1) + 16 > w || y + (mv.y >> 1) + 16> h)
av_log(s->avctx, AV_LOG_INFO, "%d %d %d %d\n", x, y, x + (mv.x >> 1), y + (mv.y >> 1));
#endif
src = &previous[(x + (mv.x >> 1)) + (y + (mv.y >> 1))*pitch];
dst = current;
s->dsp.put_pixels_tab[0][((mv.y & 1) << 1) | (mv.x & 1)](dst,src,pitch,16);
return 0;
}
static int svq1_motion_inter_4v_block (MpegEncContext *s, GetBitContext *bitbuf,
uint8_t *current, uint8_t *previous, int pitch,
svq1_pmv_t *motion,int x, int y) {
uint8_t *src;
uint8_t *dst;
svq1_pmv_t mv;
svq1_pmv_t *pmv[4];
int i, result;
/* predict and decode motion vector (0) */
pmv[0] = &motion[0];
if (y == 0) {
pmv[1] =
pmv[2] = pmv[0];
}
else {
pmv[1] = &motion[(x / 8) + 2];
pmv[2] = &motion[(x / 8) + 4];
}
result = svq1_decode_motion_vector (bitbuf, &mv, pmv);
if (result != 0)
return result;
/* predict and decode motion vector (1) */
pmv[0] = &mv;
if (y == 0) {
pmv[1] =
pmv[2] = pmv[0];
}
else {
pmv[1] = &motion[(x / 8) + 3];
}
result = svq1_decode_motion_vector (bitbuf, &motion[0], pmv);
if (result != 0)
return result;
/* predict and decode motion vector (2) */
pmv[1] = &motion[0];
pmv[2] = &motion[(x / 8) + 1];
result = svq1_decode_motion_vector (bitbuf, &motion[(x / 8) + 2], pmv);
if (result != 0)
return result;
/* predict and decode motion vector (3) */
pmv[2] = &motion[(x / 8) + 2];
pmv[3] = &motion[(x / 8) + 3];
result = svq1_decode_motion_vector (bitbuf, pmv[3], pmv);
if (result != 0)
return result;
/* form predictions */
for (i=0; i < 4; i++) {
int mvx= pmv[i]->x + (i&1)*16;
int mvy= pmv[i]->y + (i>>1)*16;
///XXX /FIXME clipping or padding?
if(y + (mvy >> 1)<0)
mvy= 0;
if(x + (mvx >> 1)<0)
mvx= 0;
#if 0
int w= (s->width+15)&~15;
int h= (s->height+15)&~15;
if(x + (mvx >> 1)<0 || y + (mvy >> 1)<0 || x + (mvx >> 1) + 8 > w || y + (mvy >> 1) + 8> h)
av_log(s->avctx, AV_LOG_INFO, "%d %d %d %d\n", x, y, x + (mvx >> 1), y + (mvy >> 1));
#endif
src = &previous[(x + (mvx >> 1)) + (y + (mvy >> 1))*pitch];
dst = current;
s->dsp.put_pixels_tab[1][((mvy & 1) << 1) | (mvx & 1)](dst,src,pitch,8);
/* select next block */
if (i & 1) {
current += 8*(pitch - 1);
} else {
current += 8;
}
}
return 0;
}
static int svq1_decode_delta_block (MpegEncContext *s, GetBitContext *bitbuf,
uint8_t *current, uint8_t *previous, int pitch,
svq1_pmv_t *motion, int x, int y) {
uint32_t block_type;
int result = 0;
/* get block type */
block_type = get_vlc2(bitbuf, svq1_block_type.table, 2, 2);
/* reset motion vectors */
if (block_type == SVQ1_BLOCK_SKIP || block_type == SVQ1_BLOCK_INTRA) {
motion[0].x =
motion[0].y =
motion[(x / 8) + 2].x =
motion[(x / 8) + 2].y =
motion[(x / 8) + 3].x =
motion[(x / 8) + 3].y = 0;
}
switch (block_type) {
case SVQ1_BLOCK_SKIP:
svq1_skip_block (current, previous, pitch, x, y);
break;
case SVQ1_BLOCK_INTER:
result = svq1_motion_inter_block (s, bitbuf, current, previous, pitch, motion, x, y);
if (result != 0)
{
#ifdef DEBUG_SVQ1
av_log(s->avctx, AV_LOG_INFO, "Error in svq1_motion_inter_block %i\n",result);
#endif
break;
}
result = svq1_decode_block_non_intra (bitbuf, current, pitch);
break;
case SVQ1_BLOCK_INTER_4V:
result = svq1_motion_inter_4v_block (s, bitbuf, current, previous, pitch, motion, x, y);
if (result != 0)
{
#ifdef DEBUG_SVQ1
av_log(s->avctx, AV_LOG_INFO, "Error in svq1_motion_inter_4v_block %i\n",result);
#endif
break;
}
result = svq1_decode_block_non_intra (bitbuf, current, pitch);
break;
case SVQ1_BLOCK_INTRA:
result = svq1_decode_block_intra (bitbuf, current, pitch);
break;
}
return result;
}
static uint16_t svq1_packet_checksum (const uint8_t *data, const int length, int value) {
int i;
for (i=0; i < length; i++) {
value = checksum_table[data[i] ^ (value >> 8)] ^ ((value & 0xFF) << 8);
}
return value;
}
static void svq1_parse_string (GetBitContext *bitbuf, uint8_t *out) {
uint8_t seed;
int i;
out[0] = get_bits (bitbuf, 8);
seed = string_table[out[0]];
for (i=1; i <= out[0]; i++) {
out[i] = get_bits (bitbuf, 8) ^ seed;
seed = string_table[out[i] ^ seed];
}
}
static int svq1_decode_frame_header (GetBitContext *bitbuf,MpegEncContext *s) {
int frame_size_code;
int temporal_reference;
temporal_reference = get_bits (bitbuf, 8);
/* frame type */
s->pict_type= get_bits (bitbuf, 2)+1;
if(s->pict_type==4)
return -1;
if (s->pict_type == FF_I_TYPE) {
/* unknown fields */
if (s->f_code == 0x50 || s->f_code == 0x60) {
int csum = get_bits (bitbuf, 16);
csum = svq1_packet_checksum (bitbuf->buffer, bitbuf->size_in_bits>>3, csum);
// av_log(s->avctx, AV_LOG_INFO, "%s checksum (%02x) for packet data\n",
// (csum == 0) ? "correct" : "incorrect", csum);
}
if ((s->f_code ^ 0x10) >= 0x50) {
uint8_t msg[256];
svq1_parse_string (bitbuf, msg);
av_log(s->avctx, AV_LOG_INFO, "embedded message: \"%s\"\n", (char *) msg);
}
skip_bits (bitbuf, 2);
skip_bits (bitbuf, 2);
skip_bits1 (bitbuf);
/* load frame size */
frame_size_code = get_bits (bitbuf, 3);
if (frame_size_code == 7) {
/* load width, height (12 bits each) */
s->width = get_bits (bitbuf, 12);
s->height = get_bits (bitbuf, 12);
if (!s->width || !s->height)
return -1;
} else {
/* get width, height from table */
s->width = ff_svq1_frame_size_table[frame_size_code].width;
s->height = ff_svq1_frame_size_table[frame_size_code].height;
}
}
/* unknown fields */
if (get_bits1 (bitbuf) == 1) {
skip_bits1 (bitbuf); /* use packet checksum if (1) */
skip_bits1 (bitbuf); /* component checksums after image data if (1) */
if (get_bits (bitbuf, 2) != 0)
return -1;
}
if (get_bits1 (bitbuf) == 1) {
skip_bits1 (bitbuf);
skip_bits (bitbuf, 4);
skip_bits1 (bitbuf);
skip_bits (bitbuf, 2);
while (get_bits1 (bitbuf) == 1) {
skip_bits (bitbuf, 8);
}
}
return 0;
}
static int svq1_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
const uint8_t *buf, int buf_size)
{
MpegEncContext *s=avctx->priv_data;
uint8_t *current, *previous;
int result, i, x, y, width, height;
AVFrame *pict = data;
/* initialize bit buffer */
init_get_bits(&s->gb,buf,buf_size*8);
/* decode frame header */
s->f_code = get_bits (&s->gb, 22);
if ((s->f_code & ~0x70) || !(s->f_code & 0x60))
return -1;
/* swap some header bytes (why?) */
if (s->f_code != 0x20) {
uint32_t *src = (uint32_t *) (buf + 4);
for (i=0; i < 4; i++) {
src[i] = ((src[i] << 16) | (src[i] >> 16)) ^ src[7 - i];
}
}
result = svq1_decode_frame_header (&s->gb, s);
if (result != 0)
{
#ifdef DEBUG_SVQ1
av_log(s->avctx, AV_LOG_INFO, "Error in svq1_decode_frame_header %i\n",result);
#endif
return result;
}
//FIXME this avoids some confusion for "B frames" without 2 references
//this should be removed after libavcodec can handle more flexible picture types & ordering
if(s->pict_type==FF_B_TYPE && s->last_picture_ptr==NULL) return buf_size;
if(avctx->hurry_up && s->pict_type==FF_B_TYPE) return buf_size;
if( (avctx->skip_frame >= AVDISCARD_NONREF && s->pict_type==FF_B_TYPE)
||(avctx->skip_frame >= AVDISCARD_NONKEY && s->pict_type!=FF_I_TYPE)
|| avctx->skip_frame >= AVDISCARD_ALL)
return buf_size;
if(MPV_frame_start(s, avctx) < 0)
return -1;
/* decode y, u and v components */
for (i=0; i < 3; i++) {
int linesize;
if (i == 0) {
width = (s->width+15)&~15;
height = (s->height+15)&~15;
linesize= s->linesize;
} else {
if(s->flags&CODEC_FLAG_GRAY) break;
width = (s->width/4+15)&~15;
height = (s->height/4+15)&~15;
linesize= s->uvlinesize;
}
current = s->current_picture.data[i];
if(s->pict_type==FF_B_TYPE){
previous = s->next_picture.data[i];
}else{
previous = s->last_picture.data[i];
}
if (s->pict_type == FF_I_TYPE) {
/* keyframe */
for (y=0; y < height; y+=16) {
for (x=0; x < width; x+=16) {
result = svq1_decode_block_intra (&s->gb, &current[x], linesize);
if (result != 0)
{
//#ifdef DEBUG_SVQ1
av_log(s->avctx, AV_LOG_INFO, "Error in svq1_decode_block %i (keyframe)\n",result);
//#endif
return result;
}
}
current += 16*linesize;
}
} else {
svq1_pmv_t pmv[width/8+3];
/* delta frame */
memset (pmv, 0, ((width / 8) + 3) * sizeof(svq1_pmv_t));
for (y=0; y < height; y+=16) {
for (x=0; x < width; x+=16) {
result = svq1_decode_delta_block (s, &s->gb, &current[x], previous,
linesize, pmv, x, y);
if (result != 0)
{
#ifdef DEBUG_SVQ1
av_log(s->avctx, AV_LOG_INFO, "Error in svq1_decode_delta_block %i\n",result);
#endif
return result;
}
}
pmv[0].x =
pmv[0].y = 0;
current += 16*linesize;
}
}
}
*pict = *(AVFrame*)&s->current_picture;
MPV_frame_end(s);
*data_size=sizeof(AVFrame);
return buf_size;
}
static av_cold int svq1_decode_init(AVCodecContext *avctx)
{
MpegEncContext *s = avctx->priv_data;
int i;
MPV_decode_defaults(s);
s->avctx = avctx;
s->width = (avctx->width+3)&~3;
s->height = (avctx->height+3)&~3;
s->codec_id= avctx->codec->id;
avctx->pix_fmt = PIX_FMT_YUV410P;
avctx->has_b_frames= 1; // not true, but DP frames and these behave like unidirectional b frames
s->flags= avctx->flags;
if (MPV_common_init(s) < 0) return -1;
init_vlc(&svq1_block_type, 2, 4,
&ff_svq1_block_type_vlc[0][1], 2, 1,
&ff_svq1_block_type_vlc[0][0], 2, 1, 1);
init_vlc(&svq1_motion_component, 7, 33,
&mvtab[0][1], 2, 1,
&mvtab[0][0], 2, 1, 1);
for (i = 0; i < 6; i++) {
init_vlc(&svq1_intra_multistage[i], 3, 8,
&ff_svq1_intra_multistage_vlc[i][0][1], 2, 1,
&ff_svq1_intra_multistage_vlc[i][0][0], 2, 1, 1);
init_vlc(&svq1_inter_multistage[i], 3, 8,
&ff_svq1_inter_multistage_vlc[i][0][1], 2, 1,
&ff_svq1_inter_multistage_vlc[i][0][0], 2, 1, 1);
}
init_vlc(&svq1_intra_mean, 8, 256,
&ff_svq1_intra_mean_vlc[0][1], 4, 2,
&ff_svq1_intra_mean_vlc[0][0], 4, 2, 1);
init_vlc(&svq1_inter_mean, 9, 512,
&ff_svq1_inter_mean_vlc[0][1], 4, 2,
&ff_svq1_inter_mean_vlc[0][0], 4, 2, 1);
return 0;
}
static av_cold int svq1_decode_end(AVCodecContext *avctx)
{
MpegEncContext *s = avctx->priv_data;
MPV_common_end(s);
return 0;
}
AVCodec svq1_decoder = {
"svq1",
CODEC_TYPE_VIDEO,
CODEC_ID_SVQ1,
sizeof(MpegEncContext),
svq1_decode_init,
NULL,
svq1_decode_end,
svq1_decode_frame,
CODEC_CAP_DR1,
.flush= ff_mpeg_flush,
.pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV410P, PIX_FMT_NONE},
.long_name= NULL_IF_CONFIG_SMALL("Sorenson Vector Quantizer 1"),
};
@@ -0,0 +1,589 @@
/*
* SVQ1 Encoder
* Copyright (C) 2004 Mike Melanson <melanson@pcisys.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 svq1enc.c
* Sorenson Vector Quantizer #1 (SVQ1) video codec.
* For more information of the SVQ1 algorithm, visit:
* http://www.pcisys.net/~melanson/codecs/
*/
#include "avcodec.h"
#include "dsputil.h"
#include "mpegvideo.h"
#include "svq1.h"
#include "svq1enc_cb.h"
#undef NDEBUG
#include <assert.h>
typedef struct SVQ1Context {
MpegEncContext m; // needed for motion estimation, should not be used for anything else, the idea is to make the motion estimation eventually independent of MpegEncContext, so this will be removed then (FIXME/XXX)
AVCodecContext *avctx;
DSPContext dsp;
AVFrame picture;
AVFrame current_picture;
AVFrame last_picture;
PutBitContext pb;
GetBitContext gb;
PutBitContext reorder_pb[6]; //why ooh why this sick breadth first order, everything is slower and more complex
int frame_width;
int frame_height;
/* Y plane block dimensions */
int y_block_width;
int y_block_height;
/* U & V plane (C planes) block dimensions */
int c_block_width;
int c_block_height;
uint16_t *mb_type;
uint32_t *dummy;
int16_t (*motion_val8[3])[2];
int16_t (*motion_val16[3])[2];
int64_t rd_total;
} SVQ1Context;
static void svq1_write_header(SVQ1Context *s, int frame_type)
{
int i;
/* frame code */
put_bits(&s->pb, 22, 0x20);
/* temporal reference (sure hope this is a "don't care") */
put_bits(&s->pb, 8, 0x00);
/* frame type */
put_bits(&s->pb, 2, frame_type - 1);
if (frame_type == FF_I_TYPE) {
/* no checksum since frame code is 0x20 */
/* no embedded string either */
/* output 5 unknown bits (2 + 2 + 1) */
put_bits(&s->pb, 5, 2); /* 2 needed by quicktime decoder */
for (i = 0; i < 7; i++)
{
if ((ff_svq1_frame_size_table[i].width == s->frame_width) &&
(ff_svq1_frame_size_table[i].height == s->frame_height))
{
put_bits(&s->pb, 3, i);
break;
}
}
if (i == 7)
{
put_bits(&s->pb, 3, 7);
put_bits(&s->pb, 12, s->frame_width);
put_bits(&s->pb, 12, s->frame_height);
}
}
/* no checksum or extra data (next 2 bits get 0) */
put_bits(&s->pb, 2, 0);
}
#define QUALITY_THRESHOLD 100
#define THRESHOLD_MULTIPLIER 0.6
#if defined(HAVE_ALTIVEC)
#undef vector
#endif
static int encode_block(SVQ1Context *s, uint8_t *src, uint8_t *ref, uint8_t *decoded, int stride, int level, int threshold, int lambda, int intra){
int count, y, x, i, j, split, best_mean, best_score, best_count;
int best_vector[6];
int block_sum[7]= {0, 0, 0, 0, 0, 0};
int w= 2<<((level+2)>>1);
int h= 2<<((level+1)>>1);
int size=w*h;
int16_t block[7][256];
const int8_t *codebook_sum, *codebook;
const uint16_t (*mean_vlc)[2];
const uint8_t (*multistage_vlc)[2];
best_score=0;
//FIXME optimize, this doenst need to be done multiple times
if(intra){
codebook_sum= svq1_intra_codebook_sum[level];
codebook= ff_svq1_intra_codebooks[level];
mean_vlc= ff_svq1_intra_mean_vlc;
multistage_vlc= ff_svq1_intra_multistage_vlc[level];
for(y=0; y<h; y++){
for(x=0; x<w; x++){
int v= src[x + y*stride];
block[0][x + w*y]= v;
best_score += v*v;
block_sum[0] += v;
}
}
}else{
codebook_sum= svq1_inter_codebook_sum[level];
codebook= ff_svq1_inter_codebooks[level];
mean_vlc= ff_svq1_inter_mean_vlc + 256;
multistage_vlc= ff_svq1_inter_multistage_vlc[level];
for(y=0; y<h; y++){
for(x=0; x<w; x++){
int v= src[x + y*stride] - ref[x + y*stride];
block[0][x + w*y]= v;
best_score += v*v;
block_sum[0] += v;
}
}
}
best_count=0;
best_score -= ((block_sum[0]*block_sum[0])>>(level+3));
best_mean= (block_sum[0] + (size>>1)) >> (level+3);
if(level<4){
for(count=1; count<7; count++){
int best_vector_score= INT_MAX;
int best_vector_sum=-999, best_vector_mean=-999;
const int stage= count-1;
const int8_t *vector;
for(i=0; i<16; i++){
int sum= codebook_sum[stage*16 + i];
int sqr, diff, score;
vector = codebook + stage*size*16 + i*size;
sqr = s->dsp.ssd_int8_vs_int16(vector, block[stage], size);
diff= block_sum[stage] - sum;
score= sqr - ((diff*(int64_t)diff)>>(level+3)); //FIXME 64bit slooow
if(score < best_vector_score){
int mean= (diff + (size>>1)) >> (level+3);
assert(mean >-300 && mean<300);
mean= av_clip(mean, intra?0:-256, 255);
best_vector_score= score;
best_vector[stage]= i;
best_vector_sum= sum;
best_vector_mean= mean;
}
}
assert(best_vector_mean != -999);
vector= codebook + stage*size*16 + best_vector[stage]*size;
for(j=0; j<size; j++){
block[stage+1][j] = block[stage][j] - vector[j];
}
block_sum[stage+1]= block_sum[stage] - best_vector_sum;
best_vector_score +=
lambda*(+ 1 + 4*count
+ multistage_vlc[1+count][1]
+ mean_vlc[best_vector_mean][1]);
if(best_vector_score < best_score){
best_score= best_vector_score;
best_count= count;
best_mean= best_vector_mean;
}
}
}
split=0;
if(best_score > threshold && level){
int score=0;
int offset= (level&1) ? stride*h/2 : w/2;
PutBitContext backup[6];
for(i=level-1; i>=0; i--){
backup[i]= s->reorder_pb[i];
}
score += encode_block(s, src , ref , decoded , stride, level-1, threshold>>1, lambda, intra);
score += encode_block(s, src + offset, ref + offset, decoded + offset, stride, level-1, threshold>>1, lambda, intra);
score += lambda;
if(score < best_score){
best_score= score;
split=1;
}else{
for(i=level-1; i>=0; i--){
s->reorder_pb[i]= backup[i];
}
}
}
if (level > 0)
put_bits(&s->reorder_pb[level], 1, split);
if(!split){
assert((best_mean >= 0 && best_mean<256) || !intra);
assert(best_mean >= -256 && best_mean<256);
assert(best_count >=0 && best_count<7);
assert(level<4 || best_count==0);
/* output the encoding */
put_bits(&s->reorder_pb[level],
multistage_vlc[1 + best_count][1],
multistage_vlc[1 + best_count][0]);
put_bits(&s->reorder_pb[level], mean_vlc[best_mean][1],
mean_vlc[best_mean][0]);
for (i = 0; i < best_count; i++){
assert(best_vector[i]>=0 && best_vector[i]<16);
put_bits(&s->reorder_pb[level], 4, best_vector[i]);
}
for(y=0; y<h; y++){
for(x=0; x<w; x++){
decoded[x + y*stride]= src[x + y*stride] - block[best_count][x + w*y] + best_mean;
}
}
}
return best_score;
}
static int svq1_encode_plane(SVQ1Context *s, int plane, unsigned char *src_plane, unsigned char *ref_plane, unsigned char *decoded_plane,
int width, int height, int src_stride, int stride)
{
int x, y;
int i;
int block_width, block_height;
int level;
int threshold[6];
const int lambda= (s->picture.quality*s->picture.quality) >> (2*FF_LAMBDA_SHIFT);
/* figure out the acceptable level thresholds in advance */
threshold[5] = QUALITY_THRESHOLD;
for (level = 4; level >= 0; level--)
threshold[level] = threshold[level + 1] * THRESHOLD_MULTIPLIER;
block_width = (width + 15) / 16;
block_height = (height + 15) / 16;
if(s->picture.pict_type == FF_P_TYPE){
s->m.avctx= s->avctx;
s->m.current_picture_ptr= &s->m.current_picture;
s->m.last_picture_ptr = &s->m.last_picture;
s->m.last_picture.data[0]= ref_plane;
s->m.linesize=
s->m.last_picture.linesize[0]=
s->m.new_picture.linesize[0]=
s->m.current_picture.linesize[0]= stride;
s->m.width= width;
s->m.height= height;
s->m.mb_width= block_width;
s->m.mb_height= block_height;
s->m.mb_stride= s->m.mb_width+1;
s->m.b8_stride= 2*s->m.mb_width+1;
s->m.f_code=1;
s->m.pict_type= s->picture.pict_type;
s->m.me_method= s->avctx->me_method;
s->m.me.scene_change_score=0;
s->m.flags= s->avctx->flags;
// s->m.out_format = FMT_H263;
// s->m.unrestricted_mv= 1;
s->m.lambda= s->picture.quality;
s->m.qscale= (s->m.lambda*139 + FF_LAMBDA_SCALE*64) >> (FF_LAMBDA_SHIFT + 7);
s->m.lambda2= (s->m.lambda*s->m.lambda + FF_LAMBDA_SCALE/2) >> FF_LAMBDA_SHIFT;
if(!s->motion_val8[plane]){
s->motion_val8 [plane]= av_mallocz((s->m.b8_stride*block_height*2 + 2)*2*sizeof(int16_t));
s->motion_val16[plane]= av_mallocz((s->m.mb_stride*(block_height + 2) + 1)*2*sizeof(int16_t));
}
s->m.mb_type= s->mb_type;
//dummies, to avoid segfaults
s->m.current_picture.mb_mean= (uint8_t *)s->dummy;
s->m.current_picture.mb_var= (uint16_t*)s->dummy;
s->m.current_picture.mc_mb_var= (uint16_t*)s->dummy;
s->m.current_picture.mb_type= s->dummy;
s->m.current_picture.motion_val[0]= s->motion_val8[plane] + 2;
s->m.p_mv_table= s->motion_val16[plane] + s->m.mb_stride + 1;
s->m.dsp= s->dsp; //move
ff_init_me(&s->m);
s->m.me.dia_size= s->avctx->dia_size;
s->m.first_slice_line=1;
for (y = 0; y < block_height; y++) {
uint8_t src[stride*16];
s->m.new_picture.data[0]= src - y*16*stride; //ugly
s->m.mb_y= y;
for(i=0; i<16 && i + 16*y<height; i++){
memcpy(&src[i*stride], &src_plane[(i+16*y)*src_stride], width);
for(x=width; x<16*block_width; x++)
src[i*stride+x]= src[i*stride+x-1];
}
for(; i<16 && i + 16*y<16*block_height; i++)
memcpy(&src[i*stride], &src[(i-1)*stride], 16*block_width);
for (x = 0; x < block_width; x++) {
s->m.mb_x= x;
ff_init_block_index(&s->m);
ff_update_block_index(&s->m);
ff_estimate_p_frame_motion(&s->m, x, y);
}
s->m.first_slice_line=0;
}
ff_fix_long_p_mvs(&s->m);
ff_fix_long_mvs(&s->m, NULL, 0, s->m.p_mv_table, s->m.f_code, CANDIDATE_MB_TYPE_INTER, 0);
}
s->m.first_slice_line=1;
for (y = 0; y < block_height; y++) {
uint8_t src[stride*16];
for(i=0; i<16 && i + 16*y<height; i++){
memcpy(&src[i*stride], &src_plane[(i+16*y)*src_stride], width);
for(x=width; x<16*block_width; x++)
src[i*stride+x]= src[i*stride+x-1];
}
for(; i<16 && i + 16*y<16*block_height; i++)
memcpy(&src[i*stride], &src[(i-1)*stride], 16*block_width);
s->m.mb_y= y;
for (x = 0; x < block_width; x++) {
uint8_t reorder_buffer[3][6][7*32];
int count[3][6];
int offset = y * 16 * stride + x * 16;
uint8_t *decoded= decoded_plane + offset;
uint8_t *ref= ref_plane + offset;
int score[4]={0,0,0,0}, best;
uint8_t temp[16*stride];
if(s->pb.buf_end - s->pb.buf - (put_bits_count(&s->pb)>>3) < 3000){ //FIXME check size
av_log(s->avctx, AV_LOG_ERROR, "encoded frame too large\n");
return -1;
}
s->m.mb_x= x;
ff_init_block_index(&s->m);
ff_update_block_index(&s->m);
if(s->picture.pict_type == FF_I_TYPE || (s->m.mb_type[x + y*s->m.mb_stride]&CANDIDATE_MB_TYPE_INTRA)){
for(i=0; i<6; i++){
init_put_bits(&s->reorder_pb[i], reorder_buffer[0][i], 7*32);
}
if(s->picture.pict_type == FF_P_TYPE){
const uint8_t *vlc= ff_svq1_block_type_vlc[SVQ1_BLOCK_INTRA];
put_bits(&s->reorder_pb[5], vlc[1], vlc[0]);
score[0]= vlc[1]*lambda;
}
score[0]+= encode_block(s, src+16*x, NULL, temp, stride, 5, 64, lambda, 1);
for(i=0; i<6; i++){
count[0][i]= put_bits_count(&s->reorder_pb[i]);
flush_put_bits(&s->reorder_pb[i]);
}
}else
score[0]= INT_MAX;
best=0;
if(s->picture.pict_type == FF_P_TYPE){
const uint8_t *vlc= ff_svq1_block_type_vlc[SVQ1_BLOCK_INTER];
int mx, my, pred_x, pred_y, dxy;
int16_t *motion_ptr;
motion_ptr= h263_pred_motion(&s->m, 0, 0, &pred_x, &pred_y);
if(s->m.mb_type[x + y*s->m.mb_stride]&CANDIDATE_MB_TYPE_INTER){
for(i=0; i<6; i++)
init_put_bits(&s->reorder_pb[i], reorder_buffer[1][i], 7*32);
put_bits(&s->reorder_pb[5], vlc[1], vlc[0]);
s->m.pb= s->reorder_pb[5];
mx= motion_ptr[0];
my= motion_ptr[1];
assert(mx>=-32 && mx<=31);
assert(my>=-32 && my<=31);
assert(pred_x>=-32 && pred_x<=31);
assert(pred_y>=-32 && pred_y<=31);
ff_h263_encode_motion(&s->m, mx - pred_x, 1);
ff_h263_encode_motion(&s->m, my - pred_y, 1);
s->reorder_pb[5]= s->m.pb;
score[1] += lambda*put_bits_count(&s->reorder_pb[5]);
dxy= (mx&1) + 2*(my&1);
s->dsp.put_pixels_tab[0][dxy](temp+16, ref + (mx>>1) + stride*(my>>1), stride, 16);
score[1]+= encode_block(s, src+16*x, temp+16, decoded, stride, 5, 64, lambda, 0);
best= score[1] <= score[0];
vlc= ff_svq1_block_type_vlc[SVQ1_BLOCK_SKIP];
score[2]= s->dsp.sse[0](NULL, src+16*x, ref, stride, 16);
score[2]+= vlc[1]*lambda;
if(score[2] < score[best] && mx==0 && my==0){
best=2;
s->dsp.put_pixels_tab[0][0](decoded, ref, stride, 16);
for(i=0; i<6; i++){
count[2][i]=0;
}
put_bits(&s->pb, vlc[1], vlc[0]);
}
}
if(best==1){
for(i=0; i<6; i++){
count[1][i]= put_bits_count(&s->reorder_pb[i]);
flush_put_bits(&s->reorder_pb[i]);
}
}else{
motion_ptr[0 ] = motion_ptr[1 ]=
motion_ptr[2 ] = motion_ptr[3 ]=
motion_ptr[0+2*s->m.b8_stride] = motion_ptr[1+2*s->m.b8_stride]=
motion_ptr[2+2*s->m.b8_stride] = motion_ptr[3+2*s->m.b8_stride]=0;
}
}
s->rd_total += score[best];
for(i=5; i>=0; i--){
ff_copy_bits(&s->pb, reorder_buffer[best][i], count[best][i]);
}
if(best==0){
s->dsp.put_pixels_tab[0][0](decoded, temp, stride, 16);
}
}
s->m.first_slice_line=0;
}
return 0;
}
static av_cold int svq1_encode_init(AVCodecContext *avctx)
{
SVQ1Context * const s = avctx->priv_data;
dsputil_init(&s->dsp, avctx);
avctx->coded_frame= (AVFrame*)&s->picture;
s->frame_width = avctx->width;
s->frame_height = avctx->height;
s->y_block_width = (s->frame_width + 15) / 16;
s->y_block_height = (s->frame_height + 15) / 16;
s->c_block_width = (s->frame_width / 4 + 15) / 16;
s->c_block_height = (s->frame_height / 4 + 15) / 16;
s->avctx= avctx;
s->m.avctx= avctx;
s->m.me.scratchpad= av_mallocz((avctx->width+64)*2*16*2*sizeof(uint8_t));
s->m.me.map = av_mallocz(ME_MAP_SIZE*sizeof(uint32_t));
s->m.me.score_map = av_mallocz(ME_MAP_SIZE*sizeof(uint32_t));
s->mb_type = av_mallocz((s->y_block_width+1)*s->y_block_height*sizeof(int16_t));
s->dummy = av_mallocz((s->y_block_width+1)*s->y_block_height*sizeof(int32_t));
h263_encode_init(&s->m); //mv_penalty
return 0;
}
static int svq1_encode_frame(AVCodecContext *avctx, unsigned char *buf,
int buf_size, void *data)
{
SVQ1Context * const s = avctx->priv_data;
AVFrame *pict = data;
AVFrame * const p= (AVFrame*)&s->picture;
AVFrame temp;
int i;
if(avctx->pix_fmt != PIX_FMT_YUV410P){
av_log(avctx, AV_LOG_ERROR, "unsupported pixel format\n");
return -1;
}
if(!s->current_picture.data[0]){
avctx->get_buffer(avctx, &s->current_picture);
avctx->get_buffer(avctx, &s->last_picture);
}
temp= s->current_picture;
s->current_picture= s->last_picture;
s->last_picture= temp;
init_put_bits(&s->pb, buf, buf_size);
*p = *pict;
p->pict_type = avctx->gop_size && avctx->frame_number % avctx->gop_size ? FF_P_TYPE : FF_I_TYPE;
p->key_frame = p->pict_type == FF_I_TYPE;
svq1_write_header(s, p->pict_type);
for(i=0; i<3; i++){
if(svq1_encode_plane(s, i,
s->picture.data[i], s->last_picture.data[i], s->current_picture.data[i],
s->frame_width / (i?4:1), s->frame_height / (i?4:1),
s->picture.linesize[i], s->current_picture.linesize[i]) < 0)
return -1;
}
// align_put_bits(&s->pb);
while(put_bits_count(&s->pb) & 31)
put_bits(&s->pb, 1, 0);
flush_put_bits(&s->pb);
return put_bits_count(&s->pb) / 8;
}
static av_cold int svq1_encode_end(AVCodecContext *avctx)
{
SVQ1Context * const s = avctx->priv_data;
int i;
av_log(avctx, AV_LOG_DEBUG, "RD: %f\n", s->rd_total/(double)(avctx->width*avctx->height*avctx->frame_number));
av_freep(&s->m.me.scratchpad);
av_freep(&s->m.me.map);
av_freep(&s->m.me.score_map);
av_freep(&s->mb_type);
av_freep(&s->dummy);
for(i=0; i<3; i++){
av_freep(&s->motion_val8[i]);
av_freep(&s->motion_val16[i]);
}
return 0;
}
AVCodec svq1_encoder = {
"svq1",
CODEC_TYPE_VIDEO,
CODEC_ID_SVQ1,
sizeof(SVQ1Context),
svq1_encode_init,
svq1_encode_frame,
svq1_encode_end,
.pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV410P, PIX_FMT_NONE},
.long_name= NULL_IF_CONFIG_SMALL("Sorenson Vector Quantizer 1"),
};
@@ -0,0 +1,96 @@
/*
* SVQ1 Encoder
* Copyright (C) 2004 Mike Melanson <melanson@pcisys.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 svq1enc_cb.h
* svq1 code books.
*/
#ifndef FFMPEG_SVQ1ENC_CB_H
#define FFMPEG_SVQ1ENC_CB_H
#include <stdint.h>
static const int8_t svq1_inter_codebook_sum[4][16*6] = {
{
-1, 1, -2, 0, 1, -1, -1, -1, -2, -1, 1, -1, -1, 0, -1, -1,
0, -1, -1, -1, -1, 0, -1, 0, 0, 0, -3, 1, -1, 0, 1, -1,
1, -1, 2, 2, 1, 1, 2, 0, 0, 0, -1, 1, 1, 0, 0, 0,
1, -1, 0, 1, -1, 1, 1, 0, 1, 0, -1, 1, 1, 0, 0, 0,
-2, 0, 0, -2, 0, 0, -2, 0, -2, -1, -2, -1, 0, 0, -1, 0,
1, 0, 1, -1, 2, 2, 1, 2, 2, 1, 0, 1, 1, 0, 1, 1,
},{
-2, 1, -1, -1, 1, 0, 1, -1, -1, -1, 1, -1, 0, -1, 0, -1,
0, 0, 0, -2, 0, 1, 0, -1, -1, 0, 2, -3, 1, -2, 3, -1,
2, 0, 2, 1, 1, -1, 1, 1, 0, 0, 1, 1, 2, -2, 1, 0,
-2, -1, 2, -2, -2, 0, -3, 0, -1, 0, -1, 0, -1, 0, -2, -3,
1, -2, -2, -1, 1, -1, -1, 1, -1, 1, 1, 0, -2, 0, 1, 1,
1, 1, 2, 1, 0, 0, -1, 0, 0, 1, 0, 1, -1, 1, 0, 2,
},{
0, 0, 0, -3, 1, 1, 1, -3, 0, -1, 0, -3, 1, -3, 0, -2,
1, 2, -1, -3, 0, -3, 1, -1, 0, -1, 0, 0, 1, 2, 1, 1,
-1, 2, -3, 3, 1, 0, -5, 1, 0, -1, -3, 1, 0, 2, 0, -3,
4, 2, 0, -2, 1, -2, 3, -2, 1, 1, 0, -1, 2, 5, 3, 1,
-1, 0, 2, -3, -2, 0, 0, -2, 2, -3, -1, -1, 2, 1, 0, -2,
3, -1, 1, -1, 2, 4, 0, 1, 0, 1, 0, -1, -3, -2, -1, 0,
},{
0, 2, -1, -1, 2, -4, -2, 3, 0, -1, -5, 1, 0, 1, 0, 6,
-2, 2, 0, 1, 1, -1, -1, -2, 1, -2, -1, 0, 2, -2, -2, -1,
-4, 2, -1, -3, -1, -2, 2, -1, 2, -1, 2, 0, 3, -3, -3, 0,
-3, 0, 0, -2, 4, -4, 0, -1, 4, 0, -2, -2, 3, -2, 0, 4,
5, 0, 1, 0, -3, 3, 3, 2, 0, 0, 1, 2, -5, -2, -3, 0,
-3, 2, -2, 2, -2, 4, 7, -3, 4, 2, 3, 2, -1, 0, -3, 1,
}
};
static const int8_t svq1_intra_codebook_sum[4][16*6] = {
{
0, 0, 0, -1, -1, -1, -1, -2, 0, -1, -1, 0, -1, 0, 1, 0,
1, 0, -1, 1, 0, 0, -1, 1, -1, 0, 0, 0, -1, 1, 0, 0,
-1, 0, 0, 1, -1, 1, 0, -1, -1, 0, 1, 1, 0, 0, -1, 1,
0, 1, 0, 0, 1, -1, 0, 0, 0, -1, 1, 0, 1, 0, -2, 1,
0, -1, 1, 0, 0, 0, 1, 0, -1, 0, 0, 0, -1, 0, 0, 0,
0, 1, 1, 0, 0, -1, 0, 1, 0, 0, 0, 0, -1, 1, 1, -1,
},{
-1, -2, 0, -1, 1, 0, -1, 0, -1, -4, -1, -2, -1, -2, 1, -2,
0, 0, 4, -2, -1, 1, 1, 0, 2, 1, 1, 0, 2, 0, 0, 0,
1, 1, 0, -1, -1, -1, 1, 0, -1, -3, -3, 1, -1, 1, -2, -1,
1, -1, 0, 1, 2, 1, -1, -1, 1, 1, 1, 2, 1, 0, 1, -2,
-2, 0, -1, -2, -2, 0, -1, -1, -1, 0, 1, 0, -1, -1, 0, -1,
0, 2, 1, 2, 2, 1, -1, 1, 0, 2, 0, -1, 1, 0, 0, 0,
},{
-2, 0, -1, -1, 1, 1, -2, 0, -2, 0, 1, -2, -2, 1, -1, -1,
3, -2, 0, -3, -4, -3, 2, 1, 0, 3, -2, 2, 3, 2, 2, -1,
-3, 1, 0, 1, 0, 0, 0, 1, -2, 1, -2, -2, -1, -2, -2, 2,
0, -4, 0, 2, -1, 0, 2, 2, 2, 1, 0, -1, -1, 1, -3, 2,
2, 1, 0, 3, 1, -1, 1, 3, 1, 0, 1, 1, 2, -1, 1, -1,
-2, -1, 0, -1, 1, -1, 1, -2, -2, -1, -1, -3, 1, -4, -3, 1,
},{
-2, 0, -2, 3, -1, -1, 0, 2, 2, -1, -3, 2, 1, 0, -2, -1,
-3, -2, -2, 1, 2, -3, 0, 1, -5, -2, -3, 0, -2, -1, 2, 0,
-1, -1, 0, -2, 1, 3, -7, -2, -2, -1, 2, -1, 0, 3, 1, 3,
1, 0, 0, 1, 2, 3, 1, 2, 0, -2, -2, 1, 1, 2, 2, 3,
4, 1, -1, 2, -2, 4, 0, 0, 0, 4, 2, 0, -2, -2, 2, -4,
-1, 5, -2, -2, -3, 2, -3, -1, 3, -3, 0, 4, 3, 0, 1, -2,
}
};
#endif /* FFMPEG_SVQ1ENC_CB_H */
@@ -1,21 +1,24 @@
/* /*
* Copyright (c) 2003 The FFmpeg Project. * Copyright (c) 2003 The FFmpeg Project.
* *
* This library is free software; you can redistribute it and/or * This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This library is distributed in the hope that it will be useful, * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
* */
*
/*
* How to use this decoder: * How to use this decoder:
* SVQ3 data is transported within Apple Quicktime files. Quicktime files * SVQ3 data is transported within Apple Quicktime files. Quicktime files
* have stsd atoms to describe media trak properties. A stsd atom for a * have stsd atoms to describe media trak properties. A stsd atom for a
@@ -35,7 +38,6 @@
* You will know you have these parameters passed correctly when the decoder * You will know you have these parameters passed correctly when the decoder
* correctly decodes this file: * correctly decodes this file:
* ftp://ftp.mplayerhq.hu/MPlayer/samples/V-codecs/SVQ3/Vertical400kbit.sorenson3.mov * ftp://ftp.mplayerhq.hu/MPlayer/samples/V-codecs/SVQ3/Vertical400kbit.sorenson3.mov
*
*/ */
/** /**
@@ -145,7 +147,7 @@ static void svq3_luma_dc_dequant_idct_c(DCTELEM *block, int qp){
static void svq3_add_idct_c (uint8_t *dst, DCTELEM *block, int stride, int qp, int dc){ static void svq3_add_idct_c (uint8_t *dst, DCTELEM *block, int stride, int qp, int dc){
const int qmul= svq3_dequant_coeff[qp]; const int qmul= svq3_dequant_coeff[qp];
int i; int i;
uint8_t *cm = cropTbl + MAX_NEG_CROP; uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
if (dc) { if (dc) {
dc = 13*13*((dc == 1) ? 1538*block[0] : ((qmul*(block[0] >> 3)) / 2)); dc = 13*13*((dc == 1) ? 1538*block[0] : ((qmul*(block[0] >> 3)) / 2));
@@ -178,36 +180,8 @@ static void svq3_add_idct_c (uint8_t *dst, DCTELEM *block, int stride, int qp, i
} }
} }
static void pred4x4_down_left_svq3_c(uint8_t *src, uint8_t *topright, int stride){
LOAD_TOP_EDGE
LOAD_LEFT_EDGE
const __attribute__((unused)) int unu0= t0;
const __attribute__((unused)) int unu1= l0;
src[0+0*stride]=(l1 + t1)>>1;
src[1+0*stride]=
src[0+1*stride]=(l2 + t2)>>1;
src[2+0*stride]=
src[1+1*stride]=
src[0+2*stride]=
src[3+0*stride]=
src[2+1*stride]=
src[1+2*stride]=
src[0+3*stride]=
src[3+1*stride]=
src[2+2*stride]=
src[1+3*stride]=
src[3+2*stride]=
src[2+3*stride]=
src[3+3*stride]=(l3 + t3)>>1;
}
static void pred16x16_plane_svq3_c(uint8_t *src, int stride){
pred16x16_plane_compat_c(src, stride, 1);
}
static inline int svq3_decode_block (GetBitContext *gb, DCTELEM *block, static inline int svq3_decode_block (GetBitContext *gb, DCTELEM *block,
int index, const int type) { int index, const int type) {
static const uint8_t *const scan_patterns[4] = static const uint8_t *const scan_patterns[4] =
{ luma_dc_zigzag_scan, zigzag_scan, svq3_scan, chroma_dc_scan }; { luma_dc_zigzag_scan, zigzag_scan, svq3_scan, chroma_dc_scan };
@@ -220,37 +194,37 @@ static inline int svq3_decode_block (GetBitContext *gb, DCTELEM *block,
for (; (vlc = svq3_get_ue_golomb (gb)) != 0; index++) { for (; (vlc = svq3_get_ue_golomb (gb)) != 0; index++) {
if (vlc == INVALID_VLC) if (vlc == INVALID_VLC)
return -1; return -1;
sign = (vlc & 0x1) - 1; sign = (vlc & 0x1) - 1;
vlc = (vlc + 1) >> 1; vlc = (vlc + 1) >> 1;
if (type == 3) { if (type == 3) {
if (vlc < 3) { if (vlc < 3) {
run = 0; run = 0;
level = vlc; level = vlc;
} else if (vlc < 4) { } else if (vlc < 4) {
run = 1; run = 1;
level = 1; level = 1;
} else { } else {
run = (vlc & 0x3); run = (vlc & 0x3);
level = ((vlc + 9) >> 2) - run; level = ((vlc + 9) >> 2) - run;
} }
} else { } else {
if (vlc < 16) { if (vlc < 16) {
run = svq3_dct_tables[intra][vlc].run; run = svq3_dct_tables[intra][vlc].run;
level = svq3_dct_tables[intra][vlc].level; level = svq3_dct_tables[intra][vlc].level;
} else if (intra) { } else if (intra) {
run = (vlc & 0x7); run = (vlc & 0x7);
level = (vlc >> 3) + ((run == 0) ? 8 : ((run < 2) ? 2 : ((run < 5) ? 0 : -1))); level = (vlc >> 3) + ((run == 0) ? 8 : ((run < 2) ? 2 : ((run < 5) ? 0 : -1)));
} else { } else {
run = (vlc & 0xF); run = (vlc & 0xF);
level = (vlc >> 4) + ((run == 0) ? 4 : ((run < 3) ? 2 : ((run < 10) ? 1 : 0))); level = (vlc >> 4) + ((run == 0) ? 4 : ((run < 3) ? 2 : ((run < 10) ? 1 : 0)));
} }
} }
if ((index += run) >= limit) if ((index += run) >= limit)
return -1; return -1;
block[scan[index]] = (level ^ sign) - sign; block[scan[index]] = (level ^ sign) - sign;
} }
@@ -264,9 +238,9 @@ static inline int svq3_decode_block (GetBitContext *gb, DCTELEM *block,
} }
static inline void svq3_mc_dir_part (MpegEncContext *s, static inline void svq3_mc_dir_part (MpegEncContext *s,
int x, int y, int width, int height, int x, int y, int width, int height,
int mx, int my, int dxy, int mx, int my, int dxy,
int thirdpel, int dir, int avg) { int thirdpel, int dir, int avg) {
const Picture *pic = (dir == 0) ? &s->last_picture : &s->next_picture; const Picture *pic = (dir == 0) ? &s->last_picture : &s->next_picture;
uint8_t *src, *dest; uint8_t *src, *dest;
@@ -283,8 +257,8 @@ static inline void svq3_mc_dir_part (MpegEncContext *s,
emu = 1; emu = 1;
} }
mx = clip (mx, -16, (s->h_edge_pos - width + 15)); mx = av_clip (mx, -16, (s->h_edge_pos - width + 15));
my = clip (my, -16, (s->v_edge_pos - height + 15)); my = av_clip (my, -16, (s->v_edge_pos - height + 15));
} }
/* form component predictions */ /* form component predictions */
@@ -293,7 +267,7 @@ static inline void svq3_mc_dir_part (MpegEncContext *s,
if (emu) { if (emu) {
ff_emulated_edge_mc (s->edge_emu_buffer, src, s->linesize, (width + 1), (height + 1), ff_emulated_edge_mc (s->edge_emu_buffer, src, s->linesize, (width + 1), (height + 1),
mx, my, s->h_edge_pos, s->v_edge_pos); mx, my, s->h_edge_pos, s->v_edge_pos);
src = s->edge_emu_buffer; src = s->edge_emu_buffer;
} }
if(thirdpel) if(thirdpel)
@@ -302,8 +276,8 @@ static inline void svq3_mc_dir_part (MpegEncContext *s,
(avg ? s->dsp.avg_pixels_tab : s->dsp.put_pixels_tab)[blocksize][dxy](dest, src, s->linesize, height); (avg ? s->dsp.avg_pixels_tab : s->dsp.put_pixels_tab)[blocksize][dxy](dest, src, s->linesize, height);
if (!(s->flags & CODEC_FLAG_GRAY)) { if (!(s->flags & CODEC_FLAG_GRAY)) {
mx = (mx + (mx < (int) x)) >> 1; mx = (mx + (mx < (int) x)) >> 1;
my = (my + (my < (int) y)) >> 1; my = (my + (my < (int) y)) >> 1;
width = (width >> 1); width = (width >> 1);
height = (height >> 1); height = (height >> 1);
blocksize++; blocksize++;
@@ -314,7 +288,7 @@ static inline void svq3_mc_dir_part (MpegEncContext *s,
if (emu) { if (emu) {
ff_emulated_edge_mc (s->edge_emu_buffer, src, s->uvlinesize, (width + 1), (height + 1), ff_emulated_edge_mc (s->edge_emu_buffer, src, s->uvlinesize, (width + 1), (height + 1),
mx, my, (s->h_edge_pos >> 1), (s->v_edge_pos >> 1)); mx, my, (s->h_edge_pos >> 1), (s->v_edge_pos >> 1));
src = s->edge_emu_buffer; src = s->edge_emu_buffer;
} }
if(thirdpel) if(thirdpel)
@@ -344,82 +318,83 @@ static inline int svq3_mc_dir (H264Context *h, int size, int mode, int dir, int
k = ((j>>2)&1) + ((i>>1)&2) + ((j>>1)&4) + (i&8); k = ((j>>2)&1) + ((i>>1)&2) + ((j>>1)&4) + (i&8);
if (mode != PREDICT_MODE) { if (mode != PREDICT_MODE) {
pred_motion (h, k, (part_width >> 2), dir, 1, &mx, &my); pred_motion (h, k, (part_width >> 2), dir, 1, &mx, &my);
} else { } else {
mx = s->next_picture.motion_val[0][b_xy][0]<<1; mx = s->next_picture.motion_val[0][b_xy][0]<<1;
my = s->next_picture.motion_val[0][b_xy][1]<<1; my = s->next_picture.motion_val[0][b_xy][1]<<1;
if (dir == 0) { if (dir == 0) {
mx = ((mx * h->frame_num_offset) / h->prev_frame_num_offset + 1)>>1; mx = ((mx * h->frame_num_offset) / h->prev_frame_num_offset + 1)>>1;
my = ((my * h->frame_num_offset) / h->prev_frame_num_offset + 1)>>1; my = ((my * h->frame_num_offset) / h->prev_frame_num_offset + 1)>>1;
} else { } else {
mx = ((mx * (h->frame_num_offset - h->prev_frame_num_offset)) / h->prev_frame_num_offset + 1)>>1; mx = ((mx * (h->frame_num_offset - h->prev_frame_num_offset)) / h->prev_frame_num_offset + 1)>>1;
my = ((my * (h->frame_num_offset - h->prev_frame_num_offset)) / h->prev_frame_num_offset + 1)>>1; my = ((my * (h->frame_num_offset - h->prev_frame_num_offset)) / h->prev_frame_num_offset + 1)>>1;
} }
} }
/* clip motion vector prediction to frame border */ /* clip motion vector prediction to frame border */
mx = clip (mx, extra_width - 6*x, h_edge_pos - 6*x); mx = av_clip (mx, extra_width - 6*x, h_edge_pos - 6*x);
my = clip (my, extra_width - 6*y, v_edge_pos - 6*y); my = av_clip (my, extra_width - 6*y, v_edge_pos - 6*y);
/* get (optional) motion vector differential */ /* get (optional) motion vector differential */
if (mode == PREDICT_MODE) { if (mode == PREDICT_MODE) {
dx = dy = 0; dx = dy = 0;
} else { } else {
dy = svq3_get_se_golomb (&s->gb); dy = svq3_get_se_golomb (&s->gb);
dx = svq3_get_se_golomb (&s->gb); dx = svq3_get_se_golomb (&s->gb);
if (dx == INVALID_VLC || dy == INVALID_VLC) { if (dx == INVALID_VLC || dy == INVALID_VLC) {
return -1; av_log(h->s.avctx, AV_LOG_ERROR, "invalid MV vlc\n");
} return -1;
}
} }
/* compute motion vector */ /* compute motion vector */
if (mode == THIRDPEL_MODE) { if (mode == THIRDPEL_MODE) {
int fx, fy; int fx, fy;
mx = ((mx + 1)>>1) + dx; mx = ((mx + 1)>>1) + dx;
my = ((my + 1)>>1) + dy; my = ((my + 1)>>1) + dy;
fx= ((unsigned)(mx + 0x3000))/3 - 0x1000; fx= ((unsigned)(mx + 0x3000))/3 - 0x1000;
fy= ((unsigned)(my + 0x3000))/3 - 0x1000; fy= ((unsigned)(my + 0x3000))/3 - 0x1000;
dxy= (mx - 3*fx) + 4*(my - 3*fy); dxy= (mx - 3*fx) + 4*(my - 3*fy);
svq3_mc_dir_part (s, x, y, part_width, part_height, fx, fy, dxy, 1, dir, avg); svq3_mc_dir_part (s, x, y, part_width, part_height, fx, fy, dxy, 1, dir, avg);
mx += mx; mx += mx;
my += my; my += my;
} else if (mode == HALFPEL_MODE || mode == PREDICT_MODE) { } else if (mode == HALFPEL_MODE || mode == PREDICT_MODE) {
mx = ((unsigned)(mx + 1 + 0x3000))/3 + dx - 0x1000; mx = ((unsigned)(mx + 1 + 0x3000))/3 + dx - 0x1000;
my = ((unsigned)(my + 1 + 0x3000))/3 + dy - 0x1000; my = ((unsigned)(my + 1 + 0x3000))/3 + dy - 0x1000;
dxy= (mx&1) + 2*(my&1); dxy= (mx&1) + 2*(my&1);
svq3_mc_dir_part (s, x, y, part_width, part_height, mx>>1, my>>1, dxy, 0, dir, avg); svq3_mc_dir_part (s, x, y, part_width, part_height, mx>>1, my>>1, dxy, 0, dir, avg);
mx *= 3; mx *= 3;
my *= 3; my *= 3;
} else { } else {
mx = ((unsigned)(mx + 3 + 0x6000))/6 + dx - 0x1000; mx = ((unsigned)(mx + 3 + 0x6000))/6 + dx - 0x1000;
my = ((unsigned)(my + 3 + 0x6000))/6 + dy - 0x1000; my = ((unsigned)(my + 3 + 0x6000))/6 + dy - 0x1000;
svq3_mc_dir_part (s, x, y, part_width, part_height, mx, my, 0, 0, dir, avg); svq3_mc_dir_part (s, x, y, part_width, part_height, mx, my, 0, 0, dir, avg);
mx *= 6; mx *= 6;
my *= 6; my *= 6;
} }
/* update mv_cache */ /* update mv_cache */
if (mode != PREDICT_MODE) { if (mode != PREDICT_MODE) {
int32_t mv = pack16to32(mx,my); int32_t mv = pack16to32(mx,my);
if (part_height == 8 && i < 8) { if (part_height == 8 && i < 8) {
*(int32_t *) h->mv_cache[dir][scan8[k] + 1*8] = mv; *(int32_t *) h->mv_cache[dir][scan8[k] + 1*8] = mv;
if (part_width == 8 && j < 8) { if (part_width == 8 && j < 8) {
*(int32_t *) h->mv_cache[dir][scan8[k] + 1 + 1*8] = mv; *(int32_t *) h->mv_cache[dir][scan8[k] + 1 + 1*8] = mv;
} }
} }
if (part_width == 8 && j < 8) { if (part_width == 8 && j < 8) {
*(int32_t *) h->mv_cache[dir][scan8[k] + 1] = mv; *(int32_t *) h->mv_cache[dir][scan8[k] + 1] = mv;
} }
if (part_width == 4 || part_height == 4) { if (part_width == 4 || part_height == 4) {
*(int32_t *) h->mv_cache[dir][scan8[k]] = mv; *(int32_t *) h->mv_cache[dir][scan8[k]] = mv;
} }
} }
/* write back motion vectors */ /* write back motion vectors */
@@ -436,32 +411,35 @@ static int svq3_decode_mb (H264Context *h, unsigned int mb_type) {
uint32_t vlc; uint32_t vlc;
int8_t *top, *left; int8_t *top, *left;
MpegEncContext *const s = (MpegEncContext *) h; MpegEncContext *const s = (MpegEncContext *) h;
const int mb_xy = s->mb_x + s->mb_y*s->mb_stride; const int mb_xy = h->mb_xy;
const int b_xy = 4*s->mb_x + 4*s->mb_y*h->b_stride; const int b_xy = 4*s->mb_x + 4*s->mb_y*h->b_stride;
h->top_samples_available = (s->mb_y == 0) ? 0x33FF : 0xFFFF; h->top_samples_available = (s->mb_y == 0) ? 0x33FF : 0xFFFF;
h->left_samples_available = (s->mb_x == 0) ? 0x5F5F : 0xFFFF; h->left_samples_available = (s->mb_x == 0) ? 0x5F5F : 0xFFFF;
h->topright_samples_available = 0xFFFF; h->topright_samples_available = 0xFFFF;
if (mb_type == 0) { /* SKIP */ if (mb_type == 0) { /* SKIP */
if (s->pict_type == P_TYPE || s->next_picture.mb_type[mb_xy] == -1) { if (s->pict_type == FF_P_TYPE || s->next_picture.mb_type[mb_xy] == -1) {
svq3_mc_dir_part (s, 16*s->mb_x, 16*s->mb_y, 16, 16, 0, 0, 0, 0, 0, 0); svq3_mc_dir_part (s, 16*s->mb_x, 16*s->mb_y, 16, 16, 0, 0, 0, 0, 0, 0);
if (s->pict_type == B_TYPE) { if (s->pict_type == FF_B_TYPE) {
svq3_mc_dir_part (s, 16*s->mb_x, 16*s->mb_y, 16, 16, 0, 0, 0, 0, 1, 1); svq3_mc_dir_part (s, 16*s->mb_x, 16*s->mb_y, 16, 16, 0, 0, 0, 0, 1, 1);
} }
mb_type = MB_TYPE_SKIP; mb_type = MB_TYPE_SKIP;
} else { } else {
svq3_mc_dir (h, s->next_picture.mb_type[mb_xy], PREDICT_MODE, 0, 0); mb_type= FFMIN(s->next_picture.mb_type[mb_xy], 6);
svq3_mc_dir (h, s->next_picture.mb_type[mb_xy], PREDICT_MODE, 1, 1); if(svq3_mc_dir (h, mb_type, PREDICT_MODE, 0, 0) < 0)
return -1;
if(svq3_mc_dir (h, mb_type, PREDICT_MODE, 1, 1) < 0)
return -1;
mb_type = MB_TYPE_16x16; mb_type = MB_TYPE_16x16;
} }
} else if (mb_type < 8) { /* INTER */ } else if (mb_type < 8) { /* INTER */
if (h->thirdpel_flag && h->halfpel_flag == !get_bits (&s->gb, 1)) { if (h->thirdpel_flag && h->halfpel_flag == !get_bits1 (&s->gb)) {
mode = THIRDPEL_MODE; mode = THIRDPEL_MODE;
} else if (h->halfpel_flag && h->thirdpel_flag == !get_bits (&s->gb, 1)) { } else if (h->halfpel_flag && h->thirdpel_flag == !get_bits1 (&s->gb)) {
mode = HALFPEL_MODE; mode = HALFPEL_MODE;
} else { } else {
mode = FULLPEL_MODE; mode = FULLPEL_MODE;
@@ -474,105 +452,111 @@ static int svq3_decode_mb (H264Context *h, unsigned int mb_type) {
N??11111 N??11111
N??11111 N??11111
N??11111 N??11111
N
*/ */
for (m=0; m < 2; m++) { for (m=0; m < 2; m++) {
if (s->mb_x > 0 && h->intra4x4_pred_mode[mb_xy - 1][0] != -1) { if (s->mb_x > 0 && h->intra4x4_pred_mode[mb_xy - 1][0] != -1) {
for (i=0; i < 4; i++) { for (i=0; i < 4; i++) {
*(uint32_t *) h->mv_cache[m][scan8[0] - 1 + i*8] = *(uint32_t *) s->current_picture.motion_val[m][b_xy - 1 + i*h->b_stride]; *(uint32_t *) h->mv_cache[m][scan8[0] - 1 + i*8] = *(uint32_t *) s->current_picture.motion_val[m][b_xy - 1 + i*h->b_stride];
} }
} else { } else {
for (i=0; i < 4; i++) { for (i=0; i < 4; i++) {
*(uint32_t *) h->mv_cache[m][scan8[0] - 1 + i*8] = 0; *(uint32_t *) h->mv_cache[m][scan8[0] - 1 + i*8] = 0;
} }
} }
if (s->mb_y > 0) { if (s->mb_y > 0) {
memcpy (h->mv_cache[m][scan8[0] - 1*8], s->current_picture.motion_val[m][b_xy - h->b_stride], 4*2*sizeof(int16_t)); memcpy (h->mv_cache[m][scan8[0] - 1*8], s->current_picture.motion_val[m][b_xy - h->b_stride], 4*2*sizeof(int16_t));
memset (&h->ref_cache[m][scan8[0] - 1*8], (h->intra4x4_pred_mode[mb_xy - s->mb_stride][4] == -1) ? PART_NOT_AVAILABLE : 1, 4); memset (&h->ref_cache[m][scan8[0] - 1*8], (h->intra4x4_pred_mode[mb_xy - s->mb_stride][4] == -1) ? PART_NOT_AVAILABLE : 1, 4);
if (s->mb_x < (s->mb_width - 1)) { if (s->mb_x < (s->mb_width - 1)) {
*(uint32_t *) h->mv_cache[m][scan8[0] + 4 - 1*8] = *(uint32_t *) s->current_picture.motion_val[m][b_xy - h->b_stride + 4]; *(uint32_t *) h->mv_cache[m][scan8[0] + 4 - 1*8] = *(uint32_t *) s->current_picture.motion_val[m][b_xy - h->b_stride + 4];
h->ref_cache[m][scan8[0] + 4 - 1*8] = h->ref_cache[m][scan8[0] + 4 - 1*8] =
(h->intra4x4_pred_mode[mb_xy - s->mb_stride + 1][0] == -1 || (h->intra4x4_pred_mode[mb_xy - s->mb_stride + 1][0] == -1 ||
h->intra4x4_pred_mode[mb_xy - s->mb_stride][4] == -1) ? PART_NOT_AVAILABLE : 1; h->intra4x4_pred_mode[mb_xy - s->mb_stride][4] == -1) ? PART_NOT_AVAILABLE : 1;
}else }else
h->ref_cache[m][scan8[0] + 4 - 1*8] = PART_NOT_AVAILABLE; h->ref_cache[m][scan8[0] + 4 - 1*8] = PART_NOT_AVAILABLE;
if (s->mb_x > 0) { if (s->mb_x > 0) {
*(uint32_t *) h->mv_cache[m][scan8[0] - 1 - 1*8] = *(uint32_t *) s->current_picture.motion_val[m][b_xy - h->b_stride - 1]; *(uint32_t *) h->mv_cache[m][scan8[0] - 1 - 1*8] = *(uint32_t *) s->current_picture.motion_val[m][b_xy - h->b_stride - 1];
h->ref_cache[m][scan8[0] - 1 - 1*8] = (h->intra4x4_pred_mode[mb_xy - s->mb_stride - 1][3] == -1) ? PART_NOT_AVAILABLE : 1; h->ref_cache[m][scan8[0] - 1 - 1*8] = (h->intra4x4_pred_mode[mb_xy - s->mb_stride - 1][3] == -1) ? PART_NOT_AVAILABLE : 1;
}else }else
h->ref_cache[m][scan8[0] - 1 - 1*8] = PART_NOT_AVAILABLE; h->ref_cache[m][scan8[0] - 1 - 1*8] = PART_NOT_AVAILABLE;
}else }else
memset (&h->ref_cache[m][scan8[0] - 1*8 - 1], PART_NOT_AVAILABLE, 8); memset (&h->ref_cache[m][scan8[0] - 1*8 - 1], PART_NOT_AVAILABLE, 8);
if (s->pict_type != B_TYPE) if (s->pict_type != FF_B_TYPE)
break; break;
} }
/* decode motion vector(s) and form prediction(s) */ /* decode motion vector(s) and form prediction(s) */
if (s->pict_type == P_TYPE) { if (s->pict_type == FF_P_TYPE) {
svq3_mc_dir (h, (mb_type - 1), mode, 0, 0); if(svq3_mc_dir (h, (mb_type - 1), mode, 0, 0) < 0)
} else { /* B_TYPE */ return -1;
} else { /* FF_B_TYPE */
if (mb_type != 2) { if (mb_type != 2) {
svq3_mc_dir (h, 0, mode, 0, 0); if(svq3_mc_dir (h, 0, mode, 0, 0) < 0)
return -1;
} else { } else {
for (i=0; i < 4; i++) { for (i=0; i < 4; i++) {
memset (s->current_picture.motion_val[0][b_xy + i*h->b_stride], 0, 4*2*sizeof(int16_t)); memset (s->current_picture.motion_val[0][b_xy + i*h->b_stride], 0, 4*2*sizeof(int16_t));
} }
} }
if (mb_type != 1) { if (mb_type != 1) {
svq3_mc_dir (h, 0, mode, 1, (mb_type == 3)); if(svq3_mc_dir (h, 0, mode, 1, (mb_type == 3)) < 0)
return -1;
} else { } else {
for (i=0; i < 4; i++) { for (i=0; i < 4; i++) {
memset (s->current_picture.motion_val[1][b_xy + i*h->b_stride], 0, 4*2*sizeof(int16_t)); memset (s->current_picture.motion_val[1][b_xy + i*h->b_stride], 0, 4*2*sizeof(int16_t));
} }
} }
} }
mb_type = MB_TYPE_16x16; mb_type = MB_TYPE_16x16;
} else if (mb_type == 8 || mb_type == 33) { /* INTRA4x4 */ } else if (mb_type == 8 || mb_type == 33) { /* INTRA4x4 */
memset (h->intra4x4_pred_mode_cache, -1, 8*5*sizeof(int8_t)); memset (h->intra4x4_pred_mode_cache, -1, 8*5*sizeof(int8_t));
if (mb_type == 8) { if (mb_type == 8) {
if (s->mb_x > 0) { if (s->mb_x > 0) {
for (i=0; i < 4; i++) { for (i=0; i < 4; i++) {
h->intra4x4_pred_mode_cache[scan8[0] - 1 + i*8] = h->intra4x4_pred_mode[mb_xy - 1][i]; h->intra4x4_pred_mode_cache[scan8[0] - 1 + i*8] = h->intra4x4_pred_mode[mb_xy - 1][i];
} }
if (h->intra4x4_pred_mode_cache[scan8[0] - 1] == -1) { if (h->intra4x4_pred_mode_cache[scan8[0] - 1] == -1) {
h->left_samples_available = 0x5F5F; h->left_samples_available = 0x5F5F;
} }
} }
if (s->mb_y > 0) { if (s->mb_y > 0) {
h->intra4x4_pred_mode_cache[4+8*0] = h->intra4x4_pred_mode[mb_xy - s->mb_stride][4]; h->intra4x4_pred_mode_cache[4+8*0] = h->intra4x4_pred_mode[mb_xy - s->mb_stride][4];
h->intra4x4_pred_mode_cache[5+8*0] = h->intra4x4_pred_mode[mb_xy - s->mb_stride][5]; h->intra4x4_pred_mode_cache[5+8*0] = h->intra4x4_pred_mode[mb_xy - s->mb_stride][5];
h->intra4x4_pred_mode_cache[6+8*0] = h->intra4x4_pred_mode[mb_xy - s->mb_stride][6]; h->intra4x4_pred_mode_cache[6+8*0] = h->intra4x4_pred_mode[mb_xy - s->mb_stride][6];
h->intra4x4_pred_mode_cache[7+8*0] = h->intra4x4_pred_mode[mb_xy - s->mb_stride][3]; h->intra4x4_pred_mode_cache[7+8*0] = h->intra4x4_pred_mode[mb_xy - s->mb_stride][3];
if (h->intra4x4_pred_mode_cache[4+8*0] == -1) { if (h->intra4x4_pred_mode_cache[4+8*0] == -1) {
h->top_samples_available = 0x33FF; h->top_samples_available = 0x33FF;
} }
} }
/* decode prediction codes for luma blocks */ /* decode prediction codes for luma blocks */
for (i=0; i < 16; i+=2) { for (i=0; i < 16; i+=2) {
vlc = svq3_get_ue_golomb (&s->gb); vlc = svq3_get_ue_golomb (&s->gb);
if (vlc >= 25) if (vlc >= 25){
return -1; av_log(h->s.avctx, AV_LOG_ERROR, "luma prediction:%d\n", vlc);
return -1;
}
left = &h->intra4x4_pred_mode_cache[scan8[i] - 1]; left = &h->intra4x4_pred_mode_cache[scan8[i] - 1];
top = &h->intra4x4_pred_mode_cache[scan8[i] - 8]; top = &h->intra4x4_pred_mode_cache[scan8[i] - 8];
left[1] = svq3_pred_1[top[0] + 1][left[0] + 1][svq3_pred_0[vlc][0]]; left[1] = svq3_pred_1[top[0] + 1][left[0] + 1][svq3_pred_0[vlc][0]];
left[2] = svq3_pred_1[top[1] + 1][left[1] + 1][svq3_pred_0[vlc][1]]; left[2] = svq3_pred_1[top[1] + 1][left[1] + 1][svq3_pred_0[vlc][1]];
if (left[1] == -1 || left[2] == -1) if (left[1] == -1 || left[2] == -1){
return -1; av_log(h->s.avctx, AV_LOG_ERROR, "weird prediction\n");
return -1;
}
} }
} else { /* mb_type == 33, DC_128_PRED block type */ } else { /* mb_type == 33, DC_128_PRED block type */
for (i=0; i < 4; i++) { for (i=0; i < 4; i++) {
memset (&h->intra4x4_pred_mode_cache[scan8[0] + 8*i], DC_PRED, 4); memset (&h->intra4x4_pred_mode_cache[scan8[0] + 8*i], DC_PRED, 4);
} }
} }
@@ -593,50 +577,58 @@ static int svq3_decode_mb (H264Context *h, unsigned int mb_type) {
} }
mb_type = MB_TYPE_INTRA4x4; mb_type = MB_TYPE_INTRA4x4;
} else { /* INTRA16x16 */ } else { /* INTRA16x16 */
dir = i_mb_type_info[mb_type - 8].pred_mode; dir = i_mb_type_info[mb_type - 8].pred_mode;
dir = (dir >> 1) ^ 3*(dir & 1) ^ 1; dir = (dir >> 1) ^ 3*(dir & 1) ^ 1;
if ((h->intra16x16_pred_mode = check_intra_pred_mode (h, dir)) == -1) if ((h->intra16x16_pred_mode = check_intra_pred_mode (h, dir)) == -1){
av_log(h->s.avctx, AV_LOG_ERROR, "check_intra_pred_mode = -1\n");
return -1; return -1;
}
cbp = i_mb_type_info[mb_type - 8].cbp; cbp = i_mb_type_info[mb_type - 8].cbp;
mb_type = MB_TYPE_INTRA16x16; mb_type = MB_TYPE_INTRA16x16;
} }
if (!IS_INTER(mb_type) && s->pict_type != I_TYPE) { if (!IS_INTER(mb_type) && s->pict_type != FF_I_TYPE) {
for (i=0; i < 4; i++) { for (i=0; i < 4; i++) {
memset (s->current_picture.motion_val[0][b_xy + i*h->b_stride], 0, 4*2*sizeof(int16_t)); memset (s->current_picture.motion_val[0][b_xy + i*h->b_stride], 0, 4*2*sizeof(int16_t));
} }
if (s->pict_type == B_TYPE) { if (s->pict_type == FF_B_TYPE) {
for (i=0; i < 4; i++) { for (i=0; i < 4; i++) {
memset (s->current_picture.motion_val[1][b_xy + i*h->b_stride], 0, 4*2*sizeof(int16_t)); memset (s->current_picture.motion_val[1][b_xy + i*h->b_stride], 0, 4*2*sizeof(int16_t));
} }
} }
} }
if (!IS_INTRA4x4(mb_type)) { if (!IS_INTRA4x4(mb_type)) {
memset (h->intra4x4_pred_mode[mb_xy], DC_PRED, 8); memset (h->intra4x4_pred_mode[mb_xy], DC_PRED, 8);
} }
if (!IS_SKIP(mb_type) || s->pict_type == B_TYPE) { if (!IS_SKIP(mb_type) || s->pict_type == FF_B_TYPE) {
memset (h->non_zero_count_cache + 8, 0, 4*9*sizeof(uint8_t)); memset (h->non_zero_count_cache + 8, 0, 4*9*sizeof(uint8_t));
s->dsp.clear_blocks(h->mb); s->dsp.clear_blocks(h->mb);
} }
if (!IS_INTRA16x16(mb_type) && (!IS_SKIP(mb_type) || s->pict_type == B_TYPE)) { if (!IS_INTRA16x16(mb_type) && (!IS_SKIP(mb_type) || s->pict_type == FF_B_TYPE)) {
if ((vlc = svq3_get_ue_golomb (&s->gb)) >= 48) if ((vlc = svq3_get_ue_golomb (&s->gb)) >= 48){
av_log(h->s.avctx, AV_LOG_ERROR, "cbp_vlc=%d\n", vlc);
return -1; return -1;
}
cbp = IS_INTRA(mb_type) ? golomb_to_intra4x4_cbp[vlc] : golomb_to_inter_cbp[vlc]; cbp = IS_INTRA(mb_type) ? golomb_to_intra4x4_cbp[vlc] : golomb_to_inter_cbp[vlc];
} }
if (IS_INTRA16x16(mb_type) || (s->pict_type != I_TYPE && s->adaptive_quant && cbp)) { if (IS_INTRA16x16(mb_type) || (s->pict_type != FF_I_TYPE && s->adaptive_quant && cbp)) {
s->qscale += svq3_get_se_golomb (&s->gb); s->qscale += svq3_get_se_golomb (&s->gb);
if (s->qscale > 31) if (s->qscale > 31){
av_log(h->s.avctx, AV_LOG_ERROR, "qscale:%d\n", s->qscale);
return -1; return -1;
}
} }
if (IS_INTRA16x16(mb_type)) { if (IS_INTRA16x16(mb_type)) {
if (svq3_decode_block (&s->gb, h->mb, 0, 0)) if (svq3_decode_block (&s->gb, h->mb, 0, 0)){
av_log(h->s.avctx, AV_LOG_ERROR, "error while decoding intra luma dc\n");
return -1; return -1;
}
} }
if (cbp) { if (cbp) {
@@ -645,29 +637,35 @@ static int svq3_decode_mb (H264Context *h, unsigned int mb_type) {
for (i=0; i < 4; i++) { for (i=0; i < 4; i++) {
if ((cbp & (1 << i))) { if ((cbp & (1 << i))) {
for (j=0; j < 4; j++) { for (j=0; j < 4; j++) {
k = index ? ((j&1) + 2*(i&1) + 2*(j&2) + 4*(i&2)) : (4*i + j); k = index ? ((j&1) + 2*(i&1) + 2*(j&2) + 4*(i&2)) : (4*i + j);
h->non_zero_count_cache[ scan8[k] ] = 1; h->non_zero_count_cache[ scan8[k] ] = 1;
if (svq3_decode_block (&s->gb, &h->mb[16*k], index, type)) if (svq3_decode_block (&s->gb, &h->mb[16*k], index, type)){
return -1; av_log(h->s.avctx, AV_LOG_ERROR, "error while decoding block\n");
} return -1;
}
}
} }
} }
if ((cbp & 0x30)) { if ((cbp & 0x30)) {
for (i=0; i < 2; ++i) { for (i=0; i < 2; ++i) {
if (svq3_decode_block (&s->gb, &h->mb[16*(16 + 4*i)], 0, 3)) if (svq3_decode_block (&s->gb, &h->mb[16*(16 + 4*i)], 0, 3)){
return -1; av_log(h->s.avctx, AV_LOG_ERROR, "error while decoding chroma dc block\n");
return -1;
}
} }
if ((cbp & 0x20)) { if ((cbp & 0x20)) {
for (i=0; i < 8; i++) { for (i=0; i < 8; i++) {
h->non_zero_count_cache[ scan8[16+i] ] = 1; h->non_zero_count_cache[ scan8[16+i] ] = 1;
if (svq3_decode_block (&s->gb, &h->mb[16*(16 + i)], 1, 1)) if (svq3_decode_block (&s->gb, &h->mb[16*(16 + i)], 1, 1)){
return -1; av_log(h->s.avctx, AV_LOG_ERROR, "error while decoding chroma ac block\n");
} return -1;
}
}
} }
} }
} }
@@ -683,7 +681,7 @@ static int svq3_decode_mb (H264Context *h, unsigned int mb_type) {
static int svq3_decode_slice_header (H264Context *h) { static int svq3_decode_slice_header (H264Context *h) {
MpegEncContext *const s = (MpegEncContext *) h; MpegEncContext *const s = (MpegEncContext *) h;
const int mb_xy = s->mb_x + s->mb_y*s->mb_stride; const int mb_xy = h->mb_xy;
int i, header; int i, header;
header = get_bits (&s->gb, 8); header = get_bits (&s->gb, 8);
@@ -695,7 +693,7 @@ static int svq3_decode_slice_header (H264Context *h) {
} else { } else {
int length = (header >> 5) & 3; int length = (header >> 5) & 3;
h->next_slice_index = s->gb.index + 8*show_bits (&s->gb, 8*length) + 8*length; h->next_slice_index = get_bits_count(&s->gb) + 8*show_bits (&s->gb, 8*length) + 8*length;
if (h->next_slice_index > s->gb.size_in_bits){ if (h->next_slice_index > s->gb.size_in_bits){
av_log(h->s.avctx, AV_LOG_ERROR, "slice after bitstream end\n"); av_log(h->s.avctx, AV_LOG_ERROR, "slice after bitstream end\n");
@@ -703,10 +701,10 @@ static int svq3_decode_slice_header (H264Context *h) {
} }
s->gb.size_in_bits = h->next_slice_index - 8*(length - 1); s->gb.size_in_bits = h->next_slice_index - 8*(length - 1);
s->gb.index += 8; skip_bits(&s->gb, 8);
if (length > 0) { if (length > 0) {
memcpy ((uint8_t *) &s->gb.buffer[s->gb.index >> 3], memcpy ((uint8_t *) &s->gb.buffer[get_bits_count(&s->gb) >> 3],
&s->gb.buffer[s->gb.size_in_bits >> 3], (length - 1)); &s->gb.buffer[s->gb.size_in_bits >> 3], (length - 1));
} }
} }
@@ -722,7 +720,7 @@ static int svq3_decode_slice_header (H264Context *h) {
i = (s->mb_num < 64) ? 6 : (1 + av_log2 (s->mb_num - 1)); i = (s->mb_num < 64) ? 6 : (1 + av_log2 (s->mb_num - 1));
s->mb_skip_run = get_bits (&s->gb, i) - (s->mb_x + (s->mb_y * s->mb_width)); s->mb_skip_run = get_bits (&s->gb, i) - (s->mb_x + (s->mb_y * s->mb_width));
} else { } else {
get_bits1 (&s->gb); skip_bits1 (&s->gb);
s->mb_skip_run = 0; s->mb_skip_run = 0;
} }
@@ -731,17 +729,17 @@ static int svq3_decode_slice_header (H264Context *h) {
s->adaptive_quant = get_bits1 (&s->gb); s->adaptive_quant = get_bits1 (&s->gb);
/* unknown fields */ /* unknown fields */
get_bits1 (&s->gb); skip_bits1 (&s->gb);
if (h->unknown_svq3_flag) { if (h->unknown_svq3_flag) {
get_bits1 (&s->gb); skip_bits1 (&s->gb);
} }
get_bits1 (&s->gb); skip_bits1 (&s->gb);
get_bits (&s->gb, 2); skip_bits (&s->gb, 2);
while (get_bits1 (&s->gb)) { while (get_bits1 (&s->gb)) {
get_bits (&s->gb, 8); skip_bits (&s->gb, 8);
} }
/* reset intra predictors and invalidate motion vector references */ /* reset intra predictors and invalidate motion vector references */
@@ -761,13 +759,13 @@ static int svq3_decode_slice_header (H264Context *h) {
} }
static int svq3_decode_frame (AVCodecContext *avctx, static int svq3_decode_frame (AVCodecContext *avctx,
void *data, int *data_size, void *data, int *data_size,
uint8_t *buf, int buf_size) { const uint8_t *buf, int buf_size) {
MpegEncContext *const s = avctx->priv_data; MpegEncContext *const s = avctx->priv_data;
H264Context *const h = avctx->priv_data; H264Context *const h = avctx->priv_data;
int m, mb_type; int m, mb_type;
unsigned char *extradata;
*data_size = 0; unsigned int size;
s->flags = avctx->flags; s->flags = avctx->flags;
s->flags2 = avctx->flags2; s->flags2 = avctx->flags2;
@@ -776,12 +774,10 @@ static int svq3_decode_frame (AVCodecContext *avctx,
if (!s->context_initialized) { if (!s->context_initialized) {
s->width = avctx->width; s->width = avctx->width;
s->height = avctx->height; s->height = avctx->height;
h->pred4x4[DIAG_DOWN_LEFT_PRED] = pred4x4_down_left_svq3_c;
h->pred16x16[PLANE_PRED8x8] = pred16x16_plane_svq3_c;
h->halfpel_flag = 1; h->halfpel_flag = 1;
h->thirdpel_flag = 1; h->thirdpel_flag = 1;
h->unknown_svq3_flag = 0; h->unknown_svq3_flag = 0;
h->chroma_qp = 4; h->chroma_qp[0] = h->chroma_qp[1] = 4;
if (MPV_common_init (s) < 0) if (MPV_common_init (s) < 0)
return -1; return -1;
@@ -790,36 +786,44 @@ static int svq3_decode_frame (AVCodecContext *avctx,
alloc_tables (h); alloc_tables (h);
if (avctx->extradata && avctx->extradata_size >= 0x64 /* prowl for the "SEQH" marker in the extradata */
&& !memcmp (avctx->extradata, "SVQ3", 4)) { extradata = (unsigned char *)avctx->extradata;
for (m = 0; m < avctx->extradata_size; m++) {
if (!memcmp (extradata, "SEQH", 4))
break;
extradata++;
}
/* if a match was found, parse the extra data */
if (extradata && !memcmp (extradata, "SEQH", 4)) {
GetBitContext gb; GetBitContext gb;
init_get_bits (&gb, (uint8_t *) avctx->extradata + 0x62, size = AV_RB32(&extradata[4]);
8*(avctx->extradata_size - 0x62)); init_get_bits (&gb, extradata + 8, size*8);
/* 'frame size code' and optional 'width, height' */ /* 'frame size code' and optional 'width, height' */
if (get_bits (&gb, 3) == 7) { if (get_bits (&gb, 3) == 7) {
get_bits (&gb, 12); skip_bits (&gb, 12);
get_bits (&gb, 12); skip_bits (&gb, 12);
} }
h->halfpel_flag = get_bits1 (&gb); h->halfpel_flag = get_bits1 (&gb);
h->thirdpel_flag = get_bits1 (&gb); h->thirdpel_flag = get_bits1 (&gb);
/* unknown fields */ /* unknown fields */
get_bits1 (&gb); skip_bits1 (&gb);
get_bits1 (&gb); skip_bits1 (&gb);
get_bits1 (&gb); skip_bits1 (&gb);
get_bits1 (&gb); skip_bits1 (&gb);
s->low_delay = get_bits1 (&gb); s->low_delay = get_bits1 (&gb);
/* unknown field */ /* unknown field */
get_bits1 (&gb); skip_bits1 (&gb);
while (get_bits1 (&gb)) { while (get_bits1 (&gb)) {
get_bits (&gb, 8); skip_bits (&gb, 8);
} }
h->unknown_svq3_flag = get_bits1 (&gb); h->unknown_svq3_flag = get_bits1 (&gb);
@@ -831,6 +835,7 @@ static int svq3_decode_frame (AVCodecContext *avctx,
if (buf_size == 0) { if (buf_size == 0) {
if (s->next_picture_ptr && !s->low_delay) { if (s->next_picture_ptr && !s->low_delay) {
*(AVFrame *) data = *(AVFrame *) &s->next_picture; *(AVFrame *) data = *(AVFrame *) &s->next_picture;
s->next_picture_ptr= NULL;
*data_size = sizeof(AVFrame); *data_size = sizeof(AVFrame);
} }
return 0; return 0;
@@ -838,7 +843,7 @@ static int svq3_decode_frame (AVCodecContext *avctx,
init_get_bits (&s->gb, buf, 8*buf_size); init_get_bits (&s->gb, buf, 8*buf_size);
s->mb_x = s->mb_y = 0; s->mb_x = s->mb_y = h->mb_xy = 0;
if (svq3_decode_slice_header (h)) if (svq3_decode_slice_header (h))
return -1; return -1;
@@ -847,33 +852,38 @@ static int svq3_decode_frame (AVCodecContext *avctx,
s->picture_number = h->slice_num; s->picture_number = h->slice_num;
if(avctx->debug&FF_DEBUG_PICT_INFO){ if(avctx->debug&FF_DEBUG_PICT_INFO){
av_log(h->s.avctx, AV_LOG_DEBUG, "%c hpel:%d, tpel:%d aqp:%d qp:%d\n", av_log(h->s.avctx, AV_LOG_DEBUG, "%c hpel:%d, tpel:%d aqp:%d qp:%d, slice_num:%02X\n",
av_get_pict_type_char(s->pict_type), h->halfpel_flag, h->thirdpel_flag, av_get_pict_type_char(s->pict_type), h->halfpel_flag, h->thirdpel_flag,
s->adaptive_quant, s->qscale s->adaptive_quant, s->qscale, h->slice_num
); );
} }
/* for hurry_up==5 */ /* for hurry_up==5 */
s->current_picture.pict_type = s->pict_type; s->current_picture.pict_type = s->pict_type;
s->current_picture.key_frame = (s->pict_type == I_TYPE); s->current_picture.key_frame = (s->pict_type == FF_I_TYPE);
/* skip b frames if we dont have reference frames */ /* Skip B-frames if we do not have reference frames. */
if (s->last_picture_ptr == NULL && s->pict_type == B_TYPE) return 0; if (s->last_picture_ptr == NULL && s->pict_type == FF_B_TYPE) return 0;
/* skip b frames if we are in a hurry */ /* Skip B-frames if we are in a hurry. */
if (avctx->hurry_up && s->pict_type == B_TYPE) return 0; if (avctx->hurry_up && s->pict_type == FF_B_TYPE) return 0;
/* skip everything if we are in a hurry >= 5 */ /* Skip everything if we are in a hurry >= 5. */
if (avctx->hurry_up >= 5) return 0; if (avctx->hurry_up >= 5) return 0;
if( (avctx->skip_frame >= AVDISCARD_NONREF && s->pict_type==FF_B_TYPE)
||(avctx->skip_frame >= AVDISCARD_NONKEY && s->pict_type!=FF_I_TYPE)
|| avctx->skip_frame >= AVDISCARD_ALL)
return 0;
if (s->next_p_frame_damaged) { if (s->next_p_frame_damaged) {
if (s->pict_type == B_TYPE) if (s->pict_type == FF_B_TYPE)
return 0; return 0;
else else
s->next_p_frame_damaged = 0; s->next_p_frame_damaged = 0;
} }
frame_start (h); if (frame_start (h) < 0)
return -1;
if (s->pict_type == B_TYPE) { if (s->pict_type == FF_B_TYPE) {
h->frame_num_offset = (h->slice_num - h->prev_frame_num); h->frame_num_offset = (h->slice_num - h->prev_frame_num);
if (h->frame_num_offset < 0) { if (h->frame_num_offset < 0) {
@@ -898,45 +908,47 @@ static int svq3_decode_frame (AVCodecContext *avctx,
for(i=0; i<4; i++){ for(i=0; i<4; i++){
int j; int j;
for(j=-1; j<4; j++) for(j=-1; j<4; j++)
h->ref_cache[m][scan8[0] + 8*i + j]= 1; h->ref_cache[m][scan8[0] + 8*i + j]= 1;
h->ref_cache[m][scan8[0] + 8*i + j]= PART_NOT_AVAILABLE; if(i<3)
h->ref_cache[m][scan8[0] + 8*i + j]= PART_NOT_AVAILABLE;
} }
} }
for (s->mb_y=0; s->mb_y < s->mb_height; s->mb_y++) { for (s->mb_y=0; s->mb_y < s->mb_height; s->mb_y++) {
for (s->mb_x=0; s->mb_x < s->mb_width; s->mb_x++) { for (s->mb_x=0; s->mb_x < s->mb_width; s->mb_x++) {
h->mb_xy = s->mb_x + s->mb_y*s->mb_stride;
if ( (s->gb.index + 7) >= s->gb.size_in_bits && if ( (get_bits_count(&s->gb) + 7) >= s->gb.size_in_bits &&
((s->gb.index & 7) == 0 || show_bits (&s->gb, (-s->gb.index & 7)) == 0)) { ((get_bits_count(&s->gb) & 7) == 0 || show_bits (&s->gb, (-get_bits_count(&s->gb) & 7)) == 0)) {
s->gb.index = h->next_slice_index; skip_bits(&s->gb, h->next_slice_index - get_bits_count(&s->gb));
s->gb.size_in_bits = 8*buf_size; s->gb.size_in_bits = 8*buf_size;
if (svq3_decode_slice_header (h)) if (svq3_decode_slice_header (h))
return -1; return -1;
/* TODO: support s->mb_skip_run */ /* TODO: support s->mb_skip_run */
} }
mb_type = svq3_get_ue_golomb (&s->gb); mb_type = svq3_get_ue_golomb (&s->gb);
if (s->pict_type == I_TYPE) { if (s->pict_type == FF_I_TYPE) {
mb_type += 8; mb_type += 8;
} else if (s->pict_type == B_TYPE && mb_type >= 4) { } else if (s->pict_type == FF_B_TYPE && mb_type >= 4) {
mb_type += 4; mb_type += 4;
} }
if (mb_type > 33 || svq3_decode_mb (h, mb_type)) { if (mb_type > 33 || svq3_decode_mb (h, mb_type)) {
av_log(h->s.avctx, AV_LOG_ERROR, "error while decoding MB %d %d\n", s->mb_x, s->mb_y); av_log(h->s.avctx, AV_LOG_ERROR, "error while decoding MB %d %d\n", s->mb_x, s->mb_y);
return -1; return -1;
} }
if (mb_type != 0) { if (mb_type != 0) {
hl_decode_mb (h); hl_decode_mb (h);
} }
if (s->pict_type != B_TYPE && !s->low_delay) { if (s->pict_type != FF_B_TYPE && !s->low_delay) {
s->current_picture.mb_type[s->mb_x + s->mb_y*s->mb_stride] = s->current_picture.mb_type[s->mb_x + s->mb_y*s->mb_stride] =
(s->pict_type == P_TYPE && mb_type < 8) ? (mb_type - 1) : -1; (s->pict_type == FF_P_TYPE && mb_type < 8) ? (mb_type - 1) : -1;
} }
} }
@@ -945,7 +957,7 @@ static int svq3_decode_frame (AVCodecContext *avctx,
MPV_frame_end(s); MPV_frame_end(s);
if (s->pict_type == B_TYPE || s->low_delay) { if (s->pict_type == FF_B_TYPE || s->low_delay) {
*(AVFrame *) data = *(AVFrame *) &s->current_picture; *(AVFrame *) data = *(AVFrame *) &s->current_picture;
} else { } else {
*(AVFrame *) data = *(AVFrame *) &s->last_picture; *(AVFrame *) data = *(AVFrame *) &s->last_picture;
@@ -953,7 +965,7 @@ static int svq3_decode_frame (AVCodecContext *avctx,
avctx->frame_number = s->picture_number - 1; avctx->frame_number = s->picture_number - 1;
/* dont output the last pic after seeking */ /* Do not output the last pic after seeking. */
if (s->last_picture_ptr || s->low_delay) { if (s->last_picture_ptr || s->low_delay) {
*data_size = sizeof(AVFrame); *data_size = sizeof(AVFrame);
} }
@@ -971,5 +983,6 @@ AVCodec svq3_decoder = {
NULL, NULL,
decode_end, decode_end,
svq3_decode_frame, svq3_decode_frame,
CODEC_CAP_DRAW_HORIZ_BAND | CODEC_CAP_DR1, CODEC_CAP_DRAW_HORIZ_BAND | CODEC_CAP_DR1 | CODEC_CAP_DELAY,
.long_name = NULL_IF_CONFIG_SMALL("Sorenson Vector Quantizer 3"),
}; };