Update avcodec to 20080825

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27564 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
David McPaul 2008-09-15 14:13:04 +00:00
parent a687fd7041
commit bc470b16bf
16 changed files with 2886 additions and 640 deletions

View File

@ -0,0 +1,121 @@
/*
* rectangle filling function
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
* 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 rectangle.h
* useful rectangle filling function
* @author Michael Niedermayer <michaelni@gmx.at>
*/
#ifndef FFMPEG_RECTANGLE_H
#define FFMPEG_RECTANGLE_H
#include "common.h"
/**
* fill a rectangle.
* @param h height of the rectangle, should be a constant
* @param w width of the rectangle, should be a constant
* @param size the size of val (1 or 4), should be a constant
*/
static av_always_inline void fill_rectangle(void *vp, int w, int h, int stride, uint32_t val, int size){
uint8_t *p= (uint8_t*)vp;
assert(size==1 || size==4);
assert(w<=4);
w *= size;
stride *= size;
assert((((long)vp)&(FFMIN(w, STRIDE_ALIGN)-1)) == 0);
assert((stride&(w-1))==0);
if(w==2){
const uint16_t v= size==4 ? val : val*0x0101;
*(uint16_t*)(p + 0*stride)= v;
if(h==1) return;
*(uint16_t*)(p + 1*stride)= v;
if(h==2) return;
*(uint16_t*)(p + 2*stride)= v;
*(uint16_t*)(p + 3*stride)= v;
}else if(w==4){
const uint32_t v= size==4 ? val : val*0x01010101;
*(uint32_t*)(p + 0*stride)= v;
if(h==1) return;
*(uint32_t*)(p + 1*stride)= v;
if(h==2) return;
*(uint32_t*)(p + 2*stride)= v;
*(uint32_t*)(p + 3*stride)= v;
}else if(w==8){
//gcc can't optimize 64bit math on x86_32
#ifdef HAVE_FAST_64BIT
const uint64_t v= val*0x0100000001ULL;
*(uint64_t*)(p + 0*stride)= v;
if(h==1) return;
*(uint64_t*)(p + 1*stride)= v;
if(h==2) return;
*(uint64_t*)(p + 2*stride)= v;
*(uint64_t*)(p + 3*stride)= v;
}else if(w==16){
const uint64_t v= val*0x0100000001ULL;
*(uint64_t*)(p + 0+0*stride)= v;
*(uint64_t*)(p + 8+0*stride)= v;
*(uint64_t*)(p + 0+1*stride)= v;
*(uint64_t*)(p + 8+1*stride)= v;
if(h==2) return;
*(uint64_t*)(p + 0+2*stride)= v;
*(uint64_t*)(p + 8+2*stride)= v;
*(uint64_t*)(p + 0+3*stride)= v;
*(uint64_t*)(p + 8+3*stride)= v;
#else
*(uint32_t*)(p + 0+0*stride)= val;
*(uint32_t*)(p + 4+0*stride)= val;
if(h==1) return;
*(uint32_t*)(p + 0+1*stride)= val;
*(uint32_t*)(p + 4+1*stride)= val;
if(h==2) return;
*(uint32_t*)(p + 0+2*stride)= val;
*(uint32_t*)(p + 4+2*stride)= val;
*(uint32_t*)(p + 0+3*stride)= val;
*(uint32_t*)(p + 4+3*stride)= val;
}else if(w==16){
*(uint32_t*)(p + 0+0*stride)= val;
*(uint32_t*)(p + 4+0*stride)= val;
*(uint32_t*)(p + 8+0*stride)= val;
*(uint32_t*)(p +12+0*stride)= val;
*(uint32_t*)(p + 0+1*stride)= val;
*(uint32_t*)(p + 4+1*stride)= val;
*(uint32_t*)(p + 8+1*stride)= val;
*(uint32_t*)(p +12+1*stride)= val;
if(h==2) return;
*(uint32_t*)(p + 0+2*stride)= val;
*(uint32_t*)(p + 4+2*stride)= val;
*(uint32_t*)(p + 8+2*stride)= val;
*(uint32_t*)(p +12+2*stride)= val;
*(uint32_t*)(p + 0+3*stride)= val;
*(uint32_t*)(p + 4+3*stride)= val;
*(uint32_t*)(p + 8+3*stride)= val;
*(uint32_t*)(p +12+3*stride)= val;
#endif
}else
assert(0);
assert(h==4);
}
#endif /* FFMPEG_RECTANGLE_H */

View File

@ -0,0 +1,55 @@
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
* 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"
static int remove_extradata(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args,
uint8_t **poutbuf, int *poutbuf_size,
const uint8_t *buf, int buf_size, int keyframe){
int cmd= args ? *args : 0;
AVCodecParserContext *s;
if(!bsfc->parser){
bsfc->parser= av_parser_init(avctx->codec_id);
}
s= bsfc->parser;
if(s && s->parser->split){
if( (((avctx->flags & CODEC_FLAG_GLOBAL_HEADER) || (avctx->flags2 & CODEC_FLAG2_LOCAL_HEADER)) && cmd=='a')
||(!keyframe && cmd=='k')
||(cmd=='e' || !cmd)
){
int i= s->parser->split(avctx, buf, buf_size);
buf += i;
buf_size -= i;
}
}
*poutbuf= (uint8_t *) buf;
*poutbuf_size= buf_size;
return 0;
}
AVBitStreamFilter remove_extradata_bsf={
"remove_extra",
0,
remove_extradata,
};

View File

