From bc470b16bfd0e6a21c78e481874abbe15303d01c Mon Sep 17 00:00:00 2001 From: David McPaul Date: Mon, 15 Sep 2008 14:13:04 +0000 Subject: [PATCH] Update avcodec to 20080825 git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27564 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../plugins/avcodec/libavcodec/rectangle.h | 121 ++ .../avcodec/libavcodec/remove_extradata_bsf.c | 55 + .../plugins/avcodec/libavcodec/resample.c | 203 +--- .../plugins/avcodec/libavcodec/resample2.c | 324 +++++ .../media/plugins/avcodec/libavcodec/rl.h | 86 ++ .../media/plugins/avcodec/libavcodec/rl2.c | 241 ++++ .../media/plugins/avcodec/libavcodec/rle.c | 84 ++ .../media/plugins/avcodec/libavcodec/rle.h | 39 + .../plugins/avcodec/libavcodec/roqaudioenc.c | 179 +++ .../plugins/avcodec/libavcodec/roqvideo.c | 537 ++------- .../plugins/avcodec/libavcodec/roqvideo.h | 92 ++ .../plugins/avcodec/libavcodec/roqvideodec.c | 223 ++++ .../plugins/avcodec/libavcodec/roqvideoenc.c | 1072 +++++++++++++++++ .../media/plugins/avcodec/libavcodec/rpza.c | 63 +- .../media/plugins/avcodec/libavcodec/rtjpeg.c | 165 +++ .../media/plugins/avcodec/libavcodec/rtjpeg.h | 42 + 16 files changed, 2886 insertions(+), 640 deletions(-) create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/rectangle.h create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/remove_extradata_bsf.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/resample2.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/rl.h create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/rl2.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/rle.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/rle.h create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/roqaudioenc.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/roqvideo.h create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/roqvideodec.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/roqvideoenc.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/rtjpeg.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/rtjpeg.h diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/rectangle.h b/src/add-ons/media/plugins/avcodec/libavcodec/rectangle.h new file mode 100644 index 0000000000..e138862982 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/rectangle.h @@ -0,0 +1,121 @@ +/* + * rectangle filling function + * Copyright (c) 2003 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 rectangle.h + * useful rectangle filling function + * @author Michael Niedermayer + */ + +#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 */ diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/remove_extradata_bsf.c b/src/add-ons/media/plugins/avcodec/libavcodec/remove_extradata_bsf.c new file mode 100644 index 0000000000..95bd98bef2 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/remove_extradata_bsf.c @@ -0,0 +1,55 @@ +/* + * copyright (c) 2006 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 + */ + +#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, +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/resample.c b/src/add-ons/media/plugins/avcodec/libavcodec/resample.c index f6f0bf42b9..c4a5dbdfce 100644 --- a/src/add-ons/media/plugins/avcodec/libavcodec/resample.c +++ b/src/add-ons/media/plugins/avcodec/libavcodec/resample.c @@ -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;ifilter_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; ifilter_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;ifilter_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; ifilter_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); } diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/resample2.c b/src/add-ons/media/plugins/avcodec/libavcodec/resample2.c new file mode 100644 index 0000000000..4397d2a66e --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/resample2.c @@ -0,0 +1,324 @@ +/* + * audio resampling + * Copyright (c) 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 resample2.c + * audio resampling + * @author Michael Niedermayer + */ + +#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;phphase_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_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; ifilter_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; ifilter_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; ifilter_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; +} diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/rl.h b/src/add-ons/media/plugins/avcodec/libavcodec/rl.h new file mode 100644 index 0000000000..d71d3711bd --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/rl.h @@ -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 +#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 */ diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/rl2.c b/src/add-ons/media/plugins/avcodec/libavcodec/rl2.c new file mode 100644 index 0000000000..ad830e7b65 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/rl2.c @@ -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 +#include +#include +#include + +#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;ipalette[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"), +}; + diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/rle.c b/src/add-ons/media/plugins/avcodec/libavcodec/rle.c new file mode 100644 index 0000000000..6e468f8991 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/rle.c @@ -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; +} diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/rle.h b/src/add-ons/media/plugins/avcodec/libavcodec/rle.h new file mode 100644 index 0000000000..14d07084f6 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/rle.h @@ -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 + +/** + * 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 */ diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/roqaudioenc.c b/src/add-ons/media/plugins/avcodec/libavcodec/roqaudioenc.c new file mode 100644 index 0000000000..df014a449f --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/roqaudioenc.c @@ -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; imid); + } +} + +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; ichannels; 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"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/roqvideo.c b/src/add-ons/media/plugins/avcodec/libavcodec/roqvideo.c index bd26961dc1..e125a4c67a 100644 --- a/src/add-ons/media/plugins/avcodec/libavcodec/roqvideo.c +++ b/src/add-ons/media/plugins/avcodec/libavcodec/roqvideo.c @@ -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 -#include -#include -#include - -#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, -}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/roqvideo.h b/src/add-ons/media/plugins/avcodec/libavcodec/roqvideo.h new file mode 100644 index 0000000000..e7af474da8 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/roqvideo.h @@ -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 */ diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/roqvideodec.c b/src/add-ons/media/plugins/avcodec/libavcodec/roqvideodec.c new file mode 100644 index 0000000000..5ddfa4924d --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/roqvideodec.c @@ -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 +#include +#include +#include + +#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"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/roqvideoenc.c b/src/add-ons/media/plugins/avcodec/libavcodec/roqvideoenc.c new file mode 100644 index 0000000000..a115e5851b --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/roqvideoenc.c @@ -0,0 +1,1072 @@ +/* + * RoQ Video Encoder. + * + * Copyright (C) 2007 Vitor Sessak + * Copyright (C) 2004-2007 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 + */ + +/** + * @file roqvideoenc.c + * id RoQ encoder by Vitor. Based on the Switchblade3 library and the + * Switchblade3 FFmpeg glue by Eric Lasota. + */ + +/* + * COSTS: + * Level 1: + * SKIP - 2 bits + * MOTION - 2 + 8 bits + * CODEBOOK - 2 + 8 bits + * SUBDIVIDE - 2 + combined subcel cost + * + * Level 2: + * SKIP - 2 bits + * MOTION - 2 + 8 bits + * CODEBOOK - 2 + 8 bits + * SUBDIVIDE - 2 + 4*8 bits + * + * Maximum cost: 138 bits per cel + * + * Proper evaluation requires LCD fraction comparison, which requires + * Squared Error (SE) loss * savings increase + * + * Maximum savings increase: 136 bits + * Maximum SE loss without overflow: 31580641 + * Components in 8x8 supercel: 192 + * Maximum SE precision per component: 164482 + * >65025, so no truncation is needed (phew) + */ + +#include +#include + +#include "roqvideo.h" +#include "bytestream.h" +#include "elbg.h" + +#define CHROMA_BIAS 1 + +/** + * Maximum number of generated 4x4 codebooks. Can't be 256 to workaround a + * Quake 3 bug. + */ +#define MAX_CBS_4x4 255 + +#define MAX_CBS_2x2 256 ///< Maximum number of 2x2 codebooks. + +/* The cast is useful when multiplying it by INT_MAX */ +#define ROQ_LAMBDA_SCALE ((uint64_t) FF_LAMBDA_SCALE) + +/* Macroblock support functions */ +static void unpack_roq_cell(roq_cell *cell, uint8_t u[4*3]) +{ + memcpy(u , cell->y, 4); + memset(u+4, cell->u, 4); + memset(u+8, cell->v, 4); +} + +static void unpack_roq_qcell(uint8_t cb2[], roq_qcell *qcell, uint8_t u[4*4*3]) +{ + int i,cp; + static const int offsets[4] = {0, 2, 8, 10}; + + for (cp=0; cp<3; cp++) + for (i=0; i<4; i++) { + u[4*4*cp + offsets[i] ] = cb2[qcell->idx[i]*2*2*3 + 4*cp ]; + u[4*4*cp + offsets[i]+1] = cb2[qcell->idx[i]*2*2*3 + 4*cp+1]; + u[4*4*cp + offsets[i]+4] = cb2[qcell->idx[i]*2*2*3 + 4*cp+2]; + u[4*4*cp + offsets[i]+5] = cb2[qcell->idx[i]*2*2*3 + 4*cp+3]; + } +} + + +static void enlarge_roq_mb4(uint8_t base[3*16], uint8_t u[3*64]) +{ + int x,y,cp; + + for(cp=0; cp<3; cp++) + for(y=0; y<8; y++) + for(x=0; x<8; x++) + *u++ = base[(y/2)*4 + (x/2) + 16*cp]; +} + +static inline int square(int x) +{ + return x*x; +} + +static inline int eval_sse(uint8_t *a, uint8_t *b, int count) +{ + int diff=0; + + while(count--) + diff += square(*b++ - *a++); + + return diff; +} + +// FIXME Could use DSPContext.sse, but it is not so speed critical (used +// just for motion estimation). +static int block_sse(uint8_t **buf1, uint8_t **buf2, int x1, int y1, int x2, + int y2, int *stride1, int *stride2, int size) +{ + int i, k; + int sse=0; + + for (k=0; k<3; k++) { + int bias = (k ? CHROMA_BIAS : 4); + for (i=0; i 7) + return INT_MAX; + + if (my < -7 || my > 7) + return INT_MAX; + + mx += x; + my += y; + + if ((unsigned) mx > enc->width-size || (unsigned) my > enc->height-size) + return INT_MAX; + + return block_sse(enc->frame_to_enc->data, enc->last_frame->data, x, y, + mx, my, + enc->frame_to_enc->linesize, enc->last_frame->linesize, + size); +} + +/** + * Returns distortion between two macroblocks + */ +static inline int squared_diff_macroblock(uint8_t a[], uint8_t b[], int size) +{ + int cp, sdiff=0; + + for(cp=0;cp<3;cp++) { + int bias = (cp ? CHROMA_BIAS : 4); + sdiff += bias*eval_sse(a, b, size*size); + a += size*size; + b += size*size; + } + + return sdiff; +} + +typedef struct +{ + int eval_dist[4]; + int best_bit_use; + int best_coding; + + int subCels[4]; + motion_vect motion; + int cbEntry; +} subcel_evaluation_t; + +typedef struct +{ + int eval_dist[4]; + int best_coding; + + subcel_evaluation_t subCels[4]; + + motion_vect motion; + int cbEntry; + + int sourceX, sourceY; +} cel_evaluation_t; + +typedef struct +{ + int numCB4; + int numCB2; + int usedCB2[MAX_CBS_2x2]; + int usedCB4[MAX_CBS_4x4]; + uint8_t unpacked_cb2[MAX_CBS_2x2*2*2*3]; + uint8_t unpacked_cb4[MAX_CBS_4x4*4*4*3]; + uint8_t unpacked_cb4_enlarged[MAX_CBS_4x4*8*8*3]; +} roq_codebooks_t; + +/** + * Temporary vars + */ +typedef struct +{ + cel_evaluation_t *cel_evals; + + int f2i4[MAX_CBS_4x4]; + int i2f4[MAX_CBS_4x4]; + int f2i2[MAX_CBS_2x2]; + int i2f2[MAX_CBS_2x2]; + + int mainChunkSize; + + int numCB4; + int numCB2; + + roq_codebooks_t codebooks; + + int *closest_cb2; + int used_option[4]; +} roq_tempdata_t; + +/** + * Initializes cel evaluators and sets their source coordinates + */ +static void create_cel_evals(RoqContext *enc, roq_tempdata_t *tempData) +{ + int n=0, x, y, i; + + tempData->cel_evals = av_malloc(enc->width*enc->height/64 * sizeof(cel_evaluation_t)); + + /* Map to the ROQ quadtree order */ + for (y=0; yheight; y+=16) + for (x=0; xwidth; x+=16) + for(i=0; i<4; i++) { + tempData->cel_evals[n ].sourceX = x + (i&1)*8; + tempData->cel_evals[n++].sourceY = y + (i&2)*4; + } +} + +/** + * Get macroblocks from parts of the image + */ +static void get_frame_mb(AVFrame *frame, int x, int y, uint8_t mb[], int dim) +{ + int i, j, cp; + + for (cp=0; cp<3; cp++) { + int stride = frame->linesize[cp]; + for (i=0; idata[cp][(y+i)*stride + x + j]; + } +} + +/** + * Find the codebook with the lowest distortion from an image + */ +static int index_mb(uint8_t cluster[], uint8_t cb[], int numCB, + int *outIndex, int dim) +{ + int i, lDiff = INT_MAX, pick=0; + + /* Diff against the others */ + for (i=0; iwidth/blocksize)*enc->height/blocksize; + + if (blocksize == 4) { + last_motion = enc->last_motion4; + this_motion = enc->this_motion4; + } else { + last_motion = enc->last_motion8; + this_motion = enc->this_motion8; + } + + for (i=0; iheight; i+=blocksize) + for (j=0; jwidth; j+=blocksize) { + lowestdiff = eval_motion_dist(enc, j, i, (motion_vect) {{0,0}}, + blocksize); + bestpick.d[0] = 0; + bestpick.d[1] = 0; + + if (blocksize == 4) + EVAL_MOTION(enc->this_motion8[(i/8)*(enc->width/8) + j/8]); + + offset = (i/blocksize)*enc->width/blocksize + j/blocksize; + if (offset < max && offset >= 0) + EVAL_MOTION(last_motion[offset]); + + offset++; + if (offset < max && offset >= 0) + EVAL_MOTION(last_motion[offset]); + + offset = (i/blocksize + 1)*enc->width/blocksize + j/blocksize; + if (offset < max && offset >= 0) + EVAL_MOTION(last_motion[offset]); + + off[0]= (i/blocksize)*enc->width/blocksize + j/blocksize - 1; + off[1]= off[0] - enc->width/blocksize + 1; + off[2]= off[1] + 1; + + if (i) { + + for(k=0; k<2; k++) + vect.d[k]= mid_pred(this_motion[off[0]].d[k], + this_motion[off[1]].d[k], + this_motion[off[2]].d[k]); + + EVAL_MOTION(vect); + for(k=0; k<3; k++) + EVAL_MOTION(this_motion[off[k]]); + } else if(j) + EVAL_MOTION(this_motion[off[0]]); + + vect = bestpick; + + oldbest = -1; + while (oldbest != lowestdiff) { + oldbest = lowestdiff; + for (k=0; k<8; k++) { + vect2 = vect; + vect2.d[0] += offsets[k].d[0]; + vect2.d[1] += offsets[k].d[1]; + EVAL_MOTION(vect2); + } + vect = bestpick; + } + offset = (i/blocksize)*enc->width/blocksize + j/blocksize; + this_motion[offset] = bestpick; + } +} + +/** + * Gets distortion for all options available to a subcel + */ +static void gather_data_for_subcel(subcel_evaluation_t *subcel, int x, + int y, RoqContext *enc, roq_tempdata_t *tempData) +{ + uint8_t mb4[4*4*3]; + uint8_t mb2[2*2*3]; + int cluster_index; + int i, best_dist; + + static const int bitsUsed[4] = {2, 10, 10, 34}; + + if (enc->framesSinceKeyframe >= 1) { + subcel->motion = enc->this_motion4[y*enc->width/16 + x/4]; + + subcel->eval_dist[RoQ_ID_FCC] = + eval_motion_dist(enc, x, y, + enc->this_motion4[y*enc->width/16 + x/4], 4); + } else + subcel->eval_dist[RoQ_ID_FCC] = INT_MAX; + + if (enc->framesSinceKeyframe >= 2) + subcel->eval_dist[RoQ_ID_MOT] = block_sse(enc->frame_to_enc->data, + enc->current_frame->data, x, + y, x, y, + enc->frame_to_enc->linesize, + enc->current_frame->linesize, + 4); + else + subcel->eval_dist[RoQ_ID_MOT] = INT_MAX; + + cluster_index = y*enc->width/16 + x/4; + + get_frame_mb(enc->frame_to_enc, x, y, mb4, 4); + + subcel->eval_dist[RoQ_ID_SLD] = index_mb(mb4, + tempData->codebooks.unpacked_cb4, + tempData->codebooks.numCB4, + &subcel->cbEntry, 4); + + subcel->eval_dist[RoQ_ID_CCC] = 0; + + for(i=0;i<4;i++) { + subcel->subCels[i] = tempData->closest_cb2[cluster_index*4+i]; + + get_frame_mb(enc->frame_to_enc, x+2*(i&1), + y+(i&2), mb2, 2); + + subcel->eval_dist[RoQ_ID_CCC] += + squared_diff_macroblock(tempData->codebooks.unpacked_cb2 + subcel->subCels[i]*2*2*3, mb2, 2); + } + + best_dist = INT_MAX; + for (i=0; i<4; i++) + if (ROQ_LAMBDA_SCALE*subcel->eval_dist[i] + enc->lambda*bitsUsed[i] < + best_dist) { + subcel->best_coding = i; + subcel->best_bit_use = bitsUsed[i]; + best_dist = ROQ_LAMBDA_SCALE*subcel->eval_dist[i] + + enc->lambda*bitsUsed[i]; + } +} + +/** + * Gets distortion for all options available to a cel + */ +static void gather_data_for_cel(cel_evaluation_t *cel, RoqContext *enc, + roq_tempdata_t *tempData) +{ + uint8_t mb8[8*8*3]; + int index = cel->sourceY*enc->width/64 + cel->sourceX/8; + int i, j, best_dist, divide_bit_use; + + int bitsUsed[4] = {2, 10, 10, 0}; + + if (enc->framesSinceKeyframe >= 1) { + cel->motion = enc->this_motion8[index]; + + cel->eval_dist[RoQ_ID_FCC] = + eval_motion_dist(enc, cel->sourceX, cel->sourceY, + enc->this_motion8[index], 8); + } else + cel->eval_dist[RoQ_ID_FCC] = INT_MAX; + + if (enc->framesSinceKeyframe >= 2) + cel->eval_dist[RoQ_ID_MOT] = block_sse(enc->frame_to_enc->data, + enc->current_frame->data, + cel->sourceX, cel->sourceY, + cel->sourceX, cel->sourceY, + enc->frame_to_enc->linesize, + enc->current_frame->linesize,8); + else + cel->eval_dist[RoQ_ID_MOT] = INT_MAX; + + get_frame_mb(enc->frame_to_enc, cel->sourceX, cel->sourceY, mb8, 8); + + cel->eval_dist[RoQ_ID_SLD] = + index_mb(mb8, tempData->codebooks.unpacked_cb4_enlarged, + tempData->codebooks.numCB4, &cel->cbEntry, 8); + + gather_data_for_subcel(cel->subCels + 0, cel->sourceX+0, cel->sourceY+0, enc, tempData); + gather_data_for_subcel(cel->subCels + 1, cel->sourceX+4, cel->sourceY+0, enc, tempData); + gather_data_for_subcel(cel->subCels + 2, cel->sourceX+0, cel->sourceY+4, enc, tempData); + gather_data_for_subcel(cel->subCels + 3, cel->sourceX+4, cel->sourceY+4, enc, tempData); + + cel->eval_dist[RoQ_ID_CCC] = 0; + divide_bit_use = 0; + for (i=0; i<4; i++) { + cel->eval_dist[RoQ_ID_CCC] += + cel->subCels[i].eval_dist[cel->subCels[i].best_coding]; + divide_bit_use += cel->subCels[i].best_bit_use; + } + + best_dist = INT_MAX; + bitsUsed[3] = 2 + divide_bit_use; + + for (i=0; i<4; i++) + if (ROQ_LAMBDA_SCALE*cel->eval_dist[i] + enc->lambda*bitsUsed[i] < + best_dist) { + cel->best_coding = i; + best_dist = ROQ_LAMBDA_SCALE*cel->eval_dist[i] + + enc->lambda*bitsUsed[i]; + } + + tempData->used_option[cel->best_coding]++; + tempData->mainChunkSize += bitsUsed[cel->best_coding]; + + if (cel->best_coding == RoQ_ID_SLD) + tempData->codebooks.usedCB4[cel->cbEntry]++; + + if (cel->best_coding == RoQ_ID_CCC) + for (i=0; i<4; i++) { + if (cel->subCels[i].best_coding == RoQ_ID_SLD) + tempData->codebooks.usedCB4[cel->subCels[i].cbEntry]++; + else if (cel->subCels[i].best_coding == RoQ_ID_CCC) + for (j=0; j<4; j++) + tempData->codebooks.usedCB2[cel->subCels[i].subCels[j]]++; + } +} + +static void remap_codebooks(RoqContext *enc, roq_tempdata_t *tempData) +{ + int i, j, idx=0; + + /* Make remaps for the final codebook usage */ + for (i=0; icodebooks.usedCB4[i]) { + tempData->i2f4[i] = idx; + tempData->f2i4[idx] = i; + for (j=0; j<4; j++) + tempData->codebooks.usedCB2[enc->cb4x4[i].idx[j]]++; + idx++; + } + } + + tempData->numCB4 = idx; + + idx = 0; + for (i=0; icodebooks.usedCB2[i]) { + tempData->i2f2[i] = idx; + tempData->f2i2[idx] = i; + idx++; + } + } + tempData->numCB2 = idx; + +} + +/** + * Write codebook chunk + */ +static void write_codebooks(RoqContext *enc, roq_tempdata_t *tempData) +{ + int i, j; + uint8_t **outp= &enc->out_buf; + + if (tempData->numCB2) { + bytestream_put_le16(outp, RoQ_QUAD_CODEBOOK); + bytestream_put_le32(outp, tempData->numCB2*6 + tempData->numCB4*4); + bytestream_put_byte(outp, tempData->numCB4); + bytestream_put_byte(outp, tempData->numCB2); + + for (i=0; inumCB2; i++) { + bytestream_put_buffer(outp, enc->cb2x2[tempData->f2i2[i]].y, 4); + bytestream_put_byte(outp, enc->cb2x2[tempData->f2i2[i]].u); + bytestream_put_byte(outp, enc->cb2x2[tempData->f2i2[i]].v); + } + + for (i=0; inumCB4; i++) + for (j=0; j<4; j++) + bytestream_put_byte(outp, tempData->i2f2[enc->cb4x4[tempData->f2i4[i]].idx[j]]); + + } +} + +static inline uint8_t motion_arg(motion_vect mot) +{ + uint8_t ax = 8 - ((uint8_t) mot.d[0]); + uint8_t ay = 8 - ((uint8_t) mot.d[1]); + return ((ax&15)<<4) | (ay&15); +} + +typedef struct +{ + int typeSpool; + int typeSpoolLength; + uint8_t argumentSpool[64]; + uint8_t *args; + uint8_t **pout; +} CodingSpool; + +/* NOTE: Typecodes must be spooled AFTER arguments!! */ +static void write_typecode(CodingSpool *s, uint8_t type) +{ + s->typeSpool |= (type & 3) << (14 - s->typeSpoolLength); + s->typeSpoolLength += 2; + if (s->typeSpoolLength == 16) { + bytestream_put_le16(s->pout, s->typeSpool); + bytestream_put_buffer(s->pout, s->argumentSpool, + s->args - s->argumentSpool); + s->typeSpoolLength = 0; + s->typeSpool = 0; + s->args = s->argumentSpool; + } +} + +static void reconstruct_and_encode_image(RoqContext *enc, roq_tempdata_t *tempData, int w, int h, int numBlocks) +{ + int i, j, k; + int x, y; + int subX, subY; + int dist=0; + + roq_qcell *qcell; + cel_evaluation_t *eval; + + CodingSpool spool; + + spool.typeSpool=0; + spool.typeSpoolLength=0; + spool.args = spool.argumentSpool; + spool.pout = &enc->out_buf; + + if (tempData->used_option[RoQ_ID_CCC]%2) + tempData->mainChunkSize+=8; //FIXME + + /* Write the video chunk header */ + bytestream_put_le16(&enc->out_buf, RoQ_QUAD_VQ); + bytestream_put_le32(&enc->out_buf, tempData->mainChunkSize/8); + bytestream_put_byte(&enc->out_buf, 0x0); + bytestream_put_byte(&enc->out_buf, 0x0); + + for (i=0; icel_evals + i; + + x = eval->sourceX; + y = eval->sourceY; + dist += eval->eval_dist[eval->best_coding]; + + switch (eval->best_coding) { + case RoQ_ID_MOT: + write_typecode(&spool, RoQ_ID_MOT); + break; + + case RoQ_ID_FCC: + bytestream_put_byte(&spool.args, motion_arg(eval->motion)); + + write_typecode(&spool, RoQ_ID_FCC); + ff_apply_motion_8x8(enc, x, y, + eval->motion.d[0], eval->motion.d[1]); + break; + + case RoQ_ID_SLD: + bytestream_put_byte(&spool.args, tempData->i2f4[eval->cbEntry]); + write_typecode(&spool, RoQ_ID_SLD); + + qcell = enc->cb4x4 + eval->cbEntry; + ff_apply_vector_4x4(enc, x , y , enc->cb2x2 + qcell->idx[0]); + ff_apply_vector_4x4(enc, x+4, y , enc->cb2x2 + qcell->idx[1]); + ff_apply_vector_4x4(enc, x , y+4, enc->cb2x2 + qcell->idx[2]); + ff_apply_vector_4x4(enc, x+4, y+4, enc->cb2x2 + qcell->idx[3]); + break; + + case RoQ_ID_CCC: + write_typecode(&spool, RoQ_ID_CCC); + + for (j=0; j<4; j++) { + subX = x + 4*(j&1); + subY = y + 2*(j&2); + + switch(eval->subCels[j].best_coding) { + case RoQ_ID_MOT: + break; + + case RoQ_ID_FCC: + bytestream_put_byte(&spool.args, + motion_arg(eval->subCels[j].motion)); + + ff_apply_motion_4x4(enc, subX, subY, + eval->subCels[j].motion.d[0], + eval->subCels[j].motion.d[1]); + break; + + case RoQ_ID_SLD: + bytestream_put_byte(&spool.args, + tempData->i2f4[eval->subCels[j].cbEntry]); + + qcell = enc->cb4x4 + eval->subCels[j].cbEntry; + + ff_apply_vector_2x2(enc, subX , subY , + enc->cb2x2 + qcell->idx[0]); + ff_apply_vector_2x2(enc, subX+2, subY , + enc->cb2x2 + qcell->idx[1]); + ff_apply_vector_2x2(enc, subX , subY+2, + enc->cb2x2 + qcell->idx[2]); + ff_apply_vector_2x2(enc, subX+2, subY+2, + enc->cb2x2 + qcell->idx[3]); + break; + + case RoQ_ID_CCC: + for (k=0; k<4; k++) { + int cb_idx = eval->subCels[j].subCels[k]; + bytestream_put_byte(&spool.args, + tempData->i2f2[cb_idx]); + + ff_apply_vector_2x2(enc, subX + 2*(k&1), subY + (k&2), + enc->cb2x2 + cb_idx); + } + break; + } + write_typecode(&spool, eval->subCels[j].best_coding); + } + break; + } + } + + /* Flush the remainder of the argument/type spool */ + while (spool.typeSpoolLength) + write_typecode(&spool, 0x0); + +#if 0 + uint8_t *fdata[3] = {enc->frame_to_enc->data[0], + enc->frame_to_enc->data[1], + enc->frame_to_enc->data[2]}; + uint8_t *cdata[3] = {enc->current_frame->data[0], + enc->current_frame->data[1], + enc->current_frame->data[2]}; + av_log(enc->avctx, AV_LOG_ERROR, "Expected distortion: %i Actual: %i\n", + dist, + block_sse(fdata, cdata, 0, 0, 0, 0, + enc->frame_to_enc->linesize, + enc->current_frame->linesize, + enc->width)); //WARNING: Square dimensions implied... +#endif +} + + +/** + * Create a single YUV cell from a 2x2 section of the image + */ +static inline void frame_block_to_cell(uint8_t *block, uint8_t **data, + int top, int left, int *stride) +{ + int i, j, u=0, v=0; + + for (i=0; i<2; i++) + for (j=0; j<2; j++) { + int x = (top+i)*stride[0] + left + j; + *block++ = data[0][x]; + x = (top+i)*stride[1] + left + j; + u += data[1][x]; + v += data[2][x]; + } + + *block++ = (u+2)/4; + *block++ = (v+2)/4; +} + +/** + * Creates YUV clusters for the entire image + */ +static void create_clusters(AVFrame *frame, int w, int h, uint8_t *yuvClusters) +{ + int i, j, k, l; + + for (i=0; idata, + i+2*k, j+2*l, frame->linesize); + yuvClusters += 24; + } +} + +static void generate_codebook(RoqContext *enc, roq_tempdata_t *tempdata, + int *points, int inputCount, roq_cell *results, + int size, int cbsize) +{ + int i, j, k; + int c_size = size*size/4; + int *buf = points; + int *codebook = av_malloc(6*c_size*cbsize*sizeof(int)); + int *closest_cb; + + if (size == 4) + closest_cb = av_malloc(6*c_size*inputCount*sizeof(int)); + else + closest_cb = tempdata->closest_cb2; + + ff_init_elbg(points, 6*c_size, inputCount, codebook, cbsize, 1, closest_cb, &enc->randctx); + ff_do_elbg(points, 6*c_size, inputCount, codebook, cbsize, 1, closest_cb, &enc->randctx); + + if (size == 4) + av_free(closest_cb); + + buf = codebook; + for (i=0; iy[j] = *buf++; + + results->u = (*buf++ + CHROMA_BIAS/2)/CHROMA_BIAS; + results->v = (*buf++ + CHROMA_BIAS/2)/CHROMA_BIAS; + results++; + } + + av_free(codebook); +} + +static void generate_new_codebooks(RoqContext *enc, roq_tempdata_t *tempData) +{ + int i,j; + roq_codebooks_t *codebooks = &tempData->codebooks; + int max = enc->width*enc->height/16; + uint8_t mb2[3*4]; + roq_cell *results4 = av_malloc(sizeof(roq_cell)*MAX_CBS_4x4*4); + uint8_t *yuvClusters=av_malloc(sizeof(int)*max*6*4); + int *points = av_malloc(max*6*4*sizeof(int)); + int bias; + + /* Subsample YUV data */ + create_clusters(enc->frame_to_enc, enc->width, enc->height, yuvClusters); + + /* Cast to integer and apply chroma bias */ + for (i=0; inumCB4 = MAX_CBS_4x4; + + tempData->closest_cb2 = av_malloc(max*4*sizeof(int)); + + /* Create 2x2 codebooks */ + generate_codebook(enc, tempData, points, max*4, enc->cb2x2, 2, MAX_CBS_2x2); + + codebooks->numCB2 = MAX_CBS_2x2; + + /* Unpack 2x2 codebook clusters */ + for (i=0; inumCB2; i++) + unpack_roq_cell(enc->cb2x2 + i, codebooks->unpacked_cb2 + i*2*2*3); + + /* Index all 4x4 entries to the 2x2 entries, unpack, and enlarge */ + for (i=0; inumCB4; i++) { + for (j=0; j<4; j++) { + unpack_roq_cell(&results4[4*i + j], mb2); + index_mb(mb2, codebooks->unpacked_cb2, codebooks->numCB2, + &enc->cb4x4[i].idx[j], 2); + } + unpack_roq_qcell(codebooks->unpacked_cb2, enc->cb4x4 + i, + codebooks->unpacked_cb4 + i*4*4*3); + enlarge_roq_mb4(codebooks->unpacked_cb4 + i*4*4*3, + codebooks->unpacked_cb4_enlarged + i*8*8*3); + } + + av_free(yuvClusters); + av_free(points); + av_free(results4); +} + +static void roq_encode_video(RoqContext *enc) +{ + roq_tempdata_t tempData; + int i; + + memset(&tempData, 0, sizeof(tempData)); + + create_cel_evals(enc, &tempData); + + generate_new_codebooks(enc, &tempData); + + if (enc->framesSinceKeyframe >= 1) { + motion_search(enc, 8); + motion_search(enc, 4); + } + + retry_encode: + for (i=0; iwidth*enc->height/64; i++) + gather_data_for_cel(tempData.cel_evals + i, enc, &tempData); + + /* Quake 3 can't handle chunks bigger than 65536 bytes */ + if (tempData.mainChunkSize/8 > 65536) { + enc->lambda *= .8; + goto retry_encode; + } + + remap_codebooks(enc, &tempData); + + write_codebooks(enc, &tempData); + + reconstruct_and_encode_image(enc, &tempData, enc->width, enc->height, + enc->width*enc->height/64); + + enc->avctx->coded_frame = enc->current_frame; + + /* Rotate frame history */ + FFSWAP(AVFrame *, enc->current_frame, enc->last_frame); + FFSWAP(motion_vect *, enc->last_motion4, enc->this_motion4); + FFSWAP(motion_vect *, enc->last_motion8, enc->this_motion8); + + av_free(tempData.cel_evals); + av_free(tempData.closest_cb2); + + enc->framesSinceKeyframe++; +} + +static int roq_encode_init(AVCodecContext *avctx) +{ + RoqContext *enc = avctx->priv_data; + + av_init_random(1, &enc->randctx); + + enc->framesSinceKeyframe = 0; + if ((avctx->width & 0xf) || (avctx->height & 0xf)) { + av_log(avctx, AV_LOG_ERROR, "Dimensions must be divisible by 16\n"); + return -1; + } + + if (((avctx->width)&(avctx->width-1))||((avctx->height)&(avctx->height-1))) + av_log(avctx, AV_LOG_ERROR, "Warning: dimensions not power of two\n"); + + if (avcodec_check_dimensions(avctx, avctx->width, avctx->height)) { + av_log(avctx, AV_LOG_ERROR, "Invalid dimensions (%dx%d)\n", + avctx->width, avctx->height); + return -1; + } + + enc->width = avctx->width; + enc->height = avctx->height; + + enc->framesSinceKeyframe = 0; + enc->first_frame = 1; + + enc->last_frame = &enc->frames[0]; + enc->current_frame = &enc->frames[1]; + + enc->this_motion4 = + av_mallocz((enc->width*enc->height/16)*sizeof(motion_vect)); + + enc->last_motion4 = + av_malloc ((enc->width*enc->height/16)*sizeof(motion_vect)); + + enc->this_motion8 = + av_mallocz((enc->width*enc->height/64)*sizeof(motion_vect)); + + enc->last_motion8 = + av_malloc ((enc->width*enc->height/64)*sizeof(motion_vect)); + + return 0; +} + +static void roq_write_video_info_chunk(RoqContext *enc) +{ + /* ROQ info chunk */ + bytestream_put_le16(&enc->out_buf, RoQ_INFO); + + /* Size: 8 bytes */ + bytestream_put_le32(&enc->out_buf, 8); + + /* Unused argument */ + bytestream_put_byte(&enc->out_buf, 0x00); + bytestream_put_byte(&enc->out_buf, 0x00); + + /* Width */ + bytestream_put_le16(&enc->out_buf, enc->width); + + /* Height */ + bytestream_put_le16(&enc->out_buf, enc->height); + + /* Unused in Quake 3, mimics the output of the real encoder */ + bytestream_put_byte(&enc->out_buf, 0x08); + bytestream_put_byte(&enc->out_buf, 0x00); + bytestream_put_byte(&enc->out_buf, 0x04); + bytestream_put_byte(&enc->out_buf, 0x00); +} + +static int roq_encode_frame(AVCodecContext *avctx, unsigned char *buf, int buf_size, void *data) +{ + RoqContext *enc = avctx->priv_data; + AVFrame *frame= data; + uint8_t *buf_start = buf; + + enc->out_buf = buf; + enc->avctx = avctx; + + enc->frame_to_enc = frame; + + if (frame->quality) + enc->lambda = frame->quality - 1; + else + enc->lambda = 2*ROQ_LAMBDA_SCALE; + + /* 138 bits max per 8x8 block + + * 256 codebooks*(6 bytes 2x2 + 4 bytes 4x4) + 8 bytes frame header */ + if (((enc->width*enc->height/64)*138+7)/8 + 256*(6+4) + 8 > buf_size) { + av_log(avctx, AV_LOG_ERROR, " RoQ: Output buffer too small!\n"); + return -1; + } + + /* Check for I frame */ + if (enc->framesSinceKeyframe == avctx->gop_size) + enc->framesSinceKeyframe = 0; + + if (enc->first_frame) { + /* Alloc memory for the reconstruction data (we must know the stride + for that) */ + if (avctx->get_buffer(avctx, enc->current_frame) || + avctx->get_buffer(avctx, enc->last_frame)) { + av_log(avctx, AV_LOG_ERROR, " RoQ: get_buffer() failed\n"); + return -1; + } + + /* Before the first video frame, write a "video info" chunk */ + roq_write_video_info_chunk(enc); + + enc->first_frame = 0; + } + + /* Encode the actual frame */ + roq_encode_video(enc); + + return enc->out_buf - buf_start; +} + +static int roq_encode_end(AVCodecContext *avctx) +{ + RoqContext *enc = avctx->priv_data; + + avctx->release_buffer(avctx, enc->last_frame); + avctx->release_buffer(avctx, enc->current_frame); + + av_free(enc->this_motion4); + av_free(enc->last_motion4); + av_free(enc->this_motion8); + av_free(enc->last_motion8); + + return 0; +} + +AVCodec roq_encoder = +{ + "roqvideo", + CODEC_TYPE_VIDEO, + CODEC_ID_ROQ, + sizeof(RoqContext), + roq_encode_init, + roq_encode_frame, + roq_encode_end, + .supported_framerates = (AVRational[]){{30,1}, {0,0}}, + .pix_fmts = (enum PixelFormat[]){PIX_FMT_YUV444P, PIX_FMT_NONE}, + .long_name = NULL_IF_CONFIG_SMALL("id RoQ video"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/rpza.c b/src/add-ons/media/plugins/avcodec/libavcodec/rpza.c index 965fb729b0..ddf39544ff 100644 --- a/src/add-ons/media/plugins/avcodec/libavcodec/rpza.c +++ b/src/add-ons/media/plugins/avcodec/libavcodec/rpza.c @@ -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 + * 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 #include -#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)"), }; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/rtjpeg.c b/src/add-ons/media/plugins/avcodec/libavcodec/rtjpeg.c new file mode 100644 index 0000000000..7ab808dacf --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/rtjpeg.c @@ -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; +} diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/rtjpeg.h b/src/add-ons/media/plugins/avcodec/libavcodec/rtjpeg.h new file mode 100644 index 0000000000..a5b377de53 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/rtjpeg.h @@ -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 +#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 */