Update avcodec to 20080825
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27547 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -2,21 +2,26 @@
|
|||||||
* Floating point AAN DCT
|
* Floating point AAN DCT
|
||||||
* Copyright (c) 2003 Michael Niedermayer <[email protected]>
|
* Copyright (c) 2003 Michael Niedermayer <[email protected]>
|
||||||
*
|
*
|
||||||
* 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
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
* License as published by the Free Software Foundation; either
|
||||||
* version 2 of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*
|
*
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,8 +31,6 @@
|
|||||||
* @author Michael Niedermayer <[email protected]>
|
* @author Michael Niedermayer <[email protected]>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#include "dsputil.h"
|
#include "dsputil.h"
|
||||||
#include "faandct.h"
|
#include "faandct.h"
|
||||||
|
|
||||||
@@ -59,7 +62,7 @@ for(i=0; i<8; i++){
|
|||||||
#define A5 0.38268343236508977170 // cos(pi*6/16)
|
#define A5 0.38268343236508977170 // cos(pi*6/16)
|
||||||
#define A4 1.30656296487637652774 // cos(pi*2/16)sqrt(2)
|
#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,
|
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,
|
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,
|
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,
|
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 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
|
||||||
FLOAT tmp10, tmp11, tmp12, tmp13;
|
FLOAT tmp10, tmp11, tmp12, tmp13;
|
||||||
FLOAT z1, z2, z3, z4, z5, z11, z13;
|
FLOAT z2, z4, z11, z13;
|
||||||
|
FLOAT av_unused z5;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i=0; i<8*8; i+=8) {
|
for (i=0; i<8*8; i+=8) {
|
||||||
@@ -95,21 +99,27 @@ static always_inline void row_fdct(FLOAT temp[64], DCTELEM * data)
|
|||||||
temp[0 + i]= tmp10 + tmp11;
|
temp[0 + i]= tmp10 + tmp11;
|
||||||
temp[4 + i]= tmp10 - tmp11;
|
temp[4 + i]= tmp10 - tmp11;
|
||||||
|
|
||||||
z1= (tmp12 + tmp13)*A1;
|
tmp12 += tmp13;
|
||||||
temp[2 + i]= tmp13 + z1;
|
tmp12 *= A1;
|
||||||
temp[6 + i]= tmp13 - z1;
|
temp[2 + i]= tmp13 + tmp12;
|
||||||
|
temp[6 + i]= tmp13 - tmp12;
|
||||||
|
|
||||||
tmp10= tmp4 + tmp5;
|
tmp4 += tmp5;
|
||||||
tmp11= tmp5 + tmp6;
|
tmp5 += tmp6;
|
||||||
tmp12= tmp6 + tmp7;
|
tmp6 += tmp7;
|
||||||
|
|
||||||
z5= (tmp10 - tmp12) * A5;
|
#if 0
|
||||||
z2= tmp10*A2 + z5;
|
z5= (tmp4 - tmp6) * A5;
|
||||||
z4= tmp12*A4 + z5;
|
z2= tmp4*A2 + z5;
|
||||||
z3= tmp11*A1;
|
z4= tmp6*A4 + z5;
|
||||||
|
#else
|
||||||
|
z2= tmp4*(A2+A5) - tmp6*A5;
|
||||||
|
z4= tmp6*(A4-A5) + tmp4*A5;
|
||||||
|
#endif
|
||||||
|
tmp5*=A1;
|
||||||
|
|
||||||
z11= tmp7 + z3;
|
z11= tmp7 + tmp5;
|
||||||
z13= tmp7 - z3;
|
z13= tmp7 - tmp5;
|
||||||
|
|
||||||
temp[5 + i]= z13 + z2;
|
temp[5 + i]= z13 + z2;
|
||||||
temp[3 + i]= z13 - z2;
|
temp[3 + i]= z13 - z2;
|
||||||
@@ -122,7 +132,8 @@ void ff_faandct(DCTELEM * data)
|
|||||||
{
|
{
|
||||||
FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
|
FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
|
||||||
FLOAT tmp10, tmp11, tmp12, tmp13;
|
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];
|
FLOAT temp[64];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -148,21 +159,27 @@ void ff_faandct(DCTELEM * data)
|
|||||||
data[8*0 + i]= lrintf(SCALE(8*0 + i) * (tmp10 + tmp11));
|
data[8*0 + i]= lrintf(SCALE(8*0 + i) * (tmp10 + tmp11));
|
||||||
data[8*4 + i]= lrintf(SCALE(8*4 + i) * (tmp10 - tmp11));
|
data[8*4 + i]= lrintf(SCALE(8*4 + i) * (tmp10 - tmp11));
|
||||||
|
|
||||||
z1= (tmp12 + tmp13)* A1;
|
tmp12 += tmp13;
|
||||||
data[8*2 + i]= lrintf(SCALE(8*2 + i) * (tmp13 + z1));
|
tmp12 *= A1;
|
||||||
data[8*6 + i]= lrintf(SCALE(8*6 + i) * (tmp13 - z1));
|
data[8*2 + i]= lrintf(SCALE(8*2 + i) * (tmp13 + tmp12));
|
||||||
|
data[8*6 + i]= lrintf(SCALE(8*6 + i) * (tmp13 - tmp12));
|
||||||
|
|
||||||
tmp10= tmp4 + tmp5;
|
tmp4 += tmp5;
|
||||||
tmp11= tmp5 + tmp6;
|
tmp5 += tmp6;
|
||||||
tmp12= tmp6 + tmp7;
|
tmp6 += tmp7;
|
||||||
|
|
||||||
z5= (tmp10 - tmp12) * A5;
|
#if 0
|
||||||
z2= tmp10*A2 + z5;
|
z5= (tmp4 - tmp6) * A5;
|
||||||
z4= tmp12*A4 + z5;
|
z2= tmp4*A2 + z5;
|
||||||
z3= tmp11*A1;
|
z4= tmp6*A4 + z5;
|
||||||
|
#else
|
||||||
|
z2= tmp4*(A2+A5) - tmp6*A5;
|
||||||
|
z4= tmp6*(A4-A5) + tmp4*A5;
|
||||||
|
#endif
|
||||||
|
tmp5*=A1;
|
||||||
|
|
||||||
z11= tmp7 + z3;
|
z11= tmp7 + tmp5;
|
||||||
z13= tmp7 - z3;
|
z13= tmp7 - tmp5;
|
||||||
|
|
||||||
data[8*5 + i]= lrintf(SCALE(8*5 + i) * (z13 + z2));
|
data[8*5 + i]= lrintf(SCALE(8*5 + i) * (z13 + z2));
|
||||||
data[8*3 + i]= lrintf(SCALE(8*3 + 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 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
|
||||||
FLOAT tmp10, tmp11, tmp12, tmp13;
|
FLOAT tmp10, tmp11, tmp12, tmp13;
|
||||||
FLOAT z1;
|
|
||||||
FLOAT temp[64];
|
FLOAT temp[64];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -201,20 +217,22 @@ void ff_faandct248(DCTELEM * data)
|
|||||||
data[8*0 + i] = lrintf(SCALE(8*0 + i) * (tmp10 + tmp11));
|
data[8*0 + i] = lrintf(SCALE(8*0 + i) * (tmp10 + tmp11));
|
||||||
data[8*4 + i] = lrintf(SCALE(8*4 + i) * (tmp10 - tmp11));
|
data[8*4 + i] = lrintf(SCALE(8*4 + i) * (tmp10 - tmp11));
|
||||||
|
|
||||||
z1 = (tmp12 + tmp13)* A1;
|
tmp12 += tmp13;
|
||||||
data[8*2 + i] = lrintf(SCALE(8*2 + i) * (tmp13 + z1));
|
tmp12 *= A1;
|
||||||
data[8*6 + i] = lrintf(SCALE(8*6 + i) * (tmp13 - z1));
|
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;
|
tmp10 = tmp4 + tmp7;
|
||||||
tmp11 = tmp5 + tmp6;
|
tmp11 = tmp5 + tmp6;
|
||||||
tmp12 = tmp5 - tmp6;
|
tmp12 = tmp5 - tmp6;
|
||||||
tmp13 = tmp4 - tmp7;
|
tmp13 = tmp4 - tmp7;
|
||||||
|
|
||||||
data[8*1 + i] = lrintf(SCALE(8*0 + 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));
|
data[8*5 + i] = lrintf(SCALE(8*4 + i) * (tmp10 - tmp11));
|
||||||
|
|
||||||
z1 = (tmp12 + tmp13)* A1;
|
tmp12 += tmp13;
|
||||||
data[8*3 + i] = lrintf(SCALE(8*2 + i) * (tmp13 + z1));
|
tmp12 *= A1;
|
||||||
data[8*7 + i] = lrintf(SCALE(8*6 + i) * (tmp13 - z1));
|
data[8*3 + i] = lrintf(SCALE(8*2 + i) * (tmp13 + tmp12));
|
||||||
|
data[8*7 + i] = lrintf(SCALE(8*6 + i) * (tmp13 - tmp12));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,20 +2,21 @@
|
|||||||
* Floating point AAN DCT
|
* Floating point AAN DCT
|
||||||
* Copyright (c) 2003 Michael Niedermayer <[email protected]>
|
* Copyright (c) 2003 Michael Niedermayer <[email protected]>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
* License as published by the Free Software Foundation; either
|
||||||
* version 2 of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -25,7 +26,14 @@
|
|||||||
* @author Michael Niedermayer <[email protected]>
|
* @author Michael Niedermayer <[email protected]>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef FFMPEG_FAANDCT_H
|
||||||
|
#define FFMPEG_FAANDCT_H
|
||||||
|
|
||||||
|
#include "dsputil.h"
|
||||||
|
|
||||||
#define FAAN_POSTSCALE
|
#define FAAN_POSTSCALE
|
||||||
|
|
||||||
void ff_faandct(DCTELEM * data);
|
void ff_faandct(DCTELEM * data);
|
||||||
void ff_faandct248(DCTELEM * data);
|
void ff_faandct248(DCTELEM * data);
|
||||||
|
|
||||||
|
#endif /* FFMPEG_FAANDCT_H */
|
||||||
|
|||||||
@@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
* Floating point AAN IDCT
|
||||||
|
* Copyright (c) 2008 Michael Niedermayer <[email protected]>
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
#include "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<y*8; i+=y){
|
||||||
|
s17= temp[1*x + i] + temp[7*x + i];
|
||||||
|
d17= temp[1*x + i] - temp[7*x + i];
|
||||||
|
s53= temp[5*x + i] + temp[3*x + i];
|
||||||
|
d53= temp[5*x + i] - temp[3*x + i];
|
||||||
|
|
||||||
|
od07= s17 + s53;
|
||||||
|
od25= (s17 - s53)*(2*A4);
|
||||||
|
|
||||||
|
#if 0 //these 2 are equivalent
|
||||||
|
tmp0= (d17 + d53)*(2*A2);
|
||||||
|
od34= d17*( 2*B6) - tmp0;
|
||||||
|
od16= d53*(-2*B2) + tmp0;
|
||||||
|
#else
|
||||||
|
od34= d17*(2*(B6-A2)) - d53*(2*A2);
|
||||||
|
od16= d53*(2*(A2-B2)) + d17*(2*A2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
od16 -= od07;
|
||||||
|
od25 -= od16;
|
||||||
|
od34 += od25;
|
||||||
|
|
||||||
|
s26 = temp[2*x + i] + temp[6*x + i];
|
||||||
|
d26 = temp[2*x + i] - temp[6*x + i];
|
||||||
|
d26*= 2*A4;
|
||||||
|
d26-= s26;
|
||||||
|
|
||||||
|
s04= temp[0*x + i] + temp[4*x + i];
|
||||||
|
d04= temp[0*x + i] - temp[4*x + i];
|
||||||
|
|
||||||
|
os07= s04 + s26;
|
||||||
|
os34= s04 - s26;
|
||||||
|
os16= d04 + d26;
|
||||||
|
os25= d04 - d26;
|
||||||
|
|
||||||
|
if(type==0){
|
||||||
|
temp[0*x + i]= os07 + od07;
|
||||||
|
temp[7*x + i]= os07 - od07;
|
||||||
|
temp[1*x + i]= os16 + od16;
|
||||||
|
temp[6*x + i]= os16 - od16;
|
||||||
|
temp[2*x + i]= os25 + od25;
|
||||||
|
temp[5*x + i]= os25 - od25;
|
||||||
|
temp[3*x + i]= os34 - od34;
|
||||||
|
temp[4*x + i]= os34 + od34;
|
||||||
|
}else if(type==1){
|
||||||
|
data[0*x + i]= lrintf(os07 + od07);
|
||||||
|
data[7*x + i]= lrintf(os07 - od07);
|
||||||
|
data[1*x + i]= lrintf(os16 + od16);
|
||||||
|
data[6*x + i]= lrintf(os16 - od16);
|
||||||
|
data[2*x + i]= lrintf(os25 + od25);
|
||||||
|
data[5*x + i]= lrintf(os25 - od25);
|
||||||
|
data[3*x + i]= lrintf(os34 - od34);
|
||||||
|
data[4*x + i]= lrintf(os34 + od34);
|
||||||
|
}else if(type==2){
|
||||||
|
dest[0*stride + i]= av_clip_uint8(((int)dest[0*stride + i]) + lrintf(os07 + od07));
|
||||||
|
dest[7*stride + i]= av_clip_uint8(((int)dest[7*stride + i]) + lrintf(os07 - od07));
|
||||||
|
dest[1*stride + i]= av_clip_uint8(((int)dest[1*stride + i]) + lrintf(os16 + od16));
|
||||||
|
dest[6*stride + i]= av_clip_uint8(((int)dest[6*stride + i]) + lrintf(os16 - od16));
|
||||||
|
dest[2*stride + i]= av_clip_uint8(((int)dest[2*stride + i]) + lrintf(os25 + od25));
|
||||||
|
dest[5*stride + i]= av_clip_uint8(((int)dest[5*stride + i]) + lrintf(os25 - od25));
|
||||||
|
dest[3*stride + i]= av_clip_uint8(((int)dest[3*stride + i]) + lrintf(os34 - od34));
|
||||||
|
dest[4*stride + i]= av_clip_uint8(((int)dest[4*stride + i]) + lrintf(os34 + od34));
|
||||||
|
}else{
|
||||||
|
dest[0*stride + i]= av_clip_uint8(lrintf(os07 + od07));
|
||||||
|
dest[7*stride + i]= av_clip_uint8(lrintf(os07 - od07));
|
||||||
|
dest[1*stride + i]= av_clip_uint8(lrintf(os16 + od16));
|
||||||
|
dest[6*stride + i]= av_clip_uint8(lrintf(os16 - od16));
|
||||||
|
dest[2*stride + i]= av_clip_uint8(lrintf(os25 + od25));
|
||||||
|
dest[5*stride + i]= av_clip_uint8(lrintf(os25 - od25));
|
||||||
|
dest[3*stride + i]= av_clip_uint8(lrintf(os34 - od34));
|
||||||
|
dest[4*stride + i]= av_clip_uint8(lrintf(os34 + od34));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ff_faanidct(DCTELEM block[64]){
|
||||||
|
FLOAT temp[64];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
emms_c();
|
||||||
|
|
||||||
|
for(i=0; i<64; i++)
|
||||||
|
temp[i] = block[i] * prescale[i];
|
||||||
|
|
||||||
|
p8idct(block, temp, NULL, 0, 1, 8, 0);
|
||||||
|
p8idct(block, temp, NULL, 0, 8, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ff_faanidct_add(uint8_t *dest, int line_size, DCTELEM block[64]){
|
||||||
|
FLOAT temp[64];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
emms_c();
|
||||||
|
|
||||||
|
for(i=0; i<64; i++)
|
||||||
|
temp[i] = block[i] * prescale[i];
|
||||||
|
|
||||||
|
p8idct(block, temp, NULL, 0, 1, 8, 0);
|
||||||
|
p8idct(NULL , temp, dest, line_size, 8, 1, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ff_faanidct_put(uint8_t *dest, int line_size, DCTELEM block[64]){
|
||||||
|
FLOAT temp[64];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
emms_c();
|
||||||
|
|
||||||
|
for(i=0; i<64; i++)
|
||||||
|
temp[i] = block[i] * prescale[i];
|
||||||
|
|
||||||
|
p8idct(block, temp, NULL, 0, 1, 8, 0);
|
||||||
|
p8idct(NULL , temp, dest, line_size, 8, 1, 3);
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Floating point AAN IDCT
|
||||||
|
* Copyright (c) 2008 Michael Niedermayer <[email protected]>
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FFMPEG_FAANIDCT_H
|
||||||
|
#define FFMPEG_FAANIDCT_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#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 */
|
||||||
@@ -27,7 +27,6 @@
|
|||||||
* are subject to royalty fees to patent holders. Many of these patents are
|
* are subject to royalty fees to patent holders. Many of these patents are
|
||||||
* general enough such that they are unavoidable regardless of implementation
|
* general enough such that they are unavoidable regardless of implementation
|
||||||
* design.
|
* design.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
@@ -64,51 +63,51 @@ void init_fdct()
|
|||||||
void fdct(block)
|
void fdct(block)
|
||||||
short *block;
|
short *block;
|
||||||
{
|
{
|
||||||
register int i, j;
|
register int i, j;
|
||||||
double s;
|
double s;
|
||||||
double tmp[64];
|
double tmp[64];
|
||||||
|
|
||||||
for(i = 0; i < 8; i++)
|
for(i = 0; i < 8; i++)
|
||||||
for(j = 0; j < 8; j++)
|
for(j = 0; j < 8; j++)
|
||||||
{
|
{
|
||||||
s = 0.0;
|
s = 0.0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* for(k = 0; k < 8; k++)
|
* for(k = 0; k < 8; k++)
|
||||||
* s += c[j][k] * block[8 * i + k];
|
* s += c[j][k] * block[8 * i + k];
|
||||||
*/
|
*/
|
||||||
s += c[j][0] * block[8 * i + 0];
|
s += c[j][0] * block[8 * i + 0];
|
||||||
s += c[j][1] * block[8 * i + 1];
|
s += c[j][1] * block[8 * i + 1];
|
||||||
s += c[j][2] * block[8 * i + 2];
|
s += c[j][2] * block[8 * i + 2];
|
||||||
s += c[j][3] * block[8 * i + 3];
|
s += c[j][3] * block[8 * i + 3];
|
||||||
s += c[j][4] * block[8 * i + 4];
|
s += c[j][4] * block[8 * i + 4];
|
||||||
s += c[j][5] * block[8 * i + 5];
|
s += c[j][5] * block[8 * i + 5];
|
||||||
s += c[j][6] * block[8 * i + 6];
|
s += c[j][6] * block[8 * i + 6];
|
||||||
s += c[j][7] * block[8 * i + 7];
|
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(j = 0; j < 8; j++)
|
||||||
for(i = 0; i < 8; i++)
|
for(i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
s = 0.0;
|
s = 0.0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* for(k = 0; k < 8; k++)
|
* for(k = 0; k < 8; k++)
|
||||||
* s += c[i][k] * tmp[8 * k + j];
|
* s += c[i][k] * tmp[8 * k + j];
|
||||||
*/
|
*/
|
||||||
s += c[i][0] * tmp[8 * 0 + j];
|
s += c[i][0] * tmp[8 * 0 + j];
|
||||||
s += c[i][1] * tmp[8 * 1 + j];
|
s += c[i][1] * tmp[8 * 1 + j];
|
||||||
s += c[i][2] * tmp[8 * 2 + j];
|
s += c[i][2] * tmp[8 * 2 + j];
|
||||||
s += c[i][3] * tmp[8 * 3 + j];
|
s += c[i][3] * tmp[8 * 3 + j];
|
||||||
s += c[i][4] * tmp[8 * 4 + j];
|
s += c[i][4] * tmp[8 * 4 + j];
|
||||||
s += c[i][5] * tmp[8 * 5 + j];
|
s += c[i][5] * tmp[8 * 5 + j];
|
||||||
s += c[i][6] * tmp[8 * 6 + j];
|
s += c[i][6] * tmp[8 * 6 + j];
|
||||||
s += c[i][7] * tmp[8 * 7 + j];
|
s += c[i][7] * tmp[8 * 7 + j];
|
||||||
s*=8.0;
|
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:
|
* 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)
|
* s is quite often x.5 (at least for i and/or j = 0 or 4)
|
||||||
|
|||||||
@@ -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 <math.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#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<n;i++) {
|
||||||
|
tmp_re = 0;
|
||||||
|
tmp_im = 0;
|
||||||
|
q = tab;
|
||||||
|
for(j=0;j<n;j++) {
|
||||||
|
k = (i * j) & (n - 1);
|
||||||
|
if (k >= 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<<nbits;
|
||||||
|
int k, i, a;
|
||||||
|
double sum, f;
|
||||||
|
|
||||||
|
for(i=0;i<n;i++) {
|
||||||
|
sum = 0;
|
||||||
|
for(k=0;k<n/2;k++) {
|
||||||
|
a = (2 * i + 1 + (n / 2)) * (2 * k + 1);
|
||||||
|
f = cos(M_PI * a / (double)(2 * n));
|
||||||
|
sum += f * in[k];
|
||||||
|
}
|
||||||
|
out[i] = -sum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NOTE: no normalisation by 1 / N is done */
|
||||||
|
void mdct_ref(float *output, float *input, int nbits)
|
||||||
|
{
|
||||||
|
int n = 1<<nbits;
|
||||||
|
int k, i;
|
||||||
|
double a, s;
|
||||||
|
|
||||||
|
/* do it by hand */
|
||||||
|
for(k=0;k<n/2;k++) {
|
||||||
|
s = 0;
|
||||||
|
for(i=0;i<n;i++) {
|
||||||
|
a = (2*M_PI*(2*i+1+n/2)*(2*k+1) / (4 * n));
|
||||||
|
s += input[i] * cos(a);
|
||||||
|
}
|
||||||
|
output[k] = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float frandom(void)
|
||||||
|
{
|
||||||
|
return (float)((random() & 0xffff) - 32768) / 32768.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t gettime(void)
|
||||||
|
{
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv,NULL);
|
||||||
|
return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_diff(float *tab1, float *tab2, int n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double max= 0;
|
||||||
|
double error= 0;
|
||||||
|
|
||||||
|
for(i=0;i<n;i++) {
|
||||||
|
double e= fabsf(tab1[i] - tab2[i]);
|
||||||
|
if (e >= 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<fft_size;i++) {
|
||||||
|
tab1[i].re = frandom();
|
||||||
|
tab1[i].im = frandom();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* checking result */
|
||||||
|
av_log(NULL, AV_LOG_INFO,"Checking...\n");
|
||||||
|
|
||||||
|
if (do_mdct) {
|
||||||
|
if (do_inverse) {
|
||||||
|
imdct_ref((float *)tab_ref, (float *)tab1, fft_nbits);
|
||||||
|
ff_imdct_calc(m, tab2, (float *)tab1);
|
||||||
|
check_diff((float *)tab_ref, tab2, fft_size);
|
||||||
|
} else {
|
||||||
|
mdct_ref((float *)tab_ref, (float *)tab1, fft_nbits);
|
||||||
|
|
||||||
|
ff_mdct_calc(m, tab2, (float *)tab1);
|
||||||
|
|
||||||
|
check_diff((float *)tab_ref, tab2, fft_size / 2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
memcpy(tab, tab1, fft_size * sizeof(FFTComplex));
|
||||||
|
ff_fft_permute(s, tab);
|
||||||
|
ff_fft_calc(s, tab);
|
||||||
|
|
||||||
|
fft_ref(tab_ref, tab1, fft_nbits);
|
||||||
|
check_diff((float *)tab_ref, (float *)tab, fft_size * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* do a speed test */
|
||||||
|
|
||||||
|
if (do_speed) {
|
||||||
|
int64_t time_start, duration;
|
||||||
|
int nb_its;
|
||||||
|
|
||||||
|
av_log(NULL, AV_LOG_INFO,"Speed test...\n");
|
||||||
|
/* we measure during about 1 seconds */
|
||||||
|
nb_its = 1;
|
||||||
|
for(;;) {
|
||||||
|
time_start = gettime();
|
||||||
|
for(it=0;it<nb_its;it++) {
|
||||||
|
if (do_mdct) {
|
||||||
|
if (do_inverse) {
|
||||||
|
ff_imdct_calc(m, (float *)tab, (float *)tab1);
|
||||||
|
} else {
|
||||||
|
ff_mdct_calc(m, (float *)tab, (float *)tab1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
memcpy(tab, tab1, fft_size * sizeof(FFTComplex));
|
||||||
|
ff_fft_calc(s, tab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
duration = gettime() - time_start;
|
||||||
|
if (duration >= 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;
|
||||||
|
}
|
||||||
@@ -1,20 +1,24 @@
|
|||||||
/*
|
/*
|
||||||
* FFT/IFFT transforms
|
* FFT/IFFT transforms
|
||||||
|
* Copyright (c) 2008 Loren Merritt
|
||||||
* Copyright (c) 2002 Fabrice Bellard.
|
* 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
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
* License as published by the Free Software Foundation; either
|
||||||
* version 2 of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -24,18 +28,53 @@
|
|||||||
|
|
||||||
#include "dsputil.h"
|
#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
|
* 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;
|
int i, j, m, n;
|
||||||
float alpha, c1, s1, s2;
|
float alpha, c1, s1, s2;
|
||||||
|
int split_radix = 1;
|
||||||
|
int av_unused has_vectors;
|
||||||
|
|
||||||
|
if (nbits < 2 || nbits > 16)
|
||||||
|
goto fail;
|
||||||
s->nbits = nbits;
|
s->nbits = nbits;
|
||||||
n = 1 << nbits;
|
n = 1 << nbits;
|
||||||
|
|
||||||
|
s->tmp_buf = NULL;
|
||||||
s->exptab = av_malloc((n / 2) * sizeof(FFTComplex));
|
s->exptab = av_malloc((n / 2) * sizeof(FFTComplex));
|
||||||
if (!s->exptab)
|
if (!s->exptab)
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -46,191 +85,124 @@ int fft_init(FFTContext *s, int nbits, int inverse)
|
|||||||
|
|
||||||
s2 = inverse ? 1.0 : -1.0;
|
s2 = inverse ? 1.0 : -1.0;
|
||||||
|
|
||||||
for(i=0;i<(n/2);i++) {
|
s->fft_permute = ff_fft_permute_c;
|
||||||
alpha = 2 * M_PI * (float)i / (float)n;
|
s->fft_calc = ff_fft_calc_c;
|
||||||
c1 = cos(alpha);
|
s->imdct_calc = ff_imdct_calc_c;
|
||||||
s1 = sin(alpha) * s2;
|
s->imdct_half = ff_imdct_half_c;
|
||||||
s->exptab[i].re = c1;
|
|
||||||
s->exptab[i].im = s1;
|
|
||||||
}
|
|
||||||
s->fft_calc = fft_calc_c;
|
|
||||||
s->exptab1 = NULL;
|
s->exptab1 = NULL;
|
||||||
|
|
||||||
/* compute constant table for HAVE_SSE version */
|
#if defined HAVE_MMX && defined HAVE_YASM
|
||||||
#if (defined(HAVE_MMX) && defined(HAVE_BUILTIN_VECTOR)) || defined(HAVE_ALTIVEC)
|
has_vectors = mm_support();
|
||||||
{
|
if (has_vectors & MM_SSE) {
|
||||||
int has_vectors = 0;
|
/* SSE for P3/P4/K8 */
|
||||||
|
s->imdct_calc = ff_imdct_calc_sse;
|
||||||
#if defined(HAVE_MMX)
|
s->imdct_half = ff_imdct_half_sse;
|
||||||
has_vectors = mm_support() & MM_SSE;
|
s->fft_permute = ff_fft_permute_sse;
|
||||||
#endif
|
s->fft_calc = ff_fft_calc_sse;
|
||||||
#if defined(HAVE_ALTIVEC) && !defined(ALTIVEC_USE_REFERENCE_C_CODE)
|
} else if (has_vectors & MM_3DNOWEXT) {
|
||||||
has_vectors = mm_support() & MM_ALTIVEC;
|
/* 3DNowEx for K7 */
|
||||||
#endif
|
s->imdct_calc = ff_imdct_calc_3dn2;
|
||||||
if (has_vectors) {
|
s->imdct_half = ff_imdct_half_3dn2;
|
||||||
int np, nblocks, np2, l;
|
s->fft_calc = ff_fft_calc_3dn2;
|
||||||
FFTComplex *q;
|
} else if (has_vectors & MM_3DNOW) {
|
||||||
|
/* 3DNow! for K6-2/3 */
|
||||||
np = 1 << nbits;
|
s->imdct_calc = ff_imdct_calc_3dn;
|
||||||
nblocks = np >> 3;
|
s->imdct_half = ff_imdct_half_3dn;
|
||||||
np2 = np >> 1;
|
s->fft_calc = ff_fft_calc_3dn;
|
||||||
s->exptab1 = av_malloc(np * 2 * sizeof(FFTComplex));
|
}
|
||||||
if (!s->exptab1)
|
#elif defined HAVE_ALTIVEC && !defined ALTIVEC_USE_REFERENCE_C_CODE
|
||||||
goto fail;
|
has_vectors = mm_support();
|
||||||
q = s->exptab1;
|
if (has_vectors & MM_ALTIVEC) {
|
||||||
do {
|
s->fft_calc = ff_fft_calc_altivec;
|
||||||
for(l = 0; l < np2; l += 2 * nblocks) {
|
split_radix = 0;
|
||||||
*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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* compute bit reverse table */
|
if (split_radix) {
|
||||||
|
for(j=4; j<=nbits; j++) {
|
||||||
for(i=0;i<n;i++) {
|
int m = 1<<j;
|
||||||
m=0;
|
double freq = 2*M_PI/m;
|
||||||
for(j=0;j<nbits;j++) {
|
FFTSample *tab = ff_cos_tabs[j-4];
|
||||||
m |= ((i >> j) & 1) << (nbits-j-1);
|
for(i=0; i<=m/4; i++)
|
||||||
|
tab[i] = cos(i*freq);
|
||||||
|
for(i=1; i<m/4; i++)
|
||||||
|
tab[m/2-i] = tab[i];
|
||||||
|
}
|
||||||
|
for(i=0; i<n; i++)
|
||||||
|
s->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<n;i++) {
|
||||||
|
m=0;
|
||||||
|
for(j=0;j<nbits;j++) {
|
||||||
|
m |= ((i >> j) & 1) << (nbits-j-1);
|
||||||
|
}
|
||||||
|
s->revtab[i]=m;
|
||||||
}
|
}
|
||||||
s->revtab[i]=m;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
fail:
|
fail:
|
||||||
av_freep(&s->revtab);
|
av_freep(&s->revtab);
|
||||||
av_freep(&s->exptab);
|
av_freep(&s->exptab);
|
||||||
av_freep(&s->exptab1);
|
av_freep(&s->exptab1);
|
||||||
|
av_freep(&s->tmp_buf);
|
||||||
return -1;
|
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
|
* Do the permutation needed BEFORE calling ff_fft_calc()
|
||||||
* input data must be permuted before with s->revtab table. No
|
|
||||||
* 1.0/sqrt(n) normalization is done.
|
|
||||||
*/
|
*/
|
||||||
void fft_calc_c(FFTContext *s, FFTComplex *z)
|
void ff_fft_permute_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)
|
|
||||||
{
|
{
|
||||||
int j, k, np;
|
int j, k, np;
|
||||||
FFTComplex tmp;
|
FFTComplex tmp;
|
||||||
const uint16_t *revtab = s->revtab;
|
const uint16_t *revtab = s->revtab;
|
||||||
|
np = 1 << s->nbits;
|
||||||
|
|
||||||
|
if (s->tmp_buf) {
|
||||||
|
/* TODO: handle split-radix permute in a more optimal way, probably in-place */
|
||||||
|
for(j=0;j<np;j++) s->tmp_buf[revtab[j]] = z[j];
|
||||||
|
memcpy(z, s->tmp_buf, np * sizeof(FFTComplex));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* reverse */
|
/* reverse */
|
||||||
np = 1 << s->nbits;
|
|
||||||
for(j=0;j<np;j++) {
|
for(j=0;j<np;j++) {
|
||||||
k = revtab[j];
|
k = revtab[j];
|
||||||
if (k < j) {
|
if (k < j) {
|
||||||
@@ -241,10 +213,174 @@ void fft_permute(FFTContext *s, FFTComplex *z)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void fft_end(FFTContext *s)
|
void ff_fft_end(FFTContext *s)
|
||||||
{
|
{
|
||||||
av_freep(&s->revtab);
|
av_freep(&s->revtab);
|
||||||
av_freep(&s->exptab);
|
av_freep(&s->exptab);
|
||||||
av_freep(&s->exptab1);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,20 +3,21 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2003 Michael Niedermayer <[email protected]>
|
* Copyright (c) 2003 Michael Niedermayer <[email protected]>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
* License as published by the Free Software Foundation; either
|
||||||
* version 2 of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -24,15 +25,17 @@
|
|||||||
* FF Video Codec 1 (an experimental lossless codec)
|
* FF Video Codec 1 (an experimental lossless codec)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "avcodec.h"
|
#include "avcodec.h"
|
||||||
|
#include "bitstream.h"
|
||||||
#include "dsputil.h"
|
#include "dsputil.h"
|
||||||
#include "cabac.h"
|
#include "rangecoder.h"
|
||||||
#include "golomb.h"
|
#include "golomb.h"
|
||||||
|
|
||||||
#define MAX_PLANES 4
|
#define MAX_PLANES 4
|
||||||
#define CONTEXT_SIZE 32
|
#define CONTEXT_SIZE 32
|
||||||
|
|
||||||
|
extern const uint8_t ff_log2_run[32];
|
||||||
|
|
||||||
static const int8_t quant3[256]={
|
static const int8_t quant3[256]={
|
||||||
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
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,
|
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,
|
-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{
|
typedef struct VlcState{
|
||||||
int16_t drift;
|
int16_t drift;
|
||||||
uint16_t error_sum;
|
uint16_t error_sum;
|
||||||
@@ -164,7 +161,7 @@ typedef struct PlaneContext{
|
|||||||
|
|
||||||
typedef struct FFV1Context{
|
typedef struct FFV1Context{
|
||||||
AVCodecContext *avctx;
|
AVCodecContext *avctx;
|
||||||
CABACContext c;
|
RangeCoder c;
|
||||||
GetBitContext gb;
|
GetBitContext gb;
|
||||||
PutBitContext pb;
|
PutBitContext pb;
|
||||||
int version;
|
int version;
|
||||||
@@ -183,7 +180,7 @@ typedef struct FFV1Context{
|
|||||||
DSPContext dsp;
|
DSPContext dsp;
|
||||||
}FFV1Context;
|
}FFV1Context;
|
||||||
|
|
||||||
static always_inline int fold(int diff, int bits){
|
static av_always_inline int fold(int diff, int bits){
|
||||||
if(bits==8)
|
if(bits==8)
|
||||||
diff= (int8_t)diff;
|
diff= (int8_t)diff;
|
||||||
else{
|
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];
|
return f->quant_table[0][(L-LT) & 0xFF] + f->quant_table[1][(LT-T) & 0xFF] + f->quant_table[2][(T-RT) & 0xFF];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static inline void put_symbol(RangeCoder *c, uint8_t *state, int v, int is_signed){
|
||||||
* put
|
|
||||||
*/
|
|
||||||
static inline void put_symbol(CABACContext *c, uint8_t *state, int v, int is_signed, int max_exp){
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if(v){
|
if(v){
|
||||||
const int a= ABS(v);
|
const int a= FFABS(v);
|
||||||
const int e= av_log2(a);
|
const int e= av_log2(a);
|
||||||
|
put_rac(c, state+0, 0);
|
||||||
|
|
||||||
put_cabac(c, state+0, 0);
|
assert(e<=9);
|
||||||
|
|
||||||
for(i=0; i<e; i++){
|
for(i=0; i<e; i++){
|
||||||
put_cabac(c, state+1+i, 1); //1..8
|
put_rac(c, state+1+i, 1); //1..10
|
||||||
|
}
|
||||||
|
put_rac(c, state+1+i, 0);
|
||||||
|
|
||||||
|
for(i=e-1; i>=0; i--){
|
||||||
|
put_rac(c, state+22+i, (a>>i)&1); //22..31
|
||||||
}
|
}
|
||||||
|
|
||||||
if(e<max_exp){
|
if(is_signed)
|
||||||
put_cabac(c, state+1+i, 0); //1..8
|
put_rac(c, state+11 + e, v < 0); //11..21
|
||||||
|
|
||||||
for(i=e-1; i>=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
|
|
||||||
}
|
|
||||||
}else{
|
}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){
|
static inline int get_symbol(RangeCoder *c, uint8_t *state, int is_signed){
|
||||||
if(get_cabac(c, state+0))
|
if(get_rac(c, state+0))
|
||||||
return 0;
|
return 0;
|
||||||
else{
|
else{
|
||||||
int i, e;
|
int i, e, a;
|
||||||
|
e= 0;
|
||||||
for(e=0; e<max_exp; e++){
|
while(get_rac(c, state+1 + e)){ //1..10
|
||||||
int a= 1<<e;
|
e++;
|
||||||
|
|
||||||
if(get_cabac(c, state + 1 + e)==0){ // 1..8
|
|
||||||
for(i=e-1; i>=0; i--){
|
|
||||||
a += get_cabac(c, state+16+e+i)<<i; //17..29
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_signed && get_cabac(c, state+9 + e)) //9..16
|
|
||||||
return -a;
|
|
||||||
else
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return -(1<<e);
|
assert(e<=9);
|
||||||
|
|
||||||
|
a= 1;
|
||||||
|
for(i=e-1; 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){
|
static inline void update_vlc_state(VlcState * const state, const int v){
|
||||||
int drift= state->drift;
|
int drift= state->drift;
|
||||||
int count= state->count;
|
int count= state->count;
|
||||||
state->error_sum += ABS(v);
|
state->error_sum += FFABS(v);
|
||||||
drift += v;
|
drift += v;
|
||||||
|
|
||||||
if(count == 128){ //FIXME variable
|
if(count == 128){ //FIXME variable
|
||||||
@@ -324,10 +316,8 @@ static inline void put_vlc_symbol(PutBitContext *pb, VlcState * const state, int
|
|||||||
code= v ^ ((2*state->drift + state->count)>>31);
|
code= v ^ ((2*state->drift + state->count)>>31);
|
||||||
#endif
|
#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);
|
//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);
|
update_vlc_state(state, v);
|
||||||
}
|
}
|
||||||
@@ -344,13 +334,9 @@ static inline int get_vlc_symbol(GetBitContext *gb, VlcState * const state, int
|
|||||||
|
|
||||||
assert(k<=8);
|
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);
|
//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 0 // JPEG LS
|
||||||
if(k==0 && 2*state->drift <= - state->count) v ^= (-1);
|
if(k==0 && 2*state->drift <= - state->count) v ^= (-1);
|
||||||
#else
|
#else
|
||||||
@@ -364,19 +350,32 @@ static inline int get_vlc_symbol(GetBitContext *gb, VlcState * const state, int
|
|||||||
return 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];
|
PlaneContext * const p= &s->plane[plane_index];
|
||||||
CABACContext * const c= &s->c;
|
RangeCoder * const c= &s->c;
|
||||||
int x;
|
int x;
|
||||||
int run_index= s->run_index;
|
int run_index= s->run_index;
|
||||||
int run_count=0;
|
int run_count=0;
|
||||||
int run_mode=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; x<w; x++){
|
for(x=0; x<w; x++){
|
||||||
int diff, context;
|
int diff, context;
|
||||||
|
|
||||||
context= get_context(s, sample[1]+x, sample[0]+x, sample[2]+x);
|
context= get_context(s, sample[0]+x, sample[1]+x, sample[2]+x);
|
||||||
diff= sample[1][x] - predict(sample[1]+x, sample[0]+x);
|
diff= sample[0][x] - predict(sample[0]+x, sample[1]+x);
|
||||||
|
|
||||||
if(context < 0){
|
if(context < 0){
|
||||||
context = -context;
|
context = -context;
|
||||||
@@ -386,20 +385,20 @@ static inline void encode_line(FFV1Context *s, int w, int_fast16_t *sample[2], i
|
|||||||
diff= fold(diff, bits);
|
diff= fold(diff, bits);
|
||||||
|
|
||||||
if(s->ac){
|
if(s->ac){
|
||||||
put_symbol(c, p->state[context], diff, 1, bits-1);
|
put_symbol(c, p->state[context], diff, 1);
|
||||||
}else{
|
}else{
|
||||||
if(context == 0) run_mode=1;
|
if(context == 0) run_mode=1;
|
||||||
|
|
||||||
if(run_mode){
|
if(run_mode){
|
||||||
|
|
||||||
if(diff){
|
if(diff){
|
||||||
while(run_count >= 1<<log2_run[run_index]){
|
while(run_count >= 1<<ff_log2_run[run_index]){
|
||||||
run_count -= 1<<log2_run[run_index];
|
run_count -= 1<<ff_log2_run[run_index];
|
||||||
run_index++;
|
run_index++;
|
||||||
put_bits(&s->pb, 1, 1);
|
put_bits(&s->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--;
|
if(run_index) run_index--;
|
||||||
run_count=0;
|
run_count=0;
|
||||||
run_mode=0;
|
run_mode=0;
|
||||||
@@ -409,15 +408,15 @@ static inline void encode_line(FFV1Context *s, int w, int_fast16_t *sample[2], i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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)
|
if(run_mode == 0)
|
||||||
put_vlc_symbol(&s->pb, &p->vlc_state[context], diff, bits);
|
put_vlc_symbol(&s->pb, &p->vlc_state[context], diff, bits);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(run_mode){
|
if(run_mode){
|
||||||
while(run_count >= 1<<log2_run[run_index]){
|
while(run_count >= 1<<ff_log2_run[run_index]){
|
||||||
run_count -= 1<<log2_run[run_index];
|
run_count -= 1<<ff_log2_run[run_index];
|
||||||
run_index++;
|
run_index++;
|
||||||
put_bits(&s->pb, 1, 1);
|
put_bits(&s->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);
|
put_bits(&s->pb, 1, 1);
|
||||||
}
|
}
|
||||||
s->run_index= run_index;
|
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){
|
static void encode_plane(FFV1Context *s, uint8_t *src, int w, int h, int stride, int plane_index){
|
||||||
int x,y;
|
int x,y,i;
|
||||||
int_fast16_t sample_buffer[3][w+6];
|
const int ring_size= s->avctx->context_model ? 3 : 2;
|
||||||
int_fast16_t *sample[3]= {sample_buffer[0]+3, sample_buffer[1]+3, sample_buffer[2]+3};
|
int_fast16_t sample_buffer[ring_size][w+6], *sample[ring_size];
|
||||||
s->run_index=0;
|
s->run_index=0;
|
||||||
|
|
||||||
memset(sample_buffer, 0, sizeof(sample_buffer));
|
memset(sample_buffer, 0, sizeof(sample_buffer));
|
||||||
|
|
||||||
for(y=0; y<h; y++){
|
for(y=0; y<h; y++){
|
||||||
int_fast16_t *temp= sample[0]; //FIXME try a normal buffer
|
for(i=0; i<ring_size; i++)
|
||||||
|
sample[i]= sample_buffer[(h+i-y)%ring_size]+3;
|
||||||
|
|
||||||
sample[0]= sample[1];
|
sample[0][-1]= sample[1][0 ];
|
||||||
sample[1]= sample[2];
|
sample[1][ w]= sample[1][w-1];
|
||||||
sample[2]= temp;
|
|
||||||
|
|
||||||
sample[1][-1]= sample[0][0 ];
|
|
||||||
sample[0][ w]= sample[0][w-1];
|
|
||||||
//{START_TIMER
|
//{START_TIMER
|
||||||
for(x=0; x<w; x++){
|
for(x=0; x<w; x++){
|
||||||
sample[1][x]= src[x + stride*y];
|
sample[0][x]= src[x + stride*y];
|
||||||
}
|
}
|
||||||
encode_line(s, w, sample, plane_index, 8);
|
encode_line(s, w, sample, plane_index, 8);
|
||||||
//STOP_TIMER("encode line")}
|
//STOP_TIMER("encode line")}
|
||||||
@@ -455,17 +453,18 @@ static void encode_plane(FFV1Context *s, uint8_t *src, int w, int h, int stride,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void encode_rgb_frame(FFV1Context *s, uint32_t *src, int w, int h, int stride){
|
static void encode_rgb_frame(FFV1Context *s, uint32_t *src, int w, int h, int stride){
|
||||||
int x, y, p;
|
int x, y, p, i;
|
||||||
int_fast16_t sample_buffer[3][2][w+6];
|
const int ring_size= s->avctx->context_model ? 3 : 2;
|
||||||
int_fast16_t *sample[3][2]= {
|
int_fast16_t sample_buffer[3][ring_size][w+6], *sample[3][ring_size];
|
||||||
{sample_buffer[0][0]+3, sample_buffer[0][1]+3},
|
|
||||||
{sample_buffer[1][0]+3, sample_buffer[1][1]+3},
|
|
||||||
{sample_buffer[2][0]+3, sample_buffer[2][1]+3}};
|
|
||||||
s->run_index=0;
|
s->run_index=0;
|
||||||
|
|
||||||
memset(sample_buffer, 0, sizeof(sample_buffer));
|
memset(sample_buffer, 0, sizeof(sample_buffer));
|
||||||
|
|
||||||
for(y=0; y<h; y++){
|
for(y=0; y<h; y++){
|
||||||
|
for(i=0; i<ring_size; i++)
|
||||||
|
for(p=0; p<3; p++)
|
||||||
|
sample[p][i]= sample_buffer[p][(h+i-y)%ring_size]+3;
|
||||||
|
|
||||||
for(x=0; x<w; x++){
|
for(x=0; x<w; x++){
|
||||||
int v= src[x + stride*y];
|
int v= src[x + stride*y];
|
||||||
int b= v&0xFF;
|
int b= v&0xFF;
|
||||||
@@ -485,50 +484,49 @@ static void encode_rgb_frame(FFV1Context *s, uint32_t *src, int w, int h, int st
|
|||||||
sample[2][0][x]= r;
|
sample[2][0][x]= r;
|
||||||
}
|
}
|
||||||
for(p=0; p<3; p++){
|
for(p=0; p<3; p++){
|
||||||
int_fast16_t *temp= sample[p][0]; //FIXME try a normal buffer
|
sample[p][0][-1]= sample[p][1][0 ];
|
||||||
|
sample[p][1][ w]= sample[p][1][w-1];
|
||||||
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];
|
|
||||||
encode_line(s, w, sample[p], FFMIN(p, 1), 9);
|
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 last=0;
|
||||||
int i;
|
int i;
|
||||||
uint8_t state[CONTEXT_SIZE]={0};
|
uint8_t state[CONTEXT_SIZE];
|
||||||
|
memset(state, 128, sizeof(state));
|
||||||
|
|
||||||
for(i=1; i<128 ; i++){
|
for(i=1; i<128 ; i++){
|
||||||
if(quant_table[i] != quant_table[i-1]){
|
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;
|
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){
|
static void write_header(FFV1Context *f){
|
||||||
uint8_t state[CONTEXT_SIZE]={0};
|
uint8_t state[CONTEXT_SIZE];
|
||||||
int i;
|
int i;
|
||||||
CABACContext * const c= &f->c;
|
RangeCoder * const c= &f->c;
|
||||||
|
|
||||||
put_symbol(c, state, f->version, 0, 7);
|
memset(state, 128, sizeof(state));
|
||||||
put_symbol(c, state, f->avctx->coder_type, 0, 7);
|
|
||||||
put_symbol(c, state, f->colorspace, 0, 7); //YUV cs type
|
put_symbol(c, state, f->version, 0);
|
||||||
put_cabac(c, state, 1); //chroma planes
|
put_symbol(c, state, f->avctx->coder_type, 0);
|
||||||
put_symbol(c, state, f->chroma_h_shift, 0, 7);
|
put_symbol(c, state, f->colorspace, 0); //YUV cs type
|
||||||
put_symbol(c, state, f->chroma_v_shift, 0, 7);
|
put_rac(c, state, 1); //chroma planes
|
||||||
put_cabac(c, state, 0); //no transparency plane
|
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++)
|
for(i=0; i<5; i++)
|
||||||
write_quant_table(c, f->quant_table[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;
|
FFV1Context *s = avctx->priv_data;
|
||||||
int width, height;
|
int width, height;
|
||||||
|
|
||||||
@@ -545,7 +543,8 @@ static int common_init(AVCodecContext *avctx){
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int encode_init(AVCodecContext *avctx)
|
#ifdef CONFIG_ENCODERS
|
||||||
|
static av_cold int encode_init(AVCodecContext *avctx)
|
||||||
{
|
{
|
||||||
FFV1Context *s = avctx->priv_data;
|
FFV1Context *s = avctx->priv_data;
|
||||||
int i;
|
int i;
|
||||||
@@ -595,7 +594,7 @@ static int encode_init(AVCodecContext *avctx)
|
|||||||
case PIX_FMT_YUV410P:
|
case PIX_FMT_YUV410P:
|
||||||
s->colorspace= 0;
|
s->colorspace= 0;
|
||||||
break;
|
break;
|
||||||
case PIX_FMT_RGBA32:
|
case PIX_FMT_RGB32:
|
||||||
s->colorspace= 1;
|
s->colorspace= 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -608,6 +607,7 @@ static int encode_init(AVCodecContext *avctx)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_ENCODERS */
|
||||||
|
|
||||||
|
|
||||||
static void clear_state(FFV1Context *f){
|
static void clear_state(FFV1Context *f){
|
||||||
@@ -616,13 +616,12 @@ static void clear_state(FFV1Context *f){
|
|||||||
for(i=0; i<f->plane_count; i++){
|
for(i=0; i<f->plane_count; i++){
|
||||||
PlaneContext *p= &f->plane[i];
|
PlaneContext *p= &f->plane[i];
|
||||||
|
|
||||||
p->interlace_bit_state[0]= 0;
|
p->interlace_bit_state[0]= 128;
|
||||||
p->interlace_bit_state[1]= 0;
|
p->interlace_bit_state[1]= 128;
|
||||||
|
|
||||||
for(j=0; j<p->context_count; j++){
|
for(j=0; j<p->context_count; j++){
|
||||||
if(f->ac){
|
if(f->ac){
|
||||||
memset(p->state[j], 0, sizeof(uint8_t)*CONTEXT_SIZE);
|
memset(p->state[j], 128, sizeof(uint8_t)*CONTEXT_SIZE);
|
||||||
p->state[j][7] = 2*62;
|
|
||||||
}else{
|
}else{
|
||||||
p->vlc_state[j].drift= 0;
|
p->vlc_state[j].drift= 0;
|
||||||
p->vlc_state[j].error_sum= 4; //FFMAX((RANGE + 32)/64, 2);
|
p->vlc_state[j].error_sum= 4; //FFMAX((RANGE + 32)/64, 2);
|
||||||
@@ -633,39 +632,36 @@ static void clear_state(FFV1Context *f){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_ENCODERS
|
||||||
static int encode_frame(AVCodecContext *avctx, unsigned char *buf, int buf_size, void *data){
|
static int encode_frame(AVCodecContext *avctx, unsigned char *buf, int buf_size, void *data){
|
||||||
FFV1Context *f = avctx->priv_data;
|
FFV1Context *f = avctx->priv_data;
|
||||||
CABACContext * const c= &f->c;
|
RangeCoder * const c= &f->c;
|
||||||
AVFrame *pict = data;
|
AVFrame *pict = data;
|
||||||
const int width= f->width;
|
const int width= f->width;
|
||||||
const int height= f->height;
|
const int height= f->height;
|
||||||
AVFrame * const p= &f->picture;
|
AVFrame * const p= &f->picture;
|
||||||
int used_count= 0;
|
int used_count= 0;
|
||||||
|
uint8_t keystate=128;
|
||||||
|
|
||||||
if(avctx->strict_std_compliance >= 0){
|
ff_init_range_encoder(c, buf, buf_size);
|
||||||
av_log(avctx, AV_LOG_ERROR, "this codec is under development, files encoded with it wont be decodeable with future versions!!!\n"
|
// ff_init_cabac_states(c, ff_h264_lps_range, ff_h264_mps_state, ff_h264_lps_state, 64);
|
||||||
"use vstrict=-1 to use it anyway\n");
|
ff_build_rac_states(c, 0.05*(1LL<<32), 256-8);
|
||||||
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;
|
||||||
p->pict_type= FF_I_TYPE;
|
p->pict_type= FF_I_TYPE;
|
||||||
|
|
||||||
if(avctx->gop_size==0 || f->picture_number % avctx->gop_size == 0){
|
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;
|
p->key_frame= 1;
|
||||||
write_header(f);
|
write_header(f);
|
||||||
clear_state(f);
|
clear_state(f);
|
||||||
}else{
|
}else{
|
||||||
put_cabac_bypass(c, 0);
|
put_rac(c, &keystate, 0);
|
||||||
p->key_frame= 0;
|
p->key_frame= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!f->ac){
|
if(!f->ac){
|
||||||
used_count += put_cabac_terminate(c, 1);
|
used_count += ff_rac_terminate(c);
|
||||||
//printf("pos=%d\n", used_count);
|
//printf("pos=%d\n", used_count);
|
||||||
init_put_bits(&f->pb, buf + used_count, buf_size - used_count);
|
init_put_bits(&f->pb, buf + used_count, buf_size - used_count);
|
||||||
}
|
}
|
||||||
@@ -686,35 +682,31 @@ static int encode_frame(AVCodecContext *avctx, unsigned char *buf, int buf_size,
|
|||||||
f->picture_number++;
|
f->picture_number++;
|
||||||
|
|
||||||
if(f->ac){
|
if(f->ac){
|
||||||
return put_cabac_terminate(c, 1);
|
return ff_rac_terminate(c);
|
||||||
}else{
|
}else{
|
||||||
flush_put_bits(&f->pb); //nicer padding FIXME
|
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){
|
static av_cold int common_end(AVCodecContext *avctx){
|
||||||
|
FFV1Context *s = avctx->priv_data;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i=0; i<s->plane_count; i++){
|
for(i=0; i<s->plane_count; i++){
|
||||||
PlaneContext *p= &s->plane[i];
|
PlaneContext *p= &s->plane[i];
|
||||||
|
|
||||||
av_freep(&p->state);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void decode_line(FFV1Context *s, int w, int_fast16_t *sample[2], int plane_index, int bits){
|
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];
|
PlaneContext * const p= &s->plane[plane_index];
|
||||||
CABACContext * const c= &s->c;
|
RangeCoder * const c= &s->c;
|
||||||
int x;
|
int x;
|
||||||
int run_count=0;
|
int run_count=0;
|
||||||
int run_mode=0;
|
int run_mode=0;
|
||||||
@@ -731,18 +723,18 @@ static inline void decode_line(FFV1Context *s, int w, int_fast16_t *sample[2], i
|
|||||||
sign=0;
|
sign=0;
|
||||||
|
|
||||||
|
|
||||||
if(s->ac)
|
if(s->ac){
|
||||||
diff= get_symbol(c, p->state[context], 1, bits-1);
|
diff= get_symbol(c, p->state[context], 1);
|
||||||
else{
|
}else{
|
||||||
if(context == 0 && run_mode==0) run_mode=1;
|
if(context == 0 && run_mode==0) run_mode=1;
|
||||||
|
|
||||||
if(run_mode){
|
if(run_mode){
|
||||||
if(run_count==0 && run_mode==1){
|
if(run_count==0 && run_mode==1){
|
||||||
if(get_bits1(&s->gb)){
|
if(get_bits1(&s->gb)){
|
||||||
run_count = 1<<log2_run[run_index];
|
run_count = 1<<ff_log2_run[run_index];
|
||||||
if(x + run_count <= w) run_index++;
|
if(x + run_count <= w) run_index++;
|
||||||
}else{
|
}else{
|
||||||
if(log2_run[run_index]) run_count = get_bits(&s->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;
|
else run_count=0;
|
||||||
if(run_index) run_index--;
|
if(run_index) run_index--;
|
||||||
run_mode=2;
|
run_mode=2;
|
||||||
@@ -772,7 +764,9 @@ static inline void decode_line(FFV1Context *s, int w, int_fast16_t *sample[2], i
|
|||||||
static void decode_plane(FFV1Context *s, uint8_t *src, int w, int h, int stride, int plane_index){
|
static void decode_plane(FFV1Context *s, uint8_t *src, int w, int h, int stride, int plane_index){
|
||||||
int x, y;
|
int x, y;
|
||||||
int_fast16_t sample_buffer[2][w+6];
|
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;
|
s->run_index=0;
|
||||||
|
|
||||||
@@ -799,10 +793,11 @@ static void decode_plane(FFV1Context *s, uint8_t *src, int w, int h, int stride,
|
|||||||
static void decode_rgb_frame(FFV1Context *s, uint32_t *src, int w, int h, int stride){
|
static void decode_rgb_frame(FFV1Context *s, uint32_t *src, int w, int h, int stride){
|
||||||
int x, y, p;
|
int x, y, p;
|
||||||
int_fast16_t sample_buffer[3][2][w+6];
|
int_fast16_t sample_buffer[3][2][w+6];
|
||||||
int_fast16_t *sample[3][2]= {
|
int_fast16_t *sample[3][2];
|
||||||
{sample_buffer[0][0]+3, sample_buffer[0][1]+3},
|
for(x=0; x<3; x++){
|
||||||
{sample_buffer[1][0]+3, sample_buffer[1][1]+3},
|
sample[x][0] = sample_buffer[x][0]+3;
|
||||||
{sample_buffer[2][0]+3, sample_buffer[2][1]+3}};
|
sample[x][1] = sample_buffer[x][1]+3;
|
||||||
|
}
|
||||||
|
|
||||||
s->run_index=0;
|
s->run_index=0;
|
||||||
|
|
||||||
@@ -838,13 +833,15 @@ static void decode_rgb_frame(FFV1Context *s, uint32_t *src, int w, int h, int st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 v;
|
||||||
int i=0;
|
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++){
|
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;
|
if(len + i > 128) return -1;
|
||||||
|
|
||||||
@@ -865,17 +862,19 @@ static int read_quant_table(CABACContext *c, int16_t *quant_table, int scale){
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int read_header(FFV1Context *f){
|
static int read_header(FFV1Context *f){
|
||||||
uint8_t state[CONTEXT_SIZE]={0};
|
uint8_t state[CONTEXT_SIZE];
|
||||||
int i, context_count;
|
int i, context_count;
|
||||||
CABACContext * const c= &f->c;
|
RangeCoder * const c= &f->c;
|
||||||
|
|
||||||
f->version= get_symbol(c, state, 0, 7);
|
memset(state, 128, sizeof(state));
|
||||||
f->ac= f->avctx->coder_type= get_symbol(c, state, 0, 7);
|
|
||||||
f->colorspace= get_symbol(c, state, 0, 7); //YUV cs type
|
f->version= get_symbol(c, state, 0);
|
||||||
get_cabac(c, state); //no chroma = false
|
f->ac= f->avctx->coder_type= get_symbol(c, state, 0);
|
||||||
f->chroma_h_shift= get_symbol(c, state, 0, 7);
|
f->colorspace= get_symbol(c, state, 0); //YUV cs type
|
||||||
f->chroma_v_shift= get_symbol(c, state, 0, 7);
|
get_rac(c, state); //no chroma = false
|
||||||
get_cabac(c, state); //transparency plane
|
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;
|
f->plane_count= 2;
|
||||||
|
|
||||||
if(f->colorspace==0){
|
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 0x10: f->avctx->pix_fmt= PIX_FMT_YUV422P; break;
|
||||||
case 0x11: f->avctx->pix_fmt= PIX_FMT_YUV420P; break;
|
case 0x11: f->avctx->pix_fmt= PIX_FMT_YUV420P; break;
|
||||||
case 0x20: f->avctx->pix_fmt= PIX_FMT_YUV411P; 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:
|
default:
|
||||||
av_log(f->avctx, AV_LOG_ERROR, "format not supported\n");
|
av_log(f->avctx, AV_LOG_ERROR, "format not supported\n");
|
||||||
return -1;
|
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");
|
av_log(f->avctx, AV_LOG_ERROR, "chroma subsampling not supported in this colorspace\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
f->avctx->pix_fmt= PIX_FMT_RGBA32;
|
f->avctx->pix_fmt= PIX_FMT_RGB32;
|
||||||
}else{
|
}else{
|
||||||
av_log(f->avctx, AV_LOG_ERROR, "colorspace not supported\n");
|
av_log(f->avctx, AV_LOG_ERROR, "colorspace not supported\n");
|
||||||
return -1;
|
return -1;
|
||||||
@@ -905,7 +904,7 @@ static int read_header(FFV1Context *f){
|
|||||||
context_count=1;
|
context_count=1;
|
||||||
for(i=0; i<5; i++){
|
for(i=0; i<5; i++){
|
||||||
context_count*= read_quant_table(c, f->quant_table[i], context_count);
|
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");
|
av_log(f->avctx, AV_LOG_ERROR, "read_quant_table error\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -927,7 +926,7 @@ static int read_header(FFV1Context *f){
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int decode_init(AVCodecContext *avctx)
|
static av_cold int decode_init(AVCodecContext *avctx)
|
||||||
{
|
{
|
||||||
// FFV1Context *s = avctx->priv_data;
|
// FFV1Context *s = avctx->priv_data;
|
||||||
|
|
||||||
@@ -936,33 +935,32 @@ static int decode_init(AVCodecContext *avctx)
|
|||||||
return 0;
|
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;
|
FFV1Context *f = avctx->priv_data;
|
||||||
CABACContext * const c= &f->c;
|
RangeCoder * const c= &f->c;
|
||||||
const int width= f->width;
|
const int width= f->width;
|
||||||
const int height= f->height;
|
const int height= f->height;
|
||||||
AVFrame * const p= &f->picture;
|
AVFrame * const p= &f->picture;
|
||||||
int bytes_read;
|
int bytes_read;
|
||||||
|
uint8_t keystate= 128;
|
||||||
|
|
||||||
AVFrame *picture = data;
|
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
|
p->pict_type= FF_I_TYPE; //FIXME I vs. P
|
||||||
if(get_cabac_bypass(c)){
|
if(get_rac(c, &keystate)){
|
||||||
p->key_frame= 1;
|
p->key_frame= 1;
|
||||||
read_header(f);
|
if(read_header(f) < 0)
|
||||||
|
return -1;
|
||||||
clear_state(f);
|
clear_state(f);
|
||||||
}else{
|
}else{
|
||||||
p->key_frame= 0;
|
p->key_frame= 0;
|
||||||
}
|
}
|
||||||
|
if(!f->plane[0].state && !f->plane[0].vlc_state)
|
||||||
|
return -1;
|
||||||
|
|
||||||
p->reference= 0;
|
p->reference= 0;
|
||||||
if(avctx->get_buffer(avctx, p) < 0){
|
if(avctx->get_buffer(avctx, p) < 0){
|
||||||
@@ -974,8 +972,8 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8
|
|||||||
av_log(avctx, AV_LOG_ERROR, "keyframe:%d coder:%d\n", p->key_frame, f->ac);
|
av_log(avctx, AV_LOG_ERROR, "keyframe:%d coder:%d\n", p->key_frame, f->ac);
|
||||||
|
|
||||||
if(!f->ac){
|
if(!f->ac){
|
||||||
bytes_read = get_cabac_terminate(c);
|
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");
|
if(bytes_read ==0) av_log(avctx, AV_LOG_ERROR, "error at end of AC stream\n"); //FIXME
|
||||||
//printf("pos=%d\n", bytes_read);
|
//printf("pos=%d\n", bytes_read);
|
||||||
init_get_bits(&f->gb, buf + bytes_read, buf_size - bytes_read);
|
init_get_bits(&f->gb, buf + bytes_read, buf_size - bytes_read);
|
||||||
} else {
|
} else {
|
||||||
@@ -1004,7 +1002,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8
|
|||||||
*data_size = sizeof(AVFrame);
|
*data_size = sizeof(AVFrame);
|
||||||
|
|
||||||
if(f->ac){
|
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");
|
if(bytes_read ==0) av_log(f->avctx, AV_LOG_ERROR, "error at end of frame\n");
|
||||||
}else{
|
}else{
|
||||||
bytes_read+= (get_bits_count(&f->gb)+7)/8;
|
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;
|
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 = {
|
AVCodec ffv1_decoder = {
|
||||||
"ffv1",
|
"ffv1",
|
||||||
CODEC_TYPE_VIDEO,
|
CODEC_TYPE_VIDEO,
|
||||||
@@ -1036,10 +1018,11 @@ AVCodec ffv1_decoder = {
|
|||||||
sizeof(FFV1Context),
|
sizeof(FFV1Context),
|
||||||
decode_init,
|
decode_init,
|
||||||
NULL,
|
NULL,
|
||||||
decode_end,
|
common_end,
|
||||||
decode_frame,
|
decode_frame,
|
||||||
CODEC_CAP_DR1 /*| CODEC_CAP_DRAW_HORIZ_BAND*/,
|
CODEC_CAP_DR1 /*| CODEC_CAP_DRAW_HORIZ_BAND*/,
|
||||||
NULL
|
NULL,
|
||||||
|
.long_name= NULL_IF_CONFIG_SMALL("FFmpeg codec #1"),
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_ENCODERS
|
#ifdef CONFIG_ENCODERS
|
||||||
@@ -1050,6 +1033,8 @@ AVCodec ffv1_encoder = {
|
|||||||
sizeof(FFV1Context),
|
sizeof(FFV1Context),
|
||||||
encode_init,
|
encode_init,
|
||||||
encode_frame,
|
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
|
#endif
|
||||||
|
|||||||
@@ -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 <limits.h>
|
||||||
|
|
||||||
|
#define ALT_BITSTREAM_READER
|
||||||
|
#include "crc.h"
|
||||||
|
#include "avcodec.h"
|
||||||
|
#include "bitstream.h"
|
||||||
|
#include "golomb.h"
|
||||||
|
#include "flac.h"
|
||||||
|
|
||||||
|
#undef NDEBUG
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#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; i<metadata_size; i++)
|
||||||
|
skip_bits(&s->gb, 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)"),
|
||||||
|
};
|
||||||
@@ -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 */
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -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 <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "avcodec.h"
|
||||||
|
#include "bitstream.h"
|
||||||
|
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
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 = (j<v_blocks)?s->block_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 = (i<h_blocks)?s->block_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"),
|
||||||
|
};
|
||||||
@@ -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 <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
#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 ; j<w*3 ; j++) {
|
||||||
|
diff |=npfptr[j]^nsptr[j];
|
||||||
|
dptr[j] = nsptr[j];
|
||||||
|
}
|
||||||
|
dptr += w*3;
|
||||||
|
}
|
||||||
|
if (diff)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static av_cold int flashsv_encode_init(AVCodecContext *avctx)
|
||||||
|
{
|
||||||
|
FlashSVContext *s = avctx->priv_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 = (j<v_blocks)?block_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*block_width; // vert position in frame
|
||||||
|
int ws = (i<h_blocks)?block_width:h_part; // size of block
|
||||||
|
int ret=Z_OK;
|
||||||
|
uint8_t *ptr;
|
||||||
|
|
||||||
|
ptr = buf+buf_pos;
|
||||||
|
|
||||||
|
//copy the block to the temp buffer before compression (if it differs from the previous frame's block)
|
||||||
|
res = copy_region_enc(p->data[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"),
|
||||||
|
};
|
||||||
|
|
||||||
@@ -2,20 +2,21 @@
|
|||||||
* FLI/FLC Animation Video Decoder
|
* FLI/FLC Animation Video Decoder
|
||||||
* Copyright (C) 2003, 2004 the ffmpeg project
|
* 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
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
* License as published by the Free Software Foundation; either
|
||||||
* version 2 of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,7 +27,8 @@
|
|||||||
* variations, visit:
|
* variations, visit:
|
||||||
* http://www.compuphase.com/flic.htm
|
* 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
|
* sure that your demuxer sends the FLI file header to the decoder via
|
||||||
* the extradata chunk in AVCodecContext. The chunk should be 128 bytes
|
* the extradata chunk in AVCodecContext. The chunk should be 128 bytes
|
||||||
* large. The only exception is for FLI files from the game "Magic Carpet",
|
* large. The only exception is for FLI files from the game "Magic Carpet",
|
||||||
@@ -38,9 +40,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "avcodec.h"
|
|
||||||
#include "bswap.h"
|
#include "bswap.h"
|
||||||
|
#include "avcodec.h"
|
||||||
|
|
||||||
#define FLI_256_COLOR 4
|
#define FLI_256_COLOR 4
|
||||||
#define FLI_DELTA 7
|
#define FLI_DELTA 7
|
||||||
@@ -50,12 +51,21 @@
|
|||||||
#define FLI_BRUN 15
|
#define FLI_BRUN 15
|
||||||
#define FLI_COPY 16
|
#define FLI_COPY 16
|
||||||
#define FLI_MINI 18
|
#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 FLI_TYPE_CODE (0xAF11)
|
||||||
#define LE_32(x) ((((uint8_t*)(x))[3] << 24) | \
|
#define FLC_FLX_TYPE_CODE (0xAF12)
|
||||||
(((uint8_t*)(x))[2] << 16) | \
|
#define FLC_DTA_TYPE_CODE (0xAF44) /* Marks an "Extended FLC" comes from Dave's Targa Animator (DTA) */
|
||||||
(((uint8_t*)(x))[1] << 8) | \
|
#define FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE (0xAF13)
|
||||||
((uint8_t*)(x))[0])
|
|
||||||
|
#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 {
|
typedef struct FlicDecodeContext {
|
||||||
AVCodecContext *avctx;
|
AVCodecContext *avctx;
|
||||||
@@ -66,23 +76,47 @@ typedef struct FlicDecodeContext {
|
|||||||
int fli_type; /* either 0xAF11 or 0xAF12, affects palette resolution */
|
int fli_type; /* either 0xAF11 or 0xAF12, affects palette resolution */
|
||||||
} FlicDecodeContext;
|
} 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;
|
unsigned char *fli_header = (unsigned char *)avctx->extradata;
|
||||||
|
int depth;
|
||||||
|
|
||||||
s->avctx = avctx;
|
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) {
|
if (s->avctx->extradata_size == 12) {
|
||||||
/* special case for magic carpet FLIs */
|
/* special case for magic carpet FLIs */
|
||||||
s->fli_type = 0xAF13;
|
s->fli_type = FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE;
|
||||||
} else if (s->avctx->extradata_size == 128) {
|
depth = 8;
|
||||||
s->fli_type = LE_16(&fli_header[4]);
|
} else if (s->avctx->extradata_size != 128) {
|
||||||
} else {
|
|
||||||
av_log(avctx, AV_LOG_ERROR, "Expected extradata of 12 or 128 bytes\n");
|
av_log(avctx, AV_LOG_ERROR, "Expected extradata of 12 or 128 bytes\n");
|
||||||
return -1;
|
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;
|
s->frame.data[0] = NULL;
|
||||||
@@ -91,11 +125,11 @@ static int flic_decode_init(AVCodecContext *avctx)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int flic_decode_frame(AVCodecContext *avctx,
|
static int flic_decode_frame_8BPP(AVCodecContext *avctx,
|
||||||
void *data, int *data_size,
|
void *data, int *data_size,
|
||||||
uint8_t *buf, int buf_size)
|
const uint8_t *buf, int buf_size)
|
||||||
{
|
{
|
||||||
FlicDecodeContext *s = (FlicDecodeContext *)avctx->priv_data;
|
FlicDecodeContext *s = avctx->priv_data;
|
||||||
|
|
||||||
int stream_ptr = 0;
|
int stream_ptr = 0;
|
||||||
int stream_ptr_after_color_chunk;
|
int stream_ptr_after_color_chunk;
|
||||||
@@ -122,10 +156,11 @@ static int flic_decode_frame(AVCodecContext *avctx,
|
|||||||
int starting_line;
|
int starting_line;
|
||||||
signed short line_packets;
|
signed short line_packets;
|
||||||
int y_ptr;
|
int y_ptr;
|
||||||
signed char byte_run;
|
int byte_run;
|
||||||
int pixel_skip;
|
int pixel_skip;
|
||||||
int pixel_countdown;
|
int pixel_countdown;
|
||||||
unsigned char *pixels;
|
unsigned char *pixels;
|
||||||
|
int pixel_limit;
|
||||||
|
|
||||||
s->frame.reference = 1;
|
s->frame.reference = 1;
|
||||||
s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
|
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];
|
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 */
|
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 */
|
stream_ptr += 10; /* skip padding */
|
||||||
|
|
||||||
frame_size -= 16;
|
frame_size -= 16;
|
||||||
|
|
||||||
/* iterate through the chunks */
|
/* iterate through the chunks */
|
||||||
while ((frame_size > 0) && (num_chunks > 0)) {
|
while ((frame_size > 0) && (num_chunks > 0)) {
|
||||||
chunk_size = LE_32(&buf[stream_ptr]);
|
chunk_size = AV_RL32(&buf[stream_ptr]);
|
||||||
stream_ptr += 4;
|
stream_ptr += 4;
|
||||||
chunk_type = LE_16(&buf[stream_ptr]);
|
chunk_type = AV_RL16(&buf[stream_ptr]);
|
||||||
stream_ptr += 2;
|
stream_ptr += 2;
|
||||||
|
|
||||||
switch (chunk_type) {
|
switch (chunk_type) {
|
||||||
case FLI_256_COLOR:
|
case FLI_256_COLOR:
|
||||||
case FLI_COLOR:
|
case FLI_COLOR:
|
||||||
stream_ptr_after_color_chunk = stream_ptr + chunk_size - 6;
|
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
|
/* check special case: If this file is from the Magic Carpet
|
||||||
* game and uses 6-bit colors even though it reports 256-color
|
* 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
|
* chunks in a 0xAF12-type file (fli_type is set to 0xAF13 during
|
||||||
* initialization) */
|
* 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;
|
color_shift = 0;
|
||||||
else
|
else
|
||||||
color_shift = 2;
|
color_shift = 2;
|
||||||
/* set up the palette */
|
/* set up the palette */
|
||||||
color_packets = LE_16(&buf[stream_ptr]);
|
color_packets = AV_RL16(&buf[stream_ptr]);
|
||||||
stream_ptr += 2;
|
stream_ptr += 2;
|
||||||
palette_ptr = 0;
|
palette_ptr = 0;
|
||||||
for (i = 0; i < color_packets; i++) {
|
for (i = 0; i < color_packets; i++) {
|
||||||
@@ -180,15 +215,19 @@ static int flic_decode_frame(AVCodecContext *avctx,
|
|||||||
color_changes = 256;
|
color_changes = 256;
|
||||||
|
|
||||||
for (j = 0; j < color_changes; j++) {
|
for (j = 0; j < color_changes; j++) {
|
||||||
|
unsigned int entry;
|
||||||
|
|
||||||
/* wrap around, for good measure */
|
/* wrap around, for good measure */
|
||||||
if (palette_ptr >= 256)
|
if ((unsigned)palette_ptr >= 256)
|
||||||
palette_ptr = 0;
|
palette_ptr = 0;
|
||||||
|
|
||||||
r = buf[stream_ptr++] << color_shift;
|
r = buf[stream_ptr++] << color_shift;
|
||||||
g = buf[stream_ptr++] << color_shift;
|
g = buf[stream_ptr++] << color_shift;
|
||||||
b = 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:
|
case FLI_DELTA:
|
||||||
y_ptr = 0;
|
y_ptr = 0;
|
||||||
compressed_lines = LE_16(&buf[stream_ptr]);
|
compressed_lines = AV_RL16(&buf[stream_ptr]);
|
||||||
stream_ptr += 2;
|
stream_ptr += 2;
|
||||||
while (compressed_lines > 0) {
|
while (compressed_lines > 0) {
|
||||||
line_packets = LE_16(&buf[stream_ptr]);
|
line_packets = AV_RL16(&buf[stream_ptr]);
|
||||||
stream_ptr += 2;
|
stream_ptr += 2;
|
||||||
if (line_packets < 0) {
|
if ((line_packets & 0xC000) == 0xC000) {
|
||||||
|
// line skip opcode
|
||||||
line_packets = -line_packets;
|
line_packets = -line_packets;
|
||||||
y_ptr += line_packets * s->frame.linesize[0];
|
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 {
|
} else {
|
||||||
compressed_lines--;
|
compressed_lines--;
|
||||||
pixel_ptr = y_ptr;
|
pixel_ptr = y_ptr;
|
||||||
@@ -219,16 +264,18 @@ static int flic_decode_frame(AVCodecContext *avctx,
|
|||||||
pixel_skip = buf[stream_ptr++];
|
pixel_skip = buf[stream_ptr++];
|
||||||
pixel_ptr += pixel_skip;
|
pixel_ptr += pixel_skip;
|
||||||
pixel_countdown -= pixel_skip;
|
pixel_countdown -= pixel_skip;
|
||||||
byte_run = buf[stream_ptr++];
|
byte_run = (signed char)(buf[stream_ptr++]);
|
||||||
if (byte_run < 0) {
|
if (byte_run < 0) {
|
||||||
byte_run = -byte_run;
|
byte_run = -byte_run;
|
||||||
palette_idx1 = buf[stream_ptr++];
|
palette_idx1 = buf[stream_ptr++];
|
||||||
palette_idx2 = buf[stream_ptr++];
|
palette_idx2 = buf[stream_ptr++];
|
||||||
|
CHECK_PIXEL_PTR(byte_run);
|
||||||
for (j = 0; j < byte_run; j++, pixel_countdown -= 2) {
|
for (j = 0; j < byte_run; j++, pixel_countdown -= 2) {
|
||||||
pixels[pixel_ptr++] = palette_idx1;
|
pixels[pixel_ptr++] = palette_idx1;
|
||||||
pixels[pixel_ptr++] = palette_idx2;
|
pixels[pixel_ptr++] = palette_idx2;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
CHECK_PIXEL_PTR(byte_run * 2);
|
||||||
for (j = 0; j < byte_run * 2; j++, pixel_countdown--) {
|
for (j = 0; j < byte_run * 2; j++, pixel_countdown--) {
|
||||||
palette_idx1 = buf[stream_ptr++];
|
palette_idx1 = buf[stream_ptr++];
|
||||||
pixels[pixel_ptr++] = palette_idx1;
|
pixels[pixel_ptr++] = palette_idx1;
|
||||||
@@ -243,12 +290,12 @@ static int flic_decode_frame(AVCodecContext *avctx,
|
|||||||
|
|
||||||
case FLI_LC:
|
case FLI_LC:
|
||||||
/* line compressed */
|
/* line compressed */
|
||||||
starting_line = LE_16(&buf[stream_ptr]);
|
starting_line = AV_RL16(&buf[stream_ptr]);
|
||||||
stream_ptr += 2;
|
stream_ptr += 2;
|
||||||
y_ptr = 0;
|
y_ptr = 0;
|
||||||
y_ptr += starting_line * s->frame.linesize[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;
|
stream_ptr += 2;
|
||||||
while (compressed_lines > 0) {
|
while (compressed_lines > 0) {
|
||||||
pixel_ptr = y_ptr;
|
pixel_ptr = y_ptr;
|
||||||
@@ -260,15 +307,17 @@ static int flic_decode_frame(AVCodecContext *avctx,
|
|||||||
pixel_skip = buf[stream_ptr++];
|
pixel_skip = buf[stream_ptr++];
|
||||||
pixel_ptr += pixel_skip;
|
pixel_ptr += pixel_skip;
|
||||||
pixel_countdown -= pixel_skip;
|
pixel_countdown -= pixel_skip;
|
||||||
byte_run = buf[stream_ptr++];
|
byte_run = (signed char)(buf[stream_ptr++]);
|
||||||
if (byte_run > 0) {
|
if (byte_run > 0) {
|
||||||
|
CHECK_PIXEL_PTR(byte_run);
|
||||||
for (j = 0; j < byte_run; j++, pixel_countdown--) {
|
for (j = 0; j < byte_run; j++, pixel_countdown--) {
|
||||||
palette_idx1 = buf[stream_ptr++];
|
palette_idx1 = buf[stream_ptr++];
|
||||||
pixels[pixel_ptr++] = palette_idx1;
|
pixels[pixel_ptr++] = palette_idx1;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (byte_run < 0) {
|
||||||
byte_run = -byte_run;
|
byte_run = -byte_run;
|
||||||
palette_idx1 = buf[stream_ptr++];
|
palette_idx1 = buf[stream_ptr++];
|
||||||
|
CHECK_PIXEL_PTR(byte_run);
|
||||||
for (j = 0; j < byte_run; j++, pixel_countdown--) {
|
for (j = 0; j < byte_run; j++, pixel_countdown--) {
|
||||||
pixels[pixel_ptr++] = palette_idx1;
|
pixels[pixel_ptr++] = palette_idx1;
|
||||||
}
|
}
|
||||||
@@ -298,25 +347,27 @@ static int flic_decode_frame(AVCodecContext *avctx,
|
|||||||
stream_ptr++;
|
stream_ptr++;
|
||||||
pixel_countdown = s->avctx->width;
|
pixel_countdown = s->avctx->width;
|
||||||
while (pixel_countdown > 0) {
|
while (pixel_countdown > 0) {
|
||||||
byte_run = buf[stream_ptr++];
|
byte_run = (signed char)(buf[stream_ptr++]);
|
||||||
if (byte_run > 0) {
|
if (byte_run > 0) {
|
||||||
palette_idx1 = buf[stream_ptr++];
|
palette_idx1 = buf[stream_ptr++];
|
||||||
|
CHECK_PIXEL_PTR(byte_run);
|
||||||
for (j = 0; j < byte_run; j++) {
|
for (j = 0; j < byte_run; j++) {
|
||||||
pixels[pixel_ptr++] = palette_idx1;
|
pixels[pixel_ptr++] = palette_idx1;
|
||||||
pixel_countdown--;
|
pixel_countdown--;
|
||||||
if (pixel_countdown < 0)
|
if (pixel_countdown < 0)
|
||||||
av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n",
|
av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n",
|
||||||
pixel_countdown);
|
pixel_countdown, lines);
|
||||||
}
|
}
|
||||||
} else { /* copy bytes if byte_run < 0 */
|
} else { /* copy bytes if byte_run < 0 */
|
||||||
byte_run = -byte_run;
|
byte_run = -byte_run;
|
||||||
|
CHECK_PIXEL_PTR(byte_run);
|
||||||
for (j = 0; j < byte_run; j++) {
|
for (j = 0; j < byte_run; j++) {
|
||||||
palette_idx1 = buf[stream_ptr++];
|
palette_idx1 = buf[stream_ptr++];
|
||||||
pixels[pixel_ptr++] = palette_idx1;
|
pixels[pixel_ptr++] = palette_idx1;
|
||||||
pixel_countdown--;
|
pixel_countdown--;
|
||||||
if (pixel_countdown < 0)
|
if (pixel_countdown < 0)
|
||||||
av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n",
|
av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n",
|
||||||
pixel_countdown);
|
pixel_countdown, lines);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -362,9 +413,8 @@ static int flic_decode_frame(AVCodecContext *avctx,
|
|||||||
"and final chunk ptr = %d\n", buf_size, stream_ptr);
|
"and final chunk ptr = %d\n", buf_size, stream_ptr);
|
||||||
|
|
||||||
/* make the palette available on the way out */
|
/* make the palette available on the way out */
|
||||||
// if (s->new_palette) {
|
memcpy(s->frame.data[1], s->palette, AVPALETTE_SIZE);
|
||||||
if (1) {
|
if (s->new_palette) {
|
||||||
memcpy(s->frame.data[1], s->palette, AVPALETTE_SIZE);
|
|
||||||
s->frame.palette_has_changed = 1;
|
s->frame.palette_has_changed = 1;
|
||||||
s->new_palette = 0;
|
s->new_palette = 0;
|
||||||
}
|
}
|
||||||
@@ -375,7 +425,308 @@ static int flic_decode_frame(AVCodecContext *avctx,
|
|||||||
return buf_size;
|
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;
|
FlicDecodeContext *s = avctx->priv_data;
|
||||||
|
|
||||||
@@ -395,5 +746,9 @@ AVCodec flic_decoder = {
|
|||||||
flic_decode_end,
|
flic_decode_end,
|
||||||
flic_decode_frame,
|
flic_decode_frame,
|
||||||
CODEC_CAP_DR1,
|
CODEC_CAP_DR1,
|
||||||
NULL
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
.long_name = NULL_IF_CONFIG_SMALL("Autodesk Animator Flic video"),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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 <roine at users sf net>
|
||||||
|
* @author Konstantin Shishkov
|
||||||
|
*
|
||||||
|
* Codec algorithm for version 0 is taken from Transcode <www.transcoding.org>
|
||||||
|
*
|
||||||
|
* 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; y<avctx->height/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; x<avctx->width; 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; y<avctx->height; 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"),
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user