@ -1,126 +1,42 @@
/*
* Sample rate convertion for both audio and video
* samplerate conversion for both audio and video
* Copyright (c) 2000 Fabrice Bellard.
*
* This library is free software; you can redistribute it and/or
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file resample.c
* Sample rate convertion for both audio and video.
* samplerate conversion for both audio and video
*/
#include "avcodec.h"
typedef struct {
/* fractional resampling */
uint32_t incr; /* fractional increment */
uint32_t frac;
int last_sample;
/* integer down sample */
int iratio; /* integer divison ratio */
int icount, isum;
int inv;
} ReSampleChannelContext;
struct AVResampleContext;
struct ReSampleContext {
ReSampleChannelContext channel_ctx[2];
struct AVResampleContext *resample_context;
short *temp[2];
int temp_len;
float ratio;
/* channel convert */
int input_channels, output_channels, filter_channels;
};
#define FRAC_BITS 16
#define FRAC (1 << FRAC_BITS)
static void init_mono_resample(ReSampleChannelContext *s, float ratio)
{
ratio = 1.0 / ratio;
s->iratio = (int)floorf(ratio);
if (s->iratio == 0)
s->iratio = 1;
s->incr = (int)((ratio / s->iratio) * FRAC);
s->frac = FRAC;
s->last_sample = 0;
s->icount = s->iratio;
s->isum = 0;
s->inv = (FRAC / s->iratio);
}
/* fractional audio resampling */
static int fractional_resample(ReSampleChannelContext *s, short *output, short *input, int nb_samples)
{
unsigned int frac, incr;
int l0, l1;
short *q, *p, *pend;
l0 = s->last_sample;
incr = s->incr;
frac = s->frac;
p = input;
pend = input + nb_samples;
q = output;
l1 = *p++;
for(;;) {
/* interpolate */
*q++ = (l0 * (FRAC - frac) + l1 * frac) >> FRAC_BITS;
frac = frac + s->incr;
while (frac >= FRAC) {
frac -= FRAC;
if (p >= pend)
goto the_end;
l0 = l1;
l1 = *p++;
}
}
the_end:
s->last_sample = l1;
s->frac = frac;
return q - output;
}
static int integer_downsample(ReSampleChannelContext *s, short *output, short *input, int nb_samples)
{
short *q, *p, *pend;
int c, sum;
p = input;
pend = input + nb_samples;
q = output;
c = s->icount;
sum = s->isum;
for(;;) {
sum += *p++;
if (--c == 0) {
*q++ = (sum * s->inv) >> FRAC_BITS;
c = s->iratio;
sum = 0;
}
if (p >= pend)
break;
}
s->isum = sum;
s->icount = c;
return q - output;
}
/* n1: number of samples */
static void stereo_to_mono(short *output, short *input, int n1)
{
@ -210,77 +126,49 @@ static void ac3_5p1_mux(short *output, short *input1, short *input2, int n)
}
}
static int mono_resample(ReSampleChannelContext *s, short *output, short *input, int nb_samples)
{
short *buf1;
short *buftmp;
buf1= (short*)av_malloc( nb_samples * sizeof(short) );
/* first downsample by an integer factor with averaging filter */
if (s->iratio > 1) {
buftmp = buf1;
nb_samples = integer_downsample(s, buftmp, input, nb_samples);
} else {
buftmp = input;
}
/* then do a fractional resampling with linear interpolation */
if (s->incr != FRAC) {
nb_samples = fractional_resample(s, output, buftmp, nb_samples);
} else {
memcpy(output, buftmp, nb_samples * sizeof(short));
}
av_free(buf1);
return nb_samples;
}
ReSampleContext *audio_resample_init(int output_channels, int input_channels,
ReSampleContext *audio_resample_init(int output_channels, int input_channels,
int output_rate, int input_rate)
{
ReSampleContext *s;
int i;
if ( input_channels > 2)
{
av_log(NULL, AV_LOG_ERROR, "Resampling with input channels greater than 2 unsupported.");
return NULL;
av_log(NULL, AV_LOG_ERROR, "Resampling with input channels greater than 2 unsupported.\n");
return NULL;
}
s = av_mallocz(sizeof(ReSampleContext));
if (!s)
{
av_log(NULL, AV_LOG_ERROR, "Can't allocate memory for resample context.");
return NULL;
av_log(NULL, AV_LOG_ERROR, "Can't allocate memory for resample context.\n");
return NULL;
}
s->ratio = (float)output_rate / (float)input_rate;
s->input_channels = input_channels;
s->output_channels = output_channels;
s->filter_channels = s->input_channels;
if (s->output_channels < s->filter_channels)
s->filter_channels = s->output_channels;
/*
* ac3 output is the only case where filter_channels could be greater than 2.
* AC-3 output is the only case where filter_channels could be greater than 2.
* input channels can't be greater than 2, so resample the 2 channels and then
* expand to 6 channels after the resampling.
*/
if(s->filter_channels>2)
s->filter_channels = 2;
for(i=0;i<s->filter_channels;i++) {
init_mono_resample(&s->channel_ctx[i], s->ratio);
}
#define TAPS 16
s->resample_context= av_resample_init(output_rate, input_rate, TAPS, 10, 0, 0.8);
return s;
}
/* resample audio. 'nb_samples' is the number of input samples */
/* XXX: optimize it ! */
/* XXX: do it with polyphase filters, since the quality here is
HORRIBLE. Return the number of samples available in output */
int audio_resample(ReSampleContext *s, short *output, short *input, int nb_samples)
{
int i, nb_samples1;
@ -289,44 +177,52 @@ int audio_resample(ReSampleContext *s, short *output, short *input, int nb_sampl
short *buftmp2[2], *buftmp3[2];
int lenout;
if (s->input_channels == s->output_channels && s->ratio == 1.0) {
if (s->input_channels == s->output_channels && s->ratio == 1.0 && 0) {
/* nothing to do */
memcpy(output, input, nb_samples * s->input_channels * sizeof(short));
return nb_samples;
}
/* XXX: move those malloc to resample init code */
bufin[0]= (short*) av_malloc( nb_samples * sizeof(short) );
bufin[1]= (short*) av_malloc( nb_samples * sizeof(short) );
for(i=0; i<s->filter_channels; i++){
bufin[i]= av_malloc( (nb_samples + s->temp_len) * sizeof(short) );
memcpy(bufin[i], s->temp[i], s->temp_len * sizeof(short));
buftmp2[i] = bufin[i] + s->temp_len;
}
/* make some zoom to avoid round pb */
lenout= (int)(nb_samples * s->ratio) + 16;
bufout[0]= (short*) av_malloc( lenout * sizeof(short) );
bufout[1]= (short*) av_malloc( lenout * sizeof(short) );
lenout= 4*nb_samples * s->ratio + 16;
bufout[0]= av_malloc( lenout * sizeof(short) );
bufout[1]= av_malloc( lenout * sizeof(short) );
if (s->input_channels == 2 &&
s->output_channels == 1) {
buftmp2[0] = bufin[0];
buftmp3[0] = output;
stereo_to_mono(buftmp2[0], input, nb_samples);
} else if (s->output_channels >= 2 && s->input_channels == 1) {
buftmp2[0] = input;
buftmp3[0] = bufout[0];
memcpy(buftmp2[0], input, nb_samples*sizeof(short));
} else if (s->output_channels >= 2) {
buftmp2[0] = bufin[0];
buftmp2[1] = bufin[1];
buftmp3[0] = bufout[0];
buftmp3[1] = bufout[1];
stereo_split(buftmp2[0], buftmp2[1], input, nb_samples);
} else {
buftmp2[0] = input;
buftmp3[0] = output;
memcpy(buftmp2[0], input, nb_samples*sizeof(short));
}
nb_samples += s->temp_len;
/* resample each channel */
nb_samples1 = 0; /* avoid warning */
for(i=0;i<s->filter_channels;i++) {
nb_samples1 = mono_resample(&s->channel_ctx[i], buftmp3[i], buftmp2[i], nb_samples);
int consumed;
int is_last= i+1 == s->filter_channels;
nb_samples1 = av_resample(s->resample_context, buftmp3[i], bufin[i], &consumed, nb_samples, lenout, is_last);
s->temp_len= nb_samples - consumed;
s->temp[i]= av_realloc(s->temp[i], s->temp_len*sizeof(short));
memcpy(s->temp[i], bufin[i] + consumed, s->temp_len*sizeof(short));
}
if (s->output_channels == 2 && s->input_channels == 1) {
@ -337,8 +233,8 @@ int audio_resample(ReSampleContext *s, short *output, short *input, int nb_sampl
ac3_5p1_mux(output, buftmp3[0], buftmp3[1], nb_samples1);
}
av_free(bufin[0]);
av_free(bufin[1]);
for(i=0; i<s->filter_channels; i++)
av_free(bufin[i]);
av_free(bufout[0]);
av_free(bufout[1]);
@ -347,5 +243,8 @@ int audio_resample(ReSampleContext *s, short *output, short *input, int nb_sampl
void audio_resample_close(ReSampleContext *s)
{
av_resample_close(s->resample_context);
av_freep(&s->temp[0]);
av_freep(&s->temp[1]);
av_free(s);
}

View File

@ -0,0 +1,324 @@
/*
* audio resampling
* Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
*
* 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 resample2.c
* audio resampling
* @author Michael Niedermayer <michaelni@gmx.at>
*/
#include "avcodec.h"
#include "dsputil.h"
#ifndef CONFIG_RESAMPLE_HP
#define FILTER_SHIFT 15
#define FELEM int16_t
#define FELEM2 int32_t
#define FELEML int64_t
#define FELEM_MAX INT16_MAX
#define FELEM_MIN INT16_MIN
#define WINDOW_TYPE 9
#elif !defined(CONFIG_RESAMPLE_AUDIOPHILE_KIDDY_MODE)
#define FILTER_SHIFT 30
#define FELEM int32_t
#define FELEM2 int64_t
#define FELEML int64_t
#define FELEM_MAX INT32_MAX
#define FELEM_MIN INT32_MIN
#define WINDOW_TYPE 12
#else
#define FILTER_SHIFT 0
#define FELEM double
#define FELEM2 double
#define FELEML double
#define WINDOW_TYPE 24
#endif
typedef struct AVResampleContext{
FELEM *filter_bank;
int filter_length;
int ideal_dst_incr;
int dst_incr;
int index;
int frac;
int src_incr;
int compensation_distance;
int phase_shift;
int phase_mask;
int linear;
}AVResampleContext;
/**
* 0th order modified bessel function of the first kind.
*/
static double bessel(double x){
double v=1;
double t=1;
int i;
x= x*x/4;
for(i=1; i<50; i++){
t *= x/(i*i);
v += t;
}
return v;
}
/**
* builds a polyphase filterbank.
* @param factor resampling factor
* @param scale wanted sum of coefficients for each filter
* @param type 0->cubic, 1->blackman nuttall windowed sinc, 2..16->kaiser windowed sinc beta=2..16
*/
void av_build_filter(FELEM *filter, double factor, int tap_count, int phase_count, int scale, int type){
int ph, i;
double x, y, w, tab[tap_count];
const int center= (tap_count-1)/2;
/* if upsampling, only need to interpolate, no filter */
if (factor > 1.0)
factor = 1.0;
for(ph=0;ph<phase_count;ph++) {
double norm = 0;
for(i=0;i<tap_count;i++) {
x = M_PI * ((double)(i - center) - (double)ph / phase_count) * factor;
if (x == 0) y = 1.0;
else y = sin(x) / x;
switch(type){
case 0:{
const float d= -0.5; //first order derivative = -0.5
x = fabs(((double)(i - center) - (double)ph / phase_count) * factor);
if(x<1.0) y= 1 - 3*x*x + 2*x*x*x + d*( -x*x + x*x*x);
else y= d*(-4 + 8*x - 5*x*x + x*x*x);
break;}
case 1:
w = 2.0*x / (factor*tap_count) + M_PI;
y *= 0.3635819 - 0.4891775 * cos(w) + 0.1365995 * cos(2*w) - 0.0106411 * cos(3*w);
break;
default:
w = 2.0*x / (factor*tap_count*M_PI);
y *= bessel(type*sqrt(FFMAX(1-w*w, 0)));
break;
}
tab[i] = y;
norm += y;
}
/* normalize so that an uniform color remains the same */
for(i=0;i<tap_count;i++) {
#ifdef CONFIG_RESAMPLE_AUDIOPHILE_KIDDY_MODE
filter[ph * tap_count + i] = tab[i] / norm;
#else
filter[ph * tap_count + i] = av_clip(lrintf(tab[i] * scale / norm), FELEM_MIN, FELEM_MAX);
#endif
}
}
#if 0
{
#define LEN 1024
int j,k;
double sine[LEN + tap_count];
double filtered[LEN];
double maxff=-2, minff=2, maxsf=-2, minsf=2;
for(i=0; i<LEN; i++){
double ss=0, sf=0, ff=0;
for(j=0; j<LEN+tap_count; j++)
sine[j]= cos(i*j*M_PI/LEN);
for(j=0; j<LEN; j++){
double sum=0;
ph=0;
for(k=0; k<tap_count; k++)
sum += filter[ph * tap_count + k] * sine[k+j];
filtered[j]= sum / (1<<FILTER_SHIFT);
ss+= sine[j + center] * sine[j + center];
ff+= filtered[j] * filtered[j];
sf+= sine[j + center] * filtered[j];
}
ss= sqrt(2*ss/LEN);
ff= sqrt(2*ff/LEN);
sf= 2*sf/LEN;
maxff= FFMAX(maxff, ff);
minff= FFMIN(minff, ff);
maxsf= FFMAX(maxsf, sf);
minsf= FFMIN(minsf, sf);
if(i%11==0){
av_log(NULL, AV_LOG_ERROR, "i:%4d ss:%f ff:%13.6e-%13.6e sf:%13.6e-%13.6e\n", i, ss, maxff, minff, maxsf, minsf);
minff=minsf= 2;
maxff=maxsf= -2;
}
}
}
#endif
}
/**
* Initializes an audio resampler.
* Note, if either rate is not an integer then simply scale both rates up so they are.
*/
AVResampleContext *av_resample_init(int out_rate, int in_rate, int filter_size, int phase_shift, int linear, double cutoff){
AVResampleContext *c= av_mallocz(sizeof(AVResampleContext));
double factor= FFMIN(out_rate * cutoff / in_rate, 1.0);
int phase_count= 1<<phase_shift;
c->phase_shift= phase_shift;
c->phase_mask= phase_count-1;
c->linear= linear;
c->filter_length= FFMAX((int)ceil(filter_size/factor), 1);
c->filter_bank= av_mallocz(c->filter_length*(phase_count+1)*sizeof(FELEM));
av_build_filter(c->filter_bank, factor, c->filter_length, phase_count, 1<<FILTER_SHIFT, WINDOW_TYPE);
memcpy(&c->filter_bank[c->filter_length*phase_count+1], c->filter_bank, (c->filter_length-1)*sizeof(FELEM));
c->filter_bank[c->filter_length*phase_count]= c->filter_bank[c->filter_length - 1];
c->src_incr= out_rate;
c->ideal_dst_incr= c->dst_incr= in_rate * phase_count;
c->index= -phase_count*((c->filter_length-1)/2);
return c;
}
void av_resample_close(AVResampleContext *c){
av_freep(&c->filter_bank);
av_freep(&c);
}
/**
* Compensates samplerate/timestamp drift. The compensation is done by changing
* the resampler parameters, so no audible clicks or similar distortions occur
* @param compensation_distance distance in output samples over which the compensation should be performed
* @param sample_delta number of output samples which should be output less
*
* example: av_resample_compensate(c, 10, 500)
* here instead of 510 samples only 500 samples would be output
*
* note, due to rounding the actual compensation might be slightly different,
* especially if the compensation_distance is large and the in_rate used during init is small
*/
void av_resample_compensate(AVResampleContext *c, int sample_delta, int compensation_distance){
// sample_delta += (c->ideal_dst_incr - c->dst_incr)*(int64_t)c->compensation_distance / c->ideal_dst_incr;
c->compensation_distance= compensation_distance;
c->dst_incr = c->ideal_dst_incr - c->ideal_dst_incr * (int64_t)sample_delta / compensation_distance;
}
/**
* resamples.
* @param src an array of unconsumed samples
* @param consumed the number of samples of src which have been consumed are returned here
* @param src_size the number of unconsumed samples available
* @param dst_size the amount of space in samples available in dst
* @param update_ctx If this is 0 then the context will not be modified, that way several channels can be resampled with the same context.
* @return the number of samples written in dst or -1 if an error occurred
*/
int av_resample(AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx){
int dst_index, i;
int index= c->index;
int frac= c->frac;
int dst_incr_frac= c->dst_incr % c->src_incr;
int dst_incr= c->dst_incr / c->src_incr;
int compensation_distance= c->compensation_distance;
if(compensation_distance == 0 && c->filter_length == 1 && c->phase_shift==0){
int64_t index2= ((int64_t)index)<<32;
int64_t incr= (1LL<<32) * c->dst_incr / c->src_incr;
dst_size= FFMIN(dst_size, (src_size-1-index) * (int64_t)c->src_incr / c->dst_incr);
for(dst_index=0; dst_index < dst_size; dst_index++){
dst[dst_index] = src[index2>>32];
index2 += incr;
}
frac += dst_index * dst_incr_frac;
index += dst_index * dst_incr;
index += frac / c->src_incr;
frac %= c->src_incr;
}else{
for(dst_index=0; dst_index < dst_size; dst_index++){
FELEM *filter= c->filter_bank + c->filter_length*(index & c->phase_mask);
int sample_index= index >> c->phase_shift;
FELEM2 val=0;
if(sample_index < 0){
for(i=0; i<c->filter_length; i++)
val += src[FFABS(sample_index + i) % src_size] * filter[i];
}else if(sample_index + c->filter_length > src_size){
break;
}else if(c->linear){
FELEM2 v2=0;
for(i=0; i<c->filter_length; i++){
val += src[sample_index + i] * (FELEM2)filter[i];
v2 += src[sample_index + i] * (FELEM2)filter[i + c->filter_length];
}
val+=(v2-val)*(FELEML)frac / c->src_incr;
}else{
for(i=0; i<c->filter_length; i++){
val += src[sample_index + i] * (FELEM2)filter[i];
}
}
#ifdef CONFIG_RESAMPLE_AUDIOPHILE_KIDDY_MODE
dst[dst_index] = av_clip_int16(lrintf(val));
#else
val = (val + (1<<(FILTER_SHIFT-1)))>>FILTER_SHIFT;
dst[dst_index] = (unsigned)(val + 32768) > 65535 ? (val>>31) ^ 32767 : val;
#endif
frac += dst_incr_frac;
index += dst_incr;
if(frac >= c->src_incr){
frac -= c->src_incr;
index++;
}
if(dst_index + 1 == compensation_distance){
compensation_distance= 0;
dst_incr_frac= c->ideal_dst_incr % c->src_incr;
dst_incr= c->ideal_dst_incr / c->src_incr;
}
}
}
*consumed= FFMAX(index, 0) >> c->phase_shift;
if(index>=0) index &= c->phase_mask;
if(compensation_distance){
compensation_distance -= dst_index;
assert(compensation_distance > 0);
}
if(update_ctx){
c->frac= frac;
c->index= index;
c->dst_incr= dst_incr_frac + c->src_incr*dst_incr;
c->compensation_distance= compensation_distance;
}
#if 0
if(update_ctx && !c->compensation_distance){
#undef rand
av_resample_compensate(c, rand() % (8000*2) - 8000, 8000*2);
av_log(NULL, AV_LOG_DEBUG, "%d %d %d\n", c->dst_incr, c->ideal_dst_incr, c->compensation_distance);
}
#endif
return dst_index;
}

View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2000-2002 Fabrice Bellard
* Copyright (c) 2002-2004 Michael Niedermayer
*
* 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 rl.h
* rl header.
*/
#ifndef FFMPEG_RL_H
#define FFMPEG_RL_H
#include <stdint.h>
#include "bitstream.h"
/* run length table */
#define MAX_RUN 64
#define MAX_LEVEL 64
/** RLTable. */
typedef struct RLTable {
int n; ///< number of entries of table_vlc minus 1
int last; ///< number of values for last = 0
const uint16_t (*table_vlc)[2];
const int8_t *table_run;
const int8_t *table_level;
uint8_t *index_run[2]; ///< encoding only
int8_t *max_level[2]; ///< encoding & decoding
int8_t *max_run[2]; ///< encoding & decoding
VLC vlc; ///< decoding only deprecated FIXME remove
RL_VLC_ELEM *rl_vlc[32]; ///< decoding only
} RLTable;
/**
*
* @param static_store static uint8_t array[2][2*MAX_RUN + MAX_LEVEL + 3] which will hold
* the level and run tables, if this is NULL av_malloc() will be used
*/
void init_rl(RLTable *rl, uint8_t static_store[2][2*MAX_RUN + MAX_LEVEL + 3]);
void init_vlc_rl(RLTable *rl);
#define INIT_VLC_RL(rl, static_size)\
{\
int q;\
static RL_VLC_ELEM rl_vlc_table[32][static_size];\
INIT_VLC_STATIC(&rl.vlc, 9, rl.n + 1,\
&rl.table_vlc[0][1], 4, 2,\
&rl.table_vlc[0][0], 4, 2, static_size);\
\
if(!rl.rl_vlc[0]){\
for(q=0; q<32; q++)\
rl.rl_vlc[q]= rl_vlc_table[q];\
\
init_vlc_rl(&rl);\
}\
}
static inline int get_rl_index(const RLTable *rl, int last, int run, int level)
{
int index;
index = rl->index_run[last][run];
if (index >= rl->n)
return rl->n;
if (level > rl->max_level[last][run])
return rl->n;
return index + level - 1;
}
#endif /* FFMPEG_RL_H */

View File

@ -0,0 +1,241 @@
/*
* RL2 Video Decoder
* Copyright (C) 2008 Sascha Sommer (saschasommer@freenet.de)
*
* 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
*/
/**
* RL2 Video Decoder
* @file rl2.c
* @author Sascha Sommer (saschasommer@freenet.de)
* For more information about the RL2 format, visit:
* http://wiki.multimedia.cx/index.php?title=RL2
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "avcodec.h"
#define EXTRADATA1_SIZE (6 + 256 * 3) ///< video base, clr count, palette
typedef struct Rl2Context {
AVCodecContext *avctx;
AVFrame frame;
unsigned short video_base; ///< initial drawing offset
unsigned int clr_count; ///< number of used colors (currently unused)
unsigned char* back_frame; ///< background frame
unsigned int palette[AVPALETTE_COUNT];
} Rl2Context;
/**
* Run Length Decode a single 320x200 frame
* @param s rl2 context
* @param buf input buffer
* @param size input buffer size
* @param out ouput buffer
* @param stride stride of the output buffer
* @param video_base offset of the rle data inside the frame
*/
static void rl2_rle_decode(Rl2Context *s,const unsigned char* in,int size,
unsigned char* out,int stride,int video_base){
int base_x = video_base % s->avctx->width;
int base_y = video_base / s->avctx->width;
int stride_adj = stride - s->avctx->width;
int i;
const unsigned char* back_frame = s->back_frame;
const unsigned char* in_end = in + size;
const unsigned char* out_end = out + stride * s->avctx->height;
unsigned char* line_end = out + s->avctx->width;
/** copy start of the background frame */
for(i=0;i<=base_y;i++){
if(s->back_frame)
memcpy(out,back_frame,s->avctx->width);
out += stride;
back_frame += s->avctx->width;
}
back_frame += base_x - s->avctx->width;
line_end = out - stride_adj;
out += base_x - stride;
/** decode the variable part of the frame */
while(in < in_end){
unsigned char val = *in++;
int len = 1;
if(val >= 0x80){
if(in >= in_end)
break;
len = *in++;
if(!len)
break;
}
if(len >= out_end - out)
break;
if(s->back_frame)
val |= 0x80;
else
val &= ~0x80;
while(len--){
*out++ = (val == 0x80)? *back_frame:val;
back_frame++;
if(out == line_end){
out += stride_adj;
line_end += stride;
if(len >= out_end - out)
break;
}
}
}
/** copy the rest from the background frame */
if(s->back_frame){
while(out < out_end){
memcpy(out, back_frame, line_end - out);
back_frame += line_end - out;
out = line_end + stride_adj;
line_end += stride;
}
}
}
/**
* Initialize the decoder
* @param avctx decoder context
* @return 0 success, -1 on error
*/
static av_cold int rl2_decode_init(AVCodecContext *avctx)
{
Rl2Context *s = avctx->priv_data;
int back_size;
int i;
s->avctx = avctx;
avctx->pix_fmt = PIX_FMT_PAL8;
/** parse extra data */
if(!avctx->extradata || avctx->extradata_size < EXTRADATA1_SIZE){
av_log(avctx, AV_LOG_ERROR, "invalid extradata size\n");
return -1;
}
/** get frame_offset */
s->video_base = AV_RL16(&avctx->extradata[0]);
s->clr_count = AV_RL32(&avctx->extradata[2]);
if(s->video_base >= avctx->width * avctx->height){
av_log(avctx, AV_LOG_ERROR, "invalid video_base\n");
return -1;
}
/** initialize palette */
for(i=0;i<AVPALETTE_COUNT;i++)
s->palette[i] = AV_RB24(&avctx->extradata[6 + i * 3]);
/** decode background frame if present */
back_size = avctx->extradata_size - EXTRADATA1_SIZE;
if(back_size > 0){
unsigned char* back_frame = av_mallocz(avctx->width*avctx->height);
if(!back_frame)
return -1;
rl2_rle_decode(s,avctx->extradata + EXTRADATA1_SIZE,back_size,
back_frame,avctx->width,0);
s->back_frame = back_frame;
}
return 0;
}
/**
* Decode a single frame
* @param avctx decoder context
* @param data decoded frame
* @param data_size size of the decoded frame
* @param buf input buffer
* @param buf_size input buffer size
* @return 0 success, -1 on error
*/
static int rl2_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
const uint8_t *buf, int buf_size)
{
Rl2Context *s = avctx->priv_data;
if(s->frame.data[0])
avctx->release_buffer(avctx, &s->frame);
/** get buffer */
s->frame.reference= 0;
if(avctx->get_buffer(avctx, &s->frame)) {
av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
return -1;
}
/** run length decode */
rl2_rle_decode(s,buf,buf_size,s->frame.data[0],s->frame.linesize[0],s->video_base);
/** make the palette available on the way out */
memcpy(s->frame.data[1], s->palette, AVPALETTE_SIZE);
*data_size = sizeof(AVFrame);
*(AVFrame*)data = s->frame;
/** report that the buffer was completely consumed */
return buf_size;
}
/**
* Uninit decoder
* @param avctx decoder context
* @return 0 success, -1 on error
*/
static av_cold int rl2_decode_end(AVCodecContext *avctx)
{
Rl2Context *s = avctx->priv_data;
if(s->frame.data[0])
avctx->release_buffer(avctx, &s->frame);
av_free(s->back_frame);
return 0;
}
AVCodec rl2_decoder = {
"rl2",
CODEC_TYPE_VIDEO,
CODEC_ID_RL2,
sizeof(Rl2Context),
rl2_decode_init,
NULL,
rl2_decode_end,
rl2_decode_frame,
CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("RL2 video"),
};

View File

@ -0,0 +1,84 @@
/*
* RLE encoder
* Copyright (c) 2007 Bobby Bingham
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avcodec.h"
#include "rle.h"
/**
* Count up to 127 consecutive pixels which are either all the same or
* all differ from the previous and next pixels.
* @param start Pointer to the first pixel
* @param len Maximum number of pixels
* @param bpp Bytes per pixel
* @param same 1 if searching for identical pixel values. 0 for differing
* @return Number of matching consecutive pixels found
*/
static int count_pixels(const uint8_t *start, int len, int bpp, int same)
{
const uint8_t *pos;
int count = 1;
for(pos = start + bpp; count < FFMIN(127, len); pos += bpp, count ++) {
if(same != !memcmp(pos-bpp, pos, bpp)) {
if(!same) {
/* if bpp == 1, then 0 1 1 0 is more efficiently encoded as a single
* raw block of pixels. for larger bpp, RLE is as good or better */
if(bpp == 1 && count + 1 < FFMIN(127, len) && *pos != *(pos+1))
continue;
/* if RLE can encode the next block better than as a raw block,
* back up and leave _all_ the identical pixels for RLE */
count --;
}
break;
}
}
return count;
}
int ff_rle_encode(uint8_t *outbuf, int out_size, const uint8_t *ptr , int bpp, int w,
int add_rep, int xor_rep, int add_raw, int xor_raw)
{
int count, x;
uint8_t *out = outbuf;
for(x = 0; x < w; x += count) {
/* see if we can encode the next set of pixels with RLE */
if((count = count_pixels(ptr, w-x, bpp, 1)) > 1) {
if(out + bpp + 1 > outbuf + out_size) return -1;
*out++ = (count ^ xor_rep) + add_rep;
memcpy(out, ptr, bpp);
out += bpp;
} else {
/* fall back on uncompressed */
count = count_pixels(ptr, w-x, bpp, 0);
if(out + bpp*count >= outbuf + out_size) return -1;
*out++ = (count ^ xor_raw) + add_raw;
memcpy(out, ptr, bpp * count);
out += bpp * count;
}
ptr += count * bpp;
}
return out - outbuf;
}

View File

@ -0,0 +1,39 @@
/*
* RLE encoder
*
* 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_RLE_H
#define FFMPEG_RLE_H
#include <stdint.h>
/**
* RLE compress the row, with maximum size of out_size. Value before repeated bytes is (count ^ xor_rep) + add_rep.
* Value before raw bytes is (count ^ xor_raw) + add_raw.
* @param outbuf Output buffer
* @param out_size Maximum output size
* @param ptr Input buffer
* @param bpp Bytes per pixel
* @param w Image width
* @return Size of output in bytes, or -1 if larger than out_size
*/
int ff_rle_encode(uint8_t *outbuf, int out_size, const uint8_t *inbuf, int bpp, int w,
int add_rep, int xor_rep, int add_raw, int xor_raw);
#endif /* FFMPEG_RLE_H */

View File

@ -0,0 +1,179 @@
/*
* RoQ audio encoder
*
* Copyright (c) 2005 Eric Lasota
* Based on RoQ specs (c)2001 Tim Ferguson
*
* 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"
#define ROQ_FIRST_FRAME_SIZE (735*8)
#define ROQ_FRAME_SIZE 735
#define MAX_DPCM (127*127)
static unsigned char dpcmValues[MAX_DPCM];
typedef struct
{
short lastSample[2];
} ROQDPCMContext_t;
static av_cold void roq_dpcm_table_init(void)
{
int i;
/* Create a table of quick DPCM values */
for (i=0; i<MAX_DPCM; i++) {
int s= ff_sqrt(i);
int mid= s*s + s;
dpcmValues[i]= s + (i>mid);
}
}
static int roq_dpcm_encode_init(AVCodecContext *avctx)
{
ROQDPCMContext_t *context = avctx->priv_data;
if (avctx->channels > 2) {
av_log(avctx, AV_LOG_ERROR, "Audio must be mono or stereo\n");
return -1;
}
if (avctx->sample_rate != 22050) {
av_log(avctx, AV_LOG_ERROR, "Audio must be 22050 Hz\n");
return -1;
}
if (avctx->sample_fmt != SAMPLE_FMT_S16) {
av_log(avctx, AV_LOG_ERROR, "Audio must be signed 16-bit\n");
return -1;
}
roq_dpcm_table_init();
avctx->frame_size = ROQ_FIRST_FRAME_SIZE;
context->lastSample[0] = context->lastSample[1] = 0;
avctx->coded_frame= avcodec_alloc_frame();
avctx->coded_frame->key_frame= 1;
return 0;
}
static unsigned char dpcm_predict(short *previous, short current)
{
int diff;
int negative;
int result;
int predicted;
diff = current - *previous;
negative = diff<0;
diff = FFABS(diff);
if (diff >= MAX_DPCM)
result = 127;
else
result = dpcmValues[diff];
/* See if this overflows */
retry:
diff = result*result;
if (negative)
diff = -diff;
predicted = *previous + diff;
/* If it overflows, back off a step */
if (predicted > 32767 || predicted < -32768) {
result--;
goto retry;
}
/* Add the sign bit */
result |= negative << 7; //if (negative) result |= 128;
*previous = predicted;
return result;
}
static int roq_dpcm_encode_frame(AVCodecContext *avctx,
unsigned char *frame, int buf_size, void *data)
{
int i, samples, stereo, ch;
short *in;
unsigned char *out;
ROQDPCMContext_t *context = avctx->priv_data;
stereo = (avctx->channels == 2);
if (stereo) {
context->lastSample[0] &= 0xFF00;
context->lastSample[1] &= 0xFF00;
}
out = frame;
in = data;
bytestream_put_byte(&out, stereo ? 0x21 : 0x20);
bytestream_put_byte(&out, 0x10);
bytestream_put_le32(&out, avctx->frame_size*avctx->channels);
if (stereo) {
bytestream_put_byte(&out, (context->lastSample[1])>>8);
bytestream_put_byte(&out, (context->lastSample[0])>>8);
} else
bytestream_put_le16(&out, context->lastSample[0]);
/* Write the actual samples */
samples = avctx->frame_size;
for (i=0; i<samples; i++)
for (ch=0; ch<avctx->channels; ch++)
*out++ = dpcm_predict(&context->lastSample[ch], *in++);
/* Use smaller frames from now on */
avctx->frame_size = ROQ_FRAME_SIZE;
/* Return the result size */
return out - frame;
}
static av_cold int roq_dpcm_encode_close(AVCodecContext *avctx)
{
av_freep(&avctx->coded_frame);
return 0;
}
AVCodec roq_dpcm_encoder = {
"roq_dpcm",
CODEC_TYPE_AUDIO,
CODEC_ID_ROQ_DPCM,
sizeof(ROQDPCMContext_t),
roq_dpcm_encode_init,
roq_dpcm_encode_frame,
roq_dpcm_encode_close,
NULL,
.sample_fmts = (enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_NONE},
.long_name = NULL_IF_CONFIG_SMALL("id RoQ DPCM"),
};

View File

@ -1,501 +1,138 @@
/*
* Copyright (C) 2003 the ffmpeg project
* Copyright (C) 2003 Mike Melanson
* Copyright (C) 2003 Dr. Tim Ferguson
*
* This library is free software; you can redistribute it and/or
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file roqvideo.c
* Id RoQ Video Decoder by Dr. Tim Ferguson
* For more information about the Id RoQ format, visit:
* http://www.csse.monash.edu.au/~timf/
* id RoQ Video common functions based on work by Dr. Tim Ferguson
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "common.h"
#include "avcodec.h"
#include "dsputil.h"
#include "roqvideo.h"
typedef struct {
unsigned char y0, y1, y2, y3, u, v;
} roq_cell;
typedef struct {
int idx[4];
} roq_qcell;
static int uiclip[1024], *uiclp; /* clipping table */
#define avg2(a,b) uiclp[(((int)(a)+(int)(b)+1)>>1)]
#define avg4(a,b,c,d) uiclp[(((int)(a)+(int)(b)+(int)(c)+(int)(d)+2)>>2)]
typedef struct RoqContext {
AVCodecContext *avctx;
DSPContext dsp;
AVFrame last_frame;
AVFrame current_frame;
int first_frame;
int y_stride;
int c_stride;
roq_cell cells[256];
roq_qcell qcells[256];
unsigned char *buf;
int size;
} RoqContext;
#define RoQ_INFO 0x1001
#define RoQ_QUAD_CODEBOOK 0x1002
#define RoQ_QUAD_VQ 0x1011
#define RoQ_SOUND_MONO 0x1020
#define RoQ_SOUND_STEREO 0x1021
#define RoQ_ID_MOT 0x00
#define RoQ_ID_FCC 0x01
#define RoQ_ID_SLD 0x02
#define RoQ_ID_CCC 0x03
#define get_byte(in_buffer) *(in_buffer++)
#define get_word(in_buffer) ((unsigned short)(in_buffer += 2, \
(in_buffer[-1] << 8 | in_buffer[-2])))
#define get_long(in_buffer) ((unsigned long)(in_buffer += 4, \
(in_buffer[-1] << 24 | in_buffer[-2] << 16 | in_buffer[-3] << 8 | in_buffer[-4])))
static void apply_vector_2x2(RoqContext *ri, int x, int y, roq_cell *cell)
static inline void block_copy(unsigned char *out, unsigned char *in,
int outstride, int instride, int sz)
{
unsigned char *yptr;
yptr = ri->current_frame.data[0] + (y * ri->y_stride) + x;
*yptr++ = cell->y0;
*yptr++ = cell->y1;
yptr += (ri->y_stride - 2);
*yptr++ = cell->y2;
*yptr++ = cell->y3;
ri->current_frame.data[1][(y/2) * (ri->c_stride) + x/2] = cell->u;
ri->current_frame.data[2][(y/2) * (ri->c_stride) + x/2] = cell->v;
int rows = sz;
while(rows--) {
memcpy(out, in, sz);
out += outstride;
in += instride;
}
}
static void apply_vector_4x4(RoqContext *ri, int x, int y, roq_cell *cell)
void ff_apply_vector_2x2(RoqContext *ri, int x, int y, roq_cell *cell)
{
unsigned long row_inc, c_row_inc;
register unsigned char y0, y1, u, v;
unsigned char *yptr, *uptr, *vptr;
unsigned char *bptr;
int boffs,stride;
yptr = ri->current_frame.data[0] + (y * ri->y_stride) + x;
uptr = ri->current_frame.data[1] + (y/2) * (ri->c_stride) + x/2;
vptr = ri->current_frame.data[2] + (y/2) * (ri->c_stride) + x/2;
stride = ri->current_frame->linesize[0];
boffs = y*stride + x;
row_inc = ri->y_stride - 4;
c_row_inc = (ri->c_stride) - 2;
*yptr++ = y0 = cell->y0; *uptr++ = u = cell->u; *vptr++ = v = cell->v;
*yptr++ = y0;
*yptr++ = y1 = cell->y1; *uptr++ = u; *vptr++ = v;
*yptr++ = y1;
bptr = ri->current_frame->data[0] + boffs;
bptr[0 ] = cell->y[0];
bptr[1 ] = cell->y[1];
bptr[stride ] = cell->y[2];
bptr[stride+1] = cell->y[3];
yptr += row_inc;
stride = ri->current_frame->linesize[1];
boffs = y*stride + x;
*yptr++ = y0;
*yptr++ = y0;
*yptr++ = y1;
*yptr++ = y1;
bptr = ri->current_frame->data[1] + boffs;
bptr[0 ] =
bptr[1 ] =
bptr[stride ] =
bptr[stride+1] = cell->u;
yptr += row_inc; uptr += c_row_inc; vptr += c_row_inc;
*yptr++ = y0 = cell->y2; *uptr++ = u; *vptr++ = v;
*yptr++ = y0;
*yptr++ = y1 = cell->y3; *uptr++ = u; *vptr++ = v;
*yptr++ = y1;
yptr += row_inc;
*yptr++ = y0;
*yptr++ = y0;
*yptr++ = y1;
*yptr++ = y1;
bptr = ri->current_frame->data[2] + boffs;
bptr[0 ] =
bptr[1 ] =
bptr[stride ] =
bptr[stride+1] = cell->v;
}
static void apply_motion_4x4(RoqContext *ri, int x, int y, unsigned char mv,
signed char mean_x, signed char mean_y)
void ff_apply_vector_4x4(RoqContext *ri, int x, int y, roq_cell *cell)
{
int i, hw, mx, my;
unsigned char *pa, *pb;
unsigned char *bptr;
int boffs,stride;
mx = x + 8 - (mv >> 4) - mean_x;
my = y + 8 - (mv & 0xf) - mean_y;
stride = ri->current_frame->linesize[0];
boffs = y*stride + x;
pa = ri->current_frame.data[0] + (y * ri->y_stride) + x;
pb = ri->last_frame.data[0] + (my * ri->y_stride) + mx;
for(i = 0; i < 4; i++) {
pa[0] = pb[0];
pa[1] = pb[1];
pa[2] = pb[2];
pa[3] = pb[3];
pa += ri->y_stride;
pb += ri->y_stride;
}
bptr = ri->current_frame->data[0] + boffs;
bptr[ 0] = bptr[ 1] = bptr[stride ] = bptr[stride +1] = cell->y[0];
bptr[ 2] = bptr[ 3] = bptr[stride +2] = bptr[stride +3] = cell->y[1];
bptr[stride*2 ] = bptr[stride*2+1] = bptr[stride*3 ] = bptr[stride*3+1] = cell->y[2];
bptr[stride*2+2] = bptr[stride*2+3] = bptr[stride*3+2] = bptr[stride*3+3] = cell->y[3];
#if 0
pa = ri->current_frame.data[1] + (y/2) * (ri->c_stride) + x/2;
pb = ri->last_frame.data[1] + (my/2) * (ri->c_stride) + (mx + 1)/2;
for(i = 0; i < 2; i++) {
pa[0] = pb[0];
pa[1] = pb[1];
pa += ri->c_stride;
pb += ri->c_stride;
}
stride = ri->current_frame->linesize[1];
boffs = y*stride + x;
pa = ri->current_frame.data[2] + (y/2) * (ri->c_stride) + x/2;
pb = ri->last_frame.data[2] + (my/2) * (ri->c_stride) + (mx + 1)/2;
for(i = 0; i < 2; i++) {
pa[0] = pb[0];
pa[1] = pb[1];
pa += ri->c_stride;
pb += ri->c_stride;
}
#else
hw = ri->y_stride/2;
pa = ri->current_frame.data[1] + (y * ri->y_stride)/4 + x/2;
pb = ri->last_frame.data[1] + (my/2) * (ri->y_stride/2) + (mx + 1)/2;
bptr = ri->current_frame->data[1] + boffs;
bptr[ 0] = bptr[ 1] = bptr[stride ] = bptr[stride +1] =
bptr[ 2] = bptr[ 3] = bptr[stride +2] = bptr[stride +3] =
bptr[stride*2 ] = bptr[stride*2+1] = bptr[stride*3 ] = bptr[stride*3+1] =
bptr[stride*2+2] = bptr[stride*2+3] = bptr[stride*3+2] = bptr[stride*3+3] = cell->u;
for(i = 0; i < 2; i++) {
switch(((my & 0x01) << 1) | (mx & 0x01)) {
case 0:
pa[0] = pb[0];
pa[1] = pb[1];
pa[hw] = pb[hw];
pa[hw+1] = pb[hw+1];
break;
case 1:
pa[0] = avg2(pb[0], pb[1]);
pa[1] = avg2(pb[1], pb[2]);
pa[hw] = avg2(pb[hw], pb[hw+1]);
pa[hw+1] = avg2(pb[hw+1], pb[hw+2]);
break;
case 2:
pa[0] = avg2(pb[0], pb[hw]);
pa[1] = avg2(pb[1], pb[hw+1]);
pa[hw] = avg2(pb[hw], pb[hw*2]);
pa[hw+1] = avg2(pb[hw+1], pb[(hw*2)+1]);
break;
case 3:
pa[0] = avg4(pb[0], pb[1], pb[hw], pb[hw+1]);
pa[1] = avg4(pb[1], pb[2], pb[hw+1], pb[hw+2]);
pa[hw] = avg4(pb[hw], pb[hw+1], pb[hw*2], pb[(hw*2)+1]);
pa[hw+1] = avg4(pb[hw+1], pb[hw+2], pb[(hw*2)+1], pb[(hw*2)+1]);
break;
}
pa = ri->current_frame.data[2] + (y * ri->y_stride)/4 + x/2;
pb = ri->last_frame.data[2] + (my/2) * (ri->y_stride/2) + (mx + 1)/2;
}
#endif
bptr = ri->current_frame->data[2] + boffs;
bptr[ 0] = bptr[ 1] = bptr[stride ] = bptr[stride +1] =
bptr[ 2] = bptr[ 3] = bptr[stride +2] = bptr[stride +3] =
bptr[stride*2 ] = bptr[stride*2+1] = bptr[stride*3 ] = bptr[stride*3+1] =
bptr[stride*2+2] = bptr[stride*2+3] = bptr[stride*3+2] = bptr[stride*3+3] = cell->v;
}
static void apply_motion_8x8(RoqContext *ri, int x, int y,
unsigned char mv, signed char mean_x, signed char mean_y)
static inline void apply_motion_generic(RoqContext *ri, int x, int y, int deltax,
int deltay, int sz)
{
int mx, my, i, j, hw;
unsigned char *pa, *pb;
int mx, my, cp;
mx = x + 8 - (mv >> 4) - mean_x;
my = y + 8 - (mv & 0xf) - mean_y;
mx = x + deltax;
my = y + deltay;
pa = ri->current_frame.data[0] + (y * ri->y_stride) + x;
pb = ri->last_frame.data[0] + (my * ri->y_stride) + mx;
for(i = 0; i < 8; i++) {
pa[0] = pb[0];
pa[1] = pb[1];
pa[2] = pb[2];
pa[3] = pb[3];
pa[4] = pb[4];
pa[5] = pb[5];
pa[6] = pb[6];
pa[7] = pb[7];
pa += ri->y_stride;
pb += ri->y_stride;
/* check MV against frame boundaries */
if ((mx < 0) || (mx > ri->width - sz) ||
(my < 0) || (my > ri->height - sz)) {
av_log(ri->avctx, AV_LOG_ERROR, "motion vector out of bounds: MV = (%d, %d), boundaries = (0, 0, %d, %d)\n",
mx, my, ri->width, ri->height);
return;
}
#if 0
pa = ri->current_frame.data[1] + (y/2) * (ri->c_stride) + x/2;
pb = ri->last_frame.data[1] + (my/2) * (ri->c_stride) + (mx + 1)/2;
for(i = 0; i < 4; i++) {
pa[0] = pb[0];
pa[1] = pb[1];
pa[2] = pb[2];
pa[3] = pb[3];
pa += ri->c_stride;
pb += ri->c_stride;
}
pa = ri->current_frame.data[2] + (y/2) * (ri->c_stride) + x/2;
pb = ri->last_frame.data[2] + (my/2) * (ri->c_stride) + (mx + 1)/2;
for(i = 0; i < 4; i++) {
pa[0] = pb[0];
pa[1] = pb[1];
pa[2] = pb[2];
pa[3] = pb[3];
pa += ri->c_stride;
pb += ri->c_stride;
}
#else
hw = ri->c_stride;
pa = ri->current_frame.data[1] + (y * ri->y_stride)/4 + x/2;
pb = ri->last_frame.data[1] + (my/2) * (ri->y_stride/2) + (mx + 1)/2;
for(j = 0; j < 2; j++) {
for(i = 0; i < 4; i++) {
switch(((my & 0x01) << 1) | (mx & 0x01)) {
case 0:
pa[0] = pb[0];
pa[1] = pb[1];
pa[2] = pb[2];
pa[3] = pb[3];
break;
case 1:
pa[0] = avg2(pb[0], pb[1]);
pa[1] = avg2(pb[1], pb[2]);
pa[2] = avg2(pb[2], pb[3]);
pa[3] = avg2(pb[3], pb[4]);
break;
case 2:
pa[0] = avg2(pb[0], pb[hw]);
pa[1] = avg2(pb[1], pb[hw+1]);
pa[2] = avg2(pb[2], pb[hw+2]);
pa[3] = avg2(pb[3], pb[hw+3]);
break;
case 3:
pa[0] = avg4(pb[0], pb[1], pb[hw], pb[hw+1]);
pa[1] = avg4(pb[1], pb[2], pb[hw+1], pb[hw+2]);
pa[2] = avg4(pb[2], pb[3], pb[hw+2], pb[hw+3]);
pa[3] = avg4(pb[3], pb[4], pb[hw+3], pb[hw+4]);
break;
}
pa += ri->c_stride;
pb += ri->c_stride;
}
pa = ri->current_frame.data[2] + (y * ri->y_stride)/4 + x/2;
pb = ri->last_frame.data[2] + (my/2) * (ri->y_stride/2) + (mx + 1)/2;
}
#endif
}
static void roqvideo_decode_frame(RoqContext *ri)
{
unsigned int chunk_id = 0, chunk_arg = 0;
unsigned long chunk_size = 0;
int i, j, k, nv1, nv2, vqflg = 0, vqflg_pos = -1;
int vqid, bpos, xpos, ypos, xp, yp, x, y;
int frame_stats[2][4] = {{0},{0}};
roq_qcell *qcell;
unsigned char *buf = ri->buf;
unsigned char *buf_end = ri->buf + ri->size;
while (buf < buf_end) {
chunk_id = get_word(buf);
chunk_size = get_long(buf);
chunk_arg = get_word(buf);
if(chunk_id == RoQ_QUAD_VQ)
break;
if(chunk_id == RoQ_QUAD_CODEBOOK) {
if((nv1 = chunk_arg >> 8) == 0)
nv1 = 256;
if((nv2 = chunk_arg & 0xff) == 0 && nv1 * 6 < chunk_size)
nv2 = 256;
for(i = 0; i < nv1; i++) {
ri->cells[i].y0 = get_byte(buf);
ri->cells[i].y1 = get_byte(buf);
ri->cells[i].y2 = get_byte(buf);
ri->cells[i].y3 = get_byte(buf);
ri->cells[i].u = get_byte(buf);
ri->cells[i].v = get_byte(buf);
}
for(i = 0; i < nv2; i++)
for(j = 0; j < 4; j++)
ri->qcells[i].idx[j] = get_byte(buf);
}
}
bpos = xpos = ypos = 0;
while(bpos < chunk_size) {
for (yp = ypos; yp < ypos + 16; yp += 8)
for (xp = xpos; xp < xpos + 16; xp += 8) {
if (vqflg_pos < 0) {
vqflg = buf[bpos++]; vqflg |= (buf[bpos++] << 8);
vqflg_pos = 7;
}
vqid = (vqflg >> (vqflg_pos * 2)) & 0x3;
frame_stats[0][vqid]++;
vqflg_pos--;
switch(vqid) {
case RoQ_ID_MOT:
apply_motion_8x8(ri, xp, yp, 0, 8, 8);
break;
case RoQ_ID_FCC:
apply_motion_8x8(ri, xp, yp, buf[bpos++], chunk_arg >> 8,
chunk_arg & 0xff);
break;
case RoQ_ID_SLD:
qcell = ri->qcells + buf[bpos++];
apply_vector_4x4(ri, xp, yp, ri->cells + qcell->idx[0]);
apply_vector_4x4(ri, xp+4, yp, ri->cells + qcell->idx[1]);
apply_vector_4x4(ri, xp, yp+4, ri->cells + qcell->idx[2]);
apply_vector_4x4(ri, xp+4, yp+4, ri->cells + qcell->idx[3]);
break;
case RoQ_ID_CCC:
for (k = 0; k < 4; k++) {
x = xp; y = yp;
if(k & 0x01) x += 4;
if(k & 0x02) y += 4;
if (vqflg_pos < 0) {
vqflg = buf[bpos++];
vqflg |= (buf[bpos++] << 8);
vqflg_pos = 7;
}
vqid = (vqflg >> (vqflg_pos * 2)) & 0x3;
frame_stats[1][vqid]++;
vqflg_pos--;
switch(vqid) {
case RoQ_ID_MOT:
apply_motion_4x4(ri, x, y, 0, 8, 8);
break;
case RoQ_ID_FCC:
apply_motion_4x4(ri, x, y, buf[bpos++],
chunk_arg >> 8, chunk_arg & 0xff);
break;
case RoQ_ID_SLD:
qcell = ri->qcells + buf[bpos++];
apply_vector_2x2(ri, x, y, ri->cells + qcell->idx[0]);
apply_vector_2x2(ri, x+2, y, ri->cells + qcell->idx[1]);
apply_vector_2x2(ri, x, y+2, ri->cells + qcell->idx[2]);
apply_vector_2x2(ri, x+2, y+2, ri->cells + qcell->idx[3]);
break;
case RoQ_ID_CCC:
apply_vector_2x2(ri, x, y, ri->cells + buf[bpos]);
apply_vector_2x2(ri, x+2, y, ri->cells + buf[bpos+1]);
apply_vector_2x2(ri, x, y+2, ri->cells + buf[bpos+2]);
apply_vector_2x2(ri, x+2, y+2, ri->cells + buf[bpos+3]);
bpos += 4;
break;
}
}
break;
default:
av_log(ri->avctx, AV_LOG_ERROR, "Unknown vq code: %d\n", vqid);
}
}
xpos += 16;
if (xpos >= ri->avctx->width) {
xpos -= ri->avctx->width;
ypos += 16;
}
if(ypos >= ri->avctx->height)
break;
for(cp = 0; cp < 3; cp++) {
int outstride = ri->current_frame->linesize[cp];
int instride = ri->last_frame ->linesize[cp];
block_copy(ri->current_frame->data[cp] + y*outstride + x,
ri->last_frame->data[cp] + my*instride + mx,
outstride, instride, sz);
}
}
static int roq_decode_init(AVCodecContext *avctx)
void ff_apply_motion_4x4(RoqContext *ri, int x, int y,
int deltax, int deltay)
{
RoqContext *s = avctx->priv_data;
int i;
s->avctx = avctx;
s->first_frame = 1;
avctx->pix_fmt = PIX_FMT_YUV420P;
avctx->has_b_frames = 0;
dsputil_init(&s->dsp, avctx);
uiclp = uiclip+512;
for(i = -512; i < 512; i++)
uiclp[i] = (i < 0 ? 0 : (i > 255 ? 255 : i));
return 0;
apply_motion_generic(ri, x, y, deltax, deltay, 4);
}
static int roq_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
uint8_t *buf, int buf_size)
void ff_apply_motion_8x8(RoqContext *ri, int x, int y,
int deltax, int deltay)
{
RoqContext *s = avctx->priv_data;
*data_size = 0;
if (avctx->get_buffer(avctx, &s->current_frame)) {
av_log(avctx, AV_LOG_ERROR, " RoQ: get_buffer() failed\n");
return -1;
}
s->y_stride = s->current_frame.linesize[0];
s->c_stride = s->current_frame.linesize[1];
s->buf = buf;
s->size = buf_size;
roqvideo_decode_frame(s);
/* release the last frame if it is allocated */
if (s->first_frame)
s->first_frame = 0;
else
avctx->release_buffer(avctx, &s->last_frame);
/* shuffle frames */
s->last_frame = s->current_frame;
*data_size = sizeof(AVFrame);
*(AVFrame*)data = s->current_frame;
return buf_size;
apply_motion_generic(ri, x, y, deltax, deltay, 8);
}
static int roq_decode_end(AVCodecContext *avctx)
{
RoqContext *s = avctx->priv_data;
/* release the last frame */
avctx->release_buffer(avctx, &s->last_frame);
return 0;
}
AVCodec roq_decoder = {
"roqvideo",
CODEC_TYPE_VIDEO,
CODEC_ID_ROQ,
sizeof(RoqContext),
roq_decode_init,
NULL,
roq_decode_end,
roq_decode_frame,
CODEC_CAP_DR1,
};

View File

@ -0,0 +1,92 @@
/*
* Copyright (C) 2003 Mike Melanson
* Copyright (C) 2003 Dr. Tim Ferguson
*
* 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_ROQVIDEO_H
#define FFMPEG_ROQVIDEO_H
#include "libavutil/random.h"
#include "avcodec.h"
#include "dsputil.h"
typedef struct {
unsigned char y[4];
unsigned char u, v;
} roq_cell;
typedef struct {
int idx[4];
} roq_qcell;
typedef struct {
int d[2];
} motion_vect;
typedef struct RoqContext {
AVCodecContext *avctx;
DSPContext dsp;
AVFrame frames[2];
AVFrame *last_frame;
AVFrame *current_frame;
int first_frame;
roq_cell cb2x2[256];
roq_qcell cb4x4[256];
const unsigned char *buf;
int size;
int width, height;
/* Encoder only data */
AVRandomState randctx;
uint64_t lambda;
motion_vect *this_motion4;
motion_vect *last_motion4;
motion_vect *this_motion8;
motion_vect *last_motion8;
unsigned int framesSinceKeyframe;
AVFrame *frame_to_enc;
uint8_t *out_buf;
} RoqContext;
#define RoQ_INFO 0x1001
#define RoQ_QUAD_CODEBOOK 0x1002
#define RoQ_QUAD_VQ 0x1011
#define RoQ_SOUND_MONO 0x1020
#define RoQ_SOUND_STEREO 0x1021
#define RoQ_ID_MOT 0x00
#define RoQ_ID_FCC 0x01
#define RoQ_ID_SLD 0x02
#define RoQ_ID_CCC 0x03
void ff_apply_vector_2x2(RoqContext *ri, int x, int y, roq_cell *cell);
void ff_apply_vector_4x4(RoqContext *ri, int x, int y, roq_cell *cell);
void ff_apply_motion_4x4(RoqContext *ri, int x, int y, int deltax, int deltay);
void ff_apply_motion_8x8(RoqContext *ri, int x, int y, int deltax, int deltay);
#endif /* FFMPEG_ROQVIDEO_H */

