From 66ba2a52634e729d406854918c1a410a5e6da20d Mon Sep 17 00:00:00 2001 From: David McPaul Date: Mon, 15 Sep 2008 14:03:43 +0000 Subject: [PATCH] Update avcodec to 20080825 git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27547 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../plugins/avcodec/libavcodec/faandct.c | 142 +- .../plugins/avcodec/libavcodec/faandct.h | 26 +- .../plugins/avcodec/libavcodec/faanidct.c | 168 +++ .../plugins/avcodec/libavcodec/faanidct.h | 32 + .../plugins/avcodec/libavcodec/fdctref.c | 73 +- .../plugins/avcodec/libavcodec/fft-test.c | 306 ++++ .../media/plugins/avcodec/libavcodec/fft.c | 482 +++--- .../media/plugins/avcodec/libavcodec/ffv1.c | 499 +++---- .../media/plugins/avcodec/libavcodec/flac.c | 794 ++++++++++ .../media/plugins/avcodec/libavcodec/flac.h | 57 + .../plugins/avcodec/libavcodec/flacenc.c | 1310 +++++++++++++++++ .../plugins/avcodec/libavcodec/flashsv.c | 259 ++++ .../plugins/avcodec/libavcodec/flashsvenc.c | 298 ++++ .../plugins/avcodec/libavcodec/flicvideo.c | 467 +++++- .../media/plugins/avcodec/libavcodec/fraps.c | 376 +++++ 15 files changed, 4695 insertions(+), 594 deletions(-) create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/faanidct.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/faanidct.h create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/fft-test.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/flac.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/flac.h create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/flacenc.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/flashsv.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/flashsvenc.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/fraps.c diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/faandct.c b/src/add-ons/media/plugins/avcodec/libavcodec/faandct.c index 2a91184953..40df142da5 100644 --- a/src/add-ons/media/plugins/avcodec/libavcodec/faandct.c +++ b/src/add-ons/media/plugins/avcodec/libavcodec/faandct.c @@ -2,32 +2,35 @@ * Floating point AAN DCT * Copyright (c) 2003 Michael Niedermayer * - * This library is free software; you can redistribute it and/or + * this implementation is based upon the IJG integer AAN DCT (see jfdctfst.c) + * + * 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 * - * this implementation is based upon the IJG integer AAN DCT (see jfdctfst.c) + * The AAN DCT in this file except ff_faandct248() can also be used under the + * new (3 clause) BSD license. */ /** * @file faandct.c - * @brief + * @brief * Floating point AAN DCT * @author Michael Niedermayer */ -#include - #include "dsputil.h" #include "faandct.h" @@ -59,7 +62,7 @@ for(i=0; i<8; i++){ #define A5 0.38268343236508977170 // cos(pi*6/16) #define A4 1.30656296487637652774 // cos(pi*2/16)sqrt(2) -static FLOAT postscale[64]={ +static const FLOAT postscale[64]={ B0*B0, B0*B1, B0*B2, B0*B3, B0*B4, B0*B5, B0*B6, B0*B7, B1*B0, B1*B1, B1*B2, B1*B3, B1*B4, B1*B5, B1*B6, B1*B7, B2*B0, B2*B1, B2*B2, B2*B3, B2*B4, B2*B5, B2*B6, B2*B7, @@ -70,11 +73,12 @@ B6*B0, B6*B1, B6*B2, B6*B3, B6*B4, B6*B5, B6*B6, B6*B7, B7*B0, B7*B1, B7*B2, B7*B3, B7*B4, B7*B5, B7*B6, B7*B7, }; -static always_inline void row_fdct(FLOAT temp[64], DCTELEM * data) +static av_always_inline void row_fdct(FLOAT temp[64], DCTELEM * data) { FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; FLOAT tmp10, tmp11, tmp12, tmp13; - FLOAT z1, z2, z3, z4, z5, z11, z13; + FLOAT z2, z4, z11, z13; + FLOAT av_unused z5; int i; for (i=0; i<8*8; i+=8) { @@ -86,43 +90,50 @@ static always_inline void row_fdct(FLOAT temp[64], DCTELEM * data) tmp5= data[2 + i] - data[5 + i]; tmp3= data[3 + i] + data[4 + i]; tmp4= data[3 + i] - data[4 + i]; - + tmp10= tmp0 + tmp3; tmp13= tmp0 - tmp3; tmp11= tmp1 + tmp2; tmp12= tmp1 - tmp2; - + temp[0 + i]= tmp10 + tmp11; temp[4 + i]= tmp10 - tmp11; - - z1= (tmp12 + tmp13)*A1; - temp[2 + i]= tmp13 + z1; - temp[6 + i]= tmp13 - z1; - - tmp10= tmp4 + tmp5; - tmp11= tmp5 + tmp6; - tmp12= tmp6 + tmp7; - z5= (tmp10 - tmp12) * A5; - z2= tmp10*A2 + z5; - z4= tmp12*A4 + z5; - z3= tmp11*A1; + tmp12 += tmp13; + tmp12 *= A1; + temp[2 + i]= tmp13 + tmp12; + temp[6 + i]= tmp13 - tmp12; - z11= tmp7 + z3; - z13= tmp7 - z3; + tmp4 += tmp5; + tmp5 += tmp6; + tmp6 += tmp7; + +#if 0 + z5= (tmp4 - tmp6) * A5; + z2= tmp4*A2 + z5; + z4= tmp6*A4 + z5; +#else + z2= tmp4*(A2+A5) - tmp6*A5; + z4= tmp6*(A4-A5) + tmp4*A5; +#endif + tmp5*=A1; + + z11= tmp7 + tmp5; + z13= tmp7 - tmp5; temp[5 + i]= z13 + z2; temp[3 + i]= z13 - z2; temp[1 + i]= z11 + z4; temp[7 + i]= z11 - z4; - } + } } void ff_faandct(DCTELEM * data) { FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; FLOAT tmp10, tmp11, tmp12, tmp13; - FLOAT z1, z2, z3, z4, z5, z11, z13; + FLOAT z2, z4, z11, z13; + FLOAT av_unused z5; FLOAT temp[64]; int i; @@ -139,30 +150,36 @@ void ff_faandct(DCTELEM * data) tmp5= temp[8*2 + i] - temp[8*5 + i]; tmp3= temp[8*3 + i] + temp[8*4 + i]; tmp4= temp[8*3 + i] - temp[8*4 + i]; - + tmp10= tmp0 + tmp3; tmp13= tmp0 - tmp3; tmp11= tmp1 + tmp2; tmp12= tmp1 - tmp2; - + data[8*0 + i]= lrintf(SCALE(8*0 + i) * (tmp10 + tmp11)); data[8*4 + i]= lrintf(SCALE(8*4 + i) * (tmp10 - tmp11)); - - z1= (tmp12 + tmp13)* A1; - data[8*2 + i]= lrintf(SCALE(8*2 + i) * (tmp13 + z1)); - data[8*6 + i]= lrintf(SCALE(8*6 + i) * (tmp13 - z1)); - - tmp10= tmp4 + tmp5; - tmp11= tmp5 + tmp6; - tmp12= tmp6 + tmp7; - z5= (tmp10 - tmp12) * A5; - z2= tmp10*A2 + z5; - z4= tmp12*A4 + z5; - z3= tmp11*A1; + tmp12 += tmp13; + tmp12 *= A1; + data[8*2 + i]= lrintf(SCALE(8*2 + i) * (tmp13 + tmp12)); + data[8*6 + i]= lrintf(SCALE(8*6 + i) * (tmp13 - tmp12)); - z11= tmp7 + z3; - z13= tmp7 - z3; + tmp4 += tmp5; + tmp5 += tmp6; + tmp6 += tmp7; + +#if 0 + z5= (tmp4 - tmp6) * A5; + z2= tmp4*A2 + z5; + z4= tmp6*A4 + z5; +#else + z2= tmp4*(A2+A5) - tmp6*A5; + z4= tmp6*(A4-A5) + tmp4*A5; +#endif + tmp5*=A1; + + z11= tmp7 + tmp5; + z13= tmp7 - tmp5; data[8*5 + i]= lrintf(SCALE(8*5 + i) * (z13 + z2)); data[8*3 + i]= lrintf(SCALE(8*3 + i) * (z13 - z2)); @@ -175,7 +192,6 @@ void ff_faandct248(DCTELEM * data) { FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; FLOAT tmp10, tmp11, tmp12, tmp13; - FLOAT z1; FLOAT temp[64]; int i; @@ -192,29 +208,31 @@ void ff_faandct248(DCTELEM * data) tmp5 = temp[8*2 + i] - temp[8*3 + i]; tmp6 = temp[8*4 + i] - temp[8*5 + i]; tmp7 = temp[8*6 + i] - temp[8*7 + i]; - + tmp10 = tmp0 + tmp3; tmp11 = tmp1 + tmp2; tmp12 = tmp1 - tmp2; tmp13 = tmp0 - tmp3; - + data[8*0 + i] = lrintf(SCALE(8*0 + i) * (tmp10 + tmp11)); data[8*4 + i] = lrintf(SCALE(8*4 + i) * (tmp10 - tmp11)); - - z1 = (tmp12 + tmp13)* A1; - data[8*2 + i] = lrintf(SCALE(8*2 + i) * (tmp13 + z1)); - data[8*6 + i] = lrintf(SCALE(8*6 + i) * (tmp13 - z1)); - + + tmp12 += tmp13; + tmp12 *= A1; + data[8*2 + i] = lrintf(SCALE(8*2 + i) * (tmp13 + tmp12)); + data[8*6 + i] = lrintf(SCALE(8*6 + i) * (tmp13 - tmp12)); + tmp10 = tmp4 + tmp7; - tmp11 = tmp5 + tmp6; - tmp12 = tmp5 - tmp6; - tmp13 = tmp4 - tmp7; + tmp11 = tmp5 + tmp6; + tmp12 = tmp5 - tmp6; + tmp13 = tmp4 - tmp7; - data[8*1 + i] = lrintf(SCALE(8*0 + i) * (tmp10 + tmp11)); - data[8*5 + i] = lrintf(SCALE(8*4 + i) * (tmp10 - tmp11)); + data[8*1 + i] = lrintf(SCALE(8*0 + i) * (tmp10 + tmp11)); + data[8*5 + i] = lrintf(SCALE(8*4 + i) * (tmp10 - tmp11)); - z1 = (tmp12 + tmp13)* A1; - data[8*3 + i] = lrintf(SCALE(8*2 + i) * (tmp13 + z1)); - data[8*7 + i] = lrintf(SCALE(8*6 + i) * (tmp13 - z1)); + tmp12 += tmp13; + tmp12 *= A1; + data[8*3 + i] = lrintf(SCALE(8*2 + i) * (tmp13 + tmp12)); + data[8*7 + i] = lrintf(SCALE(8*6 + i) * (tmp13 - tmp12)); } } diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/faandct.h b/src/add-ons/media/plugins/avcodec/libavcodec/faandct.h index c40f8016b1..b9a4eeb3e5 100644 --- a/src/add-ons/media/plugins/avcodec/libavcodec/faandct.h +++ b/src/add-ons/media/plugins/avcodec/libavcodec/faandct.h @@ -2,30 +2,38 @@ * Floating point AAN DCT * Copyright (c) 2003 Michael Niedermayer * - * 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 faandct.h - * @brief + * @brief * Floating point AAN DCT * @author Michael Niedermayer */ - + +#ifndef FFMPEG_FAANDCT_H +#define FFMPEG_FAANDCT_H + +#include "dsputil.h" + #define FAAN_POSTSCALE - + void ff_faandct(DCTELEM * data); void ff_faandct248(DCTELEM * data); + +#endif /* FFMPEG_FAANDCT_H */ diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/faanidct.c b/src/add-ons/media/plugins/avcodec/libavcodec/faanidct.c new file mode 100644 index 0000000000..dc3d8fbb81 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/faanidct.c @@ -0,0 +1,168 @@ +/* + * Floating point AAN IDCT + * Copyright (c) 2008 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 "faanidct.h" + +/* To allow switching to double. */ +#define FLOAT float + +#define B0 1.0000000000000000000000 +#define B1 1.3870398453221474618216 // cos(pi*1/16)sqrt(2) +#define B2 1.3065629648763765278566 // cos(pi*2/16)sqrt(2) +#define B3 1.1758756024193587169745 // cos(pi*3/16)sqrt(2) +#define B4 1.0000000000000000000000 // cos(pi*4/16)sqrt(2) +#define B5 0.7856949583871021812779 // cos(pi*5/16)sqrt(2) +#define B6 0.5411961001461969843997 // cos(pi*6/16)sqrt(2) +#define B7 0.2758993792829430123360 // cos(pi*7/16)sqrt(2) + +#define A4 0.70710678118654752438 // cos(pi*4/16) +#define A2 0.92387953251128675613 // cos(pi*2/16) + +static const FLOAT prescale[64]={ +B0*B0/8, B0*B1/8, B0*B2/8, B0*B3/8, B0*B4/8, B0*B5/8, B0*B6/8, B0*B7/8, +B1*B0/8, B1*B1/8, B1*B2/8, B1*B3/8, B1*B4/8, B1*B5/8, B1*B6/8, B1*B7/8, +B2*B0/8, B2*B1/8, B2*B2/8, B2*B3/8, B2*B4/8, B2*B5/8, B2*B6/8, B2*B7/8, +B3*B0/8, B3*B1/8, B3*B2/8, B3*B3/8, B3*B4/8, B3*B5/8, B3*B6/8, B3*B7/8, +B4*B0/8, B4*B1/8, B4*B2/8, B4*B3/8, B4*B4/8, B4*B5/8, B4*B6/8, B4*B7/8, +B5*B0/8, B5*B1/8, B5*B2/8, B5*B3/8, B5*B4/8, B5*B5/8, B5*B6/8, B5*B7/8, +B6*B0/8, B6*B1/8, B6*B2/8, B6*B3/8, B6*B4/8, B6*B5/8, B6*B6/8, B6*B7/8, +B7*B0/8, B7*B1/8, B7*B2/8, B7*B3/8, B7*B4/8, B7*B5/8, B7*B6/8, B7*B7/8, +}; + +static inline void p8idct(DCTELEM data[64], FLOAT temp[64], uint8_t *dest, int stride, int x, int y, int type){ + int i; + FLOAT av_unused tmp0; + FLOAT s04, d04, s17, d17, s26, d26, s53, d53; + FLOAT os07, os16, os25, os34; + FLOAT od07, od16, od25, od34; + + for(i=0; i + * + * 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_FAANIDCT_H +#define FFMPEG_FAANIDCT_H + +#include +#include "dsputil.h" + +void ff_faanidct(DCTELEM block[64]); +void ff_faanidct_add(uint8_t *dest, int line_size, DCTELEM block[64]); +void ff_faanidct_put(uint8_t *dest, int line_size, DCTELEM block[64]); + +#endif /* FFMPEG_FAANIDCT_H */ diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/fdctref.c b/src/add-ons/media/plugins/avcodec/libavcodec/fdctref.c index d728727ce6..c6a057b846 100644 --- a/src/add-ons/media/plugins/avcodec/libavcodec/fdctref.c +++ b/src/add-ons/media/plugins/avcodec/libavcodec/fdctref.c @@ -27,7 +27,6 @@ * are subject to royalty fees to patent holders. Many of these patents are * general enough such that they are unavoidable regardless of implementation * design. - * */ #include @@ -64,51 +63,51 @@ void init_fdct() void fdct(block) short *block; { - register int i, j; - double s; - double tmp[64]; + register int i, j; + double s; + double tmp[64]; - for(i = 0; i < 8; i++) - for(j = 0; j < 8; j++) - { - s = 0.0; + for(i = 0; i < 8; i++) + for(j = 0; j < 8; j++) + { + s = 0.0; /* - * for(k = 0; k < 8; k++) - * s += c[j][k] * block[8 * i + k]; + * for(k = 0; k < 8; k++) + * s += c[j][k] * block[8 * i + k]; */ - s += c[j][0] * block[8 * i + 0]; - s += c[j][1] * block[8 * i + 1]; - s += c[j][2] * block[8 * i + 2]; - s += c[j][3] * block[8 * i + 3]; - s += c[j][4] * block[8 * i + 4]; - s += c[j][5] * block[8 * i + 5]; - s += c[j][6] * block[8 * i + 6]; - s += c[j][7] * block[8 * i + 7]; + s += c[j][0] * block[8 * i + 0]; + s += c[j][1] * block[8 * i + 1]; + s += c[j][2] * block[8 * i + 2]; + s += c[j][3] * block[8 * i + 3]; + s += c[j][4] * block[8 * i + 4]; + s += c[j][5] * block[8 * i + 5]; + s += c[j][6] * block[8 * i + 6]; + s += c[j][7] * block[8 * i + 7]; - tmp[8 * i + j] = s; - } + tmp[8 * i + j] = s; + } - for(j = 0; j < 8; j++) - for(i = 0; i < 8; i++) - { - s = 0.0; + for(j = 0; j < 8; j++) + for(i = 0; i < 8; i++) + { + s = 0.0; /* - * for(k = 0; k < 8; k++) - * s += c[i][k] * tmp[8 * k + j]; + * for(k = 0; k < 8; k++) + * s += c[i][k] * tmp[8 * k + j]; */ - s += c[i][0] * tmp[8 * 0 + j]; - s += c[i][1] * tmp[8 * 1 + j]; - s += c[i][2] * tmp[8 * 2 + j]; - s += c[i][3] * tmp[8 * 3 + j]; - s += c[i][4] * tmp[8 * 4 + j]; - s += c[i][5] * tmp[8 * 5 + j]; - s += c[i][6] * tmp[8 * 6 + j]; - s += c[i][7] * tmp[8 * 7 + j]; - s*=8.0; + s += c[i][0] * tmp[8 * 0 + j]; + s += c[i][1] * tmp[8 * 1 + j]; + s += c[i][2] * tmp[8 * 2 + j]; + s += c[i][3] * tmp[8 * 3 + j]; + s += c[i][4] * tmp[8 * 4 + j]; + s += c[i][5] * tmp[8 * 5 + j]; + s += c[i][6] * tmp[8 * 6 + j]; + s += c[i][7] * tmp[8 * 7 + j]; + s*=8.0; - block[8 * i + j] = (short)floor(s + 0.499999); + block[8 * i + j] = (short)floor(s + 0.499999); /* * reason for adding 0.499999 instead of 0.5: * s is quite often x.5 (at least for i and/or j = 0 or 4) @@ -141,7 +140,7 @@ short *block; tmp[8*i+j] = partial_product; } - /* Transpose operation is integrated into address mapping by switching + /* Transpose operation is integrated into address mapping by switching loop order of i and j */ for (j=0; j<8; j++) diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/fft-test.c b/src/add-ons/media/plugins/avcodec/libavcodec/fft-test.c new file mode 100644 index 0000000000..1ab653fc3d --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/fft-test.c @@ -0,0 +1,306 @@ +/* + * (c) 2002 Fabrice Bellard + * + * 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 fft-test.c + * FFT and MDCT tests. + */ + +#include "dsputil.h" +#include +#include +#include +#include +#include + +#undef exit +#undef random + +/* reference fft */ + +#define MUL16(a,b) ((a) * (b)) + +#define CMAC(pre, pim, are, aim, bre, bim) \ +{\ + pre += (MUL16(are, bre) - MUL16(aim, bim));\ + pim += (MUL16(are, bim) + MUL16(bre, aim));\ +} + +FFTComplex *exptab; + +void fft_ref_init(int nbits, int inverse) +{ + int n, i; + double c1, s1, alpha; + + n = 1 << nbits; + exptab = av_malloc((n / 2) * sizeof(FFTComplex)); + + for(i=0;i<(n/2);i++) { + alpha = 2 * M_PI * (float)i / (float)n; + c1 = cos(alpha); + s1 = sin(alpha); + if (!inverse) + s1 = -s1; + exptab[i].re = c1; + exptab[i].im = s1; + } +} + +void fft_ref(FFTComplex *tabr, FFTComplex *tab, int nbits) +{ + int n, i, j, k, n2; + double tmp_re, tmp_im, s, c; + FFTComplex *q; + + n = 1 << nbits; + n2 = n >> 1; + for(i=0;i= n2) { + c = -exptab[k - n2].re; + s = -exptab[k - n2].im; + } else { + c = exptab[k].re; + s = exptab[k].im; + } + CMAC(tmp_re, tmp_im, c, s, q->re, q->im); + q++; + } + tabr[i].re = tmp_re; + tabr[i].im = tmp_im; + } +} + +void imdct_ref(float *out, float *in, int nbits) +{ + int n = 1<= 1e-3) { + av_log(NULL, AV_LOG_ERROR, "ERROR %d: %f %f\n", + i, tab1[i], tab2[i]); + } + error+= e*e; + if(e>max) max= e; + } + av_log(NULL, AV_LOG_INFO, "max:%f e:%g\n", max, sqrt(error)/n); +} + + +void help(void) +{ + av_log(NULL, AV_LOG_INFO,"usage: fft-test [-h] [-s] [-i] [-n b]\n" + "-h print this help\n" + "-s speed test\n" + "-m (I)MDCT test\n" + "-i inverse transform test\n" + "-n b set the transform size to 2^b\n" + ); + exit(1); +} + + + +int main(int argc, char **argv) +{ + FFTComplex *tab, *tab1, *tab_ref; + FFTSample *tab2; + int it, i, c; + int do_speed = 0; + int do_mdct = 0; + int do_inverse = 0; + FFTContext s1, *s = &s1; + MDCTContext m1, *m = &m1; + int fft_nbits, fft_size; + + fft_nbits = 9; + for(;;) { + c = getopt(argc, argv, "hsimn:"); + if (c == -1) + break; + switch(c) { + case 'h': + help(); + break; + case 's': + do_speed = 1; + break; + case 'i': + do_inverse = 1; + break; + case 'm': + do_mdct = 1; + break; + case 'n': + fft_nbits = atoi(optarg); + break; + } + } + + fft_size = 1 << fft_nbits; + tab = av_malloc(fft_size * sizeof(FFTComplex)); + tab1 = av_malloc(fft_size * sizeof(FFTComplex)); + tab_ref = av_malloc(fft_size * sizeof(FFTComplex)); + tab2 = av_malloc(fft_size * sizeof(FFTSample)); + + if (do_mdct) { + if (do_inverse) + av_log(NULL, AV_LOG_INFO,"IMDCT"); + else + av_log(NULL, AV_LOG_INFO,"MDCT"); + ff_mdct_init(m, fft_nbits, do_inverse); + } else { + if (do_inverse) + av_log(NULL, AV_LOG_INFO,"IFFT"); + else + av_log(NULL, AV_LOG_INFO,"FFT"); + ff_fft_init(s, fft_nbits, do_inverse); + fft_ref_init(fft_nbits, do_inverse); + } + av_log(NULL, AV_LOG_INFO," %d test\n", fft_size); + + /* generate random data */ + + for(i=0;i= 1000000) + break; + nb_its *= 2; + } + av_log(NULL, AV_LOG_INFO,"time: %0.1f us/transform [total time=%0.2f s its=%d]\n", + (double)duration / nb_its, + (double)duration / 1000000.0, + nb_its); + } + + if (do_mdct) { + ff_mdct_end(m); + } else { + ff_fft_end(s); + } + return 0; +} diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/fft.c b/src/add-ons/media/plugins/avcodec/libavcodec/fft.c index 3b5244a077..4e32b039e8 100644 --- a/src/add-ons/media/plugins/avcodec/libavcodec/fft.c +++ b/src/add-ons/media/plugins/avcodec/libavcodec/fft.c @@ -1,20 +1,24 @@ /* * FFT/IFFT transforms + * Copyright (c) 2008 Loren Merritt * Copyright (c) 2002 Fabrice Bellard. + * Partly based on libdjbfft by D. J. Bernstein * - * 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 */ /** @@ -24,18 +28,53 @@ #include "dsputil.h" +/* cos(2*pi*x/n) for 0<=x<=n/4, followed by its reverse */ +DECLARE_ALIGNED_16(FFTSample, ff_cos_16[8]); +DECLARE_ALIGNED_16(FFTSample, ff_cos_32[16]); +DECLARE_ALIGNED_16(FFTSample, ff_cos_64[32]); +DECLARE_ALIGNED_16(FFTSample, ff_cos_128[64]); +DECLARE_ALIGNED_16(FFTSample, ff_cos_256[128]); +DECLARE_ALIGNED_16(FFTSample, ff_cos_512[256]); +DECLARE_ALIGNED_16(FFTSample, ff_cos_1024[512]); +DECLARE_ALIGNED_16(FFTSample, ff_cos_2048[1024]); +DECLARE_ALIGNED_16(FFTSample, ff_cos_4096[2048]); +DECLARE_ALIGNED_16(FFTSample, ff_cos_8192[4096]); +DECLARE_ALIGNED_16(FFTSample, ff_cos_16384[8192]); +DECLARE_ALIGNED_16(FFTSample, ff_cos_32768[16384]); +DECLARE_ALIGNED_16(FFTSample, ff_cos_65536[32768]); +static FFTSample *ff_cos_tabs[] = { + ff_cos_16, ff_cos_32, ff_cos_64, ff_cos_128, ff_cos_256, ff_cos_512, ff_cos_1024, + ff_cos_2048, ff_cos_4096, ff_cos_8192, ff_cos_16384, ff_cos_32768, ff_cos_65536, +}; + +static int split_radix_permutation(int i, int n, int inverse) +{ + int m; + if(n <= 2) return i&1; + m = n >> 1; + if(!(i&m)) return split_radix_permutation(i, m, inverse)*2; + m >>= 1; + if(inverse == !(i&m)) return split_radix_permutation(i, m, inverse)*4 + 1; + else return split_radix_permutation(i, m, inverse)*4 - 1; +} + /** * The size of the FFT is 2^nbits. If inverse is TRUE, inverse FFT is - * done + * done */ -int fft_init(FFTContext *s, int nbits, int inverse) +int ff_fft_init(FFTContext *s, int nbits, int inverse) { int i, j, m, n; float alpha, c1, s1, s2; - + int split_radix = 1; + int av_unused has_vectors; + + if (nbits < 2 || nbits > 16) + goto fail; s->nbits = nbits; n = 1 << nbits; + s->tmp_buf = NULL; s->exptab = av_malloc((n / 2) * sizeof(FFTComplex)); if (!s->exptab) goto fail; @@ -45,192 +84,125 @@ int fft_init(FFTContext *s, int nbits, int inverse) s->inverse = inverse; s2 = inverse ? 1.0 : -1.0; - - for(i=0;i<(n/2);i++) { - alpha = 2 * M_PI * (float)i / (float)n; - c1 = cos(alpha); - s1 = sin(alpha) * s2; - s->exptab[i].re = c1; - s->exptab[i].im = s1; - } - s->fft_calc = fft_calc_c; + + s->fft_permute = ff_fft_permute_c; + s->fft_calc = ff_fft_calc_c; + s->imdct_calc = ff_imdct_calc_c; + s->imdct_half = ff_imdct_half_c; s->exptab1 = NULL; - /* compute constant table for HAVE_SSE version */ -#if (defined(HAVE_MMX) && defined(HAVE_BUILTIN_VECTOR)) || defined(HAVE_ALTIVEC) - { - int has_vectors = 0; - -#if defined(HAVE_MMX) - has_vectors = mm_support() & MM_SSE; -#endif -#if defined(HAVE_ALTIVEC) && !defined(ALTIVEC_USE_REFERENCE_C_CODE) - has_vectors = mm_support() & MM_ALTIVEC; -#endif - if (has_vectors) { - int np, nblocks, np2, l; - FFTComplex *q; - - np = 1 << nbits; - nblocks = np >> 3; - np2 = np >> 1; - s->exptab1 = av_malloc(np * 2 * sizeof(FFTComplex)); - if (!s->exptab1) - goto fail; - q = s->exptab1; - do { - for(l = 0; l < np2; l += 2 * nblocks) { - *q++ = s->exptab[l]; - *q++ = s->exptab[l + nblocks]; - - q->re = -s->exptab[l].im; - q->im = s->exptab[l].re; - q++; - q->re = -s->exptab[l + nblocks].im; - q->im = s->exptab[l + nblocks].re; - q++; - } - nblocks = nblocks >> 1; - } while (nblocks != 0); - av_freep(&s->exptab); -#if defined(HAVE_MMX) - s->fft_calc = fft_calc_sse; -#else - s->fft_calc = fft_calc_altivec; -#endif - } +#if defined HAVE_MMX && defined HAVE_YASM + has_vectors = mm_support(); + if (has_vectors & MM_SSE) { + /* SSE for P3/P4/K8 */ + s->imdct_calc = ff_imdct_calc_sse; + s->imdct_half = ff_imdct_half_sse; + s->fft_permute = ff_fft_permute_sse; + s->fft_calc = ff_fft_calc_sse; + } else if (has_vectors & MM_3DNOWEXT) { + /* 3DNowEx for K7 */ + s->imdct_calc = ff_imdct_calc_3dn2; + s->imdct_half = ff_imdct_half_3dn2; + s->fft_calc = ff_fft_calc_3dn2; + } else if (has_vectors & MM_3DNOW) { + /* 3DNow! for K6-2/3 */ + s->imdct_calc = ff_imdct_calc_3dn; + s->imdct_half = ff_imdct_half_3dn; + s->fft_calc = ff_fft_calc_3dn; + } +#elif defined HAVE_ALTIVEC && !defined ALTIVEC_USE_REFERENCE_C_CODE + has_vectors = mm_support(); + if (has_vectors & MM_ALTIVEC) { + s->fft_calc = ff_fft_calc_altivec; + split_radix = 0; } #endif - /* compute bit reverse table */ - - for(i=0;i> j) & 1) << (nbits-j-1); + if (split_radix) { + for(j=4; j<=nbits; j++) { + int m = 1<revtab[-split_radix_permutation(i, n, s->inverse) & (n-1)] = i; + s->tmp_buf = av_malloc(n * sizeof(FFTComplex)); + } else { + int np, nblocks, np2, l; + FFTComplex *q; + + for(i=0; i<(n/2); i++) { + alpha = 2 * M_PI * (float)i / (float)n; + c1 = cos(alpha); + s1 = sin(alpha) * s2; + s->exptab[i].re = c1; + s->exptab[i].im = s1; + } + + np = 1 << nbits; + nblocks = np >> 3; + np2 = np >> 1; + s->exptab1 = av_malloc(np * 2 * sizeof(FFTComplex)); + if (!s->exptab1) + goto fail; + q = s->exptab1; + do { + for(l = 0; l < np2; l += 2 * nblocks) { + *q++ = s->exptab[l]; + *q++ = s->exptab[l + nblocks]; + + q->re = -s->exptab[l].im; + q->im = s->exptab[l].re; + q++; + q->re = -s->exptab[l + nblocks].im; + q->im = s->exptab[l + nblocks].re; + q++; + } + nblocks = nblocks >> 1; + } while (nblocks != 0); + av_freep(&s->exptab); + + /* compute bit reverse table */ + for(i=0;i> j) & 1) << (nbits-j-1); + } + s->revtab[i]=m; } - s->revtab[i]=m; } + return 0; fail: av_freep(&s->revtab); av_freep(&s->exptab); av_freep(&s->exptab1); + av_freep(&s->tmp_buf); return -1; } -/* butter fly op */ -#define BF(pre, pim, qre, qim, pre1, pim1, qre1, qim1) \ -{\ - FFTSample ax, ay, bx, by;\ - bx=pre1;\ - by=pim1;\ - ax=qre1;\ - ay=qim1;\ - pre = (bx + ax);\ - pim = (by + ay);\ - qre = (bx - ax);\ - qim = (by - ay);\ -} - -#define MUL16(a,b) ((a) * (b)) - -#define CMUL(pre, pim, are, aim, bre, bim) \ -{\ - pre = (MUL16(are, bre) - MUL16(aim, bim));\ - pim = (MUL16(are, bim) + MUL16(bre, aim));\ -} - /** - * Do a complex FFT with the parameters defined in fft_init(). The - * input data must be permuted before with s->revtab table. No - * 1.0/sqrt(n) normalization is done. + * Do the permutation needed BEFORE calling ff_fft_calc() */ -void fft_calc_c(FFTContext *s, FFTComplex *z) -{ - int ln = s->nbits; - int j, np, np2; - int nblocks, nloops; - register FFTComplex *p, *q; - FFTComplex *exptab = s->exptab; - int l; - FFTSample tmp_re, tmp_im; - - np = 1 << ln; - - /* pass 0 */ - - p=&z[0]; - j=(np >> 1); - do { - BF(p[0].re, p[0].im, p[1].re, p[1].im, - p[0].re, p[0].im, p[1].re, p[1].im); - p+=2; - } while (--j != 0); - - /* pass 1 */ - - - p=&z[0]; - j=np >> 2; - if (s->inverse) { - do { - BF(p[0].re, p[0].im, p[2].re, p[2].im, - p[0].re, p[0].im, p[2].re, p[2].im); - BF(p[1].re, p[1].im, p[3].re, p[3].im, - p[1].re, p[1].im, -p[3].im, p[3].re); - p+=4; - } while (--j != 0); - } else { - do { - BF(p[0].re, p[0].im, p[2].re, p[2].im, - p[0].re, p[0].im, p[2].re, p[2].im); - BF(p[1].re, p[1].im, p[3].re, p[3].im, - p[1].re, p[1].im, p[3].im, -p[3].re); - p+=4; - } while (--j != 0); - } - /* pass 2 .. ln-1 */ - - nblocks = np >> 3; - nloops = 1 << 2; - np2 = np >> 1; - do { - p = z; - q = z + nloops; - for (j = 0; j < nblocks; ++j) { - BF(p->re, p->im, q->re, q->im, - p->re, p->im, q->re, q->im); - - p++; - q++; - for(l = nblocks; l < np2; l += nblocks) { - CMUL(tmp_re, tmp_im, exptab[l].re, exptab[l].im, q->re, q->im); - BF(p->re, p->im, q->re, q->im, - p->re, p->im, tmp_re, tmp_im); - p++; - q++; - } - - p += nloops; - q += nloops; - } - nblocks = nblocks >> 1; - nloops = nloops << 1; - } while (nblocks != 0); -} - -/** - * Do the permutation needed BEFORE calling fft_calc() - */ -void fft_permute(FFTContext *s, FFTComplex *z) +void ff_fft_permute_c(FFTContext *s, FFTComplex *z) { int j, k, np; FFTComplex tmp; const uint16_t *revtab = s->revtab; - - /* reverse */ np = 1 << s->nbits; + + if (s->tmp_buf) { + /* TODO: handle split-radix permute in a more optimal way, probably in-place */ + for(j=0;jtmp_buf[revtab[j]] = z[j]; + memcpy(z, s->tmp_buf, np * sizeof(FFTComplex)); + return; + } + + /* reverse */ for(j=0;jrevtab); av_freep(&s->exptab); av_freep(&s->exptab1); + av_freep(&s->tmp_buf); +} + +#define sqrthalf (float)M_SQRT1_2 + +#define BF(x,y,a,b) {\ + x = a - b;\ + y = a + b;\ +} + +#define BUTTERFLIES(a0,a1,a2,a3) {\ + BF(t3, t5, t5, t1);\ + BF(a2.re, a0.re, a0.re, t5);\ + BF(a3.im, a1.im, a1.im, t3);\ + BF(t4, t6, t2, t6);\ + BF(a3.re, a1.re, a1.re, t4);\ + BF(a2.im, a0.im, a0.im, t6);\ +} + +// force loading all the inputs before storing any. +// this is slightly slower for small data, but avoids store->load aliasing +// for addresses separated by large powers of 2. +#define BUTTERFLIES_BIG(a0,a1,a2,a3) {\ + FFTSample r0=a0.re, i0=a0.im, r1=a1.re, i1=a1.im;\ + BF(t3, t5, t5, t1);\ + BF(a2.re, a0.re, r0, t5);\ + BF(a3.im, a1.im, i1, t3);\ + BF(t4, t6, t2, t6);\ + BF(a3.re, a1.re, r1, t4);\ + BF(a2.im, a0.im, i0, t6);\ +} + +#define TRANSFORM(a0,a1,a2,a3,wre,wim) {\ + t1 = a2.re * wre + a2.im * wim;\ + t2 = a2.im * wre - a2.re * wim;\ + t5 = a3.re * wre - a3.im * wim;\ + t6 = a3.im * wre + a3.re * wim;\ + BUTTERFLIES(a0,a1,a2,a3)\ +} + +#define TRANSFORM_ZERO(a0,a1,a2,a3) {\ + t1 = a2.re;\ + t2 = a2.im;\ + t5 = a3.re;\ + t6 = a3.im;\ + BUTTERFLIES(a0,a1,a2,a3)\ +} + +/* z[0...8n-1], w[1...2n-1] */ +#define PASS(name)\ +static void name(FFTComplex *z, const FFTSample *wre, unsigned int n)\ +{\ + FFTSample t1, t2, t3, t4, t5, t6;\ + int o1 = 2*n;\ + int o2 = 4*n;\ + int o3 = 6*n;\ + const FFTSample *wim = wre+o1;\ + n--;\ +\ + TRANSFORM_ZERO(z[0],z[o1],z[o2],z[o3]);\ + TRANSFORM(z[1],z[o1+1],z[o2+1],z[o3+1],wre[1],wim[-1]);\ + do {\ + z += 2;\ + wre += 2;\ + wim -= 2;\ + TRANSFORM(z[0],z[o1],z[o2],z[o3],wre[0],wim[0]);\ + TRANSFORM(z[1],z[o1+1],z[o2+1],z[o3+1],wre[1],wim[-1]);\ + } while(--n);\ +} + +PASS(pass) +#undef BUTTERFLIES +#define BUTTERFLIES BUTTERFLIES_BIG +PASS(pass_big) + +#define DECL_FFT(n,n2,n4)\ +static void fft##n(FFTComplex *z)\ +{\ + fft##n2(z);\ + fft##n4(z+n4*2);\ + fft##n4(z+n4*3);\ + pass(z,ff_cos_##n,n4/2);\ +} + +static void fft4(FFTComplex *z) +{ + FFTSample t1, t2, t3, t4, t5, t6, t7, t8; + + BF(t3, t1, z[0].re, z[1].re); + BF(t8, t6, z[3].re, z[2].re); + BF(z[2].re, z[0].re, t1, t6); + BF(t4, t2, z[0].im, z[1].im); + BF(t7, t5, z[2].im, z[3].im); + BF(z[3].im, z[1].im, t4, t8); + BF(z[3].re, z[1].re, t3, t7); + BF(z[2].im, z[0].im, t2, t5); +} + +static void fft8(FFTComplex *z) +{ + FFTSample t1, t2, t3, t4, t5, t6, t7, t8; + + fft4(z); + + BF(t1, z[5].re, z[4].re, -z[5].re); + BF(t2, z[5].im, z[4].im, -z[5].im); + BF(t3, z[7].re, z[6].re, -z[7].re); + BF(t4, z[7].im, z[6].im, -z[7].im); + BF(t8, t1, t3, t1); + BF(t7, t2, t2, t4); + BF(z[4].re, z[0].re, z[0].re, t1); + BF(z[4].im, z[0].im, z[0].im, t2); + BF(z[6].re, z[2].re, z[2].re, t7); + BF(z[6].im, z[2].im, z[2].im, t8); + + TRANSFORM(z[1],z[3],z[5],z[7],sqrthalf,sqrthalf); +} + +#ifndef CONFIG_SMALL +static void fft16(FFTComplex *z) +{ + FFTSample t1, t2, t3, t4, t5, t6; + + fft8(z); + fft4(z+8); + fft4(z+12); + + TRANSFORM_ZERO(z[0],z[4],z[8],z[12]); + TRANSFORM(z[2],z[6],z[10],z[14],sqrthalf,sqrthalf); + TRANSFORM(z[1],z[5],z[9],z[13],ff_cos_16[1],ff_cos_16[3]); + TRANSFORM(z[3],z[7],z[11],z[15],ff_cos_16[3],ff_cos_16[1]); +} +#else +DECL_FFT(16,8,4) +#endif +DECL_FFT(32,16,8) +DECL_FFT(64,32,16) +DECL_FFT(128,64,32) +DECL_FFT(256,128,64) +DECL_FFT(512,256,128) +#ifndef CONFIG_SMALL +#define pass pass_big +#endif +DECL_FFT(1024,512,256) +DECL_FFT(2048,1024,512) +DECL_FFT(4096,2048,1024) +DECL_FFT(8192,4096,2048) +DECL_FFT(16384,8192,4096) +DECL_FFT(32768,16384,8192) +DECL_FFT(65536,32768,16384) + +static void (*fft_dispatch[])(FFTComplex*) = { + fft4, fft8, fft16, fft32, fft64, fft128, fft256, fft512, fft1024, + fft2048, fft4096, fft8192, fft16384, fft32768, fft65536, +}; + +/** + * Do a complex FFT with the parameters defined in ff_fft_init(). The + * input data must be permuted before with s->revtab table. No + * 1.0/sqrt(n) normalization is done. + */ +void ff_fft_calc_c(FFTContext *s, FFTComplex *z) +{ + fft_dispatch[s->nbits-2](z); } diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/ffv1.c b/src/add-ons/media/plugins/avcodec/libavcodec/ffv1.c index 3ac7a6a557..c1fac104b3 100644 --- a/src/add-ons/media/plugins/avcodec/libavcodec/ffv1.c +++ b/src/add-ons/media/plugins/avcodec/libavcodec/ffv1.c @@ -3,36 +3,39 @@ * * Copyright (c) 2003 Michael Niedermayer * - * 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 ffv1.c * FF Video Codec 1 (an experimental lossless codec) */ -#include "common.h" #include "avcodec.h" +#include "bitstream.h" #include "dsputil.h" -#include "cabac.h" +#include "rangecoder.h" #include "golomb.h" #define MAX_PLANES 4 #define CONTEXT_SIZE 32 +extern const uint8_t ff_log2_run[32]; + static const int8_t quant3[256]={ 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -142,12 +145,6 @@ static const int8_t quant13[256]={ -4,-4,-4,-4,-4,-4,-4,-4,-4,-3,-3,-3,-3,-2,-2,-1, }; -static const uint8_t log2_run[32]={ - 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, - 4, 4, 5, 5, 6, 6, 7, 7, - 8, 9,10,11,12,13,14,15, -}; - typedef struct VlcState{ int16_t drift; uint16_t error_sum; @@ -164,7 +161,7 @@ typedef struct PlaneContext{ typedef struct FFV1Context{ AVCodecContext *avctx; - CABACContext c; + RangeCoder c; GetBitContext gb; PutBitContext pb; int version; @@ -179,11 +176,11 @@ typedef struct FFV1Context{ int16_t quant_table[5][256]; int run_index; int colorspace; - - DSPContext dsp; + + DSPContext dsp; }FFV1Context; -static always_inline int fold(int diff, int bits){ +static av_always_inline int fold(int diff, int bits){ if(bits==8) diff= (int8_t)diff; else{ @@ -218,64 +215,59 @@ static inline int get_context(FFV1Context *f, int_fast16_t *src, int_fast16_t *l return f->quant_table[0][(L-LT) & 0xFF] + f->quant_table[1][(LT-T) & 0xFF] + f->quant_table[2][(T-RT) & 0xFF]; } -/** - * put - */ -static inline void put_symbol(CABACContext *c, uint8_t *state, int v, int is_signed, int max_exp){ +static inline void put_symbol(RangeCoder *c, uint8_t *state, int v, int is_signed){ int i; if(v){ - const int a= ABS(v); + const int a= FFABS(v); const int e= av_log2(a); + put_rac(c, state+0, 0); + + assert(e<=9); - put_cabac(c, state+0, 0); - for(i=0; i=0; i--){ + put_rac(c, state+22+i, (a>>i)&1); //22..31 } - if(e=0; i--){ - put_cabac(c, state+16+e+i, (a>>i)&1); //17..29 - } - if(is_signed) - put_cabac(c, state+9 + e, v < 0); //9..16 - } + if(is_signed) + put_rac(c, state+11 + e, v < 0); //11..21 }else{ - put_cabac(c, state+0, 1); + put_rac(c, state+0, 1); } } -static inline int get_symbol(CABACContext *c, uint8_t *state, int is_signed, int max_exp){ - if(get_cabac(c, state+0)) +static inline int get_symbol(RangeCoder *c, uint8_t *state, int is_signed){ + if(get_rac(c, state+0)) return 0; else{ - int i, e; - - for(e=0; e=0; i--){ - a += get_cabac(c, state+16+e+i)<=0; i--){ + a += a + get_rac(c, state+22 + i); //22..31 + } + + if(is_signed && get_rac(c, state+11 + e)) //11..21 + return -a; + else + return a; } } static inline void update_vlc_state(VlcState * const state, const int v){ int drift= state->drift; int count= state->count; - state->error_sum += ABS(v); + state->error_sum += FFABS(v); drift += v; if(count == 128){ //FIXME variable @@ -287,15 +279,15 @@ static inline void update_vlc_state(VlcState * const state, const int v){ if(drift <= -count){ if(state->bias > -128) state->bias--; - + drift += count; if(drift <= -count) drift= -count + 1; }else if(drift > 0){ if(state->bias < 127) state->bias++; - + drift -= count; - if(drift > 0) + if(drift > 0) drift= 0; } @@ -323,11 +315,9 @@ static inline void put_vlc_symbol(PutBitContext *pb, VlcState * const state, int #else code= v ^ ((2*state->drift + state->count)>>31); #endif - - code = -2*code-1; - code^= (code>>31); + //printf("v:%d/%d bias:%d error:%d drift:%d count:%d k:%d\n", v, code, state->bias, state->error_sum, state->drift, state->count, k); - set_ur_golomb(pb, code, k, 12, bits); + set_sr_golomb(pb, code, k, 12, bits); update_vlc_state(state, v); } @@ -344,13 +334,9 @@ static inline int get_vlc_symbol(GetBitContext *gb, VlcState * const state, int assert(k<=8); - v= get_ur_golomb(gb, k, 12, bits); + v= get_sr_golomb(gb, k, 12, bits); //printf("v:%d bias:%d error:%d drift:%d count:%d k:%d", v, state->bias, state->error_sum, state->drift, state->count, k); - v++; - if(v&1) v= (v>>1); - else v= -(v>>1); - #if 0 // JPEG LS if(k==0 && 2*state->drift <= - state->count) v ^= (-1); #else @@ -358,25 +344,38 @@ static inline int get_vlc_symbol(GetBitContext *gb, VlcState * const state, int #endif ret= fold(v + state->bias, bits); - + update_vlc_state(state, v); //printf("final: %d\n", ret); return ret; } -static inline void encode_line(FFV1Context *s, int w, int_fast16_t *sample[2], int plane_index, int bits){ +#ifdef CONFIG_ENCODERS +static inline int encode_line(FFV1Context *s, int w, int_fast16_t *sample[2], int plane_index, int bits){ PlaneContext * const p= &s->plane[plane_index]; - CABACContext * const c= &s->c; + RangeCoder * const c= &s->c; int x; int run_index= s->run_index; int run_count=0; int run_mode=0; + if(s->ac){ + if(c->bytestream_end - c->bytestream < w*20){ + av_log(s->avctx, AV_LOG_ERROR, "encoded frame too large\n"); + return -1; + } + }else{ + if(s->pb.buf_end - s->pb.buf - (put_bits_count(&s->pb)>>3) < w*4){ + av_log(s->avctx, AV_LOG_ERROR, "encoded frame too large\n"); + return -1; + } + } + for(x=0; xac){ - put_symbol(c, p->state[context], diff, 1, bits-1); + put_symbol(c, p->state[context], diff, 1); }else{ if(context == 0) run_mode=1; - + if(run_mode){ if(diff){ - while(run_count >= 1<= 1<pb, 1, 1); } - - put_bits(&s->pb, 1 + log2_run[run_index], run_count); + + put_bits(&s->pb, 1 + ff_log2_run[run_index], run_count); if(run_index) run_index--; run_count=0; run_mode=0; @@ -408,16 +407,16 @@ static inline void encode_line(FFV1Context *s, int w, int_fast16_t *sample[2], i run_count++; } } - -// printf("count:%d index:%d, mode:%d, x:%d y:%d pos:%d\n", run_count, run_index, run_mode, x, y, (int)get_bit_count(&s->pb)); + +// printf("count:%d index:%d, mode:%d, x:%d y:%d pos:%d\n", run_count, run_index, run_mode, x, y, (int)put_bits_count(&s->pb)); if(run_mode == 0) put_vlc_symbol(&s->pb, &p->vlc_state[context], diff, bits); } } if(run_mode){ - while(run_count >= 1<= 1<pb, 1, 1); } @@ -426,28 +425,27 @@ static inline void encode_line(FFV1Context *s, int w, int_fast16_t *sample[2], i put_bits(&s->pb, 1, 1); } s->run_index= run_index; + + return 0; } static void encode_plane(FFV1Context *s, uint8_t *src, int w, int h, int stride, int plane_index){ - int x,y; - int_fast16_t sample_buffer[3][w+6]; - int_fast16_t *sample[3]= {sample_buffer[0]+3, sample_buffer[1]+3, sample_buffer[2]+3}; + int x,y,i; + const int ring_size= s->avctx->context_model ? 3 : 2; + int_fast16_t sample_buffer[ring_size][w+6], *sample[ring_size]; s->run_index=0; - - memset(sample_buffer, 0, sizeof(sample_buffer)); - - for(y=0; yavctx->context_model ? 3 : 2; + int_fast16_t sample_buffer[3][ring_size][w+6], *sample[3][ring_size]; s->run_index=0; - + memset(sample_buffer, 0, sizeof(sample_buffer)); - + for(y=0; y>8)&0xFF; int r= (v>>16)&0xFF; - + b -= g; r -= g; g += (b + r)>>2; b += 0x100; r += 0x100; - + // assert(g>=0 && b>=0 && r>=0); // assert(g<256 && b<512 && r<512); sample[0][0][x]= g; @@ -485,76 +484,76 @@ static void encode_rgb_frame(FFV1Context *s, uint32_t *src, int w, int h, int st sample[2][0][x]= r; } for(p=0; p<3; p++){ - int_fast16_t *temp= sample[p][0]; //FIXME try a normal buffer - - sample[p][0]= sample[p][1]; - sample[p][1]= temp; - - sample[p][1][-1]= sample[p][0][0 ]; - sample[p][0][ w]= sample[p][0][w-1]; + sample[p][0][-1]= sample[p][1][0 ]; + sample[p][1][ w]= sample[p][1][w-1]; encode_line(s, w, sample[p], FFMIN(p, 1), 9); } } } -static void write_quant_table(CABACContext *c, int16_t *quant_table){ +static void write_quant_table(RangeCoder *c, int16_t *quant_table){ int last=0; int i; - uint8_t state[CONTEXT_SIZE]={0}; + uint8_t state[CONTEXT_SIZE]; + memset(state, 128, sizeof(state)); for(i=1; i<128 ; i++){ if(quant_table[i] != quant_table[i-1]){ - put_symbol(c, state, i-last-1, 0, 7); + put_symbol(c, state, i-last-1, 0); last= i; } } - put_symbol(c, state, i-last-1, 0, 7); + put_symbol(c, state, i-last-1, 0); } static void write_header(FFV1Context *f){ - uint8_t state[CONTEXT_SIZE]={0}; + uint8_t state[CONTEXT_SIZE]; int i; - CABACContext * const c= &f->c; + RangeCoder * const c= &f->c; - put_symbol(c, state, f->version, 0, 7); - put_symbol(c, state, f->avctx->coder_type, 0, 7); - put_symbol(c, state, f->colorspace, 0, 7); //YUV cs type - put_cabac(c, state, 1); //chroma planes - put_symbol(c, state, f->chroma_h_shift, 0, 7); - put_symbol(c, state, f->chroma_v_shift, 0, 7); - put_cabac(c, state, 0); //no transparency plane + memset(state, 128, sizeof(state)); + + put_symbol(c, state, f->version, 0); + put_symbol(c, state, f->avctx->coder_type, 0); + put_symbol(c, state, f->colorspace, 0); //YUV cs type + put_rac(c, state, 1); //chroma planes + put_symbol(c, state, f->chroma_h_shift, 0); + put_symbol(c, state, f->chroma_v_shift, 0); + put_rac(c, state, 0); //no transparency plane for(i=0; i<5; i++) write_quant_table(c, f->quant_table[i]); } +#endif /* CONFIG_ENCODERS */ -static int common_init(AVCodecContext *avctx){ +static av_cold int common_init(AVCodecContext *avctx){ FFV1Context *s = avctx->priv_data; int width, height; s->avctx= avctx; s->flags= avctx->flags; - + dsputil_init(&s->dsp, avctx); - + width= s->width= avctx->width; height= s->height= avctx->height; - + assert(width && height); return 0; } -static int encode_init(AVCodecContext *avctx) +#ifdef CONFIG_ENCODERS +static av_cold int encode_init(AVCodecContext *avctx) { FFV1Context *s = avctx->priv_data; int i; common_init(avctx); - + s->version=0; s->ac= avctx->coder_type; - + s->plane_count=2; for(i=0; i<256; i++){ s->quant_table[0][i]= quant11[i]; @@ -572,10 +571,10 @@ static int encode_init(AVCodecContext *avctx) for(i=0; iplane_count; i++){ PlaneContext * const p= &s->plane[i]; - + if(avctx->context_model==0){ p->context_count= (11*11*11+1)/2; - }else{ + }else{ p->context_count= (11*11*5*5*5+1)/2; } @@ -595,7 +594,7 @@ static int encode_init(AVCodecContext *avctx) case PIX_FMT_YUV410P: s->colorspace= 0; break; - case PIX_FMT_RGBA32: + case PIX_FMT_RGB32: s->colorspace= 1; break; default: @@ -605,9 +604,10 @@ static int encode_init(AVCodecContext *avctx) avcodec_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_h_shift, &s->chroma_v_shift); s->picture_number=0; - + return 0; } +#endif /* CONFIG_ENCODERS */ static void clear_state(FFV1Context *f){ @@ -616,13 +616,12 @@ static void clear_state(FFV1Context *f){ for(i=0; iplane_count; i++){ PlaneContext *p= &f->plane[i]; - p->interlace_bit_state[0]= 0; - p->interlace_bit_state[1]= 0; - + p->interlace_bit_state[0]= 128; + p->interlace_bit_state[1]= 128; + for(j=0; jcontext_count; j++){ if(f->ac){ - memset(p->state[j], 0, sizeof(uint8_t)*CONTEXT_SIZE); - p->state[j][7] = 2*62; + memset(p->state[j], 128, sizeof(uint8_t)*CONTEXT_SIZE); }else{ p->vlc_state[j].drift= 0; p->vlc_state[j].error_sum= 4; //FFMAX((RANGE + 32)/64, 2); @@ -633,43 +632,40 @@ static void clear_state(FFV1Context *f){ } } +#ifdef CONFIG_ENCODERS static int encode_frame(AVCodecContext *avctx, unsigned char *buf, int buf_size, void *data){ FFV1Context *f = avctx->priv_data; - CABACContext * const c= &f->c; + RangeCoder * const c= &f->c; AVFrame *pict = data; const int width= f->width; const int height= f->height; AVFrame * const p= &f->picture; int used_count= 0; + uint8_t keystate=128; + + ff_init_range_encoder(c, buf, buf_size); +// ff_init_cabac_states(c, ff_h264_lps_range, ff_h264_mps_state, ff_h264_lps_state, 64); + ff_build_rac_states(c, 0.05*(1LL<<32), 256-8); - if(avctx->strict_std_compliance >= 0){ - av_log(avctx, AV_LOG_ERROR, "this codec is under development, files encoded with it wont be decodeable with future versions!!!\n" - "use vstrict=-1 to use it anyway\n"); - return -1; - } - - ff_init_cabac_encoder(c, buf, buf_size); - ff_init_cabac_states(c, ff_h264_lps_range, ff_h264_mps_state, ff_h264_lps_state, 64); - *p = *pict; p->pict_type= FF_I_TYPE; - + if(avctx->gop_size==0 || f->picture_number % avctx->gop_size == 0){ - put_cabac_bypass(c, 1); + put_rac(c, &keystate, 1); p->key_frame= 1; write_header(f); clear_state(f); }else{ - put_cabac_bypass(c, 0); + put_rac(c, &keystate, 0); p->key_frame= 0; } if(!f->ac){ - used_count += put_cabac_terminate(c, 1); + used_count += ff_rac_terminate(c); //printf("pos=%d\n", used_count); init_put_bits(&f->pb, buf + used_count, buf_size - used_count); } - + if(f->colorspace==0){ const int chroma_width = -((-width )>>f->chroma_h_shift); const int chroma_height= -((-height)>>f->chroma_v_shift); @@ -682,39 +678,35 @@ static int encode_frame(AVCodecContext *avctx, unsigned char *buf, int buf_size, encode_rgb_frame(f, (uint32_t*)(p->data[0]), width, height, p->linesize[0]/4); } emms_c(); - + f->picture_number++; if(f->ac){ - return put_cabac_terminate(c, 1); + return ff_rac_terminate(c); }else{ flush_put_bits(&f->pb); //nicer padding FIXME - return used_count + (get_bit_count(&f->pb)+7)/8; + return used_count + (put_bits_count(&f->pb)+7)/8; } } +#endif /* CONFIG_ENCODERS */ -static void common_end(FFV1Context *s){ - int i; +static av_cold int common_end(AVCodecContext *avctx){ + FFV1Context *s = avctx->priv_data; + int i; for(i=0; iplane_count; i++){ PlaneContext *p= &s->plane[i]; av_freep(&p->state); + av_freep(&p->vlc_state); } -} - -static int encode_end(AVCodecContext *avctx) -{ - FFV1Context *s = avctx->priv_data; - - common_end(s); return 0; } static inline void decode_line(FFV1Context *s, int w, int_fast16_t *sample[2], int plane_index, int bits){ PlaneContext * const p= &s->plane[plane_index]; - CABACContext * const c= &s->c; + RangeCoder * const c= &s->c; int x; int run_count=0; int run_mode=0; @@ -722,27 +714,27 @@ static inline void decode_line(FFV1Context *s, int w, int_fast16_t *sample[2], i for(x=0; xac) - diff= get_symbol(c, p->state[context], 1, bits-1); - else{ + + if(s->ac){ + diff= get_symbol(c, p->state[context], 1); + }else{ if(context == 0 && run_mode==0) run_mode=1; - + if(run_mode){ if(run_count==0 && run_mode==1){ if(get_bits1(&s->gb)){ - run_count = 1<gb, log2_run[run_index]); + if(ff_log2_run[run_index]) run_count = get_bits(&s->gb, ff_log2_run[run_index]); else run_count=0; if(run_index) run_index--; run_mode=2; @@ -758,7 +750,7 @@ static inline void decode_line(FFV1Context *s, int w, int_fast16_t *sample[2], i diff=0; }else diff= get_vlc_symbol(&s->gb, &p->vlc_state[context], bits); - + // printf("count:%d index:%d, mode:%d, x:%d y:%d pos:%d\n", run_count, run_index, run_mode, x, y, get_bits_count(&s->gb)); } @@ -766,18 +758,20 @@ static inline void decode_line(FFV1Context *s, int w, int_fast16_t *sample[2], i sample[1][x]= (predict(sample[1] + x, sample[0] + x) + diff) & ((1<run_index= run_index; + s->run_index= run_index; } static void decode_plane(FFV1Context *s, uint8_t *src, int w, int h, int stride, int plane_index){ int x, y; int_fast16_t sample_buffer[2][w+6]; - int_fast16_t *sample[2]= {sample_buffer[0]+3, sample_buffer[1]+3}; + int_fast16_t *sample[2]; + sample[0]=sample_buffer[0]+3; + sample[1]=sample_buffer[1]+3; s->run_index=0; - + memset(sample_buffer, 0, sizeof(sample_buffer)); - + for(y=0; yrun_index=0; - + memset(sample_buffer, 0, sizeof(sample_buffer)); - + for(y=0; y=0 && b>=0 && r>=0); // assert(g<256 && b<512 && r<512); - + b -= 0x100; r -= 0x100; g -= (b + r)>>2; b += g; r += g; - + src[x + stride*y]= b + (g<<8) + (r<<16); } } } -static int read_quant_table(CABACContext *c, int16_t *quant_table, int scale){ +static int read_quant_table(RangeCoder *c, int16_t *quant_table, int scale){ int v; int i=0; - uint8_t state[CONTEXT_SIZE]={0}; + uint8_t state[CONTEXT_SIZE]; + + memset(state, 128, sizeof(state)); for(v=0; i<128 ; v++){ - int len= get_symbol(c, state, 0, 7) + 1; + int len= get_symbol(c, state, 0) + 1; if(len + i > 128) return -1; - + while(len--){ quant_table[i] = scale*v; i++; @@ -860,22 +857,24 @@ static int read_quant_table(CABACContext *c, int16_t *quant_table, int scale){ quant_table[256-i]= -quant_table[i]; } quant_table[128]= -quant_table[127]; - + return 2*v - 1; } static int read_header(FFV1Context *f){ - uint8_t state[CONTEXT_SIZE]={0}; + uint8_t state[CONTEXT_SIZE]; int i, context_count; - CABACContext * const c= &f->c; - - f->version= get_symbol(c, state, 0, 7); - f->ac= f->avctx->coder_type= get_symbol(c, state, 0, 7); - f->colorspace= get_symbol(c, state, 0, 7); //YUV cs type - get_cabac(c, state); //no chroma = false - f->chroma_h_shift= get_symbol(c, state, 0, 7); - f->chroma_v_shift= get_symbol(c, state, 0, 7); - get_cabac(c, state); //transparency plane + RangeCoder * const c= &f->c; + + memset(state, 128, sizeof(state)); + + f->version= get_symbol(c, state, 0); + f->ac= f->avctx->coder_type= get_symbol(c, state, 0); + f->colorspace= get_symbol(c, state, 0); //YUV cs type + get_rac(c, state); //no chroma = false + f->chroma_h_shift= get_symbol(c, state, 0); + f->chroma_v_shift= get_symbol(c, state, 0); + get_rac(c, state); //transparency plane f->plane_count= 2; if(f->colorspace==0){ @@ -884,7 +883,7 @@ static int read_header(FFV1Context *f){ case 0x10: f->avctx->pix_fmt= PIX_FMT_YUV422P; break; case 0x11: f->avctx->pix_fmt= PIX_FMT_YUV420P; break; case 0x20: f->avctx->pix_fmt= PIX_FMT_YUV411P; break; - case 0x33: f->avctx->pix_fmt= PIX_FMT_YUV410P; break; + case 0x22: f->avctx->pix_fmt= PIX_FMT_YUV410P; break; default: av_log(f->avctx, AV_LOG_ERROR, "format not supported\n"); return -1; @@ -894,7 +893,7 @@ static int read_header(FFV1Context *f){ av_log(f->avctx, AV_LOG_ERROR, "chroma subsampling not supported in this colorspace\n"); return -1; } - f->avctx->pix_fmt= PIX_FMT_RGBA32; + f->avctx->pix_fmt= PIX_FMT_RGB32; }else{ av_log(f->avctx, AV_LOG_ERROR, "colorspace not supported\n"); return -1; @@ -905,13 +904,13 @@ static int read_header(FFV1Context *f){ context_count=1; for(i=0; i<5; i++){ context_count*= read_quant_table(c, f->quant_table[i], context_count); - if(context_count < 0){ + if(context_count < 0 || context_count > 32768){ av_log(f->avctx, AV_LOG_ERROR, "read_quant_table error\n"); return -1; } } context_count= (context_count+1)/2; - + for(i=0; iplane_count; i++){ PlaneContext * const p= &f->plane[i]; @@ -923,46 +922,45 @@ static int read_header(FFV1Context *f){ if(!p->vlc_state) p->vlc_state= av_malloc(p->context_count*sizeof(VlcState)); } } - + return 0; } -static int decode_init(AVCodecContext *avctx) +static av_cold int decode_init(AVCodecContext *avctx) { // FFV1Context *s = avctx->priv_data; common_init(avctx); - + return 0; } -static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8_t *buf, int buf_size){ +static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, const uint8_t *buf, int buf_size){ FFV1Context *f = avctx->priv_data; - CABACContext * const c= &f->c; + RangeCoder * const c= &f->c; const int width= f->width; const int height= f->height; AVFrame * const p= &f->picture; int bytes_read; + uint8_t keystate= 128; AVFrame *picture = data; - *data_size = 0; + ff_init_range_decoder(c, buf, buf_size); + ff_build_rac_states(c, 0.05*(1LL<<32), 256-8); - /* no supplementary picture */ - if (buf_size == 0) - return 0; - - ff_init_cabac_decoder(c, buf, buf_size); - ff_init_cabac_states(c, ff_h264_lps_range, ff_h264_mps_state, ff_h264_lps_state, 64); p->pict_type= FF_I_TYPE; //FIXME I vs. P - if(get_cabac_bypass(c)){ + if(get_rac(c, &keystate)){ p->key_frame= 1; - read_header(f); + if(read_header(f) < 0) + return -1; clear_state(f); }else{ p->key_frame= 0; } + if(!f->plane[0].state && !f->plane[0].vlc_state) + return -1; p->reference= 0; if(avctx->get_buffer(avctx, p) < 0){ @@ -972,39 +970,39 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8 if(avctx->debug&FF_DEBUG_PICT_INFO) av_log(avctx, AV_LOG_ERROR, "keyframe:%d coder:%d\n", p->key_frame, f->ac); - + if(!f->ac){ - bytes_read = get_cabac_terminate(c); - if(bytes_read ==0) av_log(avctx, AV_LOG_ERROR, "error at end of AC stream\n"); + bytes_read = c->bytestream - c->bytestream_start - 1; + if(bytes_read ==0) av_log(avctx, AV_LOG_ERROR, "error at end of AC stream\n"); //FIXME //printf("pos=%d\n", bytes_read); init_get_bits(&f->gb, buf + bytes_read, buf_size - bytes_read); } else { bytes_read = 0; /* avoid warning */ } - + if(f->colorspace==0){ const int chroma_width = -((-width )>>f->chroma_h_shift); const int chroma_height= -((-height)>>f->chroma_v_shift); decode_plane(f, p->data[0], width, height, p->linesize[0], 0); - + decode_plane(f, p->data[1], chroma_width, chroma_height, p->linesize[1], 1); decode_plane(f, p->data[2], chroma_width, chroma_height, p->linesize[2], 1); }else{ decode_rgb_frame(f, (uint32_t*)p->data[0], width, height, p->linesize[0]/4); } - + emms_c(); f->picture_number++; *picture= *p; - + avctx->release_buffer(avctx, p); //FIXME *data_size = sizeof(AVFrame); - + if(f->ac){ - bytes_read= get_cabac_terminate(c); + bytes_read= c->bytestream - c->bytestream_start - 1; if(bytes_read ==0) av_log(f->avctx, AV_LOG_ERROR, "error at end of frame\n"); }else{ bytes_read+= (get_bits_count(&f->gb)+7)/8; @@ -1013,22 +1011,6 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8 return bytes_read; } -static int decode_end(AVCodecContext *avctx) -{ - FFV1Context *s = avctx->priv_data; - int i; - - if(avctx->get_buffer == avcodec_default_get_buffer){ - for(i=0; i<4; i++){ - av_freep(&s->picture.base[i]); - s->picture.data[i]= NULL; - } - av_freep(&s->picture.opaque); - } - - return 0; -} - AVCodec ffv1_decoder = { "ffv1", CODEC_TYPE_VIDEO, @@ -1036,10 +1018,11 @@ AVCodec ffv1_decoder = { sizeof(FFV1Context), decode_init, NULL, - decode_end, + common_end, decode_frame, CODEC_CAP_DR1 /*| CODEC_CAP_DRAW_HORIZ_BAND*/, - NULL + NULL, + .long_name= NULL_IF_CONFIG_SMALL("FFmpeg codec #1"), }; #ifdef CONFIG_ENCODERS @@ -1050,6 +1033,8 @@ AVCodec ffv1_encoder = { sizeof(FFV1Context), encode_init, encode_frame, - encode_end, + common_end, + .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_YUV444P, PIX_FMT_YUV422P, PIX_FMT_YUV411P, PIX_FMT_YUV410P, PIX_FMT_RGB32, PIX_FMT_NONE}, + .long_name= NULL_IF_CONFIG_SMALL("FFmpeg codec #1"), }; #endif diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/flac.c b/src/add-ons/media/plugins/avcodec/libavcodec/flac.c new file mode 100644 index 0000000000..d72efaec45 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/flac.c @@ -0,0 +1,794 @@ +/* + * FLAC (Free Lossless Audio Codec) decoder + * Copyright (c) 2003 Alex Beregszaszi + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file flac.c + * FLAC (Free Lossless Audio Codec) decoder + * @author Alex Beregszaszi + * + * For more information on the FLAC format, visit: + * http://flac.sourceforge.net/ + * + * This decoder can be used in 1 of 2 ways: Either raw FLAC data can be fed + * through, starting from the initial 'fLaC' signature; or by passing the + * 34-byte streaminfo structure through avctx->extradata[_size] followed + * by data starting with the 0xFFF8 marker. + */ + +#include + +#define ALT_BITSTREAM_READER +#include "crc.h" +#include "avcodec.h" +#include "bitstream.h" +#include "golomb.h" +#include "flac.h" + +#undef NDEBUG +#include + +#define MAX_CHANNELS 8 +#define MAX_BLOCKSIZE 65535 +#define FLAC_STREAMINFO_SIZE 34 + +enum decorrelation_type { + INDEPENDENT, + LEFT_SIDE, + RIGHT_SIDE, + MID_SIDE, +}; + +typedef struct FLACContext { + FLACSTREAMINFO + + AVCodecContext *avctx; + GetBitContext gb; + + int blocksize/*, last_blocksize*/; + int curr_bps; + enum decorrelation_type decorrelation; + + int32_t *decoded[MAX_CHANNELS]; + uint8_t *bitstream; + unsigned int bitstream_size; + unsigned int bitstream_index; + unsigned int allocated_bitstream_size; +} FLACContext; + +#define METADATA_TYPE_STREAMINFO 0 + +static const int sample_rate_table[] = +{ 0, 0, 0, 0, + 8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000, + 0, 0, 0, 0 }; + +static const int sample_size_table[] = +{ 0, 8, 12, 0, 16, 20, 24, 0 }; + +static const int blocksize_table[] = { + 0, 192, 576<<0, 576<<1, 576<<2, 576<<3, 0, 0, +256<<0, 256<<1, 256<<2, 256<<3, 256<<4, 256<<5, 256<<6, 256<<7 +}; + +static int64_t get_utf8(GetBitContext *gb){ + int64_t val; + GET_UTF8(val, get_bits(gb, 8), return -1;) + return val; +} + +static void allocate_buffers(FLACContext *s); +static int metadata_parse(FLACContext *s); + +static av_cold int flac_decode_init(AVCodecContext * avctx) +{ + FLACContext *s = avctx->priv_data; + s->avctx = avctx; + + if (avctx->extradata_size > 4) { + /* initialize based on the demuxer-supplied streamdata header */ + if (avctx->extradata_size == FLAC_STREAMINFO_SIZE) { + ff_flac_parse_streaminfo(avctx, (FLACStreaminfo *)s, avctx->extradata); + allocate_buffers(s); + } else { + init_get_bits(&s->gb, avctx->extradata, avctx->extradata_size*8); + metadata_parse(s); + } + } + + avctx->sample_fmt = SAMPLE_FMT_S16; + return 0; +} + +static void dump_headers(AVCodecContext *avctx, FLACStreaminfo *s) +{ + av_log(avctx, AV_LOG_DEBUG, " Blocksize: %d .. %d\n", s->min_blocksize, s->max_blocksize); + av_log(avctx, AV_LOG_DEBUG, " Max Framesize: %d\n", s->max_framesize); + av_log(avctx, AV_LOG_DEBUG, " Samplerate: %d\n", s->samplerate); + av_log(avctx, AV_LOG_DEBUG, " Channels: %d\n", s->channels); + av_log(avctx, AV_LOG_DEBUG, " Bits: %d\n", s->bps); +} + +static void allocate_buffers(FLACContext *s){ + int i; + + assert(s->max_blocksize); + + if(s->max_framesize == 0 && s->max_blocksize){ + s->max_framesize= (s->channels * s->bps * s->max_blocksize + 7)/ 8; //FIXME header overhead + } + + for (i = 0; i < s->channels; i++) + { + s->decoded[i] = av_realloc(s->decoded[i], sizeof(int32_t)*s->max_blocksize); + } + + if(s->allocated_bitstream_size < s->max_framesize) + s->bitstream= av_fast_realloc(s->bitstream, &s->allocated_bitstream_size, s->max_framesize); +} + +void ff_flac_parse_streaminfo(AVCodecContext *avctx, struct FLACStreaminfo *s, + const uint8_t *buffer) +{ + GetBitContext gb; + init_get_bits(&gb, buffer, FLAC_STREAMINFO_SIZE*8); + + /* mandatory streaminfo */ + s->min_blocksize = get_bits(&gb, 16); + s->max_blocksize = get_bits(&gb, 16); + + skip_bits(&gb, 24); /* skip min frame size */ + s->max_framesize = get_bits_long(&gb, 24); + + s->samplerate = get_bits_long(&gb, 20); + s->channels = get_bits(&gb, 3) + 1; + s->bps = get_bits(&gb, 5) + 1; + + avctx->channels = s->channels; + avctx->sample_rate = s->samplerate; + + skip_bits(&gb, 36); /* total num of samples */ + + skip_bits(&gb, 64); /* md5 sum */ + skip_bits(&gb, 64); /* md5 sum */ + + dump_headers(avctx, s); +} + +/** + * Parse a list of metadata blocks. This list of blocks must begin with + * the fLaC marker. + * @param s the flac decoding context containing the gb bit reader used to + * parse metadata + * @return 1 if some metadata was read, 0 if no fLaC marker was found + */ +static int metadata_parse(FLACContext *s) +{ + int i, metadata_last, metadata_type, metadata_size, streaminfo_updated=0; + int initial_pos= get_bits_count(&s->gb); + + if (show_bits_long(&s->gb, 32) == MKBETAG('f','L','a','C')) { + skip_bits(&s->gb, 32); + + av_log(s->avctx, AV_LOG_DEBUG, "STREAM HEADER\n"); + do { + metadata_last = get_bits1(&s->gb); + metadata_type = get_bits(&s->gb, 7); + metadata_size = get_bits_long(&s->gb, 24); + + if(get_bits_count(&s->gb) + 8*metadata_size > s->gb.size_in_bits){ + skip_bits_long(&s->gb, initial_pos - get_bits_count(&s->gb)); + break; + } + + av_log(s->avctx, AV_LOG_DEBUG, + " metadata block: flag = %d, type = %d, size = %d\n", + metadata_last, metadata_type, metadata_size); + if (metadata_size) { + switch (metadata_type) { + case METADATA_TYPE_STREAMINFO: + ff_flac_parse_streaminfo(s->avctx, (FLACStreaminfo *)s, s->gb.buffer+get_bits_count(&s->gb)/8); + streaminfo_updated = 1; + + default: + for (i=0; igb, 8); + } + } + } while (!metadata_last); + + if (streaminfo_updated) + allocate_buffers(s); + return 1; + } + return 0; +} + +static int decode_residuals(FLACContext *s, int channel, int pred_order) +{ + int i, tmp, partition, method_type, rice_order; + int sample = 0, samples; + + method_type = get_bits(&s->gb, 2); + if (method_type > 1){ + av_log(s->avctx, AV_LOG_DEBUG, "illegal residual coding method %d\n", method_type); + return -1; + } + + rice_order = get_bits(&s->gb, 4); + + samples= s->blocksize >> rice_order; + if (pred_order > samples) { + av_log(s->avctx, AV_LOG_ERROR, "invalid predictor order: %i > %i\n", pred_order, samples); + return -1; + } + + sample= + i= pred_order; + for (partition = 0; partition < (1 << rice_order); partition++) + { + tmp = get_bits(&s->gb, method_type == 0 ? 4 : 5); + if (tmp == (method_type == 0 ? 15 : 31)) + { + av_log(s->avctx, AV_LOG_DEBUG, "fixed len partition\n"); + tmp = get_bits(&s->gb, 5); + for (; i < samples; i++, sample++) + s->decoded[channel][sample] = get_sbits(&s->gb, tmp); + } + else + { +// av_log(s->avctx, AV_LOG_DEBUG, "rice coded partition k=%d\n", tmp); + for (; i < samples; i++, sample++){ + s->decoded[channel][sample] = get_sr_golomb_flac(&s->gb, tmp, INT_MAX, 0); + } + } + i= 0; + } + +// av_log(s->avctx, AV_LOG_DEBUG, "partitions: %d, samples: %d\n", 1 << rice_order, sample); + + return 0; +} + +static int decode_subframe_fixed(FLACContext *s, int channel, int pred_order) +{ + const int blocksize = s->blocksize; + int32_t *decoded = s->decoded[channel]; + int a, b, c, d, i; + +// av_log(s->avctx, AV_LOG_DEBUG, " SUBFRAME FIXED\n"); + + /* warm up samples */ +// av_log(s->avctx, AV_LOG_DEBUG, " warm up samples: %d\n", pred_order); + + for (i = 0; i < pred_order; i++) + { + decoded[i] = get_sbits(&s->gb, s->curr_bps); +// av_log(s->avctx, AV_LOG_DEBUG, " %d: %d\n", i, s->decoded[channel][i]); + } + + if (decode_residuals(s, channel, pred_order) < 0) + return -1; + + if(pred_order > 0) + a = decoded[pred_order-1]; + if(pred_order > 1) + b = a - decoded[pred_order-2]; + if(pred_order > 2) + c = b - decoded[pred_order-2] + decoded[pred_order-3]; + if(pred_order > 3) + d = c - decoded[pred_order-2] + 2*decoded[pred_order-3] - decoded[pred_order-4]; + + switch(pred_order) + { + case 0: + break; + case 1: + for (i = pred_order; i < blocksize; i++) + decoded[i] = a += decoded[i]; + break; + case 2: + for (i = pred_order; i < blocksize; i++) + decoded[i] = a += b += decoded[i]; + break; + case 3: + for (i = pred_order; i < blocksize; i++) + decoded[i] = a += b += c += decoded[i]; + break; + case 4: + for (i = pred_order; i < blocksize; i++) + decoded[i] = a += b += c += d += decoded[i]; + break; + default: + av_log(s->avctx, AV_LOG_ERROR, "illegal pred order %d\n", pred_order); + return -1; + } + + return 0; +} + +static int decode_subframe_lpc(FLACContext *s, int channel, int pred_order) +{ + int i, j; + int coeff_prec, qlevel; + int coeffs[pred_order]; + int32_t *decoded = s->decoded[channel]; + +// av_log(s->avctx, AV_LOG_DEBUG, " SUBFRAME LPC\n"); + + /* warm up samples */ +// av_log(s->avctx, AV_LOG_DEBUG, " warm up samples: %d\n", pred_order); + + for (i = 0; i < pred_order; i++) + { + decoded[i] = get_sbits(&s->gb, s->curr_bps); +// av_log(s->avctx, AV_LOG_DEBUG, " %d: %d\n", i, decoded[i]); + } + + coeff_prec = get_bits(&s->gb, 4) + 1; + if (coeff_prec == 16) + { + av_log(s->avctx, AV_LOG_DEBUG, "invalid coeff precision\n"); + return -1; + } +// av_log(s->avctx, AV_LOG_DEBUG, " qlp coeff prec: %d\n", coeff_prec); + qlevel = get_sbits(&s->gb, 5); +// av_log(s->avctx, AV_LOG_DEBUG, " quant level: %d\n", qlevel); + if(qlevel < 0){ + av_log(s->avctx, AV_LOG_DEBUG, "qlevel %d not supported, maybe buggy stream\n", qlevel); + return -1; + } + + for (i = 0; i < pred_order; i++) + { + coeffs[i] = get_sbits(&s->gb, coeff_prec); +// av_log(s->avctx, AV_LOG_DEBUG, " %d: %d\n", i, coeffs[i]); + } + + if (decode_residuals(s, channel, pred_order) < 0) + return -1; + + if (s->bps > 16) { + int64_t sum; + for (i = pred_order; i < s->blocksize; i++) + { + sum = 0; + for (j = 0; j < pred_order; j++) + sum += (int64_t)coeffs[j] * decoded[i-j-1]; + decoded[i] += sum >> qlevel; + } + } else { + for (i = pred_order; i < s->blocksize-1; i += 2) + { + int c; + int d = decoded[i-pred_order]; + int s0 = 0, s1 = 0; + for (j = pred_order-1; j > 0; j--) + { + c = coeffs[j]; + s0 += c*d; + d = decoded[i-j]; + s1 += c*d; + } + c = coeffs[0]; + s0 += c*d; + d = decoded[i] += s0 >> qlevel; + s1 += c*d; + decoded[i+1] += s1 >> qlevel; + } + if (i < s->blocksize) + { + int sum = 0; + for (j = 0; j < pred_order; j++) + sum += coeffs[j] * decoded[i-j-1]; + decoded[i] += sum >> qlevel; + } + } + + return 0; +} + +static inline int decode_subframe(FLACContext *s, int channel) +{ + int type, wasted = 0; + int i, tmp; + + s->curr_bps = s->bps; + if(channel == 0){ + if(s->decorrelation == RIGHT_SIDE) + s->curr_bps++; + }else{ + if(s->decorrelation == LEFT_SIDE || s->decorrelation == MID_SIDE) + s->curr_bps++; + } + + if (get_bits1(&s->gb)) + { + av_log(s->avctx, AV_LOG_ERROR, "invalid subframe padding\n"); + return -1; + } + type = get_bits(&s->gb, 6); +// wasted = get_bits1(&s->gb); + +// if (wasted) +// { +// while (!get_bits1(&s->gb)) +// wasted++; +// if (wasted) +// wasted++; +// s->curr_bps -= wasted; +// } +#if 0 + wasted= 16 - av_log2(show_bits(&s->gb, 17)); + skip_bits(&s->gb, wasted+1); + s->curr_bps -= wasted; +#else + if (get_bits1(&s->gb)) + { + wasted = 1; + while (!get_bits1(&s->gb)) + wasted++; + s->curr_bps -= wasted; + av_log(s->avctx, AV_LOG_DEBUG, "%d wasted bits\n", wasted); + } +#endif +//FIXME use av_log2 for types + if (type == 0) + { + av_log(s->avctx, AV_LOG_DEBUG, "coding type: constant\n"); + tmp = get_sbits(&s->gb, s->curr_bps); + for (i = 0; i < s->blocksize; i++) + s->decoded[channel][i] = tmp; + } + else if (type == 1) + { + av_log(s->avctx, AV_LOG_DEBUG, "coding type: verbatim\n"); + for (i = 0; i < s->blocksize; i++) + s->decoded[channel][i] = get_sbits(&s->gb, s->curr_bps); + } + else if ((type >= 8) && (type <= 12)) + { +// av_log(s->avctx, AV_LOG_DEBUG, "coding type: fixed\n"); + if (decode_subframe_fixed(s, channel, type & ~0x8) < 0) + return -1; + } + else if (type >= 32) + { +// av_log(s->avctx, AV_LOG_DEBUG, "coding type: lpc\n"); + if (decode_subframe_lpc(s, channel, (type & ~0x20)+1) < 0) + return -1; + } + else + { + av_log(s->avctx, AV_LOG_ERROR, "invalid coding type\n"); + return -1; + } + + if (wasted) + { + int i; + for (i = 0; i < s->blocksize; i++) + s->decoded[channel][i] <<= wasted; + } + + return 0; +} + +static int decode_frame(FLACContext *s, int alloc_data_size) +{ + int blocksize_code, sample_rate_code, sample_size_code, assignment, i, crc8; + int decorrelation, bps, blocksize, samplerate; + + blocksize_code = get_bits(&s->gb, 4); + + sample_rate_code = get_bits(&s->gb, 4); + + assignment = get_bits(&s->gb, 4); /* channel assignment */ + if (assignment < 8 && s->channels == assignment+1) + decorrelation = INDEPENDENT; + else if (assignment >=8 && assignment < 11 && s->channels == 2) + decorrelation = LEFT_SIDE + assignment - 8; + else + { + av_log(s->avctx, AV_LOG_ERROR, "unsupported channel assignment %d (channels=%d)\n", assignment, s->channels); + return -1; + } + + sample_size_code = get_bits(&s->gb, 3); + if(sample_size_code == 0) + bps= s->bps; + else if((sample_size_code != 3) && (sample_size_code != 7)) + bps = sample_size_table[sample_size_code]; + else + { + av_log(s->avctx, AV_LOG_ERROR, "invalid sample size code (%d)\n", sample_size_code); + return -1; + } + + if (get_bits1(&s->gb)) + { + av_log(s->avctx, AV_LOG_ERROR, "broken stream, invalid padding\n"); + return -1; + } + + if(get_utf8(&s->gb) < 0){ + av_log(s->avctx, AV_LOG_ERROR, "utf8 fscked\n"); + return -1; + } +#if 0 + if (/*((blocksize_code == 6) || (blocksize_code == 7)) &&*/ + (s->min_blocksize != s->max_blocksize)){ + }else{ + } +#endif + + if (blocksize_code == 0) + blocksize = s->min_blocksize; + else if (blocksize_code == 6) + blocksize = get_bits(&s->gb, 8)+1; + else if (blocksize_code == 7) + blocksize = get_bits(&s->gb, 16)+1; + else + blocksize = blocksize_table[blocksize_code]; + + if(blocksize > s->max_blocksize){ + av_log(s->avctx, AV_LOG_ERROR, "blocksize %d > %d\n", blocksize, s->max_blocksize); + return -1; + } + + if(blocksize * s->channels * sizeof(int16_t) > alloc_data_size) + return -1; + + if (sample_rate_code == 0){ + samplerate= s->samplerate; + }else if ((sample_rate_code > 3) && (sample_rate_code < 12)) + samplerate = sample_rate_table[sample_rate_code]; + else if (sample_rate_code == 12) + samplerate = get_bits(&s->gb, 8) * 1000; + else if (sample_rate_code == 13) + samplerate = get_bits(&s->gb, 16); + else if (sample_rate_code == 14) + samplerate = get_bits(&s->gb, 16) * 10; + else{ + av_log(s->avctx, AV_LOG_ERROR, "illegal sample rate code %d\n", sample_rate_code); + return -1; + } + + skip_bits(&s->gb, 8); + crc8 = av_crc(av_crc_get_table(AV_CRC_8_ATM), 0, + s->gb.buffer, get_bits_count(&s->gb)/8); + if(crc8){ + av_log(s->avctx, AV_LOG_ERROR, "header crc mismatch crc=%2X\n", crc8); + return -1; + } + + s->blocksize = blocksize; + s->samplerate = samplerate; + s->bps = bps; + s->decorrelation= decorrelation; + +// dump_headers(s->avctx, (FLACStreaminfo *)s); + + /* subframes */ + for (i = 0; i < s->channels; i++) + { +// av_log(s->avctx, AV_LOG_DEBUG, "decoded: %x residual: %x\n", s->decoded[i], s->residual[i]); + if (decode_subframe(s, i) < 0) + return -1; + } + + align_get_bits(&s->gb); + + /* frame footer */ + skip_bits(&s->gb, 16); /* data crc */ + + return 0; +} + +static int flac_decode_frame(AVCodecContext *avctx, + void *data, int *data_size, + const uint8_t *buf, int buf_size) +{ + FLACContext *s = avctx->priv_data; + int tmp = 0, i, j = 0, input_buf_size = 0; + int16_t *samples = data; + int alloc_data_size= *data_size; + + *data_size=0; + + if(s->max_framesize == 0){ + s->max_framesize= 65536; // should hopefully be enough for the first header + s->bitstream= av_fast_realloc(s->bitstream, &s->allocated_bitstream_size, s->max_framesize); + } + + if(1 && s->max_framesize){//FIXME truncated + if(s->bitstream_size < 4 || AV_RL32(s->bitstream) != MKTAG('f','L','a','C')) + buf_size= FFMIN(buf_size, s->max_framesize - FFMIN(s->bitstream_size, s->max_framesize)); + input_buf_size= buf_size; + + if(s->bitstream_size + buf_size < buf_size || s->bitstream_index + s->bitstream_size + buf_size < s->bitstream_index) + return -1; + + if(s->allocated_bitstream_size < s->bitstream_size + buf_size) + s->bitstream= av_fast_realloc(s->bitstream, &s->allocated_bitstream_size, s->bitstream_size + buf_size); + + if(s->bitstream_index + s->bitstream_size + buf_size > s->allocated_bitstream_size){ +// printf("memmove\n"); + memmove(s->bitstream, &s->bitstream[s->bitstream_index], s->bitstream_size); + s->bitstream_index=0; + } + memcpy(&s->bitstream[s->bitstream_index + s->bitstream_size], buf, buf_size); + buf= &s->bitstream[s->bitstream_index]; + buf_size += s->bitstream_size; + s->bitstream_size= buf_size; + + if(buf_size < s->max_framesize && input_buf_size){ +// printf("wanna more data ...\n"); + return input_buf_size; + } + } + + init_get_bits(&s->gb, buf, buf_size*8); + + if(metadata_parse(s)) + goto end; + + tmp = show_bits(&s->gb, 16); + if((tmp & 0xFFFE) != 0xFFF8){ + av_log(s->avctx, AV_LOG_ERROR, "FRAME HEADER not here\n"); + while(get_bits_count(&s->gb)/8+2 < buf_size && (show_bits(&s->gb, 16) & 0xFFFE) != 0xFFF8) + skip_bits(&s->gb, 8); + goto end; // we may not have enough bits left to decode a frame, so try next time + } + skip_bits(&s->gb, 16); + if (decode_frame(s, alloc_data_size) < 0){ + av_log(s->avctx, AV_LOG_ERROR, "decode_frame() failed\n"); + s->bitstream_size=0; + s->bitstream_index=0; + return -1; + } + + +#if 0 + /* fix the channel order here */ + if (s->order == MID_SIDE) + { + short *left = samples; + short *right = samples + s->blocksize; + for (i = 0; i < s->blocksize; i += 2) + { + uint32_t x = s->decoded[0][i]; + uint32_t y = s->decoded[0][i+1]; + + right[i] = x - (y / 2); + left[i] = right[i] + y; + } + *data_size = 2 * s->blocksize; + } + else + { + for (i = 0; i < s->channels; i++) + { + switch(s->order) + { + case INDEPENDENT: + for (j = 0; j < s->blocksize; j++) + samples[(s->blocksize*i)+j] = s->decoded[i][j]; + break; + case LEFT_SIDE: + case RIGHT_SIDE: + if (i == 0) + for (j = 0; j < s->blocksize; j++) + samples[(s->blocksize*i)+j] = s->decoded[0][j]; + else + for (j = 0; j < s->blocksize; j++) + samples[(s->blocksize*i)+j] = s->decoded[0][j] - s->decoded[i][j]; + break; +// case MID_SIDE: +// av_log(s->avctx, AV_LOG_DEBUG, "mid-side unsupported\n"); + } + *data_size += s->blocksize; + } + } +#else +#define DECORRELATE(left, right)\ + assert(s->channels == 2);\ + for (i = 0; i < s->blocksize; i++)\ + {\ + int a= s->decoded[0][i];\ + int b= s->decoded[1][i];\ + *samples++ = ((left) << (24 - s->bps)) >> 8;\ + *samples++ = ((right) << (24 - s->bps)) >> 8;\ + }\ + break; + + switch(s->decorrelation) + { + case INDEPENDENT: + for (j = 0; j < s->blocksize; j++) + { + for (i = 0; i < s->channels; i++) + *samples++ = (s->decoded[i][j] << (24 - s->bps)) >> 8; + } + break; + case LEFT_SIDE: + DECORRELATE(a,a-b) + case RIGHT_SIDE: + DECORRELATE(a+b,b) + case MID_SIDE: + DECORRELATE( (a-=b>>1) + b, a) + } +#endif + + *data_size = (int8_t *)samples - (int8_t *)data; +// av_log(s->avctx, AV_LOG_DEBUG, "data size: %d\n", *data_size); + +// s->last_blocksize = s->blocksize; +end: + i= (get_bits_count(&s->gb)+7)/8; + if(i > buf_size){ + av_log(s->avctx, AV_LOG_ERROR, "overread: %d\n", i - buf_size); + s->bitstream_size=0; + s->bitstream_index=0; + return -1; + } + + if(s->bitstream_size){ + s->bitstream_index += i; + s->bitstream_size -= i; + return input_buf_size; + }else + return i; +} + +static av_cold int flac_decode_close(AVCodecContext *avctx) +{ + FLACContext *s = avctx->priv_data; + int i; + + for (i = 0; i < s->channels; i++) + { + av_freep(&s->decoded[i]); + } + av_freep(&s->bitstream); + + return 0; +} + +static void flac_flush(AVCodecContext *avctx){ + FLACContext *s = avctx->priv_data; + + s->bitstream_size= + s->bitstream_index= 0; +} + +AVCodec flac_decoder = { + "flac", + CODEC_TYPE_AUDIO, + CODEC_ID_FLAC, + sizeof(FLACContext), + flac_decode_init, + NULL, + flac_decode_close, + flac_decode_frame, + CODEC_CAP_DELAY, + .flush= flac_flush, + .long_name= NULL_IF_CONFIG_SMALL("FLAC (Free Lossless Audio Codec)"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/flac.h b/src/add-ons/media/plugins/avcodec/libavcodec/flac.h new file mode 100644 index 0000000000..d9da14927c --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/flac.h @@ -0,0 +1,57 @@ +/* + * FLAC (Free Lossless Audio Codec) decoder/demuxer common functions + * Copyright (c) 2008 Justin Ruggles + * + * 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 flac.h + * FLAC (Free Lossless Audio Codec) decoder/demuxer common functions + */ + +#ifndef FFMPEG_FLAC_H +#define FFMPEG_FLAC_H + +#include "avcodec.h" + +/** + * Data needed from the Streaminfo header for use by the raw FLAC demuxer + * and/or the FLAC decoder. + */ +#define FLACSTREAMINFO \ + int min_blocksize; /**< minimum block size, in samples */\ + int max_blocksize; /**< maximum block size, in samples */\ + int max_framesize; /**< maximum frame size, in bytes */\ + int samplerate; /**< sample rate */\ + int channels; /**< number of channels */\ + int bps; /**< bits-per-sample */\ + +typedef struct FLACStreaminfo { + FLACSTREAMINFO +} FLACStreaminfo; + +/** + * Parse the Streaminfo metadata block + * @param[out] avctx codec context to set basic stream parameters + * @param[out] s where parsed information is stored + * @param[in] buffer pointer to start of 34-byte streaminfo data + */ +void ff_flac_parse_streaminfo(AVCodecContext *avctx, struct FLACStreaminfo *s, + const uint8_t *buffer); + +#endif /* FFMPEG_FLAC_H */ diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/flacenc.c b/src/add-ons/media/plugins/avcodec/libavcodec/flacenc.c new file mode 100644 index 0000000000..1bba6f84cd --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/flacenc.c @@ -0,0 +1,1310 @@ +/** + * FLAC audio encoder + * Copyright (c) 2006 Justin Ruggles + * + * 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 "libavutil/crc.h" +#include "libavutil/lls.h" +#include "avcodec.h" +#include "bitstream.h" +#include "dsputil.h" +#include "golomb.h" +#include "lpc.h" + +#define FLAC_MAX_CH 8 +#define FLAC_MIN_BLOCKSIZE 16 +#define FLAC_MAX_BLOCKSIZE 65535 + +#define FLAC_SUBFRAME_CONSTANT 0 +#define FLAC_SUBFRAME_VERBATIM 1 +#define FLAC_SUBFRAME_FIXED 8 +#define FLAC_SUBFRAME_LPC 32 + +#define FLAC_CHMODE_NOT_STEREO 0 +#define FLAC_CHMODE_LEFT_RIGHT 1 +#define FLAC_CHMODE_LEFT_SIDE 8 +#define FLAC_CHMODE_RIGHT_SIDE 9 +#define FLAC_CHMODE_MID_SIDE 10 + +#define FLAC_STREAMINFO_SIZE 34 + +#define MAX_FIXED_ORDER 4 +#define MAX_PARTITION_ORDER 8 +#define MAX_PARTITIONS (1 << MAX_PARTITION_ORDER) +#define MAX_LPC_PRECISION 15 +#define MAX_LPC_SHIFT 15 +#define MAX_RICE_PARAM 14 + +typedef struct CompressionOptions { + int compression_level; + int block_time_ms; + int use_lpc; + int lpc_coeff_precision; + int min_prediction_order; + int max_prediction_order; + int prediction_order_method; + int min_partition_order; + int max_partition_order; +} CompressionOptions; + +typedef struct RiceContext { + int porder; + int params[MAX_PARTITIONS]; +} RiceContext; + +typedef struct FlacSubframe { + int type; + int type_code; + int obits; + int order; + int32_t coefs[MAX_LPC_ORDER]; + int shift; + RiceContext rc; + int32_t samples[FLAC_MAX_BLOCKSIZE]; + int32_t residual[FLAC_MAX_BLOCKSIZE+1]; +} FlacSubframe; + +typedef struct FlacFrame { + FlacSubframe subframes[FLAC_MAX_CH]; + int blocksize; + int bs_code[2]; + uint8_t crc8; + int ch_mode; +} FlacFrame; + +typedef struct FlacEncodeContext { + PutBitContext pb; + int channels; + int ch_code; + int samplerate; + int sr_code[2]; + int max_framesize; + uint32_t frame_count; + FlacFrame frame; + CompressionOptions options; + AVCodecContext *avctx; + DSPContext dsp; +} FlacEncodeContext; + +static const int flac_samplerates[16] = { + 0, 0, 0, 0, + 8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000, + 0, 0, 0, 0 +}; + +static const int flac_blocksizes[16] = { + 0, + 192, + 576, 1152, 2304, 4608, + 0, 0, + 256, 512, 1024, 2048, 4096, 8192, 16384, 32768 +}; + +/** + * Writes streaminfo metadata block to byte array + */ +static void write_streaminfo(FlacEncodeContext *s, uint8_t *header) +{ + PutBitContext pb; + + memset(header, 0, FLAC_STREAMINFO_SIZE); + init_put_bits(&pb, header, FLAC_STREAMINFO_SIZE); + + /* streaminfo metadata block */ + put_bits(&pb, 16, s->avctx->frame_size); + put_bits(&pb, 16, s->avctx->frame_size); + put_bits(&pb, 24, 0); + put_bits(&pb, 24, s->max_framesize); + put_bits(&pb, 20, s->samplerate); + put_bits(&pb, 3, s->channels-1); + put_bits(&pb, 5, 15); /* bits per sample - 1 */ + flush_put_bits(&pb); + /* total samples = 0 */ + /* MD5 signature = 0 */ +} + +/** + * Sets blocksize based on samplerate + * Chooses the closest predefined blocksize >= BLOCK_TIME_MS milliseconds + */ +static int select_blocksize(int samplerate, int block_time_ms) +{ + int i; + int target; + int blocksize; + + assert(samplerate > 0); + blocksize = flac_blocksizes[1]; + target = (samplerate * block_time_ms) / 1000; + for(i=0; i<16; i++) { + if(target >= flac_blocksizes[i] && flac_blocksizes[i] > blocksize) { + blocksize = flac_blocksizes[i]; + } + } + return blocksize; +} + +static av_cold int flac_encode_init(AVCodecContext *avctx) +{ + int freq = avctx->sample_rate; + int channels = avctx->channels; + FlacEncodeContext *s = avctx->priv_data; + int i, level; + uint8_t *streaminfo; + + s->avctx = avctx; + + dsputil_init(&s->dsp, avctx); + + if(avctx->sample_fmt != SAMPLE_FMT_S16) { + return -1; + } + + if(channels < 1 || channels > FLAC_MAX_CH) { + return -1; + } + s->channels = channels; + s->ch_code = s->channels-1; + + /* find samplerate in table */ + if(freq < 1) + return -1; + for(i=4; i<12; i++) { + if(freq == flac_samplerates[i]) { + s->samplerate = flac_samplerates[i]; + s->sr_code[0] = i; + s->sr_code[1] = 0; + break; + } + } + /* if not in table, samplerate is non-standard */ + if(i == 12) { + if(freq % 1000 == 0 && freq < 255000) { + s->sr_code[0] = 12; + s->sr_code[1] = freq / 1000; + } else if(freq % 10 == 0 && freq < 655350) { + s->sr_code[0] = 14; + s->sr_code[1] = freq / 10; + } else if(freq < 65535) { + s->sr_code[0] = 13; + s->sr_code[1] = freq; + } else { + return -1; + } + s->samplerate = freq; + } + + /* set compression option defaults based on avctx->compression_level */ + if(avctx->compression_level < 0) { + s->options.compression_level = 5; + } else { + s->options.compression_level = avctx->compression_level; + } + av_log(avctx, AV_LOG_DEBUG, " compression: %d\n", s->options.compression_level); + + level= s->options.compression_level; + if(level > 12) { + av_log(avctx, AV_LOG_ERROR, "invalid compression level: %d\n", + s->options.compression_level); + return -1; + } + + s->options.block_time_ms = ((int[]){ 27, 27, 27,105,105,105,105,105,105,105,105,105,105})[level]; + s->options.use_lpc = ((int[]){ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})[level]; + s->options.min_prediction_order= ((int[]){ 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})[level]; + s->options.max_prediction_order= ((int[]){ 3, 4, 4, 6, 8, 8, 8, 8, 12, 12, 12, 32, 32})[level]; + s->options.prediction_order_method = ((int[]){ ORDER_METHOD_EST, ORDER_METHOD_EST, ORDER_METHOD_EST, + ORDER_METHOD_EST, ORDER_METHOD_EST, ORDER_METHOD_EST, + ORDER_METHOD_4LEVEL, ORDER_METHOD_LOG, ORDER_METHOD_4LEVEL, + ORDER_METHOD_LOG, ORDER_METHOD_SEARCH, ORDER_METHOD_LOG, + ORDER_METHOD_SEARCH})[level]; + s->options.min_partition_order = ((int[]){ 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})[level]; + s->options.max_partition_order = ((int[]){ 2, 2, 3, 3, 3, 8, 8, 8, 8, 8, 8, 8, 8})[level]; + + /* set compression option overrides from AVCodecContext */ + if(avctx->use_lpc >= 0) { + s->options.use_lpc = av_clip(avctx->use_lpc, 0, 11); + } + if(s->options.use_lpc == 1) + av_log(avctx, AV_LOG_DEBUG, " use lpc: Levinson-Durbin recursion with Welch window\n"); + else if(s->options.use_lpc > 1) + av_log(avctx, AV_LOG_DEBUG, " use lpc: Cholesky factorization\n"); + + if(avctx->min_prediction_order >= 0) { + if(s->options.use_lpc) { + if(avctx->min_prediction_order < MIN_LPC_ORDER || + avctx->min_prediction_order > MAX_LPC_ORDER) { + av_log(avctx, AV_LOG_ERROR, "invalid min prediction order: %d\n", + avctx->min_prediction_order); + return -1; + } + } else { + if(avctx->min_prediction_order > MAX_FIXED_ORDER) { + av_log(avctx, AV_LOG_ERROR, "invalid min prediction order: %d\n", + avctx->min_prediction_order); + return -1; + } + } + s->options.min_prediction_order = avctx->min_prediction_order; + } + if(avctx->max_prediction_order >= 0) { + if(s->options.use_lpc) { + if(avctx->max_prediction_order < MIN_LPC_ORDER || + avctx->max_prediction_order > MAX_LPC_ORDER) { + av_log(avctx, AV_LOG_ERROR, "invalid max prediction order: %d\n", + avctx->max_prediction_order); + return -1; + } + } else { + if(avctx->max_prediction_order > MAX_FIXED_ORDER) { + av_log(avctx, AV_LOG_ERROR, "invalid max prediction order: %d\n", + avctx->max_prediction_order); + return -1; + } + } + s->options.max_prediction_order = avctx->max_prediction_order; + } + if(s->options.max_prediction_order < s->options.min_prediction_order) { + av_log(avctx, AV_LOG_ERROR, "invalid prediction orders: min=%d max=%d\n", + s->options.min_prediction_order, s->options.max_prediction_order); + return -1; + } + av_log(avctx, AV_LOG_DEBUG, " prediction order: %d, %d\n", + s->options.min_prediction_order, s->options.max_prediction_order); + + if(avctx->prediction_order_method >= 0) { + if(avctx->prediction_order_method > ORDER_METHOD_LOG) { + av_log(avctx, AV_LOG_ERROR, "invalid prediction order method: %d\n", + avctx->prediction_order_method); + return -1; + } + s->options.prediction_order_method = avctx->prediction_order_method; + } + switch(s->options.prediction_order_method) { + case ORDER_METHOD_EST: av_log(avctx, AV_LOG_DEBUG, " order method: %s\n", + "estimate"); break; + case ORDER_METHOD_2LEVEL: av_log(avctx, AV_LOG_DEBUG, " order method: %s\n", + "2-level"); break; + case ORDER_METHOD_4LEVEL: av_log(avctx, AV_LOG_DEBUG, " order method: %s\n", + "4-level"); break; + case ORDER_METHOD_8LEVEL: av_log(avctx, AV_LOG_DEBUG, " order method: %s\n", + "8-level"); break; + case ORDER_METHOD_SEARCH: av_log(avctx, AV_LOG_DEBUG, " order method: %s\n", + "full search"); break; + case ORDER_METHOD_LOG: av_log(avctx, AV_LOG_DEBUG, " order method: %s\n", + "log search"); break; + } + + if(avctx->min_partition_order >= 0) { + if(avctx->min_partition_order > MAX_PARTITION_ORDER) { + av_log(avctx, AV_LOG_ERROR, "invalid min partition order: %d\n", + avctx->min_partition_order); + return -1; + } + s->options.min_partition_order = avctx->min_partition_order; + } + if(avctx->max_partition_order >= 0) { + if(avctx->max_partition_order > MAX_PARTITION_ORDER) { + av_log(avctx, AV_LOG_ERROR, "invalid max partition order: %d\n", + avctx->max_partition_order); + return -1; + } + s->options.max_partition_order = avctx->max_partition_order; + } + if(s->options.max_partition_order < s->options.min_partition_order) { + av_log(avctx, AV_LOG_ERROR, "invalid partition orders: min=%d max=%d\n", + s->options.min_partition_order, s->options.max_partition_order); + return -1; + } + av_log(avctx, AV_LOG_DEBUG, " partition order: %d, %d\n", + s->options.min_partition_order, s->options.max_partition_order); + + if(avctx->frame_size > 0) { + if(avctx->frame_size < FLAC_MIN_BLOCKSIZE || + avctx->frame_size > FLAC_MAX_BLOCKSIZE) { + av_log(avctx, AV_LOG_ERROR, "invalid block size: %d\n", + avctx->frame_size); + return -1; + } + } else { + s->avctx->frame_size = select_blocksize(s->samplerate, s->options.block_time_ms); + } + av_log(avctx, AV_LOG_DEBUG, " block size: %d\n", s->avctx->frame_size); + + /* set LPC precision */ + if(avctx->lpc_coeff_precision > 0) { + if(avctx->lpc_coeff_precision > MAX_LPC_PRECISION) { + av_log(avctx, AV_LOG_ERROR, "invalid lpc coeff precision: %d\n", + avctx->lpc_coeff_precision); + return -1; + } + s->options.lpc_coeff_precision = avctx->lpc_coeff_precision; + } else { + /* default LPC precision */ + s->options.lpc_coeff_precision = 15; + } + av_log(avctx, AV_LOG_DEBUG, " lpc precision: %d\n", + s->options.lpc_coeff_precision); + + /* set maximum encoded frame size in verbatim mode */ + if(s->channels == 2) { + s->max_framesize = 14 + ((s->avctx->frame_size * 33 + 7) >> 3); + } else { + s->max_framesize = 14 + (s->avctx->frame_size * s->channels * 2); + } + + streaminfo = av_malloc(FLAC_STREAMINFO_SIZE); + write_streaminfo(s, streaminfo); + avctx->extradata = streaminfo; + avctx->extradata_size = FLAC_STREAMINFO_SIZE; + + s->frame_count = 0; + + avctx->coded_frame = avcodec_alloc_frame(); + avctx->coded_frame->key_frame = 1; + + return 0; +} + +static void init_frame(FlacEncodeContext *s) +{ + int i, ch; + FlacFrame *frame; + + frame = &s->frame; + + for(i=0; i<16; i++) { + if(s->avctx->frame_size == flac_blocksizes[i]) { + frame->blocksize = flac_blocksizes[i]; + frame->bs_code[0] = i; + frame->bs_code[1] = 0; + break; + } + } + if(i == 16) { + frame->blocksize = s->avctx->frame_size; + if(frame->blocksize <= 256) { + frame->bs_code[0] = 6; + frame->bs_code[1] = frame->blocksize-1; + } else { + frame->bs_code[0] = 7; + frame->bs_code[1] = frame->blocksize-1; + } + } + + for(ch=0; chchannels; ch++) { + frame->subframes[ch].obits = 16; + } +} + +/** + * Copy channel-interleaved input samples into separate subframes + */ +static void copy_samples(FlacEncodeContext *s, int16_t *samples) +{ + int i, j, ch; + FlacFrame *frame; + + frame = &s->frame; + for(i=0,j=0; iblocksize; i++) { + for(ch=0; chchannels; ch++,j++) { + frame->subframes[ch].samples[i] = samples[j]; + } + } +} + + +#define rice_encode_count(sum, n, k) (((n)*((k)+1))+((sum-(n>>1))>>(k))) + +/** + * Solve for d/dk(rice_encode_count) = n-((sum-(n>>1))>>(k+1)) = 0 + */ +static int find_optimal_param(uint32_t sum, int n) +{ + int k; + uint32_t sum2; + + if(sum <= n>>1) + return 0; + sum2 = sum-(n>>1); + k = av_log2(n<256 ? FASTDIV(sum2,n) : sum2/n); + return FFMIN(k, MAX_RICE_PARAM); +} + +static uint32_t calc_optimal_rice_params(RiceContext *rc, int porder, + uint32_t *sums, int n, int pred_order) +{ + int i; + int k, cnt, part; + uint32_t all_bits; + + part = (1 << porder); + all_bits = 4 * part; + + cnt = (n >> porder) - pred_order; + for(i=0; iparams[i] = k; + all_bits += rice_encode_count(sums[i], cnt, k); + cnt = n >> porder; + } + + rc->porder = porder; + + return all_bits; +} + +static void calc_sums(int pmin, int pmax, uint32_t *data, int n, int pred_order, + uint32_t sums[][MAX_PARTITIONS]) +{ + int i, j; + int parts; + uint32_t *res, *res_end; + + /* sums for highest level */ + parts = (1 << pmax); + res = &data[pred_order]; + res_end = &data[n >> pmax]; + for(i=0; i> pmax; + } + /* sums for lower levels */ + for(i=pmax-1; i>=pmin; i--) { + parts = (1 << i); + for(j=0; j= 0 && pmin <= MAX_PARTITION_ORDER); + assert(pmax >= 0 && pmax <= MAX_PARTITION_ORDER); + assert(pmin <= pmax); + + udata = av_malloc(n * sizeof(uint32_t)); + for(i=0; i>31); + } + + calc_sums(pmin, pmax, udata, n, pred_order, sums); + + opt_porder = pmin; + bits[pmin] = UINT32_MAX; + for(i=pmin; i<=pmax; i++) { + bits[i] = calc_optimal_rice_params(&tmp_rc, i, sums[i], n, pred_order); + if(bits[i] <= bits[opt_porder]) { + opt_porder = i; + *rc= tmp_rc; + } + } + + av_freep(&udata); + return bits[opt_porder]; +} + +static int get_max_p_order(int max_porder, int n, int order) +{ + int porder = FFMIN(max_porder, av_log2(n^(n-1))); + if(order > 0) + porder = FFMIN(porder, av_log2(n/order)); + return porder; +} + +static uint32_t calc_rice_params_fixed(RiceContext *rc, int pmin, int pmax, + int32_t *data, int n, int pred_order, + int bps) +{ + uint32_t bits; + pmin = get_max_p_order(pmin, n, pred_order); + pmax = get_max_p_order(pmax, n, pred_order); + bits = pred_order*bps + 6; + bits += calc_rice_params(rc, pmin, pmax, data, n, pred_order); + return bits; +} + +static uint32_t calc_rice_params_lpc(RiceContext *rc, int pmin, int pmax, + int32_t *data, int n, int pred_order, + int bps, int precision) +{ + uint32_t bits; + pmin = get_max_p_order(pmin, n, pred_order); + pmax = get_max_p_order(pmax, n, pred_order); + bits = pred_order*bps + 4 + 5 + pred_order*precision + 6; + bits += calc_rice_params(rc, pmin, pmax, data, n, pred_order); + return bits; +} + +/** + * Apply Welch window function to audio block + */ +static void apply_welch_window(const int32_t *data, int len, double *w_data) +{ + int i, n2; + double w; + double c; + + assert(!(len&1)); //the optimization in r11881 does not support odd len + //if someone wants odd len extend the change in r11881 + + n2 = (len >> 1); + c = 2.0 / (len - 1.0); + + w_data+=n2; + data+=n2; + for(i=0; i 0); + memcpy(res, smp, n * sizeof(int32_t)); +} + +static void encode_residual_fixed(int32_t *res, const int32_t *smp, int n, + int order) +{ + int i; + + for(i=0; i> shift); + res[i+1] = smp[i+1] - (p1 >> shift); + } +} + +static void encode_residual_lpc(int32_t *res, const int32_t *smp, int n, + int order, const int32_t *coefs, int shift) +{ + int i; + for(i=0; i> shift); + res[i+1] = smp[i+1] - (p1 >> shift); + } +#else + switch(order) { + case 1: encode_residual_lpc_unrolled(res, smp, n, 1, coefs, shift, 0); break; + case 2: encode_residual_lpc_unrolled(res, smp, n, 2, coefs, shift, 0); break; + case 3: encode_residual_lpc_unrolled(res, smp, n, 3, coefs, shift, 0); break; + case 4: encode_residual_lpc_unrolled(res, smp, n, 4, coefs, shift, 0); break; + case 5: encode_residual_lpc_unrolled(res, smp, n, 5, coefs, shift, 0); break; + case 6: encode_residual_lpc_unrolled(res, smp, n, 6, coefs, shift, 0); break; + case 7: encode_residual_lpc_unrolled(res, smp, n, 7, coefs, shift, 0); break; + case 8: encode_residual_lpc_unrolled(res, smp, n, 8, coefs, shift, 0); break; + default: encode_residual_lpc_unrolled(res, smp, n, order, coefs, shift, 1); break; + } +#endif +} + +static int encode_residual(FlacEncodeContext *ctx, int ch) +{ + int i, n; + int min_order, max_order, opt_order, precision, omethod; + int min_porder, max_porder; + FlacFrame *frame; + FlacSubframe *sub; + int32_t coefs[MAX_LPC_ORDER][MAX_LPC_ORDER]; + int shift[MAX_LPC_ORDER]; + int32_t *res, *smp; + + frame = &ctx->frame; + sub = &frame->subframes[ch]; + res = sub->residual; + smp = sub->samples; + n = frame->blocksize; + + /* CONSTANT */ + for(i=1; itype = sub->type_code = FLAC_SUBFRAME_CONSTANT; + res[0] = smp[0]; + return sub->obits; + } + + /* VERBATIM */ + if(n < 5) { + sub->type = sub->type_code = FLAC_SUBFRAME_VERBATIM; + encode_residual_verbatim(res, smp, n); + return sub->obits * n; + } + + min_order = ctx->options.min_prediction_order; + max_order = ctx->options.max_prediction_order; + min_porder = ctx->options.min_partition_order; + max_porder = ctx->options.max_partition_order; + precision = ctx->options.lpc_coeff_precision; + omethod = ctx->options.prediction_order_method; + + /* FIXED */ + if(!ctx->options.use_lpc || max_order == 0 || (n <= max_order)) { + uint32_t bits[MAX_FIXED_ORDER+1]; + if(max_order > MAX_FIXED_ORDER) max_order = MAX_FIXED_ORDER; + opt_order = 0; + bits[0] = UINT32_MAX; + for(i=min_order; i<=max_order; i++) { + encode_residual_fixed(res, smp, n, i); + bits[i] = calc_rice_params_fixed(&sub->rc, min_porder, max_porder, res, + n, i, sub->obits); + if(bits[i] < bits[opt_order]) { + opt_order = i; + } + } + sub->order = opt_order; + sub->type = FLAC_SUBFRAME_FIXED; + sub->type_code = sub->type | sub->order; + if(sub->order != max_order) { + encode_residual_fixed(res, smp, n, sub->order); + return calc_rice_params_fixed(&sub->rc, min_porder, max_porder, res, n, + sub->order, sub->obits); + } + return bits[sub->order]; + } + + /* LPC */ + opt_order = ff_lpc_calc_coefs(&ctx->dsp, smp, n, min_order, max_order, + precision, coefs, shift, ctx->options.use_lpc, + omethod, MAX_LPC_SHIFT, 0); + + if(omethod == ORDER_METHOD_2LEVEL || + omethod == ORDER_METHOD_4LEVEL || + omethod == ORDER_METHOD_8LEVEL) { + int levels = 1 << omethod; + uint32_t bits[levels]; + int order; + int opt_index = levels-1; + opt_order = max_order-1; + bits[opt_index] = UINT32_MAX; + for(i=levels-1; i>=0; i--) { + order = min_order + (((max_order-min_order+1) * (i+1)) / levels)-1; + if(order < 0) order = 0; + encode_residual_lpc(res, smp, n, order+1, coefs[order], shift[order]); + bits[i] = calc_rice_params_lpc(&sub->rc, min_porder, max_porder, + res, n, order+1, sub->obits, precision); + if(bits[i] < bits[opt_index]) { + opt_index = i; + opt_order = order; + } + } + opt_order++; + } else if(omethod == ORDER_METHOD_SEARCH) { + // brute-force optimal order search + uint32_t bits[MAX_LPC_ORDER]; + opt_order = 0; + bits[0] = UINT32_MAX; + for(i=min_order-1; irc, min_porder, max_porder, + res, n, i+1, sub->obits, precision); + if(bits[i] < bits[opt_order]) { + opt_order = i; + } + } + opt_order++; + } else if(omethod == ORDER_METHOD_LOG) { + uint32_t bits[MAX_LPC_ORDER]; + int step; + + opt_order= min_order - 1 + (max_order-min_order)/3; + memset(bits, -1, sizeof(bits)); + + for(step=16 ;step; step>>=1){ + int last= opt_order; + for(i=last-step; i<=last+step; i+= step){ + if(i=max_order || bits[i] < UINT32_MAX) + continue; + encode_residual_lpc(res, smp, n, i+1, coefs[i], shift[i]); + bits[i] = calc_rice_params_lpc(&sub->rc, min_porder, max_porder, + res, n, i+1, sub->obits, precision); + if(bits[i] < bits[opt_order]) + opt_order= i; + } + } + opt_order++; + } + + sub->order = opt_order; + sub->type = FLAC_SUBFRAME_LPC; + sub->type_code = sub->type | (sub->order-1); + sub->shift = shift[sub->order-1]; + for(i=0; iorder; i++) { + sub->coefs[i] = coefs[sub->order-1][i]; + } + encode_residual_lpc(res, smp, n, sub->order, sub->coefs, sub->shift); + return calc_rice_params_lpc(&sub->rc, min_porder, max_porder, res, n, sub->order, + sub->obits, precision); +} + +static int encode_residual_v(FlacEncodeContext *ctx, int ch) +{ + int i, n; + FlacFrame *frame; + FlacSubframe *sub; + int32_t *res, *smp; + + frame = &ctx->frame; + sub = &frame->subframes[ch]; + res = sub->residual; + smp = sub->samples; + n = frame->blocksize; + + /* CONSTANT */ + for(i=1; itype = sub->type_code = FLAC_SUBFRAME_CONSTANT; + res[0] = smp[0]; + return sub->obits; + } + + /* VERBATIM */ + sub->type = sub->type_code = FLAC_SUBFRAME_VERBATIM; + encode_residual_verbatim(res, smp, n); + return sub->obits * n; +} + +static int estimate_stereo_mode(int32_t *left_ch, int32_t *right_ch, int n) +{ + int i, best; + int32_t lt, rt; + uint64_t sum[4]; + uint64_t score[4]; + int k; + + /* calculate sum of 2nd order residual for each channel */ + sum[0] = sum[1] = sum[2] = sum[3] = 0; + for(i=2; i> 1); + sum[3] += FFABS(lt - rt); + sum[0] += FFABS(lt); + sum[1] += FFABS(rt); + } + /* estimate bit counts */ + for(i=0; i<4; i++) { + k = find_optimal_param(2*sum[i], n); + sum[i] = rice_encode_count(2*sum[i], n, k); + } + + /* calculate score for each mode */ + score[0] = sum[0] + sum[1]; + score[1] = sum[0] + sum[3]; + score[2] = sum[1] + sum[3]; + score[3] = sum[2] + sum[3]; + + /* return mode with lowest score */ + best = 0; + for(i=1; i<4; i++) { + if(score[i] < score[best]) { + best = i; + } + } + if(best == 0) { + return FLAC_CHMODE_LEFT_RIGHT; + } else if(best == 1) { + return FLAC_CHMODE_LEFT_SIDE; + } else if(best == 2) { + return FLAC_CHMODE_RIGHT_SIDE; + } else { + return FLAC_CHMODE_MID_SIDE; + } +} + +/** + * Perform stereo channel decorrelation + */ +static void channel_decorrelation(FlacEncodeContext *ctx) +{ + FlacFrame *frame; + int32_t *left, *right; + int i, n; + + frame = &ctx->frame; + n = frame->blocksize; + left = frame->subframes[0].samples; + right = frame->subframes[1].samples; + + if(ctx->channels != 2) { + frame->ch_mode = FLAC_CHMODE_NOT_STEREO; + return; + } + + frame->ch_mode = estimate_stereo_mode(left, right, n); + + /* perform decorrelation and adjust bits-per-sample */ + if(frame->ch_mode == FLAC_CHMODE_LEFT_RIGHT) { + return; + } + if(frame->ch_mode == FLAC_CHMODE_MID_SIDE) { + int32_t tmp; + for(i=0; i> 1; + right[i] = tmp - right[i]; + } + frame->subframes[1].obits++; + } else if(frame->ch_mode == FLAC_CHMODE_LEFT_SIDE) { + for(i=0; isubframes[1].obits++; + } else { + for(i=0; isubframes[0].obits++; + } +} + +static void write_utf8(PutBitContext *pb, uint32_t val) +{ + uint8_t tmp; + PUT_UTF8(val, tmp, put_bits(pb, 8, tmp);) +} + +static void output_frame_header(FlacEncodeContext *s) +{ + FlacFrame *frame; + int crc; + + frame = &s->frame; + + put_bits(&s->pb, 16, 0xFFF8); + put_bits(&s->pb, 4, frame->bs_code[0]); + put_bits(&s->pb, 4, s->sr_code[0]); + if(frame->ch_mode == FLAC_CHMODE_NOT_STEREO) { + put_bits(&s->pb, 4, s->ch_code); + } else { + put_bits(&s->pb, 4, frame->ch_mode); + } + put_bits(&s->pb, 3, 4); /* bits-per-sample code */ + put_bits(&s->pb, 1, 0); + write_utf8(&s->pb, s->frame_count); + if(frame->bs_code[0] == 6) { + put_bits(&s->pb, 8, frame->bs_code[1]); + } else if(frame->bs_code[0] == 7) { + put_bits(&s->pb, 16, frame->bs_code[1]); + } + if(s->sr_code[0] == 12) { + put_bits(&s->pb, 8, s->sr_code[1]); + } else if(s->sr_code[0] > 12) { + put_bits(&s->pb, 16, s->sr_code[1]); + } + flush_put_bits(&s->pb); + crc = av_crc(av_crc_get_table(AV_CRC_8_ATM), 0, + s->pb.buf, put_bits_count(&s->pb)>>3); + put_bits(&s->pb, 8, crc); +} + +static void output_subframe_constant(FlacEncodeContext *s, int ch) +{ + FlacSubframe *sub; + int32_t res; + + sub = &s->frame.subframes[ch]; + res = sub->residual[0]; + put_sbits(&s->pb, sub->obits, res); +} + +static void output_subframe_verbatim(FlacEncodeContext *s, int ch) +{ + int i; + FlacFrame *frame; + FlacSubframe *sub; + int32_t res; + + frame = &s->frame; + sub = &frame->subframes[ch]; + + for(i=0; iblocksize; i++) { + res = sub->residual[i]; + put_sbits(&s->pb, sub->obits, res); + } +} + +static void output_residual(FlacEncodeContext *ctx, int ch) +{ + int i, j, p, n, parts; + int k, porder, psize, res_cnt; + FlacFrame *frame; + FlacSubframe *sub; + int32_t *res; + + frame = &ctx->frame; + sub = &frame->subframes[ch]; + res = sub->residual; + n = frame->blocksize; + + /* rice-encoded block */ + put_bits(&ctx->pb, 2, 0); + + /* partition order */ + porder = sub->rc.porder; + psize = n >> porder; + parts = (1 << porder); + put_bits(&ctx->pb, 4, porder); + res_cnt = psize - sub->order; + + /* residual */ + j = sub->order; + for(p=0; prc.params[p]; + put_bits(&ctx->pb, 4, k); + if(p == 1) res_cnt = psize; + for(i=0; ipb, res[j], k, INT32_MAX, 0); + } + } +} + +static void output_subframe_fixed(FlacEncodeContext *ctx, int ch) +{ + int i; + FlacFrame *frame; + FlacSubframe *sub; + + frame = &ctx->frame; + sub = &frame->subframes[ch]; + + /* warm-up samples */ + for(i=0; iorder; i++) { + put_sbits(&ctx->pb, sub->obits, sub->residual[i]); + } + + /* residual */ + output_residual(ctx, ch); +} + +static void output_subframe_lpc(FlacEncodeContext *ctx, int ch) +{ + int i, cbits; + FlacFrame *frame; + FlacSubframe *sub; + + frame = &ctx->frame; + sub = &frame->subframes[ch]; + + /* warm-up samples */ + for(i=0; iorder; i++) { + put_sbits(&ctx->pb, sub->obits, sub->residual[i]); + } + + /* LPC coefficients */ + cbits = ctx->options.lpc_coeff_precision; + put_bits(&ctx->pb, 4, cbits-1); + put_sbits(&ctx->pb, 5, sub->shift); + for(i=0; iorder; i++) { + put_sbits(&ctx->pb, cbits, sub->coefs[i]); + } + + /* residual */ + output_residual(ctx, ch); +} + +static void output_subframes(FlacEncodeContext *s) +{ + FlacFrame *frame; + FlacSubframe *sub; + int ch; + + frame = &s->frame; + + for(ch=0; chchannels; ch++) { + sub = &frame->subframes[ch]; + + /* subframe header */ + put_bits(&s->pb, 1, 0); + put_bits(&s->pb, 6, sub->type_code); + put_bits(&s->pb, 1, 0); /* no wasted bits */ + + /* subframe */ + if(sub->type == FLAC_SUBFRAME_CONSTANT) { + output_subframe_constant(s, ch); + } else if(sub->type == FLAC_SUBFRAME_VERBATIM) { + output_subframe_verbatim(s, ch); + } else if(sub->type == FLAC_SUBFRAME_FIXED) { + output_subframe_fixed(s, ch); + } else if(sub->type == FLAC_SUBFRAME_LPC) { + output_subframe_lpc(s, ch); + } + } +} + +static void output_frame_footer(FlacEncodeContext *s) +{ + int crc; + flush_put_bits(&s->pb); + crc = bswap_16(av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, + s->pb.buf, put_bits_count(&s->pb)>>3)); + put_bits(&s->pb, 16, crc); + flush_put_bits(&s->pb); +} + +static int flac_encode_frame(AVCodecContext *avctx, uint8_t *frame, + int buf_size, void *data) +{ + int ch; + FlacEncodeContext *s; + int16_t *samples = data; + int out_bytes; + int reencoded=0; + + s = avctx->priv_data; + + if(buf_size < s->max_framesize*2) { + av_log(avctx, AV_LOG_ERROR, "output buffer too small\n"); + return 0; + } + + init_frame(s); + + copy_samples(s, samples); + + channel_decorrelation(s); + + for(ch=0; chchannels; ch++) { + encode_residual(s, ch); + } + +write_frame: + init_put_bits(&s->pb, frame, buf_size); + output_frame_header(s); + output_subframes(s); + output_frame_footer(s); + out_bytes = put_bits_count(&s->pb) >> 3; + + if(out_bytes > s->max_framesize) { + if(reencoded) { + /* still too large. must be an error. */ + av_log(avctx, AV_LOG_ERROR, "error encoding frame\n"); + return -1; + } + + /* frame too large. use verbatim mode */ + for(ch=0; chchannels; ch++) { + encode_residual_v(s, ch); + } + reencoded = 1; + goto write_frame; + } + + s->frame_count++; + return out_bytes; +} + +static av_cold int flac_encode_close(AVCodecContext *avctx) +{ + av_freep(&avctx->extradata); + avctx->extradata_size = 0; + av_freep(&avctx->coded_frame); + return 0; +} + +AVCodec flac_encoder = { + "flac", + CODEC_TYPE_AUDIO, + CODEC_ID_FLAC, + sizeof(FlacEncodeContext), + flac_encode_init, + flac_encode_frame, + flac_encode_close, + NULL, + .capabilities = CODEC_CAP_SMALL_LAST_FRAME, + .sample_fmts = (enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_NONE}, + .long_name = NULL_IF_CONFIG_SMALL("FLAC (Free Lossless Audio Codec)"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/flashsv.c b/src/add-ons/media/plugins/avcodec/libavcodec/flashsv.c new file mode 100644 index 0000000000..3842594ad2 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/flashsv.c @@ -0,0 +1,259 @@ +/* + * Flash Screen Video decoder + * Copyright (C) 2004 Alex Beregszaszi + * Copyright (C) 2006 Benjamin Larsson + * + * 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 flashsv.c + * Flash Screen Video decoder + * @author Alex Beregszaszi + * @author Benjamin Larsson + */ + +/* Bitstream description + * The picture is divided into blocks that are zlib compressed. + * + * The decoder is fed complete frames, the frameheader contains: + * 4bits of block width + * 12bits of frame width + * 4bits of block height + * 12bits of frame height + * + * Directly after the header are the compressed blocks. The blocks + * have their compressed size represented with 16bits in the beginnig. + * If the size = 0 then the block is unchanged from the previous frame. + * All blocks are decompressed until the buffer is consumed. + * + * Encoding ideas, a basic encoder would just use a fixed block size. + * Block sizes can be multipels of 16, from 16 to 256. The blocks don't + * have to be quadratic. A brute force search with a set of diffrent + * block sizes should give a better result then to just use a fixed size. + */ + +#include +#include + +#include "avcodec.h" +#include "bitstream.h" + +#include + +typedef struct FlashSVContext { + AVCodecContext *avctx; + AVFrame frame; + int image_width, image_height; + int block_width, block_height; + uint8_t* tmpblock; + int block_size; + z_stream zstream; +} FlashSVContext; + + +static void copy_region(uint8_t *sptr, uint8_t *dptr, + int dx, int dy, int h, int w, int stride) +{ + int i; + + for (i = dx+h; i > dx; i--) + { + memcpy(dptr+(i*stride)+dy*3, sptr, w*3); + sptr += w*3; + } +} + + +static av_cold int flashsv_decode_init(AVCodecContext *avctx) +{ + FlashSVContext *s = avctx->priv_data; + int zret; // Zlib return code + + s->avctx = avctx; + s->zstream.zalloc = Z_NULL; + s->zstream.zfree = Z_NULL; + s->zstream.opaque = Z_NULL; + zret = inflateInit(&(s->zstream)); + if (zret != Z_OK) { + av_log(avctx, AV_LOG_ERROR, "Inflate init error: %d\n", zret); + return 1; + } + avctx->pix_fmt = PIX_FMT_BGR24; + s->frame.data[0] = NULL; + + return 0; +} + + +static int flashsv_decode_frame(AVCodecContext *avctx, + void *data, int *data_size, + const uint8_t *buf, int buf_size) +{ + FlashSVContext *s = avctx->priv_data; + int h_blocks, v_blocks, h_part, v_part, i, j; + GetBitContext gb; + + /* no supplementary picture */ + if (buf_size == 0) + return 0; + + if(s->frame.data[0]) + avctx->release_buffer(avctx, &s->frame); + + init_get_bits(&gb, buf, buf_size * 8); + + /* start to parse the bitstream */ + s->block_width = 16* (get_bits(&gb, 4)+1); + s->image_width = get_bits(&gb,12); + s->block_height= 16* (get_bits(&gb, 4)+1); + s->image_height= get_bits(&gb,12); + + /* calculate amount of blocks and the size of the border blocks */ + h_blocks = s->image_width / s->block_width; + h_part = s->image_width % s->block_width; + v_blocks = s->image_height / s->block_height; + v_part = s->image_height % s->block_height; + + /* the block size could change between frames, make sure the buffer + * is large enough, if not, get a larger one */ + if(s->block_size < s->block_width*s->block_height) { + if (s->tmpblock != NULL) + av_free(s->tmpblock); + if ((s->tmpblock = av_malloc(3*s->block_width*s->block_height)) == NULL) { + av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n"); + return -1; + } + } + s->block_size = s->block_width*s->block_height; + + /* init the image size once */ + if((avctx->width==0) && (avctx->height==0)){ + avctx->width = s->image_width; + avctx->height = s->image_height; + } + + /* check for changes of image width and image height */ + if ((avctx->width != s->image_width) || (avctx->height != s->image_height)) { + av_log(avctx, AV_LOG_ERROR, "Frame width or height differs from first frames!\n"); + av_log(avctx, AV_LOG_ERROR, "fh = %d, fv %d vs ch = %d, cv = %d\n",avctx->height, + avctx->width,s->image_height,s->image_width); + return -1; + } + + av_log(avctx, AV_LOG_DEBUG, "image: %dx%d block: %dx%d num: %dx%d part: %dx%d\n", + s->image_width, s->image_height, s->block_width, s->block_height, + h_blocks, v_blocks, h_part, v_part); + + s->frame.reference = 1; + s->frame.buffer_hints = FF_BUFFER_HINTS_VALID; + if (avctx->get_buffer(avctx, &s->frame) < 0) { + av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n"); + return -1; + } + + /* loop over all block columns */ + for (j = 0; j < v_blocks + (v_part?1:0); j++) + { + + int hp = j*s->block_height; // horiz position in frame + int hs = (jblock_height:v_part; // size of block + + + /* loop over all block rows */ + for (i = 0; i < h_blocks + (h_part?1:0); i++) + { + int wp = i*s->block_width; // vert position in frame + int ws = (iblock_width:h_part; // size of block + + /* get the size of the compressed zlib chunk */ + int size = get_bits(&gb, 16); + + if (size == 0) { + /* no change, don't do anything */ + } else { + /* decompress block */ + int ret = inflateReset(&(s->zstream)); + if (ret != Z_OK) + { + av_log(avctx, AV_LOG_ERROR, "error in decompression (reset) of block %dx%d\n", i, j); + /* return -1; */ + } + s->zstream.next_in = buf+(get_bits_count(&gb)/8); + s->zstream.avail_in = size; + s->zstream.next_out = s->tmpblock; + s->zstream.avail_out = s->block_size*3; + ret = inflate(&(s->zstream), Z_FINISH); + if (ret == Z_DATA_ERROR) + { + av_log(avctx, AV_LOG_ERROR, "Zlib resync occurred\n"); + inflateSync(&(s->zstream)); + ret = inflate(&(s->zstream), Z_FINISH); + } + + if ((ret != Z_OK) && (ret != Z_STREAM_END)) + { + av_log(avctx, AV_LOG_ERROR, "error in decompression of block %dx%d: %d\n", i, j, ret); + /* return -1; */ + } + copy_region(s->tmpblock, s->frame.data[0], s->image_height-(hp+hs+1), wp, hs, ws, s->frame.linesize[0]); + skip_bits(&gb, 8*size); /* skip the consumed bits */ + } + } + } + + *data_size = sizeof(AVFrame); + *(AVFrame*)data = s->frame; + + if ((get_bits_count(&gb)/8) != buf_size) + av_log(avctx, AV_LOG_ERROR, "buffer not fully consumed (%d != %d)\n", + buf_size, (get_bits_count(&gb)/8)); + + /* report that the buffer was completely consumed */ + return buf_size; +} + + +static av_cold int flashsv_decode_end(AVCodecContext *avctx) +{ + FlashSVContext *s = avctx->priv_data; + inflateEnd(&(s->zstream)); + /* release the frame if needed */ + if (s->frame.data[0]) + avctx->release_buffer(avctx, &s->frame); + + /* free the tmpblock */ + if (s->tmpblock != NULL) + av_free(s->tmpblock); + + return 0; +} + + +AVCodec flashsv_decoder = { + "flashsv", + CODEC_TYPE_VIDEO, + CODEC_ID_FLASHSV, + sizeof(FlashSVContext), + flashsv_decode_init, + NULL, + flashsv_decode_end, + flashsv_decode_frame, + CODEC_CAP_DR1, + .pix_fmts = (enum PixelFormat[]){PIX_FMT_BGR24, PIX_FMT_NONE}, + .long_name = NULL_IF_CONFIG_SMALL("Flash Screen Video v1"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/flashsvenc.c b/src/add-ons/media/plugins/avcodec/libavcodec/flashsvenc.c new file mode 100644 index 0000000000..645a4eb6f2 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/flashsvenc.c @@ -0,0 +1,298 @@ +/* + * Flash Screen Video encoder + * Copyright (C) 2004 Alex Beregszaszi + * Copyright (C) 2006 Benjamin Larsson + * + * 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 + */ + +/* Encoding development sponsored by http://fh-campuswien.ac.at */ + +/** + * @file flashsvenc.c + * Flash Screen Video encoder + * @author Alex Beregszaszi + * @author Benjamin Larsson + */ + +/* Bitstream description + * The picture is divided into blocks that are zlib-compressed. + * + * The decoder is fed complete frames, the frameheader contains: + * 4bits of block width + * 12bits of frame width + * 4bits of block height + * 12bits of frame height + * + * Directly after the header are the compressed blocks. The blocks + * have their compressed size represented with 16bits in the beginig. + * If the size = 0 then the block is unchanged from the previous frame. + * All blocks are decompressed until the buffer is consumed. + * + * Encoding ideas, a basic encoder would just use a fixed block size. + * Block sizes can be multipels of 16, from 16 to 256. The blocks don't + * have to be quadratic. A brute force search with a set of different + * block sizes should give a better result than to just use a fixed size. + */ + +/* TODO: + * Don't reencode the frame in brute force mode if the frame is a dupe. Speed up. + * Make the difference check faster. + */ + +#include +#include +#include + +#include "avcodec.h" +#include "bitstream.h" +#include "bytestream.h" + + +typedef struct FlashSVContext { + AVCodecContext *avctx; + uint8_t *previous_frame; + AVFrame frame; + int image_width, image_height; + int block_width, block_height; + uint8_t* tmpblock; + uint8_t* encbuffer; + int block_size; + z_stream zstream; + int last_key_frame; +} FlashSVContext; + +static int copy_region_enc(uint8_t *sptr, uint8_t *dptr, + int dx, int dy, int h, int w, int stride, uint8_t *pfptr) { + int i,j; + uint8_t *nsptr; + uint8_t *npfptr; + int diff = 0; + + for (i = dx+h; i > dx; i--) { + nsptr = sptr+(i*stride)+dy*3; + npfptr = pfptr+(i*stride)+dy*3; + for (j=0 ; jpriv_data; + + s->avctx = avctx; + + if ((avctx->width > 4095) || (avctx->height > 4095)) { + av_log(avctx, AV_LOG_ERROR, "Input dimensions too large, input must be max 4096x4096 !\n"); + return -1; + } + + if (avcodec_check_dimensions(avctx, avctx->width, avctx->height) < 0) { + return -1; + } + + // Needed if zlib unused or init aborted before deflateInit + memset(&(s->zstream), 0, sizeof(z_stream)); + + s->last_key_frame=0; + + s->image_width = avctx->width; + s->image_height = avctx->height; + + s->tmpblock = av_mallocz(3*256*256); + s->encbuffer = av_mallocz(s->image_width*s->image_height*3); + + if (!s->tmpblock || !s->encbuffer) { + av_log(avctx, AV_LOG_ERROR, "Memory allocation failed.\n"); + return -1; + } + + return 0; +} + + +static int encode_bitstream(FlashSVContext *s, AVFrame *p, uint8_t *buf, int buf_size, + int block_width, int block_height, uint8_t *previous_frame, int* I_frame) { + + PutBitContext pb; + int h_blocks, v_blocks, h_part, v_part, i, j; + int buf_pos, res; + int pred_blocks = 0; + + init_put_bits(&pb, buf, buf_size*8); + + put_bits(&pb, 4, (block_width/16)-1); + put_bits(&pb, 12, s->image_width); + put_bits(&pb, 4, (block_height/16)-1); + put_bits(&pb, 12, s->image_height); + flush_put_bits(&pb); + buf_pos=4; + + h_blocks = s->image_width / block_width; + h_part = s->image_width % block_width; + v_blocks = s->image_height / block_height; + v_part = s->image_height % block_height; + + /* loop over all block columns */ + for (j = 0; j < v_blocks + (v_part?1:0); j++) + { + + int hp = j*block_height; // horiz position in frame + int hs = (jdata[0], s->tmpblock, s->image_height-(hp+hs+1), wp, hs, ws, p->linesize[0], previous_frame); + + if (res || *I_frame) { + unsigned long zsize; + zsize = 3*block_width*block_height; + ret = compress2(ptr+2, &zsize, s->tmpblock, 3*ws*hs, 9); + + + //ret = deflateReset(&(s->zstream)); + if (ret != Z_OK) + av_log(s->avctx, AV_LOG_ERROR, "error while compressing block %dx%d\n", i, j); + + bytestream_put_be16(&ptr,(unsigned int)zsize); + buf_pos += zsize+2; + //av_log(avctx, AV_LOG_ERROR, "buf_pos = %d\n", buf_pos); + } else { + pred_blocks++; + bytestream_put_be16(&ptr,0); + buf_pos += 2; + } + } + } + + if (pred_blocks) + *I_frame = 0; + else + *I_frame = 1; + + return buf_pos; +} + + +static int flashsv_encode_frame(AVCodecContext *avctx, uint8_t *buf, int buf_size, void *data) +{ + FlashSVContext * const s = avctx->priv_data; + AVFrame *pict = data; + AVFrame * const p = &s->frame; + uint8_t *pfptr; + int res; + int I_frame = 0; + int opt_w, opt_h; + + *p = *pict; + + /* First frame needs to be a keyframe */ + if (avctx->frame_number == 0) { + s->previous_frame = av_mallocz(FFABS(p->linesize[0])*s->image_height); + if (!s->previous_frame) { + av_log(avctx, AV_LOG_ERROR, "Memory allocation failed.\n"); + return -1; + } + I_frame = 1; + } + + if (p->linesize[0] < 0) + pfptr = s->previous_frame - ((s->image_height-1) * p->linesize[0]); + else + pfptr = s->previous_frame; + + /* Check the placement of keyframes */ + if (avctx->gop_size > 0) { + if (avctx->frame_number >= s->last_key_frame + avctx->gop_size) { + I_frame = 1; + } + } + + opt_w=4; + opt_h=4; + + if (buf_size < s->image_width*s->image_height*3) { + //Conservative upper bound check for compressed data + av_log(avctx, AV_LOG_ERROR, "buf_size %d < %d\n", buf_size, s->image_width*s->image_height*3); + return -1; + } + + res = encode_bitstream(s, p, buf, buf_size, opt_w*16, opt_h*16, pfptr, &I_frame); + + //save the current frame + if(p->linesize[0] > 0) + memcpy(s->previous_frame, p->data[0], s->image_height*p->linesize[0]); + else + memcpy(s->previous_frame, p->data[0] + p->linesize[0] * (s->image_height-1), s->image_height*FFABS(p->linesize[0])); + + //mark the frame type so the muxer can mux it correctly + if (I_frame) { + p->pict_type = FF_I_TYPE; + p->key_frame = 1; + s->last_key_frame = avctx->frame_number; + av_log(avctx, AV_LOG_DEBUG, "Inserting key frame at frame %d\n",avctx->frame_number); + } else { + p->pict_type = FF_P_TYPE; + p->key_frame = 0; + } + + avctx->coded_frame = p; + + return res; +} + +static av_cold int flashsv_encode_end(AVCodecContext *avctx) +{ + FlashSVContext *s = avctx->priv_data; + + deflateEnd(&(s->zstream)); + + av_free(s->encbuffer); + av_free(s->previous_frame); + av_free(s->tmpblock); + + return 0; +} + +AVCodec flashsv_encoder = { + "flashsv", + CODEC_TYPE_VIDEO, + CODEC_ID_FLASHSV, + sizeof(FlashSVContext), + flashsv_encode_init, + flashsv_encode_frame, + flashsv_encode_end, + .pix_fmts = (enum PixelFormat[]){PIX_FMT_BGR24, PIX_FMT_NONE}, + .long_name = NULL_IF_CONFIG_SMALL("Flash Screen Video"), +}; + diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/flicvideo.c b/src/add-ons/media/plugins/avcodec/libavcodec/flicvideo.c index 248fc843a3..958d0f19e4 100644 --- a/src/add-ons/media/plugins/avcodec/libavcodec/flicvideo.c +++ b/src/add-ons/media/plugins/avcodec/libavcodec/flicvideo.c @@ -2,20 +2,21 @@ * FLI/FLC Animation Video Decoder * Copyright (C) 2003, 2004 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 */ /** @@ -26,7 +27,8 @@ * variations, visit: * http://www.compuphase.com/flic.htm * - * This decoder outputs PAL8 colorspace data. To use this decoder, be + * This decoder outputs PAL8/RGB555/RGB565 and maybe one day RGB24 + * colorspace data, depending on the FLC. To use this decoder, be * sure that your demuxer sends the FLI file header to the decoder via * the extradata chunk in AVCodecContext. The chunk should be 128 bytes * large. The only exception is for FLI files from the game "Magic Carpet", @@ -38,9 +40,8 @@ #include #include -#include "common.h" -#include "avcodec.h" #include "bswap.h" +#include "avcodec.h" #define FLI_256_COLOR 4 #define FLI_DELTA 7 @@ -50,12 +51,21 @@ #define FLI_BRUN 15 #define FLI_COPY 16 #define FLI_MINI 18 +#define FLI_DTA_BRUN 25 +#define FLI_DTA_COPY 26 +#define FLI_DTA_LC 27 -#define LE_16(x) ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0]) -#define LE_32(x) ((((uint8_t*)(x))[3] << 24) | \ - (((uint8_t*)(x))[2] << 16) | \ - (((uint8_t*)(x))[1] << 8) | \ - ((uint8_t*)(x))[0]) +#define FLI_TYPE_CODE (0xAF11) +#define FLC_FLX_TYPE_CODE (0xAF12) +#define FLC_DTA_TYPE_CODE (0xAF44) /* Marks an "Extended FLC" comes from Dave's Targa Animator (DTA) */ +#define FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE (0xAF13) + +#define CHECK_PIXEL_PTR(n) \ + if (pixel_ptr + n > pixel_limit) { \ + av_log (s->avctx, AV_LOG_INFO, "Problem: pixel_ptr >= pixel_limit (%d >= %d)\n", \ + pixel_ptr + n, pixel_limit); \ + return -1; \ + } \ typedef struct FlicDecodeContext { AVCodecContext *avctx; @@ -66,23 +76,47 @@ typedef struct FlicDecodeContext { int fli_type; /* either 0xAF11 or 0xAF12, affects palette resolution */ } FlicDecodeContext; -static int flic_decode_init(AVCodecContext *avctx) +static av_cold int flic_decode_init(AVCodecContext *avctx) { - FlicDecodeContext *s = (FlicDecodeContext *)avctx->priv_data; + FlicDecodeContext *s = avctx->priv_data; unsigned char *fli_header = (unsigned char *)avctx->extradata; + int depth; s->avctx = avctx; - avctx->pix_fmt = PIX_FMT_PAL8; - avctx->has_b_frames = 0; + s->fli_type = AV_RL16(&fli_header[4]); /* Might be overridden if a Magic Carpet FLC */ + + depth = 0; if (s->avctx->extradata_size == 12) { /* special case for magic carpet FLIs */ - s->fli_type = 0xAF13; - } else if (s->avctx->extradata_size == 128) { - s->fli_type = LE_16(&fli_header[4]); - } else { + s->fli_type = FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE; + depth = 8; + } else if (s->avctx->extradata_size != 128) { av_log(avctx, AV_LOG_ERROR, "Expected extradata of 12 or 128 bytes\n"); return -1; + } else { + depth = AV_RL16(&fli_header[12]); + } + + if (depth == 0) { + depth = 8; /* Some FLC generators set depth to zero, when they mean 8Bpp. Fix up here */ + } + + if ((s->fli_type == FLC_FLX_TYPE_CODE) && (depth == 16)) { + depth = 15; /* Original Autodesk FLX's say the depth is 16Bpp when it is really 15Bpp */ + } + + switch (depth) { + case 8 : avctx->pix_fmt = PIX_FMT_PAL8; break; + case 15 : avctx->pix_fmt = PIX_FMT_RGB555; break; + case 16 : avctx->pix_fmt = PIX_FMT_RGB565; break; + case 24 : avctx->pix_fmt = PIX_FMT_BGR24; /* Supposedly BGR, but havent any files to test with */ + av_log(avctx, AV_LOG_ERROR, "24Bpp FLC/FLX is unsupported due to no test files.\n"); + return -1; + break; + default : + av_log(avctx, AV_LOG_ERROR, "Unknown FLC/FLX depth of %d Bpp is unsupported.\n",depth); + return -1; } s->frame.data[0] = NULL; @@ -91,11 +125,11 @@ static int flic_decode_init(AVCodecContext *avctx) return 0; } -static int flic_decode_frame(AVCodecContext *avctx, - void *data, int *data_size, - uint8_t *buf, int buf_size) +static int flic_decode_frame_8BPP(AVCodecContext *avctx, + void *data, int *data_size, + const uint8_t *buf, int buf_size) { - FlicDecodeContext *s = (FlicDecodeContext *)avctx->priv_data; + FlicDecodeContext *s = avctx->priv_data; int stream_ptr = 0; int stream_ptr_after_color_chunk; @@ -122,10 +156,11 @@ static int flic_decode_frame(AVCodecContext *avctx, int starting_line; signed short line_packets; int y_ptr; - signed char byte_run; + int byte_run; int pixel_skip; int pixel_countdown; unsigned char *pixels; + int pixel_limit; s->frame.reference = 1; s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; @@ -135,37 +170,37 @@ static int flic_decode_frame(AVCodecContext *avctx, } pixels = s->frame.data[0]; + pixel_limit = s->avctx->height * s->frame.linesize[0]; - frame_size = LE_32(&buf[stream_ptr]); + frame_size = AV_RL32(&buf[stream_ptr]); stream_ptr += 6; /* skip the magic number */ - num_chunks = LE_16(&buf[stream_ptr]); + num_chunks = AV_RL16(&buf[stream_ptr]); stream_ptr += 10; /* skip padding */ frame_size -= 16; /* iterate through the chunks */ while ((frame_size > 0) && (num_chunks > 0)) { - chunk_size = LE_32(&buf[stream_ptr]); + chunk_size = AV_RL32(&buf[stream_ptr]); stream_ptr += 4; - chunk_type = LE_16(&buf[stream_ptr]); + chunk_type = AV_RL16(&buf[stream_ptr]); stream_ptr += 2; switch (chunk_type) { case FLI_256_COLOR: case FLI_COLOR: stream_ptr_after_color_chunk = stream_ptr + chunk_size - 6; - s->new_palette = 1; - /* check special case: If this file is from the Magic Carpet - * game and uses 6-bit colors even though it reports 256-color + /* check special case: If this file is from the Magic Carpet + * game and uses 6-bit colors even though it reports 256-color * chunks in a 0xAF12-type file (fli_type is set to 0xAF13 during * initialization) */ - if ((chunk_type == FLI_256_COLOR) && (s->fli_type != 0xAF13)) + if ((chunk_type == FLI_256_COLOR) && (s->fli_type != FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE)) color_shift = 0; else color_shift = 2; /* set up the palette */ - color_packets = LE_16(&buf[stream_ptr]); + color_packets = AV_RL16(&buf[stream_ptr]); stream_ptr += 2; palette_ptr = 0; for (i = 0; i < color_packets; i++) { @@ -180,15 +215,19 @@ static int flic_decode_frame(AVCodecContext *avctx, color_changes = 256; for (j = 0; j < color_changes; j++) { + unsigned int entry; /* wrap around, for good measure */ - if (palette_ptr >= 256) + if ((unsigned)palette_ptr >= 256) palette_ptr = 0; r = buf[stream_ptr++] << color_shift; g = buf[stream_ptr++] << color_shift; b = buf[stream_ptr++] << color_shift; - s->palette[palette_ptr++] = (r << 16) | (g << 8) | b; + entry = (r << 16) | (g << 8) | b; + if (s->palette[palette_ptr] != entry) + s->new_palette = 1; + s->palette[palette_ptr++] = entry; } } @@ -202,14 +241,20 @@ static int flic_decode_frame(AVCodecContext *avctx, case FLI_DELTA: y_ptr = 0; - compressed_lines = LE_16(&buf[stream_ptr]); + compressed_lines = AV_RL16(&buf[stream_ptr]); stream_ptr += 2; while (compressed_lines > 0) { - line_packets = LE_16(&buf[stream_ptr]); + line_packets = AV_RL16(&buf[stream_ptr]); stream_ptr += 2; - if (line_packets < 0) { + if ((line_packets & 0xC000) == 0xC000) { + // line skip opcode line_packets = -line_packets; y_ptr += line_packets * s->frame.linesize[0]; + } else if ((line_packets & 0xC000) == 0x4000) { + av_log(avctx, AV_LOG_ERROR, "Undefined opcode (%x) in DELTA_FLI\n", line_packets); + } else if ((line_packets & 0xC000) == 0x8000) { + // "last byte" opcode + pixels[y_ptr + s->frame.linesize[0] - 1] = line_packets & 0xff; } else { compressed_lines--; pixel_ptr = y_ptr; @@ -219,16 +264,18 @@ static int flic_decode_frame(AVCodecContext *avctx, pixel_skip = buf[stream_ptr++]; pixel_ptr += pixel_skip; pixel_countdown -= pixel_skip; - byte_run = buf[stream_ptr++]; + byte_run = (signed char)(buf[stream_ptr++]); if (byte_run < 0) { byte_run = -byte_run; palette_idx1 = buf[stream_ptr++]; palette_idx2 = buf[stream_ptr++]; + CHECK_PIXEL_PTR(byte_run); for (j = 0; j < byte_run; j++, pixel_countdown -= 2) { pixels[pixel_ptr++] = palette_idx1; pixels[pixel_ptr++] = palette_idx2; } } else { + CHECK_PIXEL_PTR(byte_run * 2); for (j = 0; j < byte_run * 2; j++, pixel_countdown--) { palette_idx1 = buf[stream_ptr++]; pixels[pixel_ptr++] = palette_idx1; @@ -243,12 +290,12 @@ static int flic_decode_frame(AVCodecContext *avctx, case FLI_LC: /* line compressed */ - starting_line = LE_16(&buf[stream_ptr]); + starting_line = AV_RL16(&buf[stream_ptr]); stream_ptr += 2; y_ptr = 0; y_ptr += starting_line * s->frame.linesize[0]; - compressed_lines = LE_16(&buf[stream_ptr]); + compressed_lines = AV_RL16(&buf[stream_ptr]); stream_ptr += 2; while (compressed_lines > 0) { pixel_ptr = y_ptr; @@ -260,15 +307,17 @@ static int flic_decode_frame(AVCodecContext *avctx, pixel_skip = buf[stream_ptr++]; pixel_ptr += pixel_skip; pixel_countdown -= pixel_skip; - byte_run = buf[stream_ptr++]; + byte_run = (signed char)(buf[stream_ptr++]); if (byte_run > 0) { + CHECK_PIXEL_PTR(byte_run); for (j = 0; j < byte_run; j++, pixel_countdown--) { palette_idx1 = buf[stream_ptr++]; pixels[pixel_ptr++] = palette_idx1; } - } else { + } else if (byte_run < 0) { byte_run = -byte_run; palette_idx1 = buf[stream_ptr++]; + CHECK_PIXEL_PTR(byte_run); for (j = 0; j < byte_run; j++, pixel_countdown--) { pixels[pixel_ptr++] = palette_idx1; } @@ -298,25 +347,27 @@ static int flic_decode_frame(AVCodecContext *avctx, stream_ptr++; pixel_countdown = s->avctx->width; while (pixel_countdown > 0) { - byte_run = buf[stream_ptr++]; + byte_run = (signed char)(buf[stream_ptr++]); if (byte_run > 0) { palette_idx1 = buf[stream_ptr++]; + CHECK_PIXEL_PTR(byte_run); for (j = 0; j < byte_run; j++) { pixels[pixel_ptr++] = palette_idx1; pixel_countdown--; if (pixel_countdown < 0) - av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", - pixel_countdown); + av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", + pixel_countdown, lines); } } else { /* copy bytes if byte_run < 0 */ byte_run = -byte_run; + CHECK_PIXEL_PTR(byte_run); for (j = 0; j < byte_run; j++) { palette_idx1 = buf[stream_ptr++]; pixels[pixel_ptr++] = palette_idx1; pixel_countdown--; if (pixel_countdown < 0) - av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", - pixel_countdown); + av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", + pixel_countdown, lines); } } } @@ -362,9 +413,8 @@ static int flic_decode_frame(AVCodecContext *avctx, "and final chunk ptr = %d\n", buf_size, stream_ptr); /* make the palette available on the way out */ -// if (s->new_palette) { - if (1) { - memcpy(s->frame.data[1], s->palette, AVPALETTE_SIZE); + memcpy(s->frame.data[1], s->palette, AVPALETTE_SIZE); + if (s->new_palette) { s->frame.palette_has_changed = 1; s->new_palette = 0; } @@ -375,7 +425,308 @@ static int flic_decode_frame(AVCodecContext *avctx, return buf_size; } -static int flic_decode_end(AVCodecContext *avctx) +static int flic_decode_frame_15_16BPP(AVCodecContext *avctx, + void *data, int *data_size, + const uint8_t *buf, int buf_size) +{ + /* Note, the only difference between the 15Bpp and 16Bpp */ + /* Format is the pixel format, the packets are processed the same. */ + FlicDecodeContext *s = avctx->priv_data; + + int stream_ptr = 0; + int pixel_ptr; + unsigned char palette_idx1; + + unsigned int frame_size; + int num_chunks; + + unsigned int chunk_size; + int chunk_type; + + int i, j; + + int lines; + int compressed_lines; + signed short line_packets; + int y_ptr; + int byte_run; + int pixel_skip; + int pixel_countdown; + unsigned char *pixels; + int pixel; + int pixel_limit; + + s->frame.reference = 1; + s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; + if (avctx->reget_buffer(avctx, &s->frame) < 0) { + av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); + return -1; + } + + pixels = s->frame.data[0]; + pixel_limit = s->avctx->height * s->frame.linesize[0]; + + frame_size = AV_RL32(&buf[stream_ptr]); + stream_ptr += 6; /* skip the magic number */ + num_chunks = AV_RL16(&buf[stream_ptr]); + stream_ptr += 10; /* skip padding */ + + frame_size -= 16; + + /* iterate through the chunks */ + while ((frame_size > 0) && (num_chunks > 0)) { + chunk_size = AV_RL32(&buf[stream_ptr]); + stream_ptr += 4; + chunk_type = AV_RL16(&buf[stream_ptr]); + stream_ptr += 2; + + switch (chunk_type) { + case FLI_256_COLOR: + case FLI_COLOR: + /* For some reason, it seems that non-palettized flics do + * include one of these chunks in their first frame. + * Why I do not know, it seems rather extraneous. */ +/* av_log(avctx, AV_LOG_ERROR, "Unexpected Palette chunk %d in non-paletised FLC\n",chunk_type);*/ + stream_ptr = stream_ptr + chunk_size - 6; + break; + + case FLI_DELTA: + case FLI_DTA_LC: + y_ptr = 0; + compressed_lines = AV_RL16(&buf[stream_ptr]); + stream_ptr += 2; + while (compressed_lines > 0) { + line_packets = AV_RL16(&buf[stream_ptr]); + stream_ptr += 2; + if (line_packets < 0) { + line_packets = -line_packets; + y_ptr += line_packets * s->frame.linesize[0]; + } else { + compressed_lines--; + pixel_ptr = y_ptr; + pixel_countdown = s->avctx->width; + for (i = 0; i < line_packets; i++) { + /* account for the skip bytes */ + pixel_skip = buf[stream_ptr++]; + pixel_ptr += (pixel_skip*2); /* Pixel is 2 bytes wide */ + pixel_countdown -= pixel_skip; + byte_run = (signed char)(buf[stream_ptr++]); + if (byte_run < 0) { + byte_run = -byte_run; + pixel = AV_RL16(&buf[stream_ptr]); + stream_ptr += 2; + CHECK_PIXEL_PTR(byte_run); + for (j = 0; j < byte_run; j++, pixel_countdown -= 2) { + *((signed short*)(&pixels[pixel_ptr])) = pixel; + pixel_ptr += 2; + } + } else { + CHECK_PIXEL_PTR(byte_run); + for (j = 0; j < byte_run; j++, pixel_countdown--) { + *((signed short*)(&pixels[pixel_ptr])) = AV_RL16(&buf[stream_ptr]); + stream_ptr += 2; + pixel_ptr += 2; + } + } + } + + y_ptr += s->frame.linesize[0]; + } + } + break; + + case FLI_LC: + av_log(avctx, AV_LOG_ERROR, "Unexpected FLI_LC chunk in non-paletised FLC\n"); + stream_ptr = stream_ptr + chunk_size - 6; + break; + + case FLI_BLACK: + /* set the whole frame to 0x0000 which is black in both 15Bpp and 16Bpp modes. */ + memset(pixels, 0x0000, + s->frame.linesize[0] * s->avctx->height); + break; + + case FLI_BRUN: + y_ptr = 0; + for (lines = 0; lines < s->avctx->height; lines++) { + pixel_ptr = y_ptr; + /* disregard the line packets; instead, iterate through all + * pixels on a row */ + stream_ptr++; + pixel_countdown = (s->avctx->width * 2); + + while (pixel_countdown > 0) { + byte_run = (signed char)(buf[stream_ptr++]); + if (byte_run > 0) { + palette_idx1 = buf[stream_ptr++]; + CHECK_PIXEL_PTR(byte_run); + for (j = 0; j < byte_run; j++) { + pixels[pixel_ptr++] = palette_idx1; + pixel_countdown--; + if (pixel_countdown < 0) + av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) (linea%d)\n", + pixel_countdown, lines); + } + } else { /* copy bytes if byte_run < 0 */ + byte_run = -byte_run; + CHECK_PIXEL_PTR(byte_run); + for (j = 0; j < byte_run; j++) { + palette_idx1 = buf[stream_ptr++]; + pixels[pixel_ptr++] = palette_idx1; + pixel_countdown--; + if (pixel_countdown < 0) + av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", + pixel_countdown, lines); + } + } + } + + /* Now FLX is strange, in that it is "byte" as opposed to "pixel" run length compressed. + * This does not give us any good oportunity to perform word endian conversion + * during decompression. So if it is required (i.e., this is not a LE target, we do + * a second pass over the line here, swapping the bytes. + */ +#ifdef WORDS_BIGENDIAN + pixel_ptr = y_ptr; + pixel_countdown = s->avctx->width; + while (pixel_countdown > 0) { + *((signed short*)(&pixels[pixel_ptr])) = AV_RL16(&buf[pixel_ptr]); + pixel_ptr += 2; + } +#endif + y_ptr += s->frame.linesize[0]; + } + break; + + case FLI_DTA_BRUN: + y_ptr = 0; + for (lines = 0; lines < s->avctx->height; lines++) { + pixel_ptr = y_ptr; + /* disregard the line packets; instead, iterate through all + * pixels on a row */ + stream_ptr++; + pixel_countdown = s->avctx->width; /* Width is in pixels, not bytes */ + + while (pixel_countdown > 0) { + byte_run = (signed char)(buf[stream_ptr++]); + if (byte_run > 0) { + pixel = AV_RL16(&buf[stream_ptr]); + stream_ptr += 2; + CHECK_PIXEL_PTR(byte_run); + for (j = 0; j < byte_run; j++) { + *((signed short*)(&pixels[pixel_ptr])) = pixel; + pixel_ptr += 2; + pixel_countdown--; + if (pixel_countdown < 0) + av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", + pixel_countdown); + } + } else { /* copy pixels if byte_run < 0 */ + byte_run = -byte_run; + CHECK_PIXEL_PTR(byte_run); + for (j = 0; j < byte_run; j++) { + *((signed short*)(&pixels[pixel_ptr])) = AV_RL16(&buf[stream_ptr]); + stream_ptr += 2; + pixel_ptr += 2; + pixel_countdown--; + if (pixel_countdown < 0) + av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", + pixel_countdown); + } + } + } + + y_ptr += s->frame.linesize[0]; + } + break; + + case FLI_COPY: + case FLI_DTA_COPY: + /* copy the chunk (uncompressed frame) */ + if (chunk_size - 6 > (unsigned int)(s->avctx->width * s->avctx->height)*2) { + av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \ + "bigger than image, skipping chunk\n", chunk_size - 6); + stream_ptr += chunk_size - 6; + } else { + + for (y_ptr = 0; y_ptr < s->frame.linesize[0] * s->avctx->height; + y_ptr += s->frame.linesize[0]) { + + pixel_countdown = s->avctx->width; + pixel_ptr = 0; + while (pixel_countdown > 0) { + *((signed short*)(&pixels[y_ptr + pixel_ptr])) = AV_RL16(&buf[stream_ptr+pixel_ptr]); + pixel_ptr += 2; + pixel_countdown--; + } + stream_ptr += s->avctx->width*2; + } + } + break; + + case FLI_MINI: + /* some sort of a thumbnail? disregard this chunk... */ + stream_ptr += chunk_size - 6; + break; + + default: + av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type); + break; + } + + frame_size -= chunk_size; + num_chunks--; + } + + /* by the end of the chunk, the stream ptr should equal the frame + * size (minus 1, possibly); if it doesn't, issue a warning */ + if ((stream_ptr != buf_size) && (stream_ptr != buf_size - 1)) + av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \ + "and final chunk ptr = %d\n", buf_size, stream_ptr); + + + *data_size=sizeof(AVFrame); + *(AVFrame*)data = s->frame; + + return buf_size; +} + +static int flic_decode_frame_24BPP(AVCodecContext *avctx, + void *data, int *data_size, + const uint8_t *buf, int buf_size) +{ + av_log(avctx, AV_LOG_ERROR, "24Bpp FLC Unsupported due to lack of test files.\n"); + return -1; +} + +static int flic_decode_frame(AVCodecContext *avctx, + void *data, int *data_size, + const uint8_t *buf, int buf_size) +{ + if (avctx->pix_fmt == PIX_FMT_PAL8) { + return flic_decode_frame_8BPP(avctx, data, data_size, + buf, buf_size); + } + else if ((avctx->pix_fmt == PIX_FMT_RGB555) || + (avctx->pix_fmt == PIX_FMT_RGB565)) { + return flic_decode_frame_15_16BPP(avctx, data, data_size, + buf, buf_size); + } + else if (avctx->pix_fmt == PIX_FMT_BGR24) { + return flic_decode_frame_24BPP(avctx, data, data_size, + buf, buf_size); + } + + /* Should not get here, ever as the pix_fmt is processed */ + /* in flic_decode_init and the above if should deal with */ + /* the finite set of possibilites allowable by here. */ + /* But in case we do, just error out. */ + av_log(avctx, AV_LOG_ERROR, "Unknown FLC format, my science cannot explain how this happened.\n"); + return -1; +} + + +static av_cold int flic_decode_end(AVCodecContext *avctx) { FlicDecodeContext *s = avctx->priv_data; @@ -395,5 +746,9 @@ AVCodec flic_decoder = { flic_decode_end, flic_decode_frame, CODEC_CAP_DR1, - NULL + NULL, + NULL, + NULL, + NULL, + .long_name = NULL_IF_CONFIG_SMALL("Autodesk Animator Flic video"), }; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/fraps.c b/src/add-ons/media/plugins/avcodec/libavcodec/fraps.c new file mode 100644 index 0000000000..e03c1fa10c --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/fraps.c @@ -0,0 +1,376 @@ +/* + * Fraps FPS1 decoder + * Copyright (c) 2005 Roine Gustafsson + * Copyright (c) 2006 Konstantin Shishkov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file fraps.c + * Lossless Fraps 'FPS1' decoder + * @author Roine Gustafsson + * @author Konstantin Shishkov + * + * Codec algorithm for version 0 is taken from Transcode + * + * Version 2 files support by Konstantin Shishkov + */ + +#include "avcodec.h" +#include "bitstream.h" +#include "huffman.h" +#include "bytestream.h" +#include "dsputil.h" + +#define FPS_TAG MKTAG('F', 'P', 'S', 'x') + +/** + * local variable storage + */ +typedef struct FrapsContext{ + AVCodecContext *avctx; + AVFrame frame; + uint8_t *tmpbuf; + DSPContext dsp; +} FrapsContext; + + +/** + * initializes decoder + * @param avctx codec context + * @return 0 on success or negative if fails + */ +static av_cold int decode_init(AVCodecContext *avctx) +{ + FrapsContext * const s = avctx->priv_data; + + avctx->coded_frame = (AVFrame*)&s->frame; + avctx->pix_fmt= PIX_FMT_NONE; /* set in decode_frame */ + + s->avctx = avctx; + s->frame.data[0] = NULL; + s->tmpbuf = NULL; + + dsputil_init(&s->dsp, avctx); + + return 0; +} + +/** + * Comparator - our nodes should ascend by count + * but with preserved symbol order + */ +static int huff_cmp(const void *va, const void *vb){ + const Node *a = va, *b = vb; + return (a->count - b->count)*256 + a->sym - b->sym; +} + +/** + * decode Fraps v2 packed plane + */ +static int fraps2_decode_plane(FrapsContext *s, uint8_t *dst, int stride, int w, + int h, const uint8_t *src, int size, int Uoff, + const int step) +{ + int i, j; + GetBitContext gb; + VLC vlc; + Node nodes[512]; + + for(i = 0; i < 256; i++) + nodes[i].count = bytestream_get_le32(&src); + size -= 1024; + if (ff_huff_build_tree(s->avctx, &vlc, 256, nodes, huff_cmp, + FF_HUFFMAN_FLAG_ZERO_COUNT) < 0) + return -1; + /* we have built Huffman table and are ready to decode plane */ + + /* convert bits so they may be used by standard bitreader */ + s->dsp.bswap_buf((uint32_t *)s->tmpbuf, (const uint32_t *)src, size >> 2); + + init_get_bits(&gb, s->tmpbuf, size * 8); + for(j = 0; j < h; j++){ + for(i = 0; i < w*step; i += step){ + dst[i] = get_vlc2(&gb, vlc.table, 9, 3); + /* lines are stored as deltas between previous lines + * and we need to add 0x80 to the first lines of chroma planes + */ + if(j) dst[i] += dst[i - stride]; + else if(Uoff) dst[i] += 0x80; + } + dst += stride; + } + free_vlc(&vlc); + return 0; +} + +/** + * decode a frame + * @param avctx codec context + * @param data output AVFrame + * @param data_size size of output data or 0 if no picture is returned + * @param buf input data frame + * @param buf_size size of input data frame + * @return number of consumed bytes on success or negative if decode fails + */ +static int decode_frame(AVCodecContext *avctx, + void *data, int *data_size, + const uint8_t *buf, int buf_size) +{ + FrapsContext * const s = avctx->priv_data; + AVFrame *frame = data; + AVFrame * const f = (AVFrame*)&s->frame; + uint32_t header; + unsigned int version,header_size; + unsigned int x, y; + const uint32_t *buf32; + uint32_t *luma1,*luma2,*cb,*cr; + uint32_t offs[4]; + int i, j, is_chroma, planes; + + + header = AV_RL32(buf); + version = header & 0xff; + header_size = (header & (1<<30))? 8 : 4; /* bit 30 means pad to 8 bytes */ + + if (version > 2 && version != 4 && version != 5) { + av_log(avctx, AV_LOG_ERROR, + "This file is encoded with Fraps version %d. " \ + "This codec can only decode version 0, 1, 2 and 4.\n", version); + return -1; + } + + buf+=4; + if (header_size == 8) + buf+=4; + + switch(version) { + case 0: + default: + /* Fraps v0 is a reordered YUV420 */ + avctx->pix_fmt = PIX_FMT_YUV420P; + + if ( (buf_size != avctx->width*avctx->height*3/2+header_size) && + (buf_size != header_size) ) { + av_log(avctx, AV_LOG_ERROR, + "Invalid frame length %d (should be %d)\n", + buf_size, avctx->width*avctx->height*3/2+header_size); + return -1; + } + + if (( (avctx->width % 8) != 0) || ( (avctx->height % 2) != 0 )) { + av_log(avctx, AV_LOG_ERROR, "Invalid frame size %dx%d\n", + avctx->width, avctx->height); + return -1; + } + + f->reference = 1; + f->buffer_hints = FF_BUFFER_HINTS_VALID | + FF_BUFFER_HINTS_PRESERVE | + FF_BUFFER_HINTS_REUSABLE; + if (avctx->reget_buffer(avctx, f)) { + av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); + return -1; + } + /* bit 31 means same as previous pic */ + f->pict_type = (header & (1<<31))? FF_P_TYPE : FF_I_TYPE; + f->key_frame = f->pict_type == FF_I_TYPE; + + if (f->pict_type == FF_I_TYPE) { + buf32=(const uint32_t*)buf; + for(y=0; yheight/2; y++){ + luma1=(uint32_t*)&f->data[0][ y*2*f->linesize[0] ]; + luma2=(uint32_t*)&f->data[0][ (y*2+1)*f->linesize[0] ]; + cr=(uint32_t*)&f->data[1][ y*f->linesize[1] ]; + cb=(uint32_t*)&f->data[2][ y*f->linesize[2] ]; + for(x=0; xwidth; x+=8){ + *(luma1++) = *(buf32++); + *(luma1++) = *(buf32++); + *(luma2++) = *(buf32++); + *(luma2++) = *(buf32++); + *(cr++) = *(buf32++); + *(cb++) = *(buf32++); + } + } + } + break; + + case 1: + /* Fraps v1 is an upside-down BGR24 */ + avctx->pix_fmt = PIX_FMT_BGR24; + + if ( (buf_size != avctx->width*avctx->height*3+header_size) && + (buf_size != header_size) ) { + av_log(avctx, AV_LOG_ERROR, + "Invalid frame length %d (should be %d)\n", + buf_size, avctx->width*avctx->height*3+header_size); + return -1; + } + + f->reference = 1; + f->buffer_hints = FF_BUFFER_HINTS_VALID | + FF_BUFFER_HINTS_PRESERVE | + FF_BUFFER_HINTS_REUSABLE; + if (avctx->reget_buffer(avctx, f)) { + av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); + return -1; + } + /* bit 31 means same as previous pic */ + f->pict_type = (header & (1<<31))? FF_P_TYPE : FF_I_TYPE; + f->key_frame = f->pict_type == FF_I_TYPE; + + if (f->pict_type == FF_I_TYPE) { + for(y=0; yheight; y++) + memcpy(&f->data[0][ (avctx->height-y)*f->linesize[0] ], + &buf[y*avctx->width*3], + f->linesize[0]); + } + break; + + case 2: + case 4: + /** + * Fraps v2 is Huffman-coded YUV420 planes + * Fraps v4 is virtually the same + */ + avctx->pix_fmt = PIX_FMT_YUV420P; + planes = 3; + f->reference = 1; + f->buffer_hints = FF_BUFFER_HINTS_VALID | + FF_BUFFER_HINTS_PRESERVE | + FF_BUFFER_HINTS_REUSABLE; + if (avctx->reget_buffer(avctx, f)) { + av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); + return -1; + } + /* skip frame */ + if(buf_size == 8) { + f->pict_type = FF_P_TYPE; + f->key_frame = 0; + break; + } + f->pict_type = FF_I_TYPE; + f->key_frame = 1; + if ((AV_RL32(buf) != FPS_TAG)||(buf_size < (planes*1024 + 24))) { + av_log(avctx, AV_LOG_ERROR, "Fraps: error in data stream\n"); + return -1; + } + for(i = 0; i < planes; i++) { + offs[i] = AV_RL32(buf + 4 + i * 4); + if(offs[i] >= buf_size || (i && offs[i] <= offs[i - 1] + 1024)) { + av_log(avctx, AV_LOG_ERROR, "Fraps: plane %i offset is out of bounds\n", i); + return -1; + } + } + offs[planes] = buf_size; + for(i = 0; i < planes; i++){ + is_chroma = !!i; + s->tmpbuf = av_realloc(s->tmpbuf, offs[i + 1] - offs[i] - 1024 + FF_INPUT_BUFFER_PADDING_SIZE); + if(fraps2_decode_plane(s, f->data[i], f->linesize[i], avctx->width >> is_chroma, + avctx->height >> is_chroma, buf + offs[i], offs[i + 1] - offs[i], is_chroma, 1) < 0) { + av_log(avctx, AV_LOG_ERROR, "Error decoding plane %i\n", i); + return -1; + } + } + break; + case 5: + /* Virtually the same as version 4, but is for RGB24 */ + avctx->pix_fmt = PIX_FMT_BGR24; + planes = 3; + f->reference = 1; + f->buffer_hints = FF_BUFFER_HINTS_VALID | + FF_BUFFER_HINTS_PRESERVE | + FF_BUFFER_HINTS_REUSABLE; + if (avctx->reget_buffer(avctx, f)) { + av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); + return -1; + } + /* skip frame */ + if(buf_size == 8) { + f->pict_type = FF_P_TYPE; + f->key_frame = 0; + break; + } + f->pict_type = FF_I_TYPE; + f->key_frame = 1; + if ((AV_RL32(buf) != FPS_TAG)||(buf_size < (planes*1024 + 24))) { + av_log(avctx, AV_LOG_ERROR, "Fraps: error in data stream\n"); + return -1; + } + for(i = 0; i < planes; i++) { + offs[i] = AV_RL32(buf + 4 + i * 4); + if(offs[i] >= buf_size || (i && offs[i] <= offs[i - 1] + 1024)) { + av_log(avctx, AV_LOG_ERROR, "Fraps: plane %i offset is out of bounds\n", i); + return -1; + } + } + offs[planes] = buf_size; + for(i = 0; i < planes; i++){ + s->tmpbuf = av_realloc(s->tmpbuf, offs[i + 1] - offs[i] - 1024 + FF_INPUT_BUFFER_PADDING_SIZE); + if(fraps2_decode_plane(s, f->data[0] + i + (f->linesize[0] * (avctx->height - 1)), -f->linesize[0], + avctx->width, avctx->height, buf + offs[i], offs[i + 1] - offs[i], 0, 3) < 0) { + av_log(avctx, AV_LOG_ERROR, "Error decoding plane %i\n", i); + return -1; + } + } + // convert pseudo-YUV into real RGB + for(j = 0; j < avctx->height; j++){ + for(i = 0; i < avctx->width; i++){ + f->data[0][0 + i*3 + j*f->linesize[0]] += f->data[0][1 + i*3 + j*f->linesize[0]]; + f->data[0][2 + i*3 + j*f->linesize[0]] += f->data[0][1 + i*3 + j*f->linesize[0]]; + } + } + break; + } + + *frame = *f; + *data_size = sizeof(AVFrame); + + return buf_size; +} + + +/** + * closes decoder + * @param avctx codec context + * @return 0 on success or negative if fails + */ +static av_cold int decode_end(AVCodecContext *avctx) +{ + FrapsContext *s = (FrapsContext*)avctx->priv_data; + + if (s->frame.data[0]) + avctx->release_buffer(avctx, &s->frame); + + av_freep(&s->tmpbuf); + return 0; +} + + +AVCodec fraps_decoder = { + "fraps", + CODEC_TYPE_VIDEO, + CODEC_ID_FRAPS, + sizeof(FrapsContext), + decode_init, + NULL, + decode_end, + decode_frame, + CODEC_CAP_DR1, + .long_name = NULL_IF_CONFIG_SMALL("Fraps"), +};