View File

@ -0,0 +1,223 @@
/*
* Copyright (C) 2003 the ffmpeg project
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file roqvideodec.c
* id RoQ Video Decoder by Dr. Tim Ferguson
* For more information about the id RoQ format, visit:
* http://www.csse.monash.edu.au/~timf/
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "avcodec.h"
#include "bytestream.h"
#include "roqvideo.h"
static void roqvideo_decode_frame(RoqContext *ri)
{
unsigned int chunk_id = 0, chunk_arg = 0;
unsigned long chunk_size = 0;
int i, j, k, nv1, nv2, vqflg = 0, vqflg_pos = -1;
int vqid, bpos, xpos, ypos, xp, yp, x, y, mx, my;
int frame_stats[2][4] = {{0},{0}};
roq_qcell *qcell;
const unsigned char *buf = ri->buf;
const unsigned char *buf_end = ri->buf + ri->size;
while (buf < buf_end) {
chunk_id = bytestream_get_le16(&buf);
chunk_size = bytestream_get_le32(&buf);
chunk_arg = bytestream_get_le16(&buf);
if(chunk_id == RoQ_QUAD_VQ)
break;
if(chunk_id == RoQ_QUAD_CODEBOOK) {
if((nv1 = chunk_arg >> 8) == 0)
nv1 = 256;
if((nv2 = chunk_arg & 0xff) == 0 && nv1 * 6 < chunk_size)
nv2 = 256;
for(i = 0; i < nv1; i++) {
ri->cb2x2[i].y[0] = *buf++;
ri->cb2x2[i].y[1] = *buf++;
ri->cb2x2[i].y[2] = *buf++;
ri->cb2x2[i].y[3] = *buf++;
ri->cb2x2[i].u = *buf++;
ri->cb2x2[i].v = *buf++;
}
for(i = 0; i < nv2; i++)
for(j = 0; j < 4; j++)
ri->cb4x4[i].idx[j] = *buf++;
}
}
bpos = xpos = ypos = 0;
while(bpos < chunk_size) {
for (yp = ypos; yp < ypos + 16; yp += 8)
for (xp = xpos; xp < xpos + 16; xp += 8) {
if (vqflg_pos < 0) {
vqflg = buf[bpos++]; vqflg |= (buf[bpos++] << 8);
vqflg_pos = 7;
}
vqid = (vqflg >> (vqflg_pos * 2)) & 0x3;
frame_stats[0][vqid]++;
vqflg_pos--;
switch(vqid) {
case RoQ_ID_MOT:
break;
case RoQ_ID_FCC:
mx = 8 - (buf[bpos] >> 4) - ((signed char) (chunk_arg >> 8));
my = 8 - (buf[bpos++] & 0xf) - ((signed char) chunk_arg);
ff_apply_motion_8x8(ri, xp, yp, mx, my);
break;
case RoQ_ID_SLD:
qcell = ri->cb4x4 + buf[bpos++];
ff_apply_vector_4x4(ri, xp, yp, ri->cb2x2 + qcell->idx[0]);
ff_apply_vector_4x4(ri, xp+4, yp, ri->cb2x2 + qcell->idx[1]);
ff_apply_vector_4x4(ri, xp, yp+4, ri->cb2x2 + qcell->idx[2]);
ff_apply_vector_4x4(ri, xp+4, yp+4, ri->cb2x2 + qcell->idx[3]);
break;
case RoQ_ID_CCC:
for (k = 0; k < 4; k++) {
x = xp; y = yp;
if(k & 0x01) x += 4;
if(k & 0x02) y += 4;
if (vqflg_pos < 0) {
vqflg = buf[bpos++];
vqflg |= (buf[bpos++] << 8);
vqflg_pos = 7;
}
vqid = (vqflg >> (vqflg_pos * 2)) & 0x3;
frame_stats[1][vqid]++;
vqflg_pos--;
switch(vqid) {
case RoQ_ID_MOT:
break;
case RoQ_ID_FCC:
mx = 8 - (buf[bpos] >> 4) - ((signed char) (chunk_arg >> 8));
my = 8 - (buf[bpos++] & 0xf) - ((signed char) chunk_arg);
ff_apply_motion_4x4(ri, x, y, mx, my);
break;
case RoQ_ID_SLD:
qcell = ri->cb4x4 + buf[bpos++];
ff_apply_vector_2x2(ri, x, y, ri->cb2x2 + qcell->idx[0]);
ff_apply_vector_2x2(ri, x+2, y, ri->cb2x2 + qcell->idx[1]);
ff_apply_vector_2x2(ri, x, y+2, ri->cb2x2 + qcell->idx[2]);
ff_apply_vector_2x2(ri, x+2, y+2, ri->cb2x2 + qcell->idx[3]);
break;
case RoQ_ID_CCC:
ff_apply_vector_2x2(ri, x, y, ri->cb2x2 + buf[bpos]);
ff_apply_vector_2x2(ri, x+2, y, ri->cb2x2 + buf[bpos+1]);
ff_apply_vector_2x2(ri, x, y+2, ri->cb2x2 + buf[bpos+2]);
ff_apply_vector_2x2(ri, x+2, y+2, ri->cb2x2 + buf[bpos+3]);
bpos += 4;
break;
}
}
break;
default:
av_log(ri->avctx, AV_LOG_ERROR, "Unknown vq code: %d\n", vqid);
}
}
xpos += 16;
if (xpos >= ri->width) {
xpos -= ri->width;
ypos += 16;
}
if(ypos >= ri->height)
break;
}
}
static av_cold int roq_decode_init(AVCodecContext *avctx)
{
RoqContext *s = avctx->priv_data;
s->avctx = avctx;
s->width = avctx->width;
s->height = avctx->height;
s->last_frame = &s->frames[0];
s->current_frame = &s->frames[1];
avctx->pix_fmt = PIX_FMT_YUV444P;
return 0;
}
static int roq_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
const uint8_t *buf, int buf_size)
{
RoqContext *s = avctx->priv_data;
int copy= !s->current_frame->data[0];
if (avctx->reget_buffer(avctx, s->current_frame)) {
av_log(avctx, AV_LOG_ERROR, " RoQ: get_buffer() failed\n");
return -1;
}
if(copy)
av_picture_copy((AVPicture*)s->current_frame, (AVPicture*)s->last_frame,
avctx->pix_fmt, avctx->width, avctx->height);
s->buf = buf;
s->size = buf_size;
roqvideo_decode_frame(s);
*data_size = sizeof(AVFrame);
*(AVFrame*)data = *s->current_frame;
/* shuffle frames */
FFSWAP(AVFrame *, s->current_frame, s->last_frame);
return buf_size;
}
static av_cold int roq_decode_end(AVCodecContext *avctx)
{
RoqContext *s = avctx->priv_data;
/* release the last frame */
if (s->last_frame->data[0])
avctx->release_buffer(avctx, s->last_frame);
if (s->current_frame->data[0])
avctx->release_buffer(avctx, s->current_frame);
return 0;
}
AVCodec roq_decoder = {
"roqvideo",
CODEC_TYPE_VIDEO,
CODEC_ID_ROQ,
sizeof(RoqContext),
roq_decode_init,
NULL,
roq_decode_end,
roq_decode_frame,
CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("id RoQ video"),
};

File diff suppressed because it is too large Load Diff

View File

@ -2,25 +2,26 @@
* Quicktime Video (RPZA) Video Decoder
* 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
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file rpza.c
* QT RPZA Video Decoder by Roberto Togni <rtogni@bresciaonline.it>
* QT RPZA Video Decoder by Roberto Togni
* For more information about the RPZA format, visit:
* http://www.pcisys.net/~melanson/codecs/
*
@ -38,27 +39,18 @@
#include <string.h>
#include <unistd.h>
#include "common.h"
#include "avcodec.h"
#include "dsputil.h"
typedef struct RpzaContext {
AVCodecContext *avctx;
DSPContext dsp;
AVFrame frame;
unsigned char *buf;
const unsigned char *buf;
int size;
} RpzaContext;
#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 ADVANCE_BLOCK() \
{ \
pixel_ptr += 4; \
@ -98,11 +90,11 @@ static void rpza_decode_stream(RpzaContext *s)
/* First byte is always 0xe1. Warn if it's different */
if (s->buf[stream_ptr] != 0xe1)
av_log(s->avctx, AV_LOG_ERROR, "First chunk byte is 0x%02x instead of 0x1e\n",
av_log(s->avctx, AV_LOG_ERROR, "First chunk byte is 0x%02x instead of 0xe1\n",
s->buf[stream_ptr]);
/* Get chunk size, ingnoring first byte */
chunk_size = BE_32(&s->buf[stream_ptr]) & 0x00FFFFFF;
chunk_size = AV_RB32(&s->buf[stream_ptr]) & 0x00FFFFFF;
stream_ptr += 4;
/* If length mismatch use size from MOV file and try to decode anyway */
@ -112,7 +104,7 @@ static void rpza_decode_stream(RpzaContext *s)
chunk_size = s->size;
/* Number of 4x4 blocks in frame. */
total_blocks = (s->avctx->width * s->avctx->height) / (4 * 4);
total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4);
/* Process chunk data */
while (stream_ptr < chunk_size) {
@ -125,8 +117,8 @@ static void rpza_decode_stream(RpzaContext *s)
colorA = (opcode << 8) | (s->buf[stream_ptr++]);
opcode = 0;
if ((s->buf[stream_ptr] & 0x80) != 0) {
/* Must behave as opcode 110xxxxx, using colorA computed
* above. Use fake opcode 0x20 to enter switch block at
/* Must behave as opcode 110xxxxx, using colorA computed
* above. Use fake opcode 0x20 to enter switch block at
* the right place */
opcode = 0x20;
n_blocks = 1;
@ -144,7 +136,7 @@ static void rpza_decode_stream(RpzaContext *s)
/* Fill blocks with one color */
case 0xa0:
colorA = BE_16 (&s->buf[stream_ptr]);
colorA = AV_RB16 (&s->buf[stream_ptr]);
stream_ptr += 2;
while (n_blocks--) {
block_ptr = row_ptr + pixel_ptr;
@ -161,10 +153,10 @@ static void rpza_decode_stream(RpzaContext *s)
/* Fill blocks with 4 colors */
case 0xc0:
colorA = BE_16 (&s->buf[stream_ptr]);
colorA = AV_RB16 (&s->buf[stream_ptr]);
stream_ptr += 2;
case 0x20:
colorB = BE_16 (&s->buf[stream_ptr]);
colorB = AV_RB16 (&s->buf[stream_ptr]);
stream_ptr += 2;
/* sort out the colors */
@ -213,7 +205,7 @@ static void rpza_decode_stream(RpzaContext *s)
for (pixel_x = 0; pixel_x < 4; pixel_x++){
/* We already have color of upper left pixel */
if ((pixel_y != 0) || (pixel_x !=0)) {
colorA = BE_16 (&s->buf[stream_ptr]);
colorA = AV_RB16 (&s->buf[stream_ptr]);
stream_ptr += 2;
}
pixels[block_ptr] = colorA;
@ -234,14 +226,12 @@ static void rpza_decode_stream(RpzaContext *s)
}
}
static int rpza_decode_init(AVCodecContext *avctx)
static av_cold int rpza_decode_init(AVCodecContext *avctx)
{
RpzaContext *s = (RpzaContext *)avctx->priv_data;
RpzaContext *s = avctx->priv_data;
s->avctx = avctx;
avctx->pix_fmt = PIX_FMT_RGB555;
avctx->has_b_frames = 0;
dsputil_init(&s->dsp, avctx);
s->frame.data[0] = NULL;
@ -250,13 +240,9 @@ static int rpza_decode_init(AVCodecContext *avctx)
static int rpza_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
uint8_t *buf, int buf_size)
const uint8_t *buf, int buf_size)
{
RpzaContext *s = (RpzaContext *)avctx->priv_data;
/* no supplementary picture */
if (buf_size == 0)
return 0;
RpzaContext *s = avctx->priv_data;
s->buf = buf;
s->size = buf_size;
@ -277,9 +263,9 @@ static int rpza_decode_frame(AVCodecContext *avctx,
return buf_size;
}
static int rpza_decode_end(AVCodecContext *avctx)
static av_cold int rpza_decode_end(AVCodecContext *avctx)
{
RpzaContext *s = (RpzaContext *)avctx->priv_data;
RpzaContext *s = avctx->priv_data;
if (s->frame.data[0])
avctx->release_buffer(avctx, &s->frame);
@ -297,4 +283,5 @@ AVCodec rpza_decoder = {
rpza_decode_end,
rpza_decode_frame,
CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("QuickTime video (RPZA)"),
};

View File

@ -0,0 +1,165 @@
/*
* RTJpeg decoding functions
* Copyright (c) 2006 Reimar Doeffinger
*
* 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 "common.h"
#include "bitstream.h"
#include "dsputil.h"
#include "rtjpeg.h"
#define PUT_COEFF(c) \
i = scan[coeff--]; \
block[i] = (c) * quant[i];
//! aligns the bitstream to the give power of two
#define ALIGN(a) \
n = (-get_bits_count(gb)) & (a - 1); \
if (n) {skip_bits(gb, n);}
/**
* \brief read one block from stream
* \param gb contains stream data
* \param block where data is written to
* \param scan array containing the mapping stream address -> block position
* \param quant quantization factors
*
* Note: GetBitContext is used to make the code simpler, since all data is
* aligned this could be done faster in a different way, e.g. as it is done
* in MPlayer libmpcodecs/native/rtjpegn.c.
*/
static inline int get_block(GetBitContext *gb, DCTELEM *block, const uint8_t *scan,
const uint32_t *quant) {
int coeff, i, n;
int8_t ac;
uint8_t dc = get_bits(gb, 8);
// block not coded
if (dc == 255)
return 0;
// number of non-zero coefficients
coeff = get_bits(gb, 6);
// normally we would only need to clear the (63 - coeff) last values,
// but since we do not know where they are we just clear the whole block
memset(block, 0, 64 * sizeof(DCTELEM));
// 2 bits per coefficient
while (coeff) {
ac = get_sbits(gb, 2);
if (ac == -2)
break; // continue with more bits
PUT_COEFF(ac);
}
// 4 bits per coefficient
ALIGN(4);
while (coeff) {
ac = get_sbits(gb, 4);
if (ac == -8)
break; // continue with more bits
PUT_COEFF(ac);
}
// 8 bits per coefficient
ALIGN(8);
while (coeff) {
ac = get_sbits(gb, 8);
PUT_COEFF(ac);
}
PUT_COEFF(dc);
return 1;
}
/**
* \brief decode one rtjpeg YUV420 frame
* \param c context, must be initialized via rtjpeg_decode_init
* \param f AVFrame to place decoded frame into. If parts of the frame
* are not coded they are left unchanged, so consider initializing it
* \param buf buffer containing input data
* \param buf_size length of input data in bytes
* \return number of bytes consumed from the input buffer
*/
int rtjpeg_decode_frame_yuv420(RTJpegContext *c, AVFrame *f,
const uint8_t *buf, int buf_size) {
DECLARE_ALIGNED_16(DCTELEM, block[64]);
GetBitContext gb;
int w = c->w / 16, h = c->h / 16;
int x, y;
uint8_t *y1 = f->data[0], *y2 = f->data[0] + 8 * f->linesize[0];
uint8_t *u = f->data[1], *v = f->data[2];
init_get_bits(&gb, buf, buf_size * 8);
for (y = 0; y < h; y++) {
for (x = 0; x < w; x++) {
if (get_block(&gb, block, c->scan, c->lquant))
c->dsp->idct_put(y1, f->linesize[0], block);
y1 += 8;
if (get_block(&gb, block, c->scan, c->lquant))
c->dsp->idct_put(y1, f->linesize[0], block);
y1 += 8;
if (get_block(&gb, block, c->scan, c->lquant))
c->dsp->idct_put(y2, f->linesize[0], block);
y2 += 8;
if (get_block(&gb, block, c->scan, c->lquant))
c->dsp->idct_put(y2, f->linesize[0], block);
y2 += 8;
if (get_block(&gb, block, c->scan, c->cquant))
c->dsp->idct_put(u, f->linesize[1], block);
u += 8;
if (get_block(&gb, block, c->scan, c->cquant))
c->dsp->idct_put(v, f->linesize[2], block);
v += 8;
}
y1 += 2 * 8 * (f->linesize[0] - w);
y2 += 2 * 8 * (f->linesize[0] - w);
u += 8 * (f->linesize[1] - w);
v += 8 * (f->linesize[2] - w);
}
return get_bits_count(&gb) / 8;
}
/**
* \brief initialize an RTJpegContext, may be called multiple times
* \param c context to initialize
* \param dsp specifies the idct to use for decoding
* \param width width of image, will be rounded down to the nearest multiple
* of 16 for decoding
* \param height height of image, will be rounded down to the nearest multiple
* of 16 for decoding
* \param lquant luma quantization table to use
* \param cquant chroma quantization table to use
*/
void rtjpeg_decode_init(RTJpegContext *c, DSPContext *dsp,
int width, int height,
const uint32_t *lquant, const uint32_t *cquant) {
int i;
c->dsp = dsp;
for (i = 0; i < 64; i++) {
int z = ff_zigzag_direct[i];
int p = c->dsp->idct_permutation[i];
z = ((z << 3) | (z >> 3)) & 63; // rtjpeg uses a transposed variant
// permute the scan and quantization tables for the chosen idct
c->scan[i] = c->dsp->idct_permutation[z];
c->lquant[p] = lquant[i];
c->cquant[p] = cquant[i];
}
c->w = width;
c->h = height;
}

View File

@ -0,0 +1,42 @@
/*
* RTJpeg decoding functions
* copyright (c) 2006 Reimar Doeffinger
*
* 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_RTJPEG_H
#define FFMPEG_RTJPEG_H
#include <stdint.h>
#include "dsputil.h"
typedef struct {
int w, h;
DSPContext *dsp;
uint8_t scan[64];
uint32_t lquant[64];
uint32_t cquant[64];
} RTJpegContext;
void rtjpeg_decode_init(RTJpegContext *c, DSPContext *dsp,
int width, int height,
const uint32_t *lquant, const uint32_t *cquant);
int rtjpeg_decode_frame_yuv420(RTJpegContext *c, AVFrame *f,
const uint8_t *buf, int buf_size);
#endif /* FFMPEG_RTJPEG_H */