Commit a0c5917f authored by Diego Biurrun's avatar Diego Biurrun

Drop Snow codec

Snow is a toy codec with no real-world use and horrible code.
parent 6b8d8880
......@@ -123,7 +123,6 @@ Component options:
--enable-x11grab enable X11 grabbing [no]
--disable-network disable network support [no]
--disable-dct disable DCT code
--disable-dwt disable DWT code
--disable-lsp disable LSP code
--disable-lzo disable LZO decoder code
--disable-mdct disable MDCT code
......@@ -1023,7 +1022,6 @@ CONFIG_LIST="
bzlib
dct
doc
dwt
dxva2
fft
frei0r
......@@ -1559,8 +1557,6 @@ rv30_decoder_select="error_resilience golomb h264chroma h264pred h264qpel mpegvi
rv40_decoder_select="error_resilience golomb h264chroma h264pred h264qpel mpegvideo"
shorten_decoder_select="golomb"
sipr_decoder_select="lsp"
snow_decoder_select="dwt rangecoder"
snow_encoder_select="aandcttables dwt error_resilience mpegvideoenc rangecoder"
svq1_decoder_select="error_resilience mpegvideo"
svq1_encoder_select="aandcttables error_resilience mpegvideoenc"
svq3_decoder_select="error_resilience golomb h264chroma h264dsp h264pred h264qpel mpegvideo"
......@@ -1934,8 +1930,6 @@ for n in $COMPONENT_LIST; do
eval ${n}_if_any="\$$v"
done
disable snow_decoder snow_encoder
enable $ARCH_EXT_LIST
die_unknown(){
......
......@@ -606,8 +606,6 @@ following image formats are supported:
@item Smacker video @tab @tab X
@tab Video encoding used in Smacker.
@item SMPTE VC-1 @tab @tab X
@item Snow @tab X @tab X
@tab experimental wavelet codec (fourcc: SNOW)
@item Sony PlayStation MDEC (Motion DECoder) @tab @tab X
@item Sorenson Vector Quantizer 1 @tab X @tab X
@tab fourcc: SVQ1
......
......@@ -109,7 +109,6 @@ PFD[32] would for example be signed 32 bit little-endian IEEE float
@item RV20 @tab RealVideo 2.0
@item RV30 @tab RealVideo 3.0
@item RV40 @tab RealVideo 4.0
@item SNOW @tab FFmpeg Snow
@item SVQ1 @tab Sorenson Video 1
@item SVQ3 @tab Sorenson Video 3
@item theo @tab Xiph Theora
......
=============================================
Snow Video Codec Specification Draft 20080110
=============================================
Introduction:
=============
This specification describes the Snow bitstream syntax and semantics as
well as the formal Snow decoding process.
The decoding process is described precisely and any compliant decoder
MUST produce the exact same output for a spec-conformant Snow stream.
For encoding, though, any process which generates a stream compliant to
the syntactical and semantic requirements and which is decodable by
the process described in this spec shall be considered a conformant
Snow encoder.
Definitions:
============
MUST the specific part must be done to conform to this standard
SHOULD it is recommended to be done that way, but not strictly required
ilog2(x) is the rounded down logarithm of x with basis 2
ilog2(0) = 0
Type definitions:
=================
b 1-bit range coded
u unsigned scalar value range coded
s signed scalar value range coded
Bitstream syntax:
=================
frame:
header
prediction
residual
header:
keyframe b MID_STATE
if(keyframe || always_reset)
reset_contexts
if(keyframe){
version u header_state
always_reset b header_state
temporal_decomposition_type u header_state
temporal_decomposition_count u header_state
spatial_decomposition_count u header_state
colorspace_type u header_state
chroma_h_shift u header_state
chroma_v_shift u header_state
spatial_scalability b header_state
max_ref_frames-1 u header_state
qlogs
}
if(!keyframe){
update_mc b header_state
if(update_mc){
for(plane=0; plane<2; plane++){
diag_mc b header_state
htaps/2-1 u header_state
for(i= p->htaps/2; i; i--)
|hcoeff[i]| u header_state
}
}
update_qlogs b header_state
if(update_qlogs){
spatial_decomposition_count u header_state
qlogs
}
}
spatial_decomposition_type s header_state
qlog s header_state
mv_scale s header_state
qbias s header_state
block_max_depth s header_state
qlogs:
for(plane=0; plane<2; plane++){
quant_table[plane][0][0] s header_state
for(level=0; level < spatial_decomposition_count; level++){
quant_table[plane][level][1]s header_state
quant_table[plane][level][3]s header_state
}
}
reset_contexts
*_state[*]= MID_STATE
prediction:
for(y=0; y<block_count_vertical; y++)
for(x=0; x<block_count_horizontal; x++)
block(0)
block(level):
mvx_diff=mvy_diff=y_diff=cb_diff=cr_diff=0
if(keyframe){
intra=1
}else{
if(level!=max_block_depth){
s_context= 2*left->level + 2*top->level + topleft->level + topright->level
leaf b block_state[4 + s_context]
}
if(level==max_block_depth || leaf){
intra b block_state[1 + left->intra + top->intra]
if(intra){
y_diff s block_state[32]
cb_diff s block_state[64]
cr_diff s block_state[96]
}else{
ref_context= ilog2(2*left->ref) + ilog2(2*top->ref)
if(ref_frames > 1)
ref u block_state[128 + 1024 + 32*ref_context]
mx_context= ilog2(2*abs(left->mx - top->mx))
my_context= ilog2(2*abs(left->my - top->my))
mvx_diff s block_state[128 + 32*(mx_context + 16*!!ref)]
mvy_diff s block_state[128 + 32*(my_context + 16*!!ref)]
}
}else{
block(level+1)
block(level+1)
block(level+1)
block(level+1)
}
}
residual:
residual2(luma)
residual2(chroma_cr)
residual2(chroma_cb)
residual2:
for(level=0; level<spatial_decomposition_count; level++){
if(level==0)
subband(LL, 0)
subband(HL, level)
subband(LH, level)
subband(HH, level)
}
subband:
FIXME
Tag description:
----------------
version
0
this MUST NOT change within a bitstream
always_reset
if 1 then the range coder contexts will be reset after each frame
temporal_decomposition_type
0
temporal_decomposition_count
0
spatial_decomposition_count
FIXME
colorspace_type
0
this MUST NOT change within a bitstream
chroma_h_shift
log2(luma.width / chroma.width)
this MUST NOT change within a bitstream
chroma_v_shift
log2(luma.height / chroma.height)
this MUST NOT change within a bitstream
spatial_scalability
0
max_ref_frames
maximum number of reference frames
this MUST NOT change within a bitstream
update_mc
indicates that motion compensation filter parameters are stored in the
header
diag_mc
flag to enable faster diagonal interpolation
this SHOULD be 1 unless it turns out to be covered by a valid patent
htaps
number of half pel interpolation filter taps, MUST be even, >0 and <10
hcoeff
half pel interpolation filter coefficients, hcoeff[0] are the 2 middle
coefficients [1] are the next outer ones and so on, resulting in a filter
like: ...eff[2], hcoeff[1], hcoeff[0], hcoeff[0], hcoeff[1], hcoeff[2] ...
the sign of the coefficients is not explicitly stored but alternates
after each coeff and coeff[0] is positive, so ...,+,-,+,-,+,+,-,+,-,+,...
hcoeff[0] is not explicitly stored but found by subtracting the sum
of all stored coefficients with signs from 32
hcoeff[0]= 32 - hcoeff[1] - hcoeff[2] - ...
a good choice for hcoeff and htaps is
htaps= 6
hcoeff={40,-10,2}
an alternative which requires more computations at both encoder and
decoder side and may or may not be better is
htaps= 8
hcoeff={42,-14,6,-2}
ref_frames
minimum of the number of available reference frames and max_ref_frames
for example the first frame after a key frame always has ref_frames=1
spatial_decomposition_type
wavelet type
0 is a 9/7 symmetric compact integer wavelet
1 is a 5/3 symmetric compact integer wavelet
others are reserved
stored as delta from last, last is reset to 0 if always_reset || keyframe
qlog
quality (logarthmic quantizer scale)
stored as delta from last, last is reset to 0 if always_reset || keyframe
mv_scale
stored as delta from last, last is reset to 0 if always_reset || keyframe
FIXME check that everything works fine if this changes between frames
qbias
dequantization bias
stored as delta from last, last is reset to 0 if always_reset || keyframe
block_max_depth
maximum depth of the block tree
stored as delta from last, last is reset to 0 if always_reset || keyframe
quant_table
quantiztation table
Highlevel bitstream structure:
=============================
--------------------------------------------
| Header |
--------------------------------------------
| ------------------------------------ |
| | Block0 | |
| | split? | |
| | yes no | |
| | ......... intra? | |
| | : Block01 : yes no | |
| | : Block02 : ....... .......... | |
| | : Block03 : : y DC : : ref index: | |
| | : Block04 : : cb DC : : motion x : | |
| | ......... : cr DC : : motion y : | |
| | ....... .......... | |
| ------------------------------------ |
| ------------------------------------ |
| | Block1 | |
| ... |
--------------------------------------------
| ------------ ------------ ------------ |
|| Y subbands | | Cb subbands| | Cr subbands||
|| --- --- | | --- --- | | --- --- ||
|| |LL0||HL0| | | |LL0||HL0| | | |LL0||HL0| ||
|| --- --- | | --- --- | | --- --- ||
|| --- --- | | --- --- | | --- --- ||
|| |LH0||HH0| | | |LH0||HH0| | | |LH0||HH0| ||
|| --- --- | | --- --- | | --- --- ||
|| --- --- | | --- --- | | --- --- ||
|| |HL1||LH1| | | |HL1||LH1| | | |HL1||LH1| ||
|| --- --- | | --- --- | | --- --- ||
|| --- --- | | --- --- | | --- --- ||
|| |HH1||HL2| | | |HH1||HL2| | | |HH1||HL2| ||
|| ... | | ... | | ... ||
| ------------ ------------ ------------ |
--------------------------------------------
Decoding process:
=================
------------
| |
| Subbands |
------------ | |
| | ------------
| Intra DC | |
| | LL0 subband prediction
------------ |
\ Dequantizaton
------------------- \ |
| Reference frames | \ IDWT
| ------- ------- | Motion \ |
||Frame 0| |Frame 1|| Compensation . OBMC v -------
| ------- ------- | --------------. \------> + --->|Frame n|-->output
| ------- ------- | -------
||Frame 2| |Frame 3||<----------------------------------/
| ... |
-------------------
Range Coder:
============
Binary Range Coder:
-------------------
The implemented range coder is an adapted version based upon "Range encoding:
an algorithm for removing redundancy from a digitised message." by G. N. N.
Martin.
The symbols encoded by the Snow range coder are bits (0|1). The
associated probabilities are not fix but change depending on the symbol mix
seen so far.
bit seen | new state
---------+-----------------------------------------------
0 | 256 - state_transition_table[256 - old_state];
1 | state_transition_table[ old_state];
state_transition_table = {
0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 23, 24, 25, 26, 27,
28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 37, 38, 39, 40, 41, 42,
43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57,
58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
74, 75, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
89, 90, 91, 92, 93, 94, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103,
104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 114, 115, 116, 117, 118,
119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 133,
134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
150, 151, 152, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
165, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, 175, 176, 177, 178, 179,
180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 190, 191, 192, 194, 194,
195, 196, 197, 198, 199, 200, 201, 202, 202, 204, 205, 206, 207, 208, 209, 209,
210, 211, 212, 213, 215, 215, 216, 217, 218, 219, 220, 220, 222, 223, 224, 225,
226, 227, 227, 229, 229, 230, 231, 232, 234, 234, 235, 236, 237, 238, 239, 240,
241, 242, 243, 244, 245, 246, 247, 248, 248, 0, 0, 0, 0, 0, 0, 0};
FIXME
Range Coding of integers:
-------------------------
FIXME
Neighboring Blocks:
===================
left and top are set to the respective blocks unless they are outside of
the image in which case they are set to the Null block
top-left is set to the top left block unless it is outside of the image in
which case it is set to the left block
if this block has no larger parent block or it is at the left side of its
parent block and the top right block is not outside of the image then the
top right block is used for top-right else the top-left block is used
Null block
y,cb,cr are 128
level, ref, mx and my are 0
Motion Vector Prediction:
=========================
1. the motion vectors of all the neighboring blocks are scaled to
compensate for the difference of reference frames
scaled_mv= (mv * (256 * (current_reference+1) / (mv.reference+1)) + 128)>>8
2. the median of the scaled left, top and top-right vectors is used as
motion vector prediction
3. the used motion vector is the sum of the predictor and
(mvx_diff, mvy_diff)*mv_scale
Intra DC Predicton:
======================
the luma and chroma values of the left block are used as predictors
the used luma and chroma is the sum of the predictor and y_diff, cb_diff, cr_diff
to reverse this in the decoder apply the following:
block[y][x].dc[0] = block[y][x-1].dc[0] + y_diff;
block[y][x].dc[1] = block[y][x-1].dc[1] + cb_diff;
block[y][x].dc[2] = block[y][x-1].dc[2] + cr_diff;
block[*][-1].dc[*]= 128;
Motion Compensation:
====================
Halfpel interpolation:
----------------------
halfpel interpolation is done by convolution with the halfpel filter stored
in the header:
horizontal halfpel samples are found by
H1[y][x] = hcoeff[0]*(F[y][x ] + F[y][x+1])
+ hcoeff[1]*(F[y][x-1] + F[y][x+2])
+ hcoeff[2]*(F[y][x-2] + F[y][x+3])
+ ...
h1[y][x] = (H1[y][x] + 32)>>6;
vertical halfpel samples are found by
H2[y][x] = hcoeff[0]*(F[y ][x] + F[y+1][x])
+ hcoeff[1]*(F[y-1][x] + F[y+2][x])
+ ...
h2[y][x] = (H2[y][x] + 32)>>6;
vertical+horizontal halfpel samples are found by
H3[y][x] = hcoeff[0]*(H2[y][x ] + H2[y][x+1])
+ hcoeff[1]*(H2[y][x-1] + H2[y][x+2])
+ ...
H3[y][x] = hcoeff[0]*(H1[y ][x] + H1[y+1][x])
+ hcoeff[1]*(H1[y+1][x] + H1[y+2][x])
+ ...
h3[y][x] = (H3[y][x] + 2048)>>12;
F H1 F
| | |
| | |
| | |
F H1 F
| | |
| | |
| | |
F-------F-------F-> H1<-F-------F-------F
v v v
H2 H3 H2
^ ^ ^
F-------F-------F-> H1<-F-------F-------F
| | |
| | |
| | |
F H1 F
| | |
| | |
| | |
F H1 F
unavailable fullpel samples (outside the picture for example) shall be equal
to the closest available fullpel sample
Smaller pel interpolation:
--------------------------
if diag_mc is set then points which lie on a line between 2 vertically,
horiziontally or diagonally adjacent halfpel points shall be interpolated
linearls with rounding to nearest and halfway values rounded up.
points which lie on 2 diagonals at the same time should only use the one
diagonal not containing the fullpel point
F-->O---q---O<--h1->O---q---O<--F
v \ / v \ / v
O O O O O O O
| / | \ |
q q q q q
| / | \ |
O O O O O O O
^ / \ ^ / \ ^
h2-->O---q---O<--h3->O---q---O<--h2
v \ / v \ / v
O O O O O O O
| \ | / |
q q q q q
| \ | / |
O O O O O O O
^ / \ ^ / \ ^
F-->O---q---O<--h1->O---q---O<--F
the remaining points shall be bilinearly interpolated from the
up to 4 surrounding halfpel and fullpel points, again rounding should be to
nearest and halfway values rounded up
compliant Snow decoders MUST support 1-1/8 pel luma and 1/2-1/16 pel chroma
interpolation at least
Overlapped block motion compensation:
-------------------------------------
FIXME
LL band prediction:
===================
Each sample in the LL0 subband is predicted by the median of the left, top and
left+top-topleft samples, samples outside the subband shall be considered to
be 0. To reverse this prediction in the decoder apply the following.
for(y=0; y<height; y++){
for(x=0; x<width; x++){
sample[y][x] += median(sample[y-1][x],
sample[y][x-1],
sample[y-1][x]+sample[y][x-1]-sample[y-1][x-1]);
}
}
sample[-1][*]=sample[*][-1]= 0;
width,height here are the width and height of the LL0 subband not of the final
video
Dequantizaton:
==============
FIXME
Wavelet Transform:
==================
Snow supports 2 wavelet transforms, the symmetric biorthogonal 5/3 integer
transform and a integer approximation of the symmetric biorthogonal 9/7
daubechies wavelet.
2D IDWT (inverse discrete wavelet transform)
--------------------------------------------
The 2D IDWT applies a 2D filter recursively, each time combining the
4 lowest frequency subbands into a single subband until only 1 subband
remains.
The 2D filter is done by first applying a 1D filter in the vertical direction
and then applying it in the horizontal one.
--------------- --------------- --------------- ---------------
|LL0|HL0| | | | | | | | | | | |
|---+---| HL1 | | L0|H0 | HL1 | | LL1 | HL1 | | | |
|LH0|HH0| | | | | | | | | | | |
|-------+-------|->|-------+-------|->|-------+-------|->| L1 | H1 |->...
| | | | | | | | | | | |
| LH1 | HH1 | | LH1 | HH1 | | LH1 | HH1 | | | |
| | | | | | | | | | | |
--------------- --------------- --------------- ---------------
1D Filter:
----------
1. interleave the samples of the low and high frequency subbands like
s={L0, H0, L1, H1, L2, H2, L3, H3, ... }
note, this can end with a L or a H, the number of elements shall be w
s[-1] shall be considered equivalent to s[1 ]
s[w ] shall be considered equivalent to s[w-2]
2. perform the lifting steps in order as described below
5/3 Integer filter:
1. s[i] -= (s[i-1] + s[i+1] + 2)>>2; for all even i < w
2. s[i] += (s[i-1] + s[i+1] )>>1; for all odd i < w
\ | /|\ | /|\ | /|\ | /|\
\|/ | \|/ | \|/ | \|/ |
+ | + | + | + | -1/4
/|\ | /|\ | /|\ | /|\ |
/ | \|/ | \|/ | \|/ | \|/
| + | + | + | + +1/2
Snow's 9/7 Integer filter:
1. s[i] -= (3*(s[i-1] + s[i+1]) + 4)>>3; for all even i < w
2. s[i] -= s[i-1] + s[i+1] ; for all odd i < w
3. s[i] += ( s[i-1] + s[i+1] + 4*s[i] + 8)>>4; for all even i < w
4. s[i] += (3*(s[i-1] + s[i+1]) )>>1; for all odd i < w
\ | /|\ | /|\ | /|\ | /|\
\|/ | \|/ | \|/ | \|/ |
+ | + | + | + | -3/8
/|\ | /|\ | /|\ | /|\ |
/ | \|/ | \|/ | \|/ | \|/
(| + (| + (| + (| + -1
\ + /|\ + /|\ + /|\ + /|\ +1/4
\|/ | \|/ | \|/ | \|/ |
+ | + | + | + | +1/16
/|\ | /|\ | /|\ | /|\ |
/ | \|/ | \|/ | \|/ | \|/
| + | + | + | + +3/2
optimization tips:
following are exactly identical
(3a)>>1 == a + (a>>1)
(a + 4b + 8)>>4 == ((a>>2) + b + 2)>>2
16bit implementation note:
The IDWT can be implemented with 16bits, but this requires some care to
prevent overflows, the following list, lists the minimum number of bits needed
for some terms
1. lifting step
A= s[i-1] + s[i+1] 16bit
3*A + 4 18bit
A + (A>>1) + 2 17bit
3. lifting step
s[i-1] + s[i+1] 17bit
4. lifiting step
3*(s[i-1] + s[i+1]) 17bit
TODO:
=====
Important:
finetune initial contexts
flip wavelet?
try to use the wavelet transformed predicted image (motion compensated image) as context for coding the residual coefficients
try the MV length as context for coding the residual coefficients
use extradata for stuff which is in the keyframes now?
the MV median predictor is patented IIRC
implement per picture halfpel interpolation
try different range coder state transition tables for different contexts
Not Important:
compare the 6 tap and 8 tap hpel filters (psnr/bitrate and subjective quality)
spatial_scalability b vs u (!= 0 breaks syntax anyway so we can add a u later)
Credits:
========
Michael Niedermayer
Loren Merritt
Copyright:
==========
GPL + GFDL + whatever is needed to make this a RFC
......@@ -37,7 +37,6 @@ OBJS = allcodecs.o \
OBJS-$(CONFIG_AANDCTTABLES) += aandcttab.o
OBJS-$(CONFIG_AC3DSP) += ac3dsp.o
OBJS-$(CONFIG_DCT) += dct.o dct32_fixed.o dct32_float.o
OBJS-$(CONFIG_DWT) += dwt.o
OBJS-$(CONFIG_DXVA2) += dxva2.o
OBJS-$(CONFIG_ENCODERS) += faandct.o jfdctfst.o jfdctint.o
OBJS-$(CONFIG_ERROR_RESILIENCE) += error_resilience.o
......@@ -335,9 +334,6 @@ OBJS-$(CONFIG_SIPR_DECODER) += sipr.o acelp_pitch_delay.o \
OBJS-$(CONFIG_SMACKAUD_DECODER) += smacker.o
OBJS-$(CONFIG_SMACKER_DECODER) += smacker.o
OBJS-$(CONFIG_SMC_DECODER) += smc.o
OBJS-$(CONFIG_SNOW_DECODER) += snowdec.o snow.o
OBJS-$(CONFIG_SNOW_ENCODER) += snowenc.o snow.o \
h263.o ituh263enc.o
OBJS-$(CONFIG_SOL_DPCM_DECODER) += dpcm.o
OBJS-$(CONFIG_SP5X_DECODER) += sp5xdec.o mjpegdec.o mjpeg.o
OBJS-$(CONFIG_SRT_DECODER) += srtdec.o ass.o
......
......@@ -212,7 +212,6 @@ void avcodec_register_all(void)
REGISTER_ENCDEC (SGI, sgi);
REGISTER_DECODER(SMACKER, smacker);
REGISTER_DECODER(SMC, smc);
REGISTER_ENCDEC (SNOW, snow);
REGISTER_DECODER(SP5X, sp5x);
REGISTER_ENCDEC (SUNRAST, sunrast);
REGISTER_ENCDEC (SVQ1, svq1);
......
......@@ -152,7 +152,9 @@ enum AVCodecID {
AV_CODEC_ID_MSZH,
AV_CODEC_ID_ZLIB,
AV_CODEC_ID_QTRLE,
#if FF_API_SNOW
AV_CODEC_ID_SNOW,
#endif
AV_CODEC_ID_TSCC,
AV_CODEC_ID_ULTI,
AV_CODEC_ID_QDRAW,
......@@ -518,7 +520,9 @@ enum Motion_Est_ID {
ME_X1, ///< reserved for experiments
ME_HEX, ///< hexagon based search
ME_UMH, ///< uneven multi-hexagon search
#if FF_API_SNOW
ME_ITER, ///< iterative search
#endif
ME_TESA, ///< transformed exhaustive search algorithm
};
......@@ -1535,7 +1539,7 @@ typedef struct AVCodecContext {
/**
* Motion estimation algorithm used for video coding.
* 1 (zero), 2 (full), 3 (log), 4 (phods), 5 (epzs), 6 (x1), 7 (hex),
* 8 (umh), 9 (iter), 10 (tesa) [7, 8, 10 are x264 specific, 9 is snow specific]
* 8 (umh), 10 (tesa) [7, 8, 10 are x264 specific]
* - encoding: MUST be set by user.
* - decoding: unused
*/
......@@ -1758,8 +1762,10 @@ typedef struct AVCodecContext {
#define FF_CMP_VSAD 8
#define FF_CMP_VSSE 9
#define FF_CMP_NSSE 10
#if FF_API_SNOW
#define FF_CMP_W53 11
#define FF_CMP_W97 12
#endif
#define FF_CMP_DCTMAX 13
#define FF_CMP_DCT264 14
#define FF_CMP_CHROMA 256
......
......@@ -418,13 +418,6 @@ static const AVCodecDescriptor codec_descriptors[] = {
.long_name = NULL_IF_CONFIG_SMALL("QuickTime Animation (RLE) video"),
.props = AV_CODEC_PROP_LOSSLESS,
},
{
.id = AV_CODEC_ID_SNOW,
.type = AVMEDIA_TYPE_VIDEO,
.name = "snow",
.long_name = NULL_IF_CONFIG_SMALL("Snow"),
.props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS,
},
{
.id = AV_CODEC_ID_TSCC,
.type = AVMEDIA_TYPE_VIDEO,
......
......@@ -1784,14 +1784,6 @@ void ff_set_cmp(DSPContext* c, me_cmp_func *cmp, int type){
case FF_CMP_NSSE:
cmp[i]= c->nsse[i];
break;
#if CONFIG_DWT
case FF_CMP_W53:
cmp[i]= c->w53[i];
break;
case FF_CMP_W97:
cmp[i]= c->w97[i];
break;
#endif
default:
av_log(NULL, AV_LOG_ERROR,"internal error in cmp function selection\n");
}
......@@ -2820,9 +2812,6 @@ av_cold void ff_dsputil_init(DSPContext* c, AVCodecContext *avctx)
c->vsse[5]= vsse_intra8_c;
c->nsse[0]= nsse16_c;
c->nsse[1]= nsse8_c;
#if CONFIG_DWT
ff_dsputil_init_dwt(c);
#endif
c->ssd_int8_vs_int16 = ssd_int8_vs_int16_c;
......
......@@ -231,8 +231,6 @@ typedef struct DSPContext {
me_cmp_func vsad[6];
me_cmp_func vsse[6];
me_cmp_func nsse[6];
me_cmp_func w53[6];
me_cmp_func w97[6];
me_cmp_func dct_max[6];
me_cmp_func dct264_sad[6];
......@@ -543,10 +541,6 @@ static inline int get_penalty_factor(int lambda, int lambda2, int type){
return lambda>>FF_LAMBDA_SHIFT;
case FF_CMP_DCT:
return (3*lambda)>>(FF_LAMBDA_SHIFT+1);
case FF_CMP_W53:
return (4*lambda)>>(FF_LAMBDA_SHIFT);
case FF_CMP_W97:
return (2*lambda)>>(FF_LAMBDA_SHIFT);
case FF_CMP_SATD:
case FF_CMP_DCT264:
return (2*lambda)>>FF_LAMBDA_SHIFT;
......@@ -568,8 +562,6 @@ void ff_dsputil_init_ppc(DSPContext* c, AVCodecContext *avctx);
void ff_dsputil_init_sh4(DSPContext* c, AVCodecContext *avctx);
void ff_dsputil_init_vis(DSPContext* c, AVCodecContext *avctx);
void ff_dsputil_init_dwt(DSPContext *c);
#if (ARCH_ARM && HAVE_NEON) || ARCH_PPC || HAVE_MMX
# define STRIDE_ALIGN 16
#else
......
/*
* Copyright (C) 2004-2010 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of Libav.
*
* Libav 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.
*
* Libav 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 Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/attributes.h"
#include "libavutil/common.h"
#include "dsputil.h"
#include "dwt.h"
int ff_slice_buffer_init(slice_buffer *buf, int line_count,
int max_allocated_lines, int line_width,
IDWTELEM *base_buffer)
{
int i;
buf->base_buffer = base_buffer;
buf->line_count = line_count;
buf->line_width = line_width;
buf->data_count = max_allocated_lines;
buf->line = av_mallocz(sizeof(IDWTELEM *) * line_count);
if (!buf->line)
return AVERROR(ENOMEM);
buf->data_stack = av_malloc(sizeof(IDWTELEM *) * max_allocated_lines);
if (!buf->data_stack) {
av_free(buf->line);
return AVERROR(ENOMEM);
}
for (i = 0; i < max_allocated_lines; i++) {
buf->data_stack[i] = av_malloc(sizeof(IDWTELEM) * line_width);
if (!buf->data_stack[i]) {
for (i--; i >=0; i--)
av_free(buf->data_stack[i]);
av_free(buf->data_stack);
av_free(buf->line);
return AVERROR(ENOMEM);
}
}
buf->data_stack_top = max_allocated_lines - 1;
return 0;
}
IDWTELEM *ff_slice_buffer_load_line(slice_buffer *buf, int line)
{
IDWTELEM *buffer;
assert(buf->data_stack_top >= 0);
// assert(!buf->line[line]);
if (buf->line[line])
return buf->line[line];
buffer = buf->data_stack[buf->data_stack_top];
buf->data_stack_top--;
buf->line[line] = buffer;
return buffer;
}
void ff_slice_buffer_release(slice_buffer *buf, int line)
{
IDWTELEM *buffer;
assert(line >= 0 && line < buf->line_count);
assert(buf->line[line]);
buffer = buf->line[line];
buf->data_stack_top++;
buf->data_stack[buf->data_stack_top] = buffer;
buf->line[line] = NULL;
}
void ff_slice_buffer_flush(slice_buffer *buf)
{
int i;
for (i = 0; i < buf->line_count; i++)
if (buf->line[i])
ff_slice_buffer_release(buf, i);
}
void ff_slice_buffer_destroy(slice_buffer *buf)
{
int i;
ff_slice_buffer_flush(buf);
for (i = buf->data_count - 1; i >= 0; i--)
av_freep(&buf->data_stack[i]);
av_freep(&buf->data_stack);
av_freep(&buf->line);
}
static inline int mirror(int v, int m)
{
while ((unsigned)v > (unsigned)m) {
v = -v;
if (v < 0)
v += 2 * m;
}
return v;
}
static av_always_inline void lift(DWTELEM *dst, DWTELEM *src, DWTELEM *ref,
int dst_step, int src_step, int ref_step,
int width, int mul, int add, int shift,
int highpass, int inverse)
{
const int mirror_left = !highpass;
const int mirror_right = (width & 1) ^ highpass;
const int w = (width >> 1) - 1 + (highpass & width);
int i;
#define LIFT(src, ref, inv) ((src) + ((inv) ? -(ref) : +(ref)))
if (mirror_left) {
dst[0] = LIFT(src[0], ((mul * 2 * ref[0] + add) >> shift), inverse);
dst += dst_step;
src += src_step;
}
for (i = 0; i < w; i++)
dst[i * dst_step] = LIFT(src[i * src_step],
((mul * (ref[i * ref_step] +
ref[(i + 1) * ref_step]) +
add) >> shift),
inverse);
if (mirror_right)
dst[w * dst_step] = LIFT(src[w * src_step],
((mul * 2 * ref[w * ref_step] + add) >> shift),
inverse);
}
static av_always_inline void liftS(DWTELEM *dst, DWTELEM *src, DWTELEM *ref,
int dst_step, int src_step, int ref_step,
int width, int mul, int add, int shift,
int highpass, int inverse)
{
const int mirror_left = !highpass;
const int mirror_right = (width & 1) ^ highpass;
const int w = (width >> 1) - 1 + (highpass & width);
int i;
assert(shift == 4);
#define LIFTS(src, ref, inv) \
((inv) ? (src) + (((ref) + 4 * (src)) >> shift) \
: -((-16 * (src) + (ref) + add / \
4 + 1 + (5 << 25)) / (5 * 4) - (1 << 23)))
if (mirror_left) {
dst[0] = LIFTS(src[0], mul * 2 * ref[0] + add, inverse);
dst += dst_step;
src += src_step;
}
for (i = 0; i < w; i++)
dst[i * dst_step] = LIFTS(src[i * src_step],
mul * (ref[i * ref_step] +
ref[(i + 1) * ref_step]) + add,
inverse);
if (mirror_right)
dst[w * dst_step] = LIFTS(src[w * src_step],
mul * 2 * ref[w * ref_step] + add,
inverse);
}
static void horizontal_decompose53i(DWTELEM *b, DWTELEM *temp, int width)
{
const int width2 = width >> 1;
int x;
const int w2 = (width + 1) >> 1;
for (x = 0; x < width2; x++) {
temp[x] = b[2 * x];
temp[x + w2] = b[2 * x + 1];
}
if (width & 1)
temp[x] = b[2 * x];
lift(b + w2, temp + w2, temp, 1, 1, 1, width, -1, 0, 1, 1, 0);
lift(b, temp, b + w2, 1, 1, 1, width, 1, 2, 2, 0, 0);
}
static void vertical_decompose53iH0(DWTELEM *b0, DWTELEM *b1, DWTELEM *b2,
int width)
{
int i;
for (i = 0; i < width; i++)
b1[i] -= (b0[i] + b2[i]) >> 1;
}
static void vertical_decompose53iL0(DWTELEM *b0, DWTELEM *b1, DWTELEM *b2,
int width)
{
int i;
for (i = 0; i < width; i++)
b1[i] += (b0[i] + b2[i] + 2) >> 2;
}
static void spatial_decompose53i(DWTELEM *buffer, DWTELEM *temp,
int width, int height, int stride)
{
int y;
DWTELEM *b0 = buffer + mirror(-2 - 1, height - 1) * stride;
DWTELEM *b1 = buffer + mirror(-2, height - 1) * stride;
for (y = -2; y < height; y += 2) {
DWTELEM *b2 = buffer + mirror(y + 1, height - 1) * stride;
DWTELEM *b3 = buffer + mirror(y + 2, height - 1) * stride;
if (y + 1 < (unsigned)height)
horizontal_decompose53i(b2, temp, width);
if (y + 2 < (unsigned)height)
horizontal_decompose53i(b3, temp, width);
if (y + 1 < (unsigned)height)
vertical_decompose53iH0(b1, b2, b3, width);
if (y + 0 < (unsigned)height)
vertical_decompose53iL0(b0, b1, b2, width);
b0 = b2;
b1 = b3;
}
}
static void horizontal_decompose97i(DWTELEM *b, DWTELEM *temp, int width)
{
const int w2 = (width + 1) >> 1;
lift(temp + w2, b + 1, b, 1, 2, 2, width, W_AM, W_AO, W_AS, 1, 1);
liftS(temp, b, temp + w2, 1, 2, 1, width, W_BM, W_BO, W_BS, 0, 0);
lift(b + w2, temp + w2, temp, 1, 1, 1, width, W_CM, W_CO, W_CS, 1, 0);
lift(b, temp, b + w2, 1, 1, 1, width, W_DM, W_DO, W_DS, 0, 0);
}
static void vertical_decompose97iH0(DWTELEM *b0, DWTELEM *b1, DWTELEM *b2,
int width)
{
int i;
for (i = 0; i < width; i++)
b1[i] -= (W_AM * (b0[i] + b2[i]) + W_AO) >> W_AS;
}
static void vertical_decompose97iH1(DWTELEM *b0, DWTELEM *b1, DWTELEM *b2,
int width)
{
int i;
for (i = 0; i < width; i++)
b1[i] += (W_CM * (b0[i] + b2[i]) + W_CO) >> W_CS;
}
static void vertical_decompose97iL0(DWTELEM *b0, DWTELEM *b1, DWTELEM *b2,
int width)
{
int i;
for (i = 0; i < width; i++)
b1[i] = (16 * 4 * b1[i] - 4 * (b0[i] + b2[i]) + W_BO * 5 + (5 << 27)) /
(5 * 16) - (1 << 23);
}
static void vertical_decompose97iL1(DWTELEM *b0, DWTELEM *b1, DWTELEM *b2,
int width)
{
int i;
for (i = 0; i < width; i++)
b1[i] += (W_DM * (b0[i] + b2[i]) + W_DO) >> W_DS;
}
static void spatial_decompose97i(DWTELEM *buffer, DWTELEM *temp,
int width, int height, int stride)
{
int y;
DWTELEM *b0 = buffer + mirror(-4 - 1, height - 1) * stride;
DWTELEM *b1 = buffer + mirror(-4, height - 1) * stride;
DWTELEM *b2 = buffer + mirror(-4 + 1, height - 1) * stride;
DWTELEM *b3 = buffer + mirror(-4 + 2, height - 1) * stride;
for (y = -4; y < height; y += 2) {
DWTELEM *b4 = buffer + mirror(y + 3, height - 1) * stride;
DWTELEM *b5 = buffer + mirror(y + 4, height - 1) * stride;
if (y + 3 < (unsigned)height)
horizontal_decompose97i(b4, temp, width);
if (y + 4 < (unsigned)height)
horizontal_decompose97i(b5, temp, width);
if (y + 3 < (unsigned)height)
vertical_decompose97iH0(b3, b4, b5, width);
if (y + 2 < (unsigned)height)
vertical_decompose97iL0(b2, b3, b4, width);
if (y + 1 < (unsigned)height)
vertical_decompose97iH1(b1, b2, b3, width);
if (y + 0 < (unsigned)height)
vertical_decompose97iL1(b0, b1, b2, width);
b0 = b2;
b1 = b3;
b2 = b4;
b3 = b5;
}
}
void ff_spatial_dwt(DWTELEM *buffer, DWTELEM *temp, int width, int height,
int stride, int type, int decomposition_count)
{
int level;
for (level = 0; level < decomposition_count; level++) {
switch (type) {
case DWT_97:
spatial_decompose97i(buffer, temp,
width >> level, height >> level,
stride << level);
break;
case DWT_53:
spatial_decompose53i(buffer, temp,
width >> level, height >> level,
stride << level);
break;
}
}
}
static void horizontal_compose53i(IDWTELEM *b, IDWTELEM *temp, int width)
{
const int width2 = width >> 1;
const int w2 = (width + 1) >> 1;
int x;
for (x = 0; x < width2; x++) {
temp[2 * x] = b[x];
temp[2 * x + 1] = b[x + w2];
}
if (width & 1)
temp[2 * x] = b[x];
b[0] = temp[0] - ((temp[1] + 1) >> 1);
for (x = 2; x < width - 1; x += 2) {
b[x] = temp[x] - ((temp[x - 1] + temp[x + 1] + 2) >> 2);
b[x - 1] = temp[x - 1] + ((b[x - 2] + b[x] + 1) >> 1);
}
if (width & 1) {
b[x] = temp[x] - ((temp[x - 1] + 1) >> 1);
b[x - 1] = temp[x - 1] + ((b[x - 2] + b[x] + 1) >> 1);
} else
b[x - 1] = temp[x - 1] + b[x - 2];
}
static void vertical_compose53iH0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
int width)
{
int i;
for (i = 0; i < width; i++)
b1[i] += (b0[i] + b2[i]) >> 1;
}
static void vertical_compose53iL0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
int width)
{
int i;
for (i = 0; i < width; i++)
b1[i] -= (b0[i] + b2[i] + 2) >> 2;
}
static void spatial_compose53i_buffered_init(DWTCompose *cs, slice_buffer *sb,
int height, int stride_line)
{
cs->b0 = slice_buffer_get_line(sb,
mirror(-1 - 1, height - 1) * stride_line);
cs->b1 = slice_buffer_get_line(sb, mirror(-1, height - 1) * stride_line);
cs->y = -1;
}
static void spatial_compose53i_init(DWTCompose *cs, IDWTELEM *buffer,
int height, int stride)
{
cs->b0 = buffer + mirror(-1 - 1, height - 1) * stride;
cs->b1 = buffer + mirror(-1, height - 1) * stride;
cs->y = -1;
}
static void spatial_compose53i_dy_buffered(DWTCompose *cs, slice_buffer *sb,
IDWTELEM *temp,
int width, int height,
int stride_line)
{
int y = cs->y;
IDWTELEM *b0 = cs->b0;
IDWTELEM *b1 = cs->b1;
IDWTELEM *b2 = slice_buffer_get_line(sb,
mirror(y + 1, height - 1) *
stride_line);
IDWTELEM *b3 = slice_buffer_get_line(sb,
mirror(y + 2, height - 1) *
stride_line);
if (y + 1 < (unsigned)height && y < (unsigned)height) {
int x;
for (x = 0; x < width; x++) {
b2[x] -= (b1[x] + b3[x] + 2) >> 2;
b1[x] += (b0[x] + b2[x]) >> 1;
}
} else {
if (y + 1 < (unsigned)height)
vertical_compose53iL0(b1, b2, b3, width);
if (y + 0 < (unsigned)height)
vertical_compose53iH0(b0, b1, b2, width);
}
if (y - 1 < (unsigned)height)
horizontal_compose53i(b0, temp, width);
if (y + 0 < (unsigned)height)
horizontal_compose53i(b1, temp, width);
cs->b0 = b2;
cs->b1 = b3;
cs->y += 2;
}
static void spatial_compose53i_dy(DWTCompose *cs, IDWTELEM *buffer,
IDWTELEM *temp, int width, int height,
int stride)
{
int y = cs->y;
IDWTELEM *b0 = cs->b0;
IDWTELEM *b1 = cs->b1;
IDWTELEM *b2 = buffer + mirror(y + 1, height - 1) * stride;
IDWTELEM *b3 = buffer + mirror(y + 2, height - 1) * stride;
if (y + 1 < (unsigned)height)
vertical_compose53iL0(b1, b2, b3, width);
if (y + 0 < (unsigned)height)
vertical_compose53iH0(b0, b1, b2, width);
if (y - 1 < (unsigned)height)
horizontal_compose53i(b0, temp, width);
if (y + 0 < (unsigned)height)
horizontal_compose53i(b1, temp, width);
cs->b0 = b2;
cs->b1 = b3;
cs->y += 2;
}
void ff_snow_horizontal_compose97i(IDWTELEM *b, IDWTELEM *temp, int width)
{
const int w2 = (width + 1) >> 1;
int x;
temp[0] = b[0] - ((3 * b[w2] + 2) >> 2);
for (x = 1; x < (width >> 1); x++) {
temp[2 * x] = b[x] - ((3 * (b[x + w2 - 1] + b[x + w2]) + 4) >> 3);
temp[2 * x - 1] = b[x + w2 - 1] - temp[2 * x - 2] - temp[2 * x];
}
if (width & 1) {
temp[2 * x] = b[x] - ((3 * b[x + w2 - 1] + 2) >> 2);
temp[2 * x - 1] = b[x + w2 - 1] - temp[2 * x - 2] - temp[2 * x];
} else
temp[2 * x - 1] = b[x + w2 - 1] - 2 * temp[2 * x - 2];
b[0] = temp[0] + ((2 * temp[0] + temp[1] + 4) >> 3);
for (x = 2; x < width - 1; x += 2) {
b[x] = temp[x] + ((4 * temp[x] + temp[x - 1] + temp[x + 1] + 8) >> 4);
b[x - 1] = temp[x - 1] + ((3 * (b[x - 2] + b[x])) >> 1);
}
if (width & 1) {
b[x] = temp[x] + ((2 * temp[x] + temp[x - 1] + 4) >> 3);
b[x - 1] = temp[x - 1] + ((3 * (b[x - 2] + b[x])) >> 1);
} else
b[x - 1] = temp[x - 1] + 3 * b[x - 2];
}
static void vertical_compose97iH0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
int width)
{
int i;
for (i = 0; i < width; i++)
b1[i] += (W_AM * (b0[i] + b2[i]) + W_AO) >> W_AS;
}
static void vertical_compose97iH1(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
int width)
{
int i;
for (i = 0; i < width; i++)
b1[i] -= (W_CM * (b0[i] + b2[i]) + W_CO) >> W_CS;
}
static void vertical_compose97iL0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
int width)
{
int i;
for (i = 0; i < width; i++)
b1[i] += (W_BM * (b0[i] + b2[i]) + 4 * b1[i] + W_BO) >> W_BS;
}
static void vertical_compose97iL1(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
int width)
{
int i;
for (i = 0; i < width; i++)
b1[i] -= (W_DM * (b0[i] + b2[i]) + W_DO) >> W_DS;
}
void ff_snow_vertical_compose97i(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
IDWTELEM *b3, IDWTELEM *b4, IDWTELEM *b5,
int width)
{
int i;
for (i = 0; i < width; i++) {
b4[i] -= (W_DM * (b3[i] + b5[i]) + W_DO) >> W_DS;
b3[i] -= (W_CM * (b2[i] + b4[i]) + W_CO) >> W_CS;
b2[i] += (W_BM * (b1[i] + b3[i]) + 4 * b2[i] + W_BO) >> W_BS;
b1[i] += (W_AM * (b0[i] + b2[i]) + W_AO) >> W_AS;
}
}
static void spatial_compose97i_buffered_init(DWTCompose *cs, slice_buffer *sb,
int height, int stride_line)
{
cs->b0 = slice_buffer_get_line(sb, mirror(-3 - 1, height - 1) * stride_line);
cs->b1 = slice_buffer_get_line(sb, mirror(-3, height - 1) * stride_line);
cs->b2 = slice_buffer_get_line(sb, mirror(-3 + 1, height - 1) * stride_line);
cs->b3 = slice_buffer_get_line(sb, mirror(-3 + 2, height - 1) * stride_line);
cs->y = -3;
}
static void spatial_compose97i_init(DWTCompose *cs, IDWTELEM *buffer, int height,
int stride)
{
cs->b0 = buffer + mirror(-3 - 1, height - 1) * stride;
cs->b1 = buffer + mirror(-3, height - 1) * stride;
cs->b2 = buffer + mirror(-3 + 1, height - 1) * stride;
cs->b3 = buffer + mirror(-3 + 2, height - 1) * stride;
cs->y = -3;
}
static void spatial_compose97i_dy_buffered(DWTContext *dsp, DWTCompose *cs,
slice_buffer * sb, IDWTELEM *temp,
int width, int height,
int stride_line)
{
int y = cs->y;
IDWTELEM *b0 = cs->b0;
IDWTELEM *b1 = cs->b1;
IDWTELEM *b2 = cs->b2;
IDWTELEM *b3 = cs->b3;
IDWTELEM *b4 = slice_buffer_get_line(sb,
mirror(y + 3, height - 1) *
stride_line);
IDWTELEM *b5 = slice_buffer_get_line(sb,
mirror(y + 4, height - 1) *
stride_line);
if (y > 0 && y + 4 < height) {
dsp->vertical_compose97i(b0, b1, b2, b3, b4, b5, width);
} else {
if (y + 3 < (unsigned)height)
vertical_compose97iL1(b3, b4, b5, width);
if (y + 2 < (unsigned)height)
vertical_compose97iH1(b2, b3, b4, width);
if (y + 1 < (unsigned)height)
vertical_compose97iL0(b1, b2, b3, width);
if (y + 0 < (unsigned)height)
vertical_compose97iH0(b0, b1, b2, width);
}
if (y - 1 < (unsigned)height)
dsp->horizontal_compose97i(b0, temp, width);
if (y + 0 < (unsigned)height)
dsp->horizontal_compose97i(b1, temp, width);
cs->b0 = b2;
cs->b1 = b3;
cs->b2 = b4;
cs->b3 = b5;
cs->y += 2;
}
static void spatial_compose97i_dy(DWTCompose *cs, IDWTELEM *buffer,
IDWTELEM *temp, int width, int height,
int stride)
{
int y = cs->y;
IDWTELEM *b0 = cs->b0;
IDWTELEM *b1 = cs->b1;
IDWTELEM *b2 = cs->b2;
IDWTELEM *b3 = cs->b3;
IDWTELEM *b4 = buffer + mirror(y + 3, height - 1) * stride;
IDWTELEM *b5 = buffer + mirror(y + 4, height - 1) * stride;
if (y + 3 < (unsigned)height)
vertical_compose97iL1(b3, b4, b5, width);
if (y + 2 < (unsigned)height)
vertical_compose97iH1(b2, b3, b4, width);
if (y + 1 < (unsigned)height)
vertical_compose97iL0(b1, b2, b3, width);
if (y + 0 < (unsigned)height)
vertical_compose97iH0(b0, b1, b2, width);
if (y - 1 < (unsigned)height)
ff_snow_horizontal_compose97i(b0, temp, width);
if (y + 0 < (unsigned)height)
ff_snow_horizontal_compose97i(b1, temp, width);
cs->b0 = b2;
cs->b1 = b3;
cs->b2 = b4;
cs->b3 = b5;
cs->y += 2;
}
void ff_spatial_idwt_buffered_init(DWTCompose *cs, slice_buffer *sb, int width,
int height, int stride_line, int type,
int decomposition_count)
{
int level;
for (level = decomposition_count - 1; level >= 0; level--) {
switch (type) {
case DWT_97:
spatial_compose97i_buffered_init(cs + level, sb, height >> level,
stride_line << level);
break;
case DWT_53:
spatial_compose53i_buffered_init(cs + level, sb, height >> level,
stride_line << level);
break;
}
}
}
void ff_spatial_idwt_buffered_slice(DWTContext *dsp, DWTCompose *cs,
slice_buffer *slice_buf, IDWTELEM *temp,
int width, int height, int stride_line,
int type, int decomposition_count, int y)
{
const int support = type == 1 ? 3 : 5;
int level;
if (type == 2)
return;
for (level = decomposition_count - 1; level >= 0; level--)
while (cs[level].y <= FFMIN((y >> level) + support, height >> level)) {
switch (type) {
case DWT_97:
spatial_compose97i_dy_buffered(dsp, cs + level, slice_buf, temp,
width >> level,
height >> level,
stride_line << level);
break;
case DWT_53:
spatial_compose53i_dy_buffered(cs + level, slice_buf, temp,
width >> level,
height >> level,
stride_line << level);
break;
}
}
}
static void ff_spatial_idwt_init(DWTCompose *cs, IDWTELEM *buffer, int width,
int height, int stride, int type,
int decomposition_count)
{
int level;
for (level = decomposition_count - 1; level >= 0; level--) {
switch (type) {
case DWT_97:
spatial_compose97i_init(cs + level, buffer, height >> level,
stride << level);
break;
case DWT_53:
spatial_compose53i_init(cs + level, buffer, height >> level,
stride << level);
break;
}
}
}
static void ff_spatial_idwt_slice(DWTCompose *cs, IDWTELEM *buffer,
IDWTELEM *temp, int width, int height,
int stride, int type,
int decomposition_count, int y)
{
const int support = type == 1 ? 3 : 5;
int level;
if (type == 2)
return;
for (level = decomposition_count - 1; level >= 0; level--)
while (cs[level].y <= FFMIN((y >> level) + support, height >> level)) {
switch (type) {
case DWT_97:
spatial_compose97i_dy(cs + level, buffer, temp, width >> level,
height >> level, stride << level);
break;
case DWT_53:
spatial_compose53i_dy(cs + level, buffer, temp, width >> level,
height >> level, stride << level);
break;
}
}
}
void ff_spatial_idwt(IDWTELEM *buffer, IDWTELEM *temp, int width, int height,
int stride, int type, int decomposition_count)
{
DWTCompose cs[MAX_DECOMPOSITIONS];
int y;
ff_spatial_idwt_init(cs, buffer, width, height, stride, type,
decomposition_count);
for (y = 0; y < height; y += 4)
ff_spatial_idwt_slice(cs, buffer, temp, width, height, stride, type,
decomposition_count, y);
}
static inline int w_c(void *v, uint8_t *pix1, uint8_t *pix2, int line_size,
int w, int h, int type)
{
int s, i, j;
const int dec_count = w == 8 ? 3 : 4;
int tmp[32 * 32], tmp2[32];
int level, ori;
static const int scale[2][2][4][4] = {
{
{ // 9/7 8x8 dec=3
{ 268, 239, 239, 213 },
{ 0, 224, 224, 152 },
{ 0, 135, 135, 110 },
},
{ // 9/7 16x16 or 32x32 dec=4
{ 344, 310, 310, 280 },
{ 0, 320, 320, 228 },
{ 0, 175, 175, 136 },
{ 0, 129, 129, 102 },
}
},
{
{ // 5/3 8x8 dec=3
{ 275, 245, 245, 218 },
{ 0, 230, 230, 156 },
{ 0, 138, 138, 113 },
},
{ // 5/3 16x16 or 32x32 dec=4
{ 352, 317, 317, 286 },
{ 0, 328, 328, 233 },
{ 0, 180, 180, 140 },
{ 0, 132, 132, 105 },
}
}
};
for (i = 0; i < h; i++) {
for (j = 0; j < w; j += 4) {
tmp[32 * i + j + 0] = (pix1[j + 0] - pix2[j + 0]) << 4;
tmp[32 * i + j + 1] = (pix1[j + 1] - pix2[j + 1]) << 4;
tmp[32 * i + j + 2] = (pix1[j + 2] - pix2[j + 2]) << 4;
tmp[32 * i + j + 3] = (pix1[j + 3] - pix2[j + 3]) << 4;
}
pix1 += line_size;
pix2 += line_size;
}
ff_spatial_dwt(tmp, tmp2, w, h, 32, type, dec_count);
s = 0;
assert(w == h);
for (level = 0; level < dec_count; level++)
for (ori = level ? 1 : 0; ori < 4; ori++) {
int size = w >> (dec_count - level);
int sx = (ori & 1) ? size : 0;
int stride = 32 << (dec_count - level);
int sy = (ori & 2) ? stride >> 1 : 0;
for (i = 0; i < size; i++)
for (j = 0; j < size; j++) {
int v = tmp[sx + sy + i * stride + j] *
scale[type][dec_count - 3][level][ori];
s += FFABS(v);
}
}
assert(s >= 0);
return s >> 9;
}
static int w53_8_c(void *v, uint8_t *pix1, uint8_t *pix2, int line_size, int h)
{
return w_c(v, pix1, pix2, line_size, 8, h, 1);
}
static int w97_8_c(void *v, uint8_t *pix1, uint8_t *pix2, int line_size, int h)
{
return w_c(v, pix1, pix2, line_size, 8, h, 0);
}
static int w53_16_c(void *v, uint8_t *pix1, uint8_t *pix2, int line_size, int h)
{
return w_c(v, pix1, pix2, line_size, 16, h, 1);
}
static int w97_16_c(void *v, uint8_t *pix1, uint8_t *pix2, int line_size, int h)
{
return w_c(v, pix1, pix2, line_size, 16, h, 0);
}
int ff_w53_32_c(void *v, uint8_t *pix1, uint8_t *pix2, int line_size, int h)
{
return w_c(v, pix1, pix2, line_size, 32, h, 1);
}
int ff_w97_32_c(void *v, uint8_t *pix1, uint8_t *pix2, int line_size, int h)
{
return w_c(v, pix1, pix2, line_size, 32, h, 0);
}
void ff_dsputil_init_dwt(DSPContext *c)
{
c->w53[0] = w53_16_c;
c->w53[1] = w53_8_c;
c->w97[0] = w97_16_c;
c->w97[1] = w97_8_c;
}
void ff_dwt_init(DWTContext *c)
{
c->vertical_compose97i = ff_snow_vertical_compose97i;
c->horizontal_compose97i = ff_snow_horizontal_compose97i;
c->inner_add_yblock = ff_snow_inner_add_yblock;
if (HAVE_MMX)
ff_dwt_init_x86(c);
}
/*
* Copyright (C) 2004-2010 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of Libav.
*
* Libav 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.
*
* Libav 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 Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVCODEC_DWT_H
#define AVCODEC_DWT_H
#include <stdint.h>
typedef int DWTELEM;
typedef short IDWTELEM;
typedef struct DWTCompose {
IDWTELEM *b0;
IDWTELEM *b1;
IDWTELEM *b2;
IDWTELEM *b3;
int y;
} DWTCompose;
/** Used to minimize the amount of memory used in order to
* optimize cache performance. **/
typedef struct slice_buffer_s {
IDWTELEM **line; ///< For use by idwt and predict_slices.
IDWTELEM **data_stack; ///< Used for internal purposes.
int data_stack_top;
int line_count;
int line_width;
int data_count;
IDWTELEM *base_buffer; ///< Buffer that this structure is caching.
} slice_buffer;
typedef struct DWTContext {
void (*vertical_compose97i)(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
IDWTELEM *b3, IDWTELEM *b4, IDWTELEM *b5,
int width);
void (*horizontal_compose97i)(IDWTELEM *b, IDWTELEM *temp, int width);
void (*inner_add_yblock)(const uint8_t *obmc, const int obmc_stride,
uint8_t **block, int b_w, int b_h, int src_x,
int src_y, int src_stride, slice_buffer *sb,
int add, uint8_t *dst8);
} DWTContext;
#define MAX_DECOMPOSITIONS 8
#define DWT_97 0
#define DWT_53 1
#define liftS lift
#define W_AM 3
#define W_AO 0
#define W_AS 1
#undef liftS
#define W_BM 1
#define W_BO 8
#define W_BS 4
#define W_CM 1
#define W_CO 0
#define W_CS 0
#define W_DM 3
#define W_DO 4
#define W_DS 3
#define slice_buffer_get_line(slice_buf, line_num) \
((slice_buf)->line[line_num] ? (slice_buf)->line[line_num] \
: ff_slice_buffer_load_line((slice_buf), \
(line_num)))
int ff_slice_buffer_init(slice_buffer *buf, int line_count,
int max_allocated_lines, int line_width,
IDWTELEM *base_buffer);
void ff_slice_buffer_release(slice_buffer *buf, int line);
void ff_slice_buffer_flush(slice_buffer *buf);
void ff_slice_buffer_destroy(slice_buffer *buf);
IDWTELEM *ff_slice_buffer_load_line(slice_buffer *buf, int line);
void ff_snow_vertical_compose97i(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
IDWTELEM *b3, IDWTELEM *b4, IDWTELEM *b5,
int width);
void ff_snow_horizontal_compose97i(IDWTELEM *b, IDWTELEM *temp, int width);
void ff_snow_inner_add_yblock(const uint8_t *obmc, const int obmc_stride,
uint8_t **block, int b_w, int b_h, int src_x,
int src_y, int src_stride, slice_buffer *sb,
int add, uint8_t *dst8);
int ff_w53_32_c(void *v, uint8_t *pix1, uint8_t *pix2, int line_size, int h);
int ff_w97_32_c(void *v, uint8_t *pix1, uint8_t *pix2, int line_size, int h);
void ff_spatial_dwt(int *buffer, int *temp, int width, int height, int stride,
int type, int decomposition_count);
void ff_spatial_idwt_buffered_init(DWTCompose *cs, slice_buffer *sb, int width,
int height, int stride_line, int type,
int decomposition_count);
void ff_spatial_idwt_buffered_slice(DWTContext *dsp, DWTCompose *cs,
slice_buffer *slice_buf, IDWTELEM *temp,
int width, int height, int stride_line,
int type, int decomposition_count, int y);
void ff_spatial_idwt(IDWTELEM *buffer, IDWTELEM *temp, int width, int height,
int stride, int type, int decomposition_count);
void ff_dwt_init(DWTContext *c);
void ff_dwt_init_x86(DWTContext *c);
#endif /* AVCODEC_DWT_H */
......@@ -28,7 +28,6 @@
#include "avcodec.h"
#include "dsputil.h"
#include "dwt.h"
#include "ivi_common.h"
#include "ivi_dsp.h"
......@@ -40,7 +39,7 @@ void ff_ivi_recompose53(const IVIPlaneDesc *plane, uint8_t *dst,
int32_t b0_1, b0_2, b1_1, b1_2, b1_3, b2_1, b2_2, b2_3, b2_4, b2_5, b2_6;
int32_t b3_1, b3_2, b3_3, b3_4, b3_5, b3_6, b3_7, b3_8, b3_9;
int32_t pitch, back_pitch;
const IDWTELEM *b0_ptr, *b1_ptr, *b2_ptr, *b3_ptr;
const short *b0_ptr, *b1_ptr, *b2_ptr, *b3_ptr;
const int num_bands = 4;
/* all bands should have the same pitch */
......@@ -183,7 +182,7 @@ void ff_ivi_recompose_haar(const IVIPlaneDesc *plane, uint8_t *dst,
const int dst_pitch)
{
int x, y, indx, b0, b1, b2, b3, p0, p1, p2, p3;
const IDWTELEM *b0_ptr, *b1_ptr, *b2_ptr, *b3_ptr;
const short *b0_ptr, *b1_ptr, *b2_ptr, *b3_ptr;
int32_t pitch;
/* all bands should have the same pitch */
......
......@@ -302,8 +302,9 @@ int ff_init_me(MpegEncContext *s){
av_log(s->avctx, AV_LOG_ERROR, "ME_MAP size is too small for SAB diamond\n");
return -1;
}
//special case of snow is needed because snow uses its own iterative ME code
if(s->me_method!=ME_ZERO && s->me_method!=ME_EPZS && s->me_method!=ME_X1 && s->avctx->codec_id != AV_CODEC_ID_SNOW){
if (s->me_method != ME_ZERO &&
s->me_method != ME_EPZS &&
s->me_method != ME_X1) {
av_log(s->avctx, AV_LOG_ERROR, "me_method is only allowed to be set to zero and epzs; for hex,umh,full and others see dia_size\n");
return -1;
}
......@@ -354,7 +355,6 @@ int ff_init_me(MpegEncContext *s){
/* 8x8 fullpel search would need a 4x4 chroma compare, which we do
* not have yet, and even if we had, the motion estimation code
* does not expect it. */
if(s->codec_id != AV_CODEC_ID_SNOW){
if((c->avctx->me_cmp&FF_CMP_CHROMA)/* && !s->dsp.me_cmp[2]*/){
s->dsp.me_cmp[2]= zero_cmp;
}
......@@ -363,7 +363,6 @@ int ff_init_me(MpegEncContext *s){
}
c->hpel_put[2][0]= c->hpel_put[2][1]=
c->hpel_put[2][2]= c->hpel_put[2][3]= zero_hpel;
}
if(s->codec_id == AV_CODEC_ID_H261){
c->sub_motion_search= no_sub_motion_search;
......
......@@ -86,7 +86,9 @@
CODEC_ID_MSZH,
CODEC_ID_ZLIB,
CODEC_ID_QTRLE,
#if FF_API_SNOW
CODEC_ID_SNOW,
#endif
CODEC_ID_TSCC,
CODEC_ID_ULTI,
CODEC_ID_QDRAW,
......
......@@ -92,7 +92,9 @@ static const AVOption options[]={
{"x1", "X1 motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = ME_X1 }, INT_MIN, INT_MAX, V|E, "me_method" },
{"hex", "hex motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = ME_HEX }, INT_MIN, INT_MAX, V|E, "me_method" },
{"umh", "umh motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = ME_UMH }, INT_MIN, INT_MAX, V|E, "me_method" },
#if FF_API_SNOW
{"iter", "iter motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = ME_ITER }, INT_MIN, INT_MAX, V|E, "me_method" },
#endif
{"extradata_size", NULL, OFFSET(extradata_size), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX},
{"time_base", NULL, OFFSET(time_base), AV_OPT_TYPE_RATIONAL, {.dbl = 0}, INT_MIN, INT_MAX},
{"g", "set the group of picture (GOP) size", OFFSET(gop_size), AV_OPT_TYPE_INT, {.i64 = 12 }, INT_MIN, INT_MAX, V|E},
......@@ -261,10 +263,6 @@ static const AVOption options[]={
{"vsad", "sum of absolute vertical differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_VSAD }, INT_MIN, INT_MAX, V|E, "cmp_func"},
{"vsse", "sum of squared vertical differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_VSSE }, INT_MIN, INT_MAX, V|E, "cmp_func"},
{"nsse", "noise preserving sum of squared differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_NSSE }, INT_MIN, INT_MAX, V|E, "cmp_func"},
#if CONFIG_SNOW_ENCODER
{"w53", "5/3 wavelet, only used in snow", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_W53 }, INT_MIN, INT_MAX, V|E, "cmp_func"},
{"w97", "9/7 wavelet, only used in snow", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_W97 }, INT_MIN, INT_MAX, V|E, "cmp_func"},
#endif
{"dctmax", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_DCTMAX }, INT_MIN, INT_MAX, V|E, "cmp_func"},
{"chroma", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_CHROMA }, INT_MIN, INT_MAX, V|E, "cmp_func"},
{"pre_dia_size", "diamond type & size for motion estimation pre-pass", OFFSET(pre_dia_size), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E},
......
/*
* Copyright (C) 2004 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of Libav.
*
* Libav 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.
*
* Libav 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 Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/intmath.h"
#include "libavutil/log.h"
#include "libavutil/opt.h"
#include "avcodec.h"
#include "dsputil.h"
#include "dwt.h"
#include "internal.h"
#include "snow.h"
#include "snowdata.h"
#include "rangecoder.h"
#include "mathops.h"
#include "h263.h"
#undef NDEBUG
#include <assert.h>
void ff_snow_inner_add_yblock(const uint8_t *obmc, const int obmc_stride, uint8_t * * block, int b_w, int b_h,
int src_x, int src_y, int src_stride, slice_buffer * sb, int add, uint8_t * dst8){
int y, x;
IDWTELEM * dst;
for(y=0; y<b_h; y++){
//FIXME ugly misuse of obmc_stride
const uint8_t *obmc1= obmc + y*obmc_stride;
const uint8_t *obmc2= obmc1+ (obmc_stride>>1);
const uint8_t *obmc3= obmc1+ obmc_stride*(obmc_stride>>1);
const uint8_t *obmc4= obmc3+ (obmc_stride>>1);
dst = slice_buffer_get_line(sb, src_y + y);
for(x=0; x<b_w; x++){
int v= obmc1[x] * block[3][x + y*src_stride]
+obmc2[x] * block[2][x + y*src_stride]
+obmc3[x] * block[1][x + y*src_stride]
+obmc4[x] * block[0][x + y*src_stride];
v <<= 8 - LOG2_OBMC_MAX;
if(FRAC_BITS != 8){
v >>= 8 - FRAC_BITS;
}
if(add){
v += dst[x + src_x];
v = (v + (1<<(FRAC_BITS-1))) >> FRAC_BITS;
if(v&(~255)) v= ~(v>>31);
dst8[x + y*src_stride] = v;
}else{
dst[x + src_x] -= v;
}
}
}
}
void ff_snow_reset_contexts(SnowContext *s){ //FIXME better initial contexts
int plane_index, level, orientation;
for(plane_index=0; plane_index<3; plane_index++){
for(level=0; level<MAX_DECOMPOSITIONS; level++){
for(orientation=level ? 1:0; orientation<4; orientation++){
memset(s->plane[plane_index].band[level][orientation].state, MID_STATE, sizeof(s->plane[plane_index].band[level][orientation].state));
}
}
}
memset(s->header_state, MID_STATE, sizeof(s->header_state));
memset(s->block_state, MID_STATE, sizeof(s->block_state));
}
int ff_snow_alloc_blocks(SnowContext *s){
int w= -((-s->avctx->width )>>LOG2_MB_SIZE);
int h= -((-s->avctx->height)>>LOG2_MB_SIZE);
s->b_width = w;
s->b_height= h;
av_free(s->block);
s->block= av_mallocz(w * h * sizeof(BlockNode) << (s->block_max_depth*2));
return 0;
}
static void init_qexp(void){
int i;
double v=128;
for(i=0; i<QROOT; i++){
ff_qexp[i]= lrintf(v);
v *= pow(2, 1.0 / QROOT);
}
}
static void mc_block(Plane *p, uint8_t *dst, const uint8_t *src, int stride, int b_w, int b_h, int dx, int dy){
static const uint8_t weight[64]={
8,7,6,5,4,3,2,1,
7,7,0,0,0,0,0,1,
6,0,6,0,0,0,2,0,
5,0,0,5,0,3,0,0,
4,0,0,0,4,0,0,0,
3,0,0,5,0,3,0,0,
2,0,6,0,0,0,2,0,
1,7,0,0,0,0,0,1,
};
static const uint8_t brane[256]={
0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x11,0x12,0x12,0x12,0x12,0x12,0x12,0x12,
0x04,0x05,0xcc,0xcc,0xcc,0xcc,0xcc,0x41,0x15,0x16,0xcc,0xcc,0xcc,0xcc,0xcc,0x52,
0x04,0xcc,0x05,0xcc,0xcc,0xcc,0x41,0xcc,0x15,0xcc,0x16,0xcc,0xcc,0xcc,0x52,0xcc,
0x04,0xcc,0xcc,0x05,0xcc,0x41,0xcc,0xcc,0x15,0xcc,0xcc,0x16,0xcc,0x52,0xcc,0xcc,
0x04,0xcc,0xcc,0xcc,0x41,0xcc,0xcc,0xcc,0x15,0xcc,0xcc,0xcc,0x16,0xcc,0xcc,0xcc,
0x04,0xcc,0xcc,0x41,0xcc,0x05,0xcc,0xcc,0x15,0xcc,0xcc,0x52,0xcc,0x16,0xcc,0xcc,
0x04,0xcc,0x41,0xcc,0xcc,0xcc,0x05,0xcc,0x15,0xcc,0x52,0xcc,0xcc,0xcc,0x16,0xcc,
0x04,0x41,0xcc,0xcc,0xcc,0xcc,0xcc,0x05,0x15,0x52,0xcc,0xcc,0xcc,0xcc,0xcc,0x16,
0x44,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x55,0x56,0x56,0x56,0x56,0x56,0x56,0x56,
0x48,0x49,0xcc,0xcc,0xcc,0xcc,0xcc,0x85,0x59,0x5A,0xcc,0xcc,0xcc,0xcc,0xcc,0x96,
0x48,0xcc,0x49,0xcc,0xcc,0xcc,0x85,0xcc,0x59,0xcc,0x5A,0xcc,0xcc,0xcc,0x96,0xcc,
0x48,0xcc,0xcc,0x49,0xcc,0x85,0xcc,0xcc,0x59,0xcc,0xcc,0x5A,0xcc,0x96,0xcc,0xcc,
0x48,0xcc,0xcc,0xcc,0x49,0xcc,0xcc,0xcc,0x59,0xcc,0xcc,0xcc,0x96,0xcc,0xcc,0xcc,
0x48,0xcc,0xcc,0x85,0xcc,0x49,0xcc,0xcc,0x59,0xcc,0xcc,0x96,0xcc,0x5A,0xcc,0xcc,
0x48,0xcc,0x85,0xcc,0xcc,0xcc,0x49,0xcc,0x59,0xcc,0x96,0xcc,0xcc,0xcc,0x5A,0xcc,
0x48,0x85,0xcc,0xcc,0xcc,0xcc,0xcc,0x49,0x59,0x96,0xcc,0xcc,0xcc,0xcc,0xcc,0x5A,
};
static const uint8_t needs[16]={
0,1,0,0,
2,4,2,0,
0,1,0,0,
15
};
int x, y, b, r, l;
int16_t tmpIt [64*(32+HTAPS_MAX)];
uint8_t tmp2t[3][64*(32+HTAPS_MAX)];
int16_t *tmpI= tmpIt;
uint8_t *tmp2= tmp2t[0];
const uint8_t *hpel[11];
assert(dx<16 && dy<16);
r= brane[dx + 16*dy]&15;
l= brane[dx + 16*dy]>>4;
b= needs[l] | needs[r];
if(p && !p->diag_mc)
b= 15;
if(b&5){
for(y=0; y < b_h+HTAPS_MAX-1; y++){
for(x=0; x < b_w; x++){
int a_1=src[x + HTAPS_MAX/2-4];
int a0= src[x + HTAPS_MAX/2-3];
int a1= src[x + HTAPS_MAX/2-2];
int a2= src[x + HTAPS_MAX/2-1];
int a3= src[x + HTAPS_MAX/2+0];
int a4= src[x + HTAPS_MAX/2+1];
int a5= src[x + HTAPS_MAX/2+2];
int a6= src[x + HTAPS_MAX/2+3];
int am=0;
if(!p || p->fast_mc){
am= 20*(a2+a3) - 5*(a1+a4) + (a0+a5);
tmpI[x]= am;
am= (am+16)>>5;
}else{
am= p->hcoeff[0]*(a2+a3) + p->hcoeff[1]*(a1+a4) + p->hcoeff[2]*(a0+a5) + p->hcoeff[3]*(a_1+a6);
tmpI[x]= am;
am= (am+32)>>6;
}
if(am&(~255)) am= ~(am>>31);
tmp2[x]= am;
}
tmpI+= 64;
tmp2+= 64;
src += stride;
}
src -= stride*y;
}
src += HTAPS_MAX/2 - 1;
tmp2= tmp2t[1];
if(b&2){
for(y=0; y < b_h; y++){
for(x=0; x < b_w+1; x++){
int a_1=src[x + (HTAPS_MAX/2-4)*stride];
int a0= src[x + (HTAPS_MAX/2-3)*stride];
int a1= src[x + (HTAPS_MAX/2-2)*stride];
int a2= src[x + (HTAPS_MAX/2-1)*stride];
int a3= src[x + (HTAPS_MAX/2+0)*stride];
int a4= src[x + (HTAPS_MAX/2+1)*stride];
int a5= src[x + (HTAPS_MAX/2+2)*stride];
int a6= src[x + (HTAPS_MAX/2+3)*stride];
int am=0;
if(!p || p->fast_mc)
am= (20*(a2+a3) - 5*(a1+a4) + (a0+a5) + 16)>>5;
else
am= (p->hcoeff[0]*(a2+a3) + p->hcoeff[1]*(a1+a4) + p->hcoeff[2]*(a0+a5) + p->hcoeff[3]*(a_1+a6) + 32)>>6;
if(am&(~255)) am= ~(am>>31);
tmp2[x]= am;
}
src += stride;
tmp2+= 64;
}
src -= stride*y;
}
src += stride*(HTAPS_MAX/2 - 1);
tmp2= tmp2t[2];
tmpI= tmpIt;
if(b&4){
for(y=0; y < b_h; y++){
for(x=0; x < b_w; x++){
int a_1=tmpI[x + (HTAPS_MAX/2-4)*64];
int a0= tmpI[x + (HTAPS_MAX/2-3)*64];
int a1= tmpI[x + (HTAPS_MAX/2-2)*64];
int a2= tmpI[x + (HTAPS_MAX/2-1)*64];
int a3= tmpI[x + (HTAPS_MAX/2+0)*64];
int a4= tmpI[x + (HTAPS_MAX/2+1)*64];
int a5= tmpI[x + (HTAPS_MAX/2+2)*64];
int a6= tmpI[x + (HTAPS_MAX/2+3)*64];
int am=0;
if(!p || p->fast_mc)
am= (20*(a2+a3) - 5*(a1+a4) + (a0+a5) + 512)>>10;
else
am= (p->hcoeff[0]*(a2+a3) + p->hcoeff[1]*(a1+a4) + p->hcoeff[2]*(a0+a5) + p->hcoeff[3]*(a_1+a6) + 2048)>>12;
if(am&(~255)) am= ~(am>>31);
tmp2[x]= am;
}
tmpI+= 64;
tmp2+= 64;
}
}
hpel[ 0]= src;
hpel[ 1]= tmp2t[0] + 64*(HTAPS_MAX/2-1);
hpel[ 2]= src + 1;
hpel[ 4]= tmp2t[1];
hpel[ 5]= tmp2t[2];
hpel[ 6]= tmp2t[1] + 1;
hpel[ 8]= src + stride;
hpel[ 9]= hpel[1] + 64;
hpel[10]= hpel[8] + 1;
#define MC_STRIDE(x) (needs[x] ? 64 : stride)
if(b==15){
int dxy = dx / 8 + dy / 8 * 4;
const uint8_t *src1 = hpel[dxy ];
const uint8_t *src2 = hpel[dxy + 1];
const uint8_t *src3 = hpel[dxy + 4];
const uint8_t *src4 = hpel[dxy + 5];
int stride1 = MC_STRIDE(dxy);
int stride2 = MC_STRIDE(dxy + 1);
int stride3 = MC_STRIDE(dxy + 4);
int stride4 = MC_STRIDE(dxy + 5);
dx&=7;
dy&=7;
for(y=0; y < b_h; y++){
for(x=0; x < b_w; x++){
dst[x]= ((8-dx)*(8-dy)*src1[x] + dx*(8-dy)*src2[x]+
(8-dx)* dy *src3[x] + dx* dy *src4[x]+32)>>6;
}
src1+=stride1;
src2+=stride2;
src3+=stride3;
src4+=stride4;
dst +=stride;
}
}else{
const uint8_t *src1= hpel[l];
const uint8_t *src2= hpel[r];
int stride1 = MC_STRIDE(l);
int stride2 = MC_STRIDE(r);
int a= weight[((dx&7) + (8*(dy&7)))];
int b= 8-a;
for(y=0; y < b_h; y++){
for(x=0; x < b_w; x++){
dst[x]= (a*src1[x] + b*src2[x] + 4)>>3;
}
src1+=stride1;
src2+=stride2;
dst +=stride;
}
}
}
void ff_snow_pred_block(SnowContext *s, uint8_t *dst, uint8_t *tmp, int stride, int sx, int sy, int b_w, int b_h, BlockNode *block, int plane_index, int w, int h){
if(block->type & BLOCK_INTRA){
int x, y;
const unsigned color = block->color[plane_index];
const unsigned color4 = color*0x01010101;
if(b_w==32){
for(y=0; y < b_h; y++){
*(uint32_t*)&dst[0 + y*stride]= color4;
*(uint32_t*)&dst[4 + y*stride]= color4;
*(uint32_t*)&dst[8 + y*stride]= color4;
*(uint32_t*)&dst[12+ y*stride]= color4;
*(uint32_t*)&dst[16+ y*stride]= color4;
*(uint32_t*)&dst[20+ y*stride]= color4;
*(uint32_t*)&dst[24+ y*stride]= color4;
*(uint32_t*)&dst[28+ y*stride]= color4;
}
}else if(b_w==16){
for(y=0; y < b_h; y++){
*(uint32_t*)&dst[0 + y*stride]= color4;
*(uint32_t*)&dst[4 + y*stride]= color4;
*(uint32_t*)&dst[8 + y*stride]= color4;
*(uint32_t*)&dst[12+ y*stride]= color4;
}
}else if(b_w==8){
for(y=0; y < b_h; y++){
*(uint32_t*)&dst[0 + y*stride]= color4;
*(uint32_t*)&dst[4 + y*stride]= color4;
}
}else if(b_w==4){
for(y=0; y < b_h; y++){
*(uint32_t*)&dst[0 + y*stride]= color4;
}
}else{
for(y=0; y < b_h; y++){
for(x=0; x < b_w; x++){
dst[x + y*stride]= color;
}
}
}
}else{
uint8_t *src= s->last_picture[block->ref].data[plane_index];
const int scale= plane_index ? s->mv_scale : 2*s->mv_scale;
int mx= block->mx*scale;
int my= block->my*scale;
const int dx= mx&15;
const int dy= my&15;
const int tab_index= 3 - (b_w>>2) + (b_w>>4);
sx += (mx>>4) - (HTAPS_MAX/2-1);
sy += (my>>4) - (HTAPS_MAX/2-1);
src += sx + sy*stride;
if( (unsigned)sx >= w - b_w - (HTAPS_MAX-2)
|| (unsigned)sy >= h - b_h - (HTAPS_MAX-2)){
s->vdsp.emulated_edge_mc(tmp + MB_SIZE, src, stride, b_w+HTAPS_MAX-1, b_h+HTAPS_MAX-1, sx, sy, w, h);
src= tmp + MB_SIZE;
}
// assert(b_w == b_h || 2*b_w == b_h || b_w == 2*b_h);
// assert(!(b_w&(b_w-1)));
assert(b_w>1 && b_h>1);
assert((tab_index>=0 && tab_index<4) || b_w==32);
if((dx&3) || (dy&3) || !(b_w == b_h || 2*b_w == b_h || b_w == 2*b_h) || (b_w&(b_w-1)) || !s->plane[plane_index].fast_mc )
mc_block(&s->plane[plane_index], dst, src, stride, b_w, b_h, dx, dy);
else if(b_w==32){
int y;
for(y=0; y<b_h; y+=16){
s->dsp.put_h264_qpel_pixels_tab[0][dy+(dx>>2)](dst + y*stride, src + 3 + (y+3)*stride,stride);
s->dsp.put_h264_qpel_pixels_tab[0][dy+(dx>>2)](dst + 16 + y*stride, src + 19 + (y+3)*stride,stride);
}
}else if(b_w==b_h)
s->dsp.put_h264_qpel_pixels_tab[tab_index ][dy+(dx>>2)](dst,src + 3 + 3*stride,stride);
else if(b_w==2*b_h){
s->dsp.put_h264_qpel_pixels_tab[tab_index+1][dy+(dx>>2)](dst ,src + 3 + 3*stride,stride);
s->dsp.put_h264_qpel_pixels_tab[tab_index+1][dy+(dx>>2)](dst+b_h,src + 3 + b_h + 3*stride,stride);
}else{
assert(2*b_w==b_h);
s->dsp.put_h264_qpel_pixels_tab[tab_index ][dy+(dx>>2)](dst ,src + 3 + 3*stride ,stride);
s->dsp.put_h264_qpel_pixels_tab[tab_index ][dy+(dx>>2)](dst+b_w*stride,src + 3 + 3*stride+b_w*stride,stride);
}
}
}
#define mca(dx,dy,b_w)\
static void mc_block_hpel ## dx ## dy ## b_w(uint8_t *dst, const uint8_t *src, int stride, int h){\
assert(h==b_w);\
mc_block(NULL, dst, src-(HTAPS_MAX/2-1)-(HTAPS_MAX/2-1)*stride, stride, b_w, b_w, dx, dy);\
}
mca( 0, 0,16)
mca( 8, 0,16)
mca( 0, 8,16)
mca( 8, 8,16)
mca( 0, 0,8)
mca( 8, 0,8)
mca( 0, 8,8)
mca( 8, 8,8)
av_cold int ff_snow_common_init(AVCodecContext *avctx){
SnowContext *s = avctx->priv_data;
int width, height;
int i, j, ret;
int emu_buf_size;
s->avctx= avctx;
s->max_ref_frames=1; //just make sure its not an invalid value in case of no initial keyframe
ff_dsputil_init(&s->dsp, avctx);
ff_videodsp_init(&s->vdsp, 8);
ff_dwt_init(&s->dwt);
#define mcf(dx,dy)\
s->dsp.put_qpel_pixels_tab [0][dy+dx/4]=\
s->dsp.put_no_rnd_qpel_pixels_tab[0][dy+dx/4]=\
s->dsp.put_h264_qpel_pixels_tab[0][dy+dx/4];\
s->dsp.put_qpel_pixels_tab [1][dy+dx/4]=\
s->dsp.put_no_rnd_qpel_pixels_tab[1][dy+dx/4]=\
s->dsp.put_h264_qpel_pixels_tab[1][dy+dx/4];
mcf( 0, 0)
mcf( 4, 0)
mcf( 8, 0)
mcf(12, 0)
mcf( 0, 4)
mcf( 4, 4)
mcf( 8, 4)
mcf(12, 4)
mcf( 0, 8)
mcf( 4, 8)
mcf( 8, 8)
mcf(12, 8)
mcf( 0,12)
mcf( 4,12)
mcf( 8,12)
mcf(12,12)
#define mcfh(dx,dy)\
s->dsp.put_pixels_tab [0][dy/4+dx/8]=\
s->dsp.put_no_rnd_pixels_tab[0][dy/4+dx/8]=\
mc_block_hpel ## dx ## dy ## 16;\
s->dsp.put_pixels_tab [1][dy/4+dx/8]=\
s->dsp.put_no_rnd_pixels_tab[1][dy/4+dx/8]=\
mc_block_hpel ## dx ## dy ## 8;
mcfh(0, 0)
mcfh(8, 0)
mcfh(0, 8)
mcfh(8, 8)
init_qexp();
// dec += FFMAX(s->chroma_h_shift, s->chroma_v_shift);
width= s->avctx->width;
height= s->avctx->height;
FF_ALLOCZ_OR_GOTO(avctx, s->spatial_idwt_buffer, width * height * sizeof(IDWTELEM), fail);
FF_ALLOCZ_OR_GOTO(avctx, s->spatial_dwt_buffer, width * height * sizeof(DWTELEM), fail); //FIXME this does not belong here
FF_ALLOCZ_OR_GOTO(avctx, s->temp_dwt_buffer, width * sizeof(DWTELEM), fail);
FF_ALLOCZ_OR_GOTO(avctx, s->temp_idwt_buffer, width * sizeof(IDWTELEM), fail);
FF_ALLOC_OR_GOTO(avctx, s->run_buffer, ((width + 1) >> 1) * ((height + 1) >> 1) * sizeof(*s->run_buffer), fail);
for(i=0; i<MAX_REF_FRAMES; i++)
for(j=0; j<MAX_REF_FRAMES; j++)
ff_scale_mv_ref[i][j] = 256*(i+1)/(j+1);
if ((ret = ff_get_buffer(s->avctx, &s->mconly_picture)) < 0) {
av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
return ret;
}
FF_ALLOC_OR_GOTO(avctx, s->scratchbuf, s->mconly_picture.linesize[0]*7*MB_SIZE, fail);
emu_buf_size = s->mconly_picture.linesize[0] * (2 * MB_SIZE + HTAPS_MAX - 1);
FF_ALLOC_OR_GOTO(avctx, s->emu_edge_buffer, emu_buf_size, fail);
return 0;
fail:
return AVERROR(ENOMEM);
}
int ff_snow_common_init_after_header(AVCodecContext *avctx) {
SnowContext *s = avctx->priv_data;
int plane_index, level, orientation;
for(plane_index=0; plane_index<3; plane_index++){
int w= s->avctx->width;
int h= s->avctx->height;
if(plane_index){
w>>= s->chroma_h_shift;
h>>= s->chroma_v_shift;
}
s->plane[plane_index].width = w;
s->plane[plane_index].height= h;
for(level=s->spatial_decomposition_count-1; level>=0; level--){
for(orientation=level ? 1 : 0; orientation<4; orientation++){
SubBand *b= &s->plane[plane_index].band[level][orientation];
b->buf= s->spatial_dwt_buffer;
b->level= level;
b->stride= s->plane[plane_index].width << (s->spatial_decomposition_count - level);
b->width = (w + !(orientation&1))>>1;
b->height= (h + !(orientation>1))>>1;
b->stride_line = 1 << (s->spatial_decomposition_count - level);
b->buf_x_offset = 0;
b->buf_y_offset = 0;
if(orientation&1){
b->buf += (w+1)>>1;
b->buf_x_offset = (w+1)>>1;
}
if(orientation>1){
b->buf += b->stride>>1;
b->buf_y_offset = b->stride_line >> 1;
}
b->ibuf= s->spatial_idwt_buffer + (b->buf - s->spatial_dwt_buffer);
if(level)
b->parent= &s->plane[plane_index].band[level-1][orientation];
//FIXME avoid this realloc
av_freep(&b->x_coeff);
b->x_coeff=av_mallocz(((b->width+1) * b->height+1)*sizeof(x_and_coeff));
}
w= (w+1)>>1;
h= (h+1)>>1;
}
}
return 0;
}
#define USE_HALFPEL_PLANE 0
static void halfpel_interpol(SnowContext *s, uint8_t *halfpel[4][4], AVFrame *frame){
int p,x,y;
for(p=0; p<3; p++){
int is_chroma= !!p;
int w= s->avctx->width >>is_chroma;
int h= s->avctx->height >>is_chroma;
int ls= frame->linesize[p];
uint8_t *src= frame->data[p];
halfpel[1][p] = (uint8_t*) av_malloc(ls * (h + 2 * EDGE_WIDTH)) + EDGE_WIDTH * (1 + ls);
halfpel[2][p] = (uint8_t*) av_malloc(ls * (h + 2 * EDGE_WIDTH)) + EDGE_WIDTH * (1 + ls);
halfpel[3][p] = (uint8_t*) av_malloc(ls * (h + 2 * EDGE_WIDTH)) + EDGE_WIDTH * (1 + ls);
halfpel[0][p]= src;
for(y=0; y<h; y++){
for(x=0; x<w; x++){
int i= y*ls + x;
halfpel[1][p][i]= (20*(src[i] + src[i+1]) - 5*(src[i-1] + src[i+2]) + (src[i-2] + src[i+3]) + 16 )>>5;
}
}
for(y=0; y<h; y++){
for(x=0; x<w; x++){
int i= y*ls + x;
halfpel[2][p][i]= (20*(src[i] + src[i+ls]) - 5*(src[i-ls] + src[i+2*ls]) + (src[i-2*ls] + src[i+3*ls]) + 16 )>>5;
}
}
src= halfpel[1][p];
for(y=0; y<h; y++){
for(x=0; x<w; x++){
int i= y*ls + x;
halfpel[3][p][i]= (20*(src[i] + src[i+ls]) - 5*(src[i-ls] + src[i+2*ls]) + (src[i-2*ls] + src[i+3*ls]) + 16 )>>5;
}
}
//FIXME border!
}
}
void ff_snow_release_buffer(AVCodecContext *avctx)
{
SnowContext *s = avctx->priv_data;
int i;
if(s->last_picture[s->max_ref_frames-1].data[0]){
avctx->release_buffer(avctx, &s->last_picture[s->max_ref_frames-1]);
for(i=0; i<9; i++)
if(s->halfpel_plane[s->max_ref_frames-1][1+i/3][i%3])
av_free(s->halfpel_plane[s->max_ref_frames-1][1+i/3][i%3] - EDGE_WIDTH*(1+s->current_picture.linesize[i%3]));
}
}
int ff_snow_frame_start(SnowContext *s){
AVFrame tmp;
int w= s->avctx->width; //FIXME round up to x16 ?
int h= s->avctx->height;
if (s->current_picture.data[0] && !(s->avctx->flags&CODEC_FLAG_EMU_EDGE)) {
s->dsp.draw_edges(s->current_picture.data[0],
s->current_picture.linesize[0], w , h ,
EDGE_WIDTH , EDGE_WIDTH , EDGE_TOP | EDGE_BOTTOM);
s->dsp.draw_edges(s->current_picture.data[1],
s->current_picture.linesize[1], w>>1, h>>1,
EDGE_WIDTH/2, EDGE_WIDTH/2, EDGE_TOP | EDGE_BOTTOM);
s->dsp.draw_edges(s->current_picture.data[2],
s->current_picture.linesize[2], w>>1, h>>1,
EDGE_WIDTH/2, EDGE_WIDTH/2, EDGE_TOP | EDGE_BOTTOM);
}
ff_snow_release_buffer(s->avctx);
tmp= s->last_picture[s->max_ref_frames-1];
memmove(s->last_picture+1, s->last_picture, (s->max_ref_frames-1)*sizeof(AVFrame));
memmove(s->halfpel_plane+1, s->halfpel_plane, (s->max_ref_frames-1)*sizeof(void*)*4*4);
if(USE_HALFPEL_PLANE && s->current_picture.data[0])
halfpel_interpol(s, s->halfpel_plane[0], &s->current_picture);
s->last_picture[0]= s->current_picture;
s->current_picture= tmp;
if(s->keyframe){
s->ref_frames= 0;
}else{
int i;
for(i=0; i<s->max_ref_frames && s->last_picture[i].data[0]; i++)
if(i && s->last_picture[i-1].key_frame)
break;
s->ref_frames= i;
if(s->ref_frames==0){
av_log(s->avctx,AV_LOG_ERROR, "No reference frames\n");
return -1;
}
}
s->current_picture.reference= 1;
if(ff_get_buffer(s->avctx, &s->current_picture) < 0){
av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
return -1;
}
s->current_picture.key_frame= s->keyframe;
return 0;
}
av_cold void ff_snow_common_end(SnowContext *s)
{
int plane_index, level, orientation, i;
av_freep(&s->spatial_dwt_buffer);
av_freep(&s->temp_dwt_buffer);
av_freep(&s->spatial_idwt_buffer);
av_freep(&s->temp_idwt_buffer);
av_freep(&s->run_buffer);
s->m.me.temp= NULL;
av_freep(&s->m.me.scratchpad);
av_freep(&s->m.me.map);
av_freep(&s->m.me.score_map);
av_freep(&s->m.obmc_scratchpad);
av_freep(&s->block);
av_freep(&s->scratchbuf);
av_freep(&s->emu_edge_buffer);
for(i=0; i<MAX_REF_FRAMES; i++){
av_freep(&s->ref_mvs[i]);
av_freep(&s->ref_scores[i]);
if(s->last_picture[i].data[0])
s->avctx->release_buffer(s->avctx, &s->last_picture[i]);
}
for(plane_index=0; plane_index<3; plane_index++){
for(level=s->spatial_decomposition_count-1; level>=0; level--){
for(orientation=level ? 1 : 0; orientation<4; orientation++){
SubBand *b= &s->plane[plane_index].band[level][orientation];
av_freep(&b->x_coeff);
}
}
}
if (s->mconly_picture.data[0])
s->avctx->release_buffer(s->avctx, &s->mconly_picture);
if (s->current_picture.data[0])
s->avctx->release_buffer(s->avctx, &s->current_picture);
}
/*
* Copyright (C) 2004 Michael Niedermayer <michaelni@gmx.at>
* Copyright (C) 2006 Robert Edele <yartrebo@earthlink.net>
*
* This file is part of Libav.
*
* Libav 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.
*
* Libav 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 Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVCODEC_SNOW_H
#define AVCODEC_SNOW_H
#include "dsputil.h"
#include "dwt.h"
#include "rangecoder.h"
#include "mathops.h"
#include "mpegvideo.h"
#define MID_STATE 128
#define MAX_PLANES 4
#define QSHIFT 5
#define QROOT (1<<QSHIFT)
#define LOSSLESS_QLOG -128
#define FRAC_BITS 4
#define MAX_REF_FRAMES 8
#define LOG2_OBMC_MAX 8
#define OBMC_MAX (1<<(LOG2_OBMC_MAX))
typedef struct BlockNode{
int16_t mx;
int16_t my;
uint8_t ref;
uint8_t color[3];
uint8_t type;
//#define TYPE_SPLIT 1
#define BLOCK_INTRA 1
#define BLOCK_OPT 2
//#define TYPE_NOCOLOR 4
uint8_t level; //FIXME merge into type?
}BlockNode;
static const BlockNode null_block= { //FIXME add border maybe
.color= {128,128,128},
.mx= 0,
.my= 0,
.ref= 0,
.type= 0,
.level= 0,
};
#define LOG2_MB_SIZE 4
#define MB_SIZE (1<<LOG2_MB_SIZE)
#define ENCODER_EXTRA_BITS 4
#define HTAPS_MAX 8
typedef struct x_and_coeff{
int16_t x;
uint16_t coeff;
} x_and_coeff;
typedef struct SubBand{
int level;
int stride;
int width;
int height;
int qlog; ///< log(qscale)/log[2^(1/6)]
DWTELEM *buf;
IDWTELEM *ibuf;
int buf_x_offset;
int buf_y_offset;
int stride_line; ///< Stride measured in lines, not pixels.
x_and_coeff * x_coeff;
struct SubBand *parent;
uint8_t state[/*7*2*/ 7 + 512][32];
}SubBand;
typedef struct Plane{
int width;
int height;
SubBand band[MAX_DECOMPOSITIONS][4];
int htaps;
int8_t hcoeff[HTAPS_MAX/2];
int diag_mc;
int fast_mc;
int last_htaps;
int8_t last_hcoeff[HTAPS_MAX/2];
int last_diag_mc;
}Plane;
typedef struct SnowContext{
AVClass *class;
AVCodecContext *avctx;
RangeCoder c;
DSPContext dsp;
VideoDSPContext vdsp;
DWTContext dwt;
AVFrame new_picture;
AVFrame input_picture; ///< new_picture with the internal linesizes
AVFrame current_picture;
AVFrame last_picture[MAX_REF_FRAMES];
uint8_t *halfpel_plane[MAX_REF_FRAMES][4][4];
AVFrame mconly_picture;
// uint8_t q_context[16];
uint8_t header_state[32];
uint8_t block_state[128 + 32*128];
int keyframe;
int always_reset;
int version;
int spatial_decomposition_type;
int last_spatial_decomposition_type;
int temporal_decomposition_type;
int spatial_decomposition_count;
int last_spatial_decomposition_count;
int temporal_decomposition_count;
int max_ref_frames;
int ref_frames;
int16_t (*ref_mvs[MAX_REF_FRAMES])[2];
uint32_t *ref_scores[MAX_REF_FRAMES];
DWTELEM *spatial_dwt_buffer;
DWTELEM *temp_dwt_buffer;
IDWTELEM *spatial_idwt_buffer;
IDWTELEM *temp_idwt_buffer;
int *run_buffer;
int colorspace_type;
int chroma_h_shift;
int chroma_v_shift;
int spatial_scalability;
int qlog;
int last_qlog;
int lambda;
int lambda2;
int pass1_rc;
int mv_scale;
int last_mv_scale;
int qbias;
int last_qbias;
#define QBIAS_SHIFT 3
int b_width;
int b_height;
int block_max_depth;
int last_block_max_depth;
Plane plane[MAX_PLANES];
BlockNode *block;
#define ME_CACHE_SIZE 1024
unsigned me_cache[ME_CACHE_SIZE];
unsigned me_cache_generation;
slice_buffer sb;
int memc_only;
MpegEncContext m; // needed for motion estimation, should not be used for anything else, the idea is to eventually make the motion estimation independent of MpegEncContext, so this will be removed then (FIXME/XXX)
uint8_t *scratchbuf;
uint8_t *emu_edge_buffer;
}SnowContext;
/* Tables */
extern const uint8_t * const ff_obmc_tab[4];
extern uint8_t ff_qexp[QROOT];
extern int ff_scale_mv_ref[MAX_REF_FRAMES][MAX_REF_FRAMES];
/* C bits used by mmx/sse2/altivec */
static av_always_inline void snow_interleave_line_header(int * i, int width, IDWTELEM * low, IDWTELEM * high){
(*i) = (width) - 2;
if (width & 1){
low[(*i)+1] = low[((*i)+1)>>1];
(*i)--;
}
}
static av_always_inline void snow_interleave_line_footer(int * i, IDWTELEM * low, IDWTELEM * high){
for (; (*i)>=0; (*i)-=2){
low[(*i)+1] = high[(*i)>>1];
low[*i] = low[(*i)>>1];
}
}
static av_always_inline void snow_horizontal_compose_lift_lead_out(int i, IDWTELEM * dst, IDWTELEM * src, IDWTELEM * ref, int width, int w, int lift_high, int mul, int add, int shift){
for(; i<w; i++){
dst[i] = src[i] - ((mul * (ref[i] + ref[i + 1]) + add) >> shift);
}
if((width^lift_high)&1){
dst[w] = src[w] - ((mul * 2 * ref[w] + add) >> shift);
}
}
static av_always_inline void snow_horizontal_compose_liftS_lead_out(int i, IDWTELEM * dst, IDWTELEM * src, IDWTELEM * ref, int width, int w){
for(; i<w; i++){
dst[i] = src[i] + ((ref[i] + ref[(i+1)]+W_BO + 4 * src[i]) >> W_BS);
}
if(width&1){
dst[w] = src[w] + ((2 * ref[w] + W_BO + 4 * src[w]) >> W_BS);
}
}
/* common code */
int ff_snow_common_init(AVCodecContext *avctx);
int ff_snow_common_init_after_header(AVCodecContext *avctx);
void ff_snow_common_end(SnowContext *s);
void ff_snow_release_buffer(AVCodecContext *avctx);
void ff_snow_reset_contexts(SnowContext *s);
int ff_snow_alloc_blocks(SnowContext *s);
int ff_snow_frame_start(SnowContext *s);
void ff_snow_pred_block(SnowContext *s, uint8_t *dst, uint8_t *tmp, int stride,
int sx, int sy, int b_w, int b_h, BlockNode *block,
int plane_index, int w, int h);
/* common inline functions */
//XXX doublecheck all of them should stay inlined
static inline void snow_set_blocks(SnowContext *s, int level, int x, int y, int l, int cb, int cr, int mx, int my, int ref, int type){
const int w= s->b_width << s->block_max_depth;
const int rem_depth= s->block_max_depth - level;
const int index= (x + y*w) << rem_depth;
const int block_w= 1<<rem_depth;
BlockNode block;
int i,j;
block.color[0]= l;
block.color[1]= cb;
block.color[2]= cr;
block.mx= mx;
block.my= my;
block.ref= ref;
block.type= type;
block.level= level;
for(j=0; j<block_w; j++){
for(i=0; i<block_w; i++){
s->block[index + i + j*w]= block;
}
}
}
static inline void pred_mv(SnowContext *s, int *mx, int *my, int ref,
const BlockNode *left, const BlockNode *top, const BlockNode *tr){
if(s->ref_frames == 1){
*mx = mid_pred(left->mx, top->mx, tr->mx);
*my = mid_pred(left->my, top->my, tr->my);
}else{
const int *scale = ff_scale_mv_ref[ref];
*mx = mid_pred((left->mx * scale[left->ref] + 128) >>8,
(top ->mx * scale[top ->ref] + 128) >>8,
(tr ->mx * scale[tr ->ref] + 128) >>8);
*my = mid_pred((left->my * scale[left->ref] + 128) >>8,
(top ->my * scale[top ->ref] + 128) >>8,
(tr ->my * scale[tr ->ref] + 128) >>8);
}
}
static av_always_inline int same_block(BlockNode *a, BlockNode *b){
if((a->type&BLOCK_INTRA) && (b->type&BLOCK_INTRA)){
return !((a->color[0] - b->color[0]) | (a->color[1] - b->color[1]) | (a->color[2] - b->color[2]));
}else{
return !((a->mx - b->mx) | (a->my - b->my) | (a->ref - b->ref) | ((a->type ^ b->type)&BLOCK_INTRA));
}
}
//FIXME name cleanup (b_w, block_w, b_width stuff)
//XXX should we really inline it?
static av_always_inline void add_yblock(SnowContext *s, int sliced, slice_buffer *sb, IDWTELEM *dst, uint8_t *dst8, const uint8_t *obmc, int src_x, int src_y, int b_w, int b_h, int w, int h, int dst_stride, int src_stride, int obmc_stride, int b_x, int b_y, int add, int offset_dst, int plane_index){
const int b_width = s->b_width << s->block_max_depth;
const int b_height= s->b_height << s->block_max_depth;
const int b_stride= b_width;
BlockNode *lt= &s->block[b_x + b_y*b_stride];
BlockNode *rt= lt+1;
BlockNode *lb= lt+b_stride;
BlockNode *rb= lb+1;
uint8_t *block[4];
int tmp_step= src_stride >= 7*MB_SIZE ? MB_SIZE : MB_SIZE*src_stride;
uint8_t *tmp = s->scratchbuf;
uint8_t *ptmp;
int x,y;
if(b_x<0){
lt= rt;
lb= rb;
}else if(b_x + 1 >= b_width){
rt= lt;
rb= lb;
}
if(b_y<0){
lt= lb;
rt= rb;
}else if(b_y + 1 >= b_height){
lb= lt;
rb= rt;
}
if(src_x<0){ //FIXME merge with prev & always round internal width up to *16
obmc -= src_x;
b_w += src_x;
if(!sliced && !offset_dst)
dst -= src_x;
src_x=0;
}else if(src_x + b_w > w){
b_w = w - src_x;
}
if(src_y<0){
obmc -= src_y*obmc_stride;
b_h += src_y;
if(!sliced && !offset_dst)
dst -= src_y*dst_stride;
src_y=0;
}else if(src_y + b_h> h){
b_h = h - src_y;
}
if(b_w<=0 || b_h<=0) return;
assert(src_stride > 2*MB_SIZE + 5);
if(!sliced && offset_dst)
dst += src_x + src_y*dst_stride;
dst8+= src_x + src_y*src_stride;
// src += src_x + src_y*src_stride;
ptmp= tmp + 3*tmp_step;
block[0]= ptmp;
ptmp+=tmp_step;
ff_snow_pred_block(s, block[0], tmp, src_stride, src_x, src_y, b_w, b_h, lt, plane_index, w, h);
if(same_block(lt, rt)){
block[1]= block[0];
}else{
block[1]= ptmp;
ptmp+=tmp_step;
ff_snow_pred_block(s, block[1], tmp, src_stride, src_x, src_y, b_w, b_h, rt, plane_index, w, h);
}
if(same_block(lt, lb)){
block[2]= block[0];
}else if(same_block(rt, lb)){
block[2]= block[1];
}else{
block[2]= ptmp;
ptmp+=tmp_step;
ff_snow_pred_block(s, block[2], tmp, src_stride, src_x, src_y, b_w, b_h, lb, plane_index, w, h);
}
if(same_block(lt, rb) ){
block[3]= block[0];
}else if(same_block(rt, rb)){
block[3]= block[1];
}else if(same_block(lb, rb)){
block[3]= block[2];
}else{
block[3]= ptmp;
ff_snow_pred_block(s, block[3], tmp, src_stride, src_x, src_y, b_w, b_h, rb, plane_index, w, h);
}
if(sliced){
s->dwt.inner_add_yblock(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8);
}else{
for(y=0; y<b_h; y++){
//FIXME ugly misuse of obmc_stride
const uint8_t *obmc1= obmc + y*obmc_stride;
const uint8_t *obmc2= obmc1+ (obmc_stride>>1);
const uint8_t *obmc3= obmc1+ obmc_stride*(obmc_stride>>1);
const uint8_t *obmc4= obmc3+ (obmc_stride>>1);
for(x=0; x<b_w; x++){
int v= obmc1[x] * block[3][x + y*src_stride]
+obmc2[x] * block[2][x + y*src_stride]
+obmc3[x] * block[1][x + y*src_stride]
+obmc4[x] * block[0][x + y*src_stride];
v <<= 8 - LOG2_OBMC_MAX;
if(FRAC_BITS != 8){
v >>= 8 - FRAC_BITS;
}
if(add){
v += dst[x + y*dst_stride];
v = (v + (1<<(FRAC_BITS-1))) >> FRAC_BITS;
if(v&(~255)) v= ~(v>>31);
dst8[x + y*src_stride] = v;
}else{
dst[x + y*dst_stride] -= v;
}
}
}
}
}
static av_always_inline void predict_slice(SnowContext *s, IDWTELEM *buf, int plane_index, int add, int mb_y){
Plane *p= &s->plane[plane_index];
const int mb_w= s->b_width << s->block_max_depth;
const int mb_h= s->b_height << s->block_max_depth;
int x, y, mb_x;
int block_size = MB_SIZE >> s->block_max_depth;
int block_w = plane_index ? block_size/2 : block_size;
const uint8_t *obmc = plane_index ? ff_obmc_tab[s->block_max_depth+1] : ff_obmc_tab[s->block_max_depth];
const int obmc_stride= plane_index ? block_size : 2*block_size;
int ref_stride= s->current_picture.linesize[plane_index];
uint8_t *dst8= s->current_picture.data[plane_index];
int w= p->width;
int h= p->height;
if(s->keyframe || (s->avctx->debug&512)){
if(mb_y==mb_h)
return;
if(add){
for(y=block_w*mb_y; y<FFMIN(h,block_w*(mb_y+1)); y++){
for(x=0; x<w; x++){
int v= buf[x + y*w] + (128<<FRAC_BITS) + (1<<(FRAC_BITS-1));
v >>= FRAC_BITS;
if(v&(~255)) v= ~(v>>31);
dst8[x + y*ref_stride]= v;
}
}
}else{
for(y=block_w*mb_y; y<FFMIN(h,block_w*(mb_y+1)); y++){
for(x=0; x<w; x++){
buf[x + y*w]-= 128<<FRAC_BITS;
}
}
}
return;
}
for(mb_x=0; mb_x<=mb_w; mb_x++){
add_yblock(s, 0, NULL, buf, dst8, obmc,
block_w*mb_x - block_w/2,
block_w*mb_y - block_w/2,
block_w, block_w,
w, h,
w, ref_stride, obmc_stride,
mb_x - 1, mb_y - 1,
add, 1, plane_index);
}
}
static av_always_inline void predict_plane(SnowContext *s, IDWTELEM *buf, int plane_index, int add){
const int mb_h= s->b_height << s->block_max_depth;
int mb_y;
for(mb_y=0; mb_y<=mb_h; mb_y++)
predict_slice(s, buf, plane_index, add, mb_y);
}
static inline void set_blocks(SnowContext *s, int level, int x, int y, int l, int cb, int cr, int mx, int my, int ref, int type){
const int w= s->b_width << s->block_max_depth;
const int rem_depth= s->block_max_depth - level;
const int index= (x + y*w) << rem_depth;
const int block_w= 1<<rem_depth;
BlockNode block;
int i,j;
block.color[0]= l;
block.color[1]= cb;
block.color[2]= cr;
block.mx= mx;
block.my= my;
block.ref= ref;
block.type= type;
block.level= level;
for(j=0; j<block_w; j++){
for(i=0; i<block_w; i++){
s->block[index + i + j*w]= block;
}
}
}
static inline void init_ref(MotionEstContext *c, uint8_t *src[3], uint8_t *ref[3], uint8_t *ref2[3], int x, int y, int ref_index){
const int offset[3]= {
y*c-> stride + x,
((y*c->uvstride + x)>>1),
((y*c->uvstride + x)>>1),
};
int i;
for(i=0; i<3; i++){
c->src[0][i]= src [i];
c->ref[0][i]= ref [i] + offset[i];
}
assert(!ref_index);
}
/* bitstream functions */
extern const int8_t ff_quant3bA[256];
#define QEXPSHIFT (7-FRAC_BITS+8) //FIXME try to change this to 0
static inline void put_symbol(RangeCoder *c, uint8_t *state, int v, int is_signed){
int i;
if(v){
const int a= FFABS(v);
const int e= av_log2(a);
const int el= FFMIN(e, 10);
put_rac(c, state+0, 0);
for(i=0; i<el; i++){
put_rac(c, state+1+i, 1); //1..10
}
for(; i<e; i++){
put_rac(c, state+1+9, 1); //1..10
}
put_rac(c, state+1+FFMIN(i,9), 0);
for(i=e-1; i>=el; i--){
put_rac(c, state+22+9, (a>>i)&1); //22..31
}
for(; i>=0; i--){
put_rac(c, state+22+i, (a>>i)&1); //22..31
}
if(is_signed)
put_rac(c, state+11 + el, v < 0); //11..21
}else{
put_rac(c, state+0, 1);
}
}
static inline int get_symbol(RangeCoder *c, uint8_t *state, int is_signed){
if(get_rac(c, state+0))
return 0;
else{
int i, e, a;
e= 0;
while(get_rac(c, state+1 + FFMIN(e,9))){ //1..10
e++;
}
a= 1;
for(i=e-1; i>=0; i--){
a += a + get_rac(c, state+22 + FFMIN(i,9)); //22..31
}
e= -(is_signed && get_rac(c, state+11 + FFMIN(e,10))); //11..21
return (a^e)-e;
}
}
static inline void put_symbol2(RangeCoder *c, uint8_t *state, int v, int log2){
int i;
int r= log2>=0 ? 1<<log2 : 1;
assert(v>=0);
assert(log2>=-4);
while(v >= r){
put_rac(c, state+4+log2, 1);
v -= r;
log2++;
if(log2>0) r+=r;
}
put_rac(c, state+4+log2, 0);
for(i=log2-1; i>=0; i--){
put_rac(c, state+31-i, (v>>i)&1);
}
}
static inline int get_symbol2(RangeCoder *c, uint8_t *state, int log2){
int i;
int r= log2>=0 ? 1<<log2 : 1;
int v=0;
assert(log2>=-4);
while(get_rac(c, state+4+log2)){
v+= r;
log2++;
if(log2>0) r+=r;
}
for(i=log2-1; i>=0; i--){
v+= get_rac(c, state+31-i)<<i;
}
return v;
}
static inline void unpack_coeffs(SnowContext *s, SubBand *b, SubBand * parent, int orientation){
const int w= b->width;
const int h= b->height;
int x,y;
int run, runs;
x_and_coeff *xc= b->x_coeff;
x_and_coeff *prev_xc= NULL;
x_and_coeff *prev2_xc= xc;
x_and_coeff *parent_xc= parent ? parent->x_coeff : NULL;
x_and_coeff *prev_parent_xc= parent_xc;
runs= get_symbol2(&s->c, b->state[30], 0);
if(runs-- > 0) run= get_symbol2(&s->c, b->state[1], 3);
else run= INT_MAX;
for(y=0; y<h; y++){
int v=0;
int lt=0, t=0, rt=0;
if(y && prev_xc->x == 0){
rt= prev_xc->coeff;
}
for(x=0; x<w; x++){
int p=0;
const int l= v;
lt= t; t= rt;
if(y){
if(prev_xc->x <= x)
prev_xc++;
if(prev_xc->x == x + 1)
rt= prev_xc->coeff;
else
rt=0;
}
if(parent_xc){
if(x>>1 > parent_xc->x){
parent_xc++;
}
if(x>>1 == parent_xc->x){
p= parent_xc->coeff;
}
}
if(/*ll|*/l|lt|t|rt|p){
int context= av_log2(/*FFABS(ll) + */3*(l>>1) + (lt>>1) + (t&~1) + (rt>>1) + (p>>1));
v=get_rac(&s->c, &b->state[0][context]);
if(v){
v= 2*(get_symbol2(&s->c, b->state[context + 2], context-4) + 1);
v+=get_rac(&s->c, &b->state[0][16 + 1 + 3 + ff_quant3bA[l&0xFF] + 3*ff_quant3bA[t&0xFF]]);
xc->x=x;
(xc++)->coeff= v;
}
}else{
if(!run){
if(runs-- > 0) run= get_symbol2(&s->c, b->state[1], 3);
else run= INT_MAX;
v= 2*(get_symbol2(&s->c, b->state[0 + 2], 0-4) + 1);
v+=get_rac(&s->c, &b->state[0][16 + 1 + 3]);
xc->x=x;
(xc++)->coeff= v;
}else{
int max_run;
run--;
v=0;
if(y) max_run= FFMIN(run, prev_xc->x - x - 2);
else max_run= FFMIN(run, w-x-1);
if(parent_xc)
max_run= FFMIN(max_run, 2*parent_xc->x - x - 1);
x+= max_run;
run-= max_run;
}
}
}
(xc++)->x= w+1; //end marker
prev_xc= prev2_xc;
prev2_xc= xc;
if(parent_xc){
if(y&1){
while(parent_xc->x != parent->width+1)
parent_xc++;
parent_xc++;
prev_parent_xc= parent_xc;
}else{
parent_xc= prev_parent_xc;
}
}
}
(xc++)->x= w+1; //end marker
}
#endif /* AVCODEC_SNOW_H */
/*
* Copyright (C) 2004 Michael Niedermayer <michaelni@gmx.at>
* Copyright (C) 2006 Robert Edele <yartrebo@earthlink.net>
*
* This file is part of Libav.
*
* Libav 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.
*
* Libav 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 Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVCODEC_SNOWDATA_H
#define AVCODEC_SNOWDATA_H
#include "snow.h"
static const uint8_t obmc32[1024]={
0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0,
0, 4, 4, 4, 8, 8, 8, 12, 12, 16, 16, 16, 20, 20, 20, 24, 24, 20, 20, 20, 16, 16, 16, 12, 12, 8, 8, 8, 4, 4, 4, 0,
0, 4, 8, 8, 12, 12, 16, 20, 20, 24, 28, 28, 32, 32, 36, 40, 40, 36, 32, 32, 28, 28, 24, 20, 20, 16, 12, 12, 8, 8, 4, 0,
0, 4, 8, 12, 16, 20, 24, 28, 28, 32, 36, 40, 44, 48, 52, 56, 56, 52, 48, 44, 40, 36, 32, 28, 28, 24, 20, 16, 12, 8, 4, 0,
4, 8, 12, 16, 20, 24, 28, 32, 40, 44, 48, 52, 56, 60, 64, 68, 68, 64, 60, 56, 52, 48, 44, 40, 32, 28, 24, 20, 16, 12, 8, 4,
4, 8, 12, 20, 24, 32, 36, 40, 48, 52, 56, 64, 68, 76, 80, 84, 84, 80, 76, 68, 64, 56, 52, 48, 40, 36, 32, 24, 20, 12, 8, 4,
4, 8, 16, 24, 28, 36, 44, 48, 56, 60, 68, 76, 80, 88, 96,100,100, 96, 88, 80, 76, 68, 60, 56, 48, 44, 36, 28, 24, 16, 8, 4,
4, 12, 20, 28, 32, 40, 48, 56, 64, 72, 80, 88, 92,100,108,116,116,108,100, 92, 88, 80, 72, 64, 56, 48, 40, 32, 28, 20, 12, 4,
4, 12, 20, 28, 40, 48, 56, 64, 72, 80, 88, 96,108,116,124,132,132,124,116,108, 96, 88, 80, 72, 64, 56, 48, 40, 28, 20, 12, 4,
4, 16, 24, 32, 44, 52, 60, 72, 80, 92,100,108,120,128,136,148,148,136,128,120,108,100, 92, 80, 72, 60, 52, 44, 32, 24, 16, 4,
4, 16, 28, 36, 48, 56, 68, 80, 88,100,112,120,132,140,152,164,164,152,140,132,120,112,100, 88, 80, 68, 56, 48, 36, 28, 16, 4,
4, 16, 28, 40, 52, 64, 76, 88, 96,108,120,132,144,156,168,180,180,168,156,144,132,120,108, 96, 88, 76, 64, 52, 40, 28, 16, 4,
8, 20, 32, 44, 56, 68, 80, 92,108,120,132,144,156,168,180,192,192,180,168,156,144,132,120,108, 92, 80, 68, 56, 44, 32, 20, 8,
8, 20, 32, 48, 60, 76, 88,100,116,128,140,156,168,184,196,208,208,196,184,168,156,140,128,116,100, 88, 76, 60, 48, 32, 20, 8,
8, 20, 36, 52, 64, 80, 96,108,124,136,152,168,180,196,212,224,224,212,196,180,168,152,136,124,108, 96, 80, 64, 52, 36, 20, 8,
8, 24, 40, 56, 68, 84,100,116,132,148,164,180,192,208,224,240,240,224,208,192,180,164,148,132,116,100, 84, 68, 56, 40, 24, 8,
8, 24, 40, 56, 68, 84,100,116,132,148,164,180,192,208,224,240,240,224,208,192,180,164,148,132,116,100, 84, 68, 56, 40, 24, 8,
8, 20, 36, 52, 64, 80, 96,108,124,136,152,168,180,196,212,224,224,212,196,180,168,152,136,124,108, 96, 80, 64, 52, 36, 20, 8,
8, 20, 32, 48, 60, 76, 88,100,116,128,140,156,168,184,196,208,208,196,184,168,156,140,128,116,100, 88, 76, 60, 48, 32, 20, 8,
8, 20, 32, 44, 56, 68, 80, 92,108,120,132,144,156,168,180,192,192,180,168,156,144,132,120,108, 92, 80, 68, 56, 44, 32, 20, 8,
4, 16, 28, 40, 52, 64, 76, 88, 96,108,120,132,144,156,168,180,180,168,156,144,132,120,108, 96, 88, 76, 64, 52, 40, 28, 16, 4,
4, 16, 28, 36, 48, 56, 68, 80, 88,100,112,120,132,140,152,164,164,152,140,132,120,112,100, 88, 80, 68, 56, 48, 36, 28, 16, 4,
4, 16, 24, 32, 44, 52, 60, 72, 80, 92,100,108,120,128,136,148,148,136,128,120,108,100, 92, 80, 72, 60, 52, 44, 32, 24, 16, 4,
4, 12, 20, 28, 40, 48, 56, 64, 72, 80, 88, 96,108,116,124,132,132,124,116,108, 96, 88, 80, 72, 64, 56, 48, 40, 28, 20, 12, 4,
4, 12, 20, 28, 32, 40, 48, 56, 64, 72, 80, 88, 92,100,108,116,116,108,100, 92, 88, 80, 72, 64, 56, 48, 40, 32, 28, 20, 12, 4,
4, 8, 16, 24, 28, 36, 44, 48, 56, 60, 68, 76, 80, 88, 96,100,100, 96, 88, 80, 76, 68, 60, 56, 48, 44, 36, 28, 24, 16, 8, 4,
4, 8, 12, 20, 24, 32, 36, 40, 48, 52, 56, 64, 68, 76, 80, 84, 84, 80, 76, 68, 64, 56, 52, 48, 40, 36, 32, 24, 20, 12, 8, 4,
4, 8, 12, 16, 20, 24, 28, 32, 40, 44, 48, 52, 56, 60, 64, 68, 68, 64, 60, 56, 52, 48, 44, 40, 32, 28, 24, 20, 16, 12, 8, 4,
0, 4, 8, 12, 16, 20, 24, 28, 28, 32, 36, 40, 44, 48, 52, 56, 56, 52, 48, 44, 40, 36, 32, 28, 28, 24, 20, 16, 12, 8, 4, 0,
0, 4, 8, 8, 12, 12, 16, 20, 20, 24, 28, 28, 32, 32, 36, 40, 40, 36, 32, 32, 28, 28, 24, 20, 20, 16, 12, 12, 8, 8, 4, 0,
0, 4, 4, 4, 8, 8, 8, 12, 12, 16, 16, 16, 20, 20, 20, 24, 24, 20, 20, 20, 16, 16, 16, 12, 12, 8, 8, 8, 4, 4, 4, 0,
0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0,
//error:0.000020
};
static const uint8_t obmc16[256]={
0, 4, 4, 8, 8, 12, 12, 16, 16, 12, 12, 8, 8, 4, 4, 0,
4, 8, 16, 20, 28, 32, 40, 44, 44, 40, 32, 28, 20, 16, 8, 4,
4, 16, 24, 36, 44, 56, 64, 76, 76, 64, 56, 44, 36, 24, 16, 4,
8, 20, 36, 48, 64, 76, 92,104,104, 92, 76, 64, 48, 36, 20, 8,
8, 28, 44, 64, 80,100,116,136,136,116,100, 80, 64, 44, 28, 8,
12, 32, 56, 76,100,120,144,164,164,144,120,100, 76, 56, 32, 12,
12, 40, 64, 92,116,144,168,196,196,168,144,116, 92, 64, 40, 12,
16, 44, 76,104,136,164,196,224,224,196,164,136,104, 76, 44, 16,
16, 44, 76,104,136,164,196,224,224,196,164,136,104, 76, 44, 16,
12, 40, 64, 92,116,144,168,196,196,168,144,116, 92, 64, 40, 12,
12, 32, 56, 76,100,120,144,164,164,144,120,100, 76, 56, 32, 12,
8, 28, 44, 64, 80,100,116,136,136,116,100, 80, 64, 44, 28, 8,
8, 20, 36, 48, 64, 76, 92,104,104, 92, 76, 64, 48, 36, 20, 8,
4, 16, 24, 36, 44, 56, 64, 76, 76, 64, 56, 44, 36, 24, 16, 4,
4, 8, 16, 20, 28, 32, 40, 44, 44, 40, 32, 28, 20, 16, 8, 4,
0, 4, 4, 8, 8, 12, 12, 16, 16, 12, 12, 8, 8, 4, 4, 0,
//error:0.000015
};
//linear *64
static const uint8_t obmc8[64]={
4, 12, 20, 28, 28, 20, 12, 4,
12, 36, 60, 84, 84, 60, 36, 12,
20, 60,100,140,140,100, 60, 20,
28, 84,140,196,196,140, 84, 28,
28, 84,140,196,196,140, 84, 28,
20, 60,100,140,140,100, 60, 20,
12, 36, 60, 84, 84, 60, 36, 12,
4, 12, 20, 28, 28, 20, 12, 4,
//error:0.000000
};
//linear *64
static const uint8_t obmc4[16]={
16, 48, 48, 16,
48,144,144, 48,
48,144,144, 48,
16, 48, 48, 16,
//error:0.000000
};
const int8_t ff_quant3bA[256]={
0, 0, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1,
1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1,
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, 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, 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, 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, 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,
};
const uint8_t * const ff_obmc_tab[4]= {
obmc32, obmc16, obmc8, obmc4
};
/* runtime generated tables */
uint8_t ff_qexp[QROOT];
int ff_scale_mv_ref[MAX_REF_FRAMES][MAX_REF_FRAMES];
#endif /* AVCODEC_SNOW_H */
/*
* Copyright (C) 2004 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of Libav.
*
* Libav 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.
*
* Libav 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 Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/intmath.h"
#include "libavutil/log.h"
#include "libavutil/opt.h"
#include "avcodec.h"
#include "dsputil.h"
#include "dwt.h"
#include "internal.h"
#include "snow.h"
#include "rangecoder.h"
#include "mathops.h"
#include "mpegvideo.h"
#include "h263.h"
#undef NDEBUG
#include <assert.h>
static av_always_inline void predict_slice_buffered(SnowContext *s, slice_buffer * sb, IDWTELEM * old_buffer, int plane_index, int add, int mb_y){
Plane *p= &s->plane[plane_index];
const int mb_w= s->b_width << s->block_max_depth;
const int mb_h= s->b_height << s->block_max_depth;
int x, y, mb_x;
int block_size = MB_SIZE >> s->block_max_depth;
int block_w = plane_index ? block_size/2 : block_size;
const uint8_t *obmc = plane_index ? ff_obmc_tab[s->block_max_depth+1] : ff_obmc_tab[s->block_max_depth];
int obmc_stride= plane_index ? block_size : 2*block_size;
int ref_stride= s->current_picture.linesize[plane_index];
uint8_t *dst8= s->current_picture.data[plane_index];
int w= p->width;
int h= p->height;
if(s->keyframe || (s->avctx->debug&512)){
if(mb_y==mb_h)
return;
if(add){
for(y=block_w*mb_y; y<FFMIN(h,block_w*(mb_y+1)); y++){
// DWTELEM * line = slice_buffer_get_line(sb, y);
IDWTELEM * line = sb->line[y];
for(x=0; x<w; x++){
// int v= buf[x + y*w] + (128<<FRAC_BITS) + (1<<(FRAC_BITS-1));
int v= line[x] + (128<<FRAC_BITS) + (1<<(FRAC_BITS-1));
v >>= FRAC_BITS;
if(v&(~255)) v= ~(v>>31);
dst8[x + y*ref_stride]= v;
}
}
}else{
for(y=block_w*mb_y; y<FFMIN(h,block_w*(mb_y+1)); y++){
// DWTELEM * line = slice_buffer_get_line(sb, y);
IDWTELEM * line = sb->line[y];
for(x=0; x<w; x++){
line[x] -= 128 << FRAC_BITS;
// buf[x + y*w]-= 128<<FRAC_BITS;
}
}
}
return;
}
for(mb_x=0; mb_x<=mb_w; mb_x++){
add_yblock(s, 1, sb, old_buffer, dst8, obmc,
block_w*mb_x - block_w/2,
block_w*mb_y - block_w/2,
block_w, block_w,
w, h,
w, ref_stride, obmc_stride,
mb_x - 1, mb_y - 1,
add, 0, plane_index);
}
}
static inline void decode_subband_slice_buffered(SnowContext *s, SubBand *b, slice_buffer * sb, int start_y, int h, int save_state[1]){
const int w= b->width;
int y;
const int qlog= av_clip(s->qlog + b->qlog, 0, QROOT*16);
int qmul= ff_qexp[qlog&(QROOT-1)]<<(qlog>>QSHIFT);
int qadd= (s->qbias*qmul)>>QBIAS_SHIFT;
int new_index = 0;
if(b->ibuf == s->spatial_idwt_buffer || s->qlog == LOSSLESS_QLOG){
qadd= 0;
qmul= 1<<QEXPSHIFT;
}
/* If we are on the second or later slice, restore our index. */
if (start_y != 0)
new_index = save_state[0];
for(y=start_y; y<h; y++){
int x = 0;
int v;
IDWTELEM * line = slice_buffer_get_line(sb, y * b->stride_line + b->buf_y_offset) + b->buf_x_offset;
memset(line, 0, b->width*sizeof(IDWTELEM));
v = b->x_coeff[new_index].coeff;
x = b->x_coeff[new_index++].x;
while(x < w){
register int t= ( (v>>1)*qmul + qadd)>>QEXPSHIFT;
register int u= -(v&1);
line[x] = (t^u) - u;
v = b->x_coeff[new_index].coeff;
x = b->x_coeff[new_index++].x;
}
}
/* Save our variables for the next slice. */
save_state[0] = new_index;
return;
}
static int decode_q_branch(SnowContext *s, int level, int x, int y){
const int w= s->b_width << s->block_max_depth;
const int rem_depth= s->block_max_depth - level;
const int index= (x + y*w) << rem_depth;
int trx= (x+1)<<rem_depth;
const BlockNode *left = x ? &s->block[index-1] : &null_block;
const BlockNode *top = y ? &s->block[index-w] : &null_block;
const BlockNode *tl = y && x ? &s->block[index-w-1] : left;
const BlockNode *tr = y && trx<w && ((x&1)==0 || level==0) ? &s->block[index-w+(1<<rem_depth)] : tl; //FIXME use lt
int s_context= 2*left->level + 2*top->level + tl->level + tr->level;
int res;
if(s->keyframe){
set_blocks(s, level, x, y, null_block.color[0], null_block.color[1], null_block.color[2], null_block.mx, null_block.my, null_block.ref, BLOCK_INTRA);
return 0;
}
if(level==s->block_max_depth || get_rac(&s->c, &s->block_state[4 + s_context])){
int type, mx, my;
int l = left->color[0];
int cb= left->color[1];
int cr= left->color[2];
int ref = 0;
int ref_context= av_log2(2*left->ref) + av_log2(2*top->ref);
int mx_context= av_log2(2*FFABS(left->mx - top->mx)) + 0*av_log2(2*FFABS(tr->mx - top->mx));
int my_context= av_log2(2*FFABS(left->my - top->my)) + 0*av_log2(2*FFABS(tr->my - top->my));
type= get_rac(&s->c, &s->block_state[1 + left->type + top->type]) ? BLOCK_INTRA : 0;
if(type){
pred_mv(s, &mx, &my, 0, left, top, tr);
l += get_symbol(&s->c, &s->block_state[32], 1);
cb+= get_symbol(&s->c, &s->block_state[64], 1);
cr+= get_symbol(&s->c, &s->block_state[96], 1);
}else{
if(s->ref_frames > 1)
ref= get_symbol(&s->c, &s->block_state[128 + 1024 + 32*ref_context], 0);
if (ref >= s->ref_frames) {
av_log(s->avctx, AV_LOG_ERROR, "Invalid ref\n");
return AVERROR_INVALIDDATA;
}
pred_mv(s, &mx, &my, ref, left, top, tr);
mx+= get_symbol(&s->c, &s->block_state[128 + 32*(mx_context + 16*!!ref)], 1);
my+= get_symbol(&s->c, &s->block_state[128 + 32*(my_context + 16*!!ref)], 1);
}
set_blocks(s, level, x, y, l, cb, cr, mx, my, ref, type);
}else{
if ((res = decode_q_branch(s, level+1, 2*x+0, 2*y+0)) < 0 ||
(res = decode_q_branch(s, level+1, 2*x+1, 2*y+0)) < 0 ||
(res = decode_q_branch(s, level+1, 2*x+0, 2*y+1)) < 0 ||
(res = decode_q_branch(s, level+1, 2*x+1, 2*y+1)) < 0)
return res;
}
return 0;
}
static void dequantize_slice_buffered(SnowContext *s, slice_buffer * sb, SubBand *b, IDWTELEM *src, int stride, int start_y, int end_y){
const int w= b->width;
const int qlog= av_clip(s->qlog + b->qlog, 0, QROOT*16);
const int qmul= ff_qexp[qlog&(QROOT-1)]<<(qlog>>QSHIFT);
const int qadd= (s->qbias*qmul)>>QBIAS_SHIFT;
int x,y;
if(s->qlog == LOSSLESS_QLOG) return;
for(y=start_y; y<end_y; y++){
// DWTELEM * line = slice_buffer_get_line_from_address(sb, src + (y * stride));
IDWTELEM * line = slice_buffer_get_line(sb, (y * b->stride_line) + b->buf_y_offset) + b->buf_x_offset;
for(x=0; x<w; x++){
int i= line[x];
if(i<0){
line[x]= -((-i*qmul + qadd)>>(QEXPSHIFT)); //FIXME try different bias
}else if(i>0){
line[x]= (( i*qmul + qadd)>>(QEXPSHIFT));
}
}
}
}
static void correlate_slice_buffered(SnowContext *s, slice_buffer * sb, SubBand *b, IDWTELEM *src, int stride, int inverse, int use_median, int start_y, int end_y){
const int w= b->width;
int x,y;
IDWTELEM * line=0; // silence silly "could be used without having been initialized" warning
IDWTELEM * prev;
if (start_y != 0)
line = slice_buffer_get_line(sb, ((start_y - 1) * b->stride_line) + b->buf_y_offset) + b->buf_x_offset;
for(y=start_y; y<end_y; y++){
prev = line;
// line = slice_buffer_get_line_from_address(sb, src + (y * stride));
line = slice_buffer_get_line(sb, (y * b->stride_line) + b->buf_y_offset) + b->buf_x_offset;
for(x=0; x<w; x++){
if(x){
if(use_median){
if(y && x+1<w) line[x] += mid_pred(line[x - 1], prev[x], prev[x + 1]);
else line[x] += line[x - 1];
}else{
if(y) line[x] += mid_pred(line[x - 1], prev[x], line[x - 1] + prev[x] - prev[x - 1]);
else line[x] += line[x - 1];
}
}else{
if(y) line[x] += prev[x];
}
}
}
}
static void decode_qlogs(SnowContext *s){
int plane_index, level, orientation;
for(plane_index=0; plane_index<3; plane_index++){
for(level=0; level<s->spatial_decomposition_count; level++){
for(orientation=level ? 1:0; orientation<4; orientation++){
int q;
if (plane_index==2) q= s->plane[1].band[level][orientation].qlog;
else if(orientation==2) q= s->plane[plane_index].band[level][1].qlog;
else q= get_symbol(&s->c, s->header_state, 1);
s->plane[plane_index].band[level][orientation].qlog= q;
}
}
}
}
#define GET_S(dst, check) \
tmp= get_symbol(&s->c, s->header_state, 0);\
if(!(check)){\
av_log(s->avctx, AV_LOG_ERROR, "Error " #dst " is %d\n", tmp);\
return -1;\
}\
dst= tmp;
static int decode_header(SnowContext *s){
int plane_index, tmp;
uint8_t kstate[32];
memset(kstate, MID_STATE, sizeof(kstate));
s->keyframe= get_rac(&s->c, kstate);
if(s->keyframe || s->always_reset){
ff_snow_reset_contexts(s);
s->spatial_decomposition_type=
s->qlog=
s->qbias=
s->mv_scale=
s->block_max_depth= 0;
}
if(s->keyframe){
GET_S(s->version, tmp <= 0U)
s->always_reset= get_rac(&s->c, s->header_state);
s->temporal_decomposition_type= get_symbol(&s->c, s->header_state, 0);
s->temporal_decomposition_count= get_symbol(&s->c, s->header_state, 0);
GET_S(s->spatial_decomposition_count, 0 < tmp && tmp <= MAX_DECOMPOSITIONS)
s->colorspace_type= get_symbol(&s->c, s->header_state, 0);
s->chroma_h_shift= get_symbol(&s->c, s->header_state, 0);
s->chroma_v_shift= get_symbol(&s->c, s->header_state, 0);
s->spatial_scalability= get_rac(&s->c, s->header_state);
// s->rate_scalability= get_rac(&s->c, s->header_state);
GET_S(s->max_ref_frames, tmp < (unsigned)MAX_REF_FRAMES)
s->max_ref_frames++;
decode_qlogs(s);
}
if(!s->keyframe){
if(get_rac(&s->c, s->header_state)){
for(plane_index=0; plane_index<2; plane_index++){
int htaps, i, sum=0;
Plane *p= &s->plane[plane_index];
p->diag_mc= get_rac(&s->c, s->header_state);
htaps= get_symbol(&s->c, s->header_state, 0)*2 + 2;
if((unsigned)htaps > HTAPS_MAX || htaps==0)
return -1;
p->htaps= htaps;
for(i= htaps/2; i; i--){
p->hcoeff[i]= get_symbol(&s->c, s->header_state, 0) * (1-2*(i&1));
sum += p->hcoeff[i];
}
p->hcoeff[0]= 32-sum;
}
s->plane[2].diag_mc= s->plane[1].diag_mc;
s->plane[2].htaps = s->plane[1].htaps;
memcpy(s->plane[2].hcoeff, s->plane[1].hcoeff, sizeof(s->plane[1].hcoeff));
}
if(get_rac(&s->c, s->header_state)){
GET_S(s->spatial_decomposition_count, 0 < tmp && tmp <= MAX_DECOMPOSITIONS)
decode_qlogs(s);
}
}
s->spatial_decomposition_type+= get_symbol(&s->c, s->header_state, 1);
if(s->spatial_decomposition_type > 1U){
av_log(s->avctx, AV_LOG_ERROR, "spatial_decomposition_type %d not supported", s->spatial_decomposition_type);
return -1;
}
if(FFMIN(s->avctx-> width>>s->chroma_h_shift,
s->avctx->height>>s->chroma_v_shift) >> (s->spatial_decomposition_count-1) <= 0){
av_log(s->avctx, AV_LOG_ERROR, "spatial_decomposition_count %d too large for size", s->spatial_decomposition_count);
return -1;
}
if (s->chroma_h_shift != 1 || s->chroma_v_shift != 1) {
av_log(s->avctx, AV_LOG_ERROR, "Invalid chroma shift\n");
return AVERROR_PATCHWELCOME;
}
s->qlog += get_symbol(&s->c, s->header_state, 1);
s->mv_scale += get_symbol(&s->c, s->header_state, 1);
s->qbias += get_symbol(&s->c, s->header_state, 1);
s->block_max_depth+= get_symbol(&s->c, s->header_state, 1);
if(s->block_max_depth > 1 || s->block_max_depth < 0){
av_log(s->avctx, AV_LOG_ERROR, "block_max_depth= %d is too large", s->block_max_depth);
s->block_max_depth= 0;
return -1;
}
return 0;
}
static av_cold int decode_init(AVCodecContext *avctx)
{
int ret;
avctx->pix_fmt= AV_PIX_FMT_YUV420P;
if ((ret = ff_snow_common_init(avctx)) < 0) {
ff_snow_common_end(avctx->priv_data);
return ret;
}
return 0;
}
static int decode_blocks(SnowContext *s){
int x, y;
int w= s->b_width;
int h= s->b_height;
int res;
for(y=0; y<h; y++){
for(x=0; x<w; x++){
if ((res = decode_q_branch(s, 0, x, y)) < 0)
return res;
}
}
return 0;
}
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
AVPacket *avpkt)
{
const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
SnowContext *s = avctx->priv_data;
RangeCoder * const c= &s->c;
int bytes_read;
AVFrame *picture = data;
int level, orientation, plane_index;
int res;
ff_init_range_decoder(c, buf, buf_size);
ff_build_rac_states(c, 0.05*(1LL<<32), 256-8);
s->current_picture.pict_type= AV_PICTURE_TYPE_I; //FIXME I vs. P
if(decode_header(s)<0)
return -1;
ff_snow_common_init_after_header(avctx);
// realloc slice buffer for the case that spatial_decomposition_count changed
ff_slice_buffer_destroy(&s->sb);
if ((res = ff_slice_buffer_init(&s->sb, s->plane[0].height,
(MB_SIZE >> s->block_max_depth) +
s->spatial_decomposition_count * 8 + 1,
s->plane[0].width,
s->spatial_idwt_buffer)) < 0)
return res;
for(plane_index=0; plane_index<3; plane_index++){
Plane *p= &s->plane[plane_index];
p->fast_mc= p->diag_mc && p->htaps==6 && p->hcoeff[0]==40
&& p->hcoeff[1]==-10
&& p->hcoeff[2]==2;
}
ff_snow_alloc_blocks(s);
if(ff_snow_frame_start(s) < 0)
return -1;
//keyframe flag duplication mess FIXME
if(avctx->debug&FF_DEBUG_PICT_INFO)
av_log(avctx, AV_LOG_ERROR, "keyframe:%d qlog:%d\n", s->keyframe, s->qlog);
if ((res = decode_blocks(s)) < 0)
return res;
for(plane_index=0; plane_index<3; plane_index++){
Plane *p= &s->plane[plane_index];
int w= p->width;
int h= p->height;
int x, y;
int decode_state[MAX_DECOMPOSITIONS][4][1]; /* Stored state info for unpack_coeffs. 1 variable per instance. */
if(s->avctx->debug&2048){
memset(s->spatial_dwt_buffer, 0, sizeof(DWTELEM)*w*h);
predict_plane(s, s->spatial_idwt_buffer, plane_index, 1);
for(y=0; y<h; y++){
for(x=0; x<w; x++){
int v= s->current_picture.data[plane_index][y*s->current_picture.linesize[plane_index] + x];
s->mconly_picture.data[plane_index][y*s->mconly_picture.linesize[plane_index] + x]= v;
}
}
}
{
for(level=0; level<s->spatial_decomposition_count; level++){
for(orientation=level ? 1 : 0; orientation<4; orientation++){
SubBand *b= &p->band[level][orientation];
unpack_coeffs(s, b, b->parent, orientation);
}
}
}
{
const int mb_h= s->b_height << s->block_max_depth;
const int block_size = MB_SIZE >> s->block_max_depth;
const int block_w = plane_index ? block_size/2 : block_size;
int mb_y;
DWTCompose cs[MAX_DECOMPOSITIONS];
int yd=0, yq=0;
int y;
int end_y;
ff_spatial_idwt_buffered_init(cs, &s->sb, w, h, 1, s->spatial_decomposition_type, s->spatial_decomposition_count);
for(mb_y=0; mb_y<=mb_h; mb_y++){
int slice_starty = block_w*mb_y;
int slice_h = block_w*(mb_y+1);
if (!(s->keyframe || s->avctx->debug&512)){
slice_starty = FFMAX(0, slice_starty - (block_w >> 1));
slice_h -= (block_w >> 1);
}
for(level=0; level<s->spatial_decomposition_count; level++){
for(orientation=level ? 1 : 0; orientation<4; orientation++){
SubBand *b= &p->band[level][orientation];
int start_y;
int end_y;
int our_mb_start = mb_y;
int our_mb_end = (mb_y + 1);
const int extra= 3;
start_y = (mb_y ? ((block_w * our_mb_start) >> (s->spatial_decomposition_count - level)) + s->spatial_decomposition_count - level + extra: 0);
end_y = (((block_w * our_mb_end) >> (s->spatial_decomposition_count - level)) + s->spatial_decomposition_count - level + extra);
if (!(s->keyframe || s->avctx->debug&512)){
start_y = FFMAX(0, start_y - (block_w >> (1+s->spatial_decomposition_count - level)));
end_y = FFMAX(0, end_y - (block_w >> (1+s->spatial_decomposition_count - level)));
}
start_y = FFMIN(b->height, start_y);
end_y = FFMIN(b->height, end_y);
if (start_y != end_y){
if (orientation == 0){
SubBand * correlate_band = &p->band[0][0];
int correlate_end_y = FFMIN(b->height, end_y + 1);
int correlate_start_y = FFMIN(b->height, (start_y ? start_y + 1 : 0));
decode_subband_slice_buffered(s, correlate_band, &s->sb, correlate_start_y, correlate_end_y, decode_state[0][0]);
correlate_slice_buffered(s, &s->sb, correlate_band, correlate_band->ibuf, correlate_band->stride, 1, 0, correlate_start_y, correlate_end_y);
dequantize_slice_buffered(s, &s->sb, correlate_band, correlate_band->ibuf, correlate_band->stride, start_y, end_y);
}
else
decode_subband_slice_buffered(s, b, &s->sb, start_y, end_y, decode_state[level][orientation]);
}
}
}
for(; yd<slice_h; yd+=4){
ff_spatial_idwt_buffered_slice(&s->dwt, cs, &s->sb, s->temp_idwt_buffer, w, h, 1, s->spatial_decomposition_type, s->spatial_decomposition_count, yd);
}
if(s->qlog == LOSSLESS_QLOG){
for(; yq<slice_h && yq<h; yq++){
IDWTELEM * line = slice_buffer_get_line(&s->sb, yq);
for(x=0; x<w; x++){
line[x] <<= FRAC_BITS;
}
}
}
predict_slice_buffered(s, &s->sb, s->spatial_idwt_buffer, plane_index, 1, mb_y);
y = FFMIN(p->height, slice_starty);
end_y = FFMIN(p->height, slice_h);
while(y < end_y)
ff_slice_buffer_release(&s->sb, y++);
}
ff_slice_buffer_flush(&s->sb);
}
}
emms_c();
ff_snow_release_buffer(avctx);
if(!(s->avctx->debug&2048))
*picture= s->current_picture;
else
*picture= s->mconly_picture;
*got_frame = 1;
bytes_read= c->bytestream - c->bytestream_start;
if(bytes_read ==0) av_log(s->avctx, AV_LOG_ERROR, "error at end of frame\n"); //FIXME
return bytes_read;
}
static av_cold int decode_end(AVCodecContext *avctx)
{
SnowContext *s = avctx->priv_data;
ff_slice_buffer_destroy(&s->sb);
ff_snow_common_end(s);
return 0;
}
AVCodec ff_snow_decoder = {
.name = "snow",
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_SNOW,
.priv_data_size = sizeof(SnowContext),
.init = decode_init,
.close = decode_end,
.decode = decode_frame,
.capabilities = CODEC_CAP_DR1 /*| CODEC_CAP_DRAW_HORIZ_BAND*/,
.long_name = NULL_IF_CONFIG_SMALL("Snow"),
};
/*
* Copyright (C) 2004 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of Libav.
*
* Libav 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.
*
* Libav 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 Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/intmath.h"
#include "libavutil/log.h"
#include "libavutil/opt.h"
#include "avcodec.h"
#include "dsputil.h"
#include "internal.h"
#include "dwt.h"
#include "snow.h"
#include "rangecoder.h"
#include "mathops.h"
#include "mpegvideo.h"
#include "h263.h"
#undef NDEBUG
#include <assert.h>
#define QUANTIZE2 0
#if QUANTIZE2==1
#define Q2_STEP 8
static void find_sse(SnowContext *s, Plane *p, int *score, int score_stride, IDWTELEM *r0, IDWTELEM *r1, int level, int orientation){
SubBand *b= &p->band[level][orientation];
int x, y;
int xo=0;
int yo=0;
int step= 1 << (s->spatial_decomposition_count - level);
if(orientation&1)
xo= step>>1;
if(orientation&2)
yo= step>>1;
//FIXME bias for nonzero ?
//FIXME optimize
memset(score, 0, sizeof(*score)*score_stride*((p->height + Q2_STEP-1)/Q2_STEP));
for(y=0; y<p->height; y++){
for(x=0; x<p->width; x++){
int sx= (x-xo + step/2) / step / Q2_STEP;
int sy= (y-yo + step/2) / step / Q2_STEP;
int v= r0[x + y*p->width] - r1[x + y*p->width];
assert(sx>=0 && sy>=0 && sx < score_stride);
v= ((v+8)>>4)<<4;
score[sx + sy*score_stride] += v*v;
assert(score[sx + sy*score_stride] >= 0);
}
}
}
static void dequantize_all(SnowContext *s, Plane *p, IDWTELEM *buffer, int width, int height){
int level, orientation;
for(level=0; level<s->spatial_decomposition_count; level++){
for(orientation=level ? 1 : 0; orientation<4; orientation++){
SubBand *b= &p->band[level][orientation];
IDWTELEM *dst= buffer + (b->ibuf - s->spatial_idwt_buffer);
dequantize(s, b, dst, b->stride);
}
}
}
static void dwt_quantize(SnowContext *s, Plane *p, DWTELEM *buffer, int width, int height, int stride, int type){
int level, orientation, ys, xs, x, y, pass;
IDWTELEM best_dequant[height * stride];
IDWTELEM idwt2_buffer[height * stride];
const int score_stride= (width + 10)/Q2_STEP;
int best_score[(width + 10)/Q2_STEP * (height + 10)/Q2_STEP]; //FIXME size
int score[(width + 10)/Q2_STEP * (height + 10)/Q2_STEP]; //FIXME size
int threshold= (s->m.lambda * s->m.lambda) >> 6;
//FIXME pass the copy cleanly ?
// memcpy(dwt_buffer, buffer, height * stride * sizeof(DWTELEM));
ff_spatial_dwt(buffer, s->temp_dwt_buffer, width, height, stride, type, s->spatial_decomposition_count);
for(level=0; level<s->spatial_decomposition_count; level++){
for(orientation=level ? 1 : 0; orientation<4; orientation++){
SubBand *b= &p->band[level][orientation];
IDWTELEM *dst= best_dequant + (b->ibuf - s->spatial_idwt_buffer);
DWTELEM *src= buffer + (b-> buf - s->spatial_dwt_buffer);
assert(src == b->buf); // code does not depend on this but it is true currently
quantize(s, b, dst, src, b->stride, s->qbias);
}
}
for(pass=0; pass<1; pass++){
if(s->qbias == 0) //keyframe
continue;
for(level=0; level<s->spatial_decomposition_count; level++){
for(orientation=level ? 1 : 0; orientation<4; orientation++){
SubBand *b= &p->band[level][orientation];
IDWTELEM *dst= idwt2_buffer + (b->ibuf - s->spatial_idwt_buffer);
IDWTELEM *best_dst= best_dequant + (b->ibuf - s->spatial_idwt_buffer);
for(ys= 0; ys<Q2_STEP; ys++){
for(xs= 0; xs<Q2_STEP; xs++){
memcpy(idwt2_buffer, best_dequant, height * stride * sizeof(IDWTELEM));
dequantize_all(s, p, idwt2_buffer, width, height);
ff_spatial_idwt(idwt2_buffer, s->temp_idwt_buffer, width, height, stride, type, s->spatial_decomposition_count);
find_sse(s, p, best_score, score_stride, idwt2_buffer, s->spatial_idwt_buffer, level, orientation);
memcpy(idwt2_buffer, best_dequant, height * stride * sizeof(IDWTELEM));
for(y=ys; y<b->height; y+= Q2_STEP){
for(x=xs; x<b->width; x+= Q2_STEP){
if(dst[x + y*b->stride]<0) dst[x + y*b->stride]++;
if(dst[x + y*b->stride]>0) dst[x + y*b->stride]--;
//FIXME try more than just --
}
}
dequantize_all(s, p, idwt2_buffer, width, height);
ff_spatial_idwt(idwt2_buffer, s->temp_idwt_buffer, width, height, stride, type, s->spatial_decomposition_count);
find_sse(s, p, score, score_stride, idwt2_buffer, s->spatial_idwt_buffer, level, orientation);
for(y=ys; y<b->height; y+= Q2_STEP){
for(x=xs; x<b->width; x+= Q2_STEP){
int score_idx= x/Q2_STEP + (y/Q2_STEP)*score_stride;
if(score[score_idx] <= best_score[score_idx] + threshold){
best_score[score_idx]= score[score_idx];
if(best_dst[x + y*b->stride]<0) best_dst[x + y*b->stride]++;
if(best_dst[x + y*b->stride]>0) best_dst[x + y*b->stride]--;
//FIXME copy instead
}
}
}
}
}
}
}
}
memcpy(s->spatial_idwt_buffer, best_dequant, height * stride * sizeof(IDWTELEM)); //FIXME work with that directly instead of copy at the end
}
#endif /* QUANTIZE2==1 */
static av_cold int encode_init(AVCodecContext *avctx)
{
SnowContext *s = avctx->priv_data;
int plane_index, ret;
if(avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL){
av_log(avctx, AV_LOG_ERROR, "This codec is under development, files encoded with it may not be decodable with future versions!!!\n"
"Use vstrict=-2 / -strict -2 to use it anyway.\n");
return -1;
}
if(avctx->prediction_method == DWT_97
&& (avctx->flags & CODEC_FLAG_QSCALE)
&& avctx->global_quality == 0){
av_log(avctx, AV_LOG_ERROR, "The 9/7 wavelet is incompatible with lossless mode.\n");
return -1;
}
s->spatial_decomposition_type= avctx->prediction_method; //FIXME add decorrelator type r transform_type
s->mv_scale = (avctx->flags & CODEC_FLAG_QPEL) ? 2 : 4;
s->block_max_depth= (avctx->flags & CODEC_FLAG_4MV ) ? 1 : 0;
for(plane_index=0; plane_index<3; plane_index++){
s->plane[plane_index].diag_mc= 1;
s->plane[plane_index].htaps= 6;
s->plane[plane_index].hcoeff[0]= 40;
s->plane[plane_index].hcoeff[1]= -10;
s->plane[plane_index].hcoeff[2]= 2;
s->plane[plane_index].fast_mc= 1;
}
if ((ret = ff_snow_common_init(avctx)) < 0) {
ff_snow_common_end(avctx->priv_data);
return ret;
}
ff_snow_alloc_blocks(s);
s->version=0;
s->m.avctx = avctx;
s->m.flags = avctx->flags;
s->m.bit_rate= avctx->bit_rate;
s->m.me.temp =
s->m.me.scratchpad= av_mallocz((avctx->width+64)*2*16*2*sizeof(uint8_t));
s->m.me.map = av_mallocz(ME_MAP_SIZE*sizeof(uint32_t));
s->m.me.score_map = av_mallocz(ME_MAP_SIZE*sizeof(uint32_t));
s->m.obmc_scratchpad= av_mallocz(MB_SIZE*MB_SIZE*12*sizeof(uint32_t));
ff_h263_encode_init(&s->m); //mv_penalty
s->max_ref_frames = FFMAX(FFMIN(avctx->refs, MAX_REF_FRAMES), 1);
if(avctx->flags&CODEC_FLAG_PASS1){
if(!avctx->stats_out)
avctx->stats_out = av_mallocz(256);
}
if((avctx->flags&CODEC_FLAG_PASS2) || !(avctx->flags&CODEC_FLAG_QSCALE)){
if(ff_rate_control_init(&s->m) < 0)
return -1;
}
s->pass1_rc= !(avctx->flags & (CODEC_FLAG_QSCALE|CODEC_FLAG_PASS2));
avctx->coded_frame= &s->current_picture;
switch(avctx->pix_fmt){
// case AV_PIX_FMT_YUV444P:
// case AV_PIX_FMT_YUV422P:
case AV_PIX_FMT_YUV420P:
case AV_PIX_FMT_GRAY8:
// case AV_PIX_FMT_YUV411P:
// case AV_PIX_FMT_YUV410P:
s->colorspace_type= 0;
break;
/* case AV_PIX_FMT_RGB32:
s->colorspace= 1;
break;*/
default:
av_log(avctx, AV_LOG_ERROR, "pixel format not supported\n");
return -1;
}
// avcodec_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_h_shift, &s->chroma_v_shift);
s->chroma_h_shift= 1;
s->chroma_v_shift= 1;
ff_set_cmp(&s->dsp, s->dsp.me_cmp, s->avctx->me_cmp);
ff_set_cmp(&s->dsp, s->dsp.me_sub_cmp, s->avctx->me_sub_cmp);
ff_get_buffer(s->avctx, &s->input_picture);
if(s->avctx->me_method == ME_ITER){
int i;
int size= s->b_width * s->b_height << 2*s->block_max_depth;
for(i=0; i<s->max_ref_frames; i++){
s->ref_mvs[i]= av_mallocz(size*sizeof(int16_t[2]));
s->ref_scores[i]= av_mallocz(size*sizeof(uint32_t));
}
}
return 0;
}
//near copy & paste from dsputil, FIXME
static int pix_sum(uint8_t * pix, int line_size, int w)
{
int s, i, j;
s = 0;
for (i = 0; i < w; i++) {
for (j = 0; j < w; j++) {
s += pix[0];
pix ++;
}
pix += line_size - w;
}
return s;
}
//near copy & paste from dsputil, FIXME
static int pix_norm1(uint8_t * pix, int line_size, int w)
{
int s, i, j;
uint32_t *sq = ff_squareTbl + 256;
s = 0;
for (i = 0; i < w; i++) {
for (j = 0; j < w; j ++) {
s += sq[pix[0]];
pix ++;
}
pix += line_size - w;
}
return s;
}
//FIXME copy&paste
#define P_LEFT P[1]
#define P_TOP P[2]
#define P_TOPRIGHT P[3]
#define P_MEDIAN P[4]
#define P_MV1 P[9]
#define FLAG_QPEL 1 //must be 1
static int encode_q_branch(SnowContext *s, int level, int x, int y){
uint8_t p_buffer[1024];
uint8_t i_buffer[1024];
uint8_t p_state[sizeof(s->block_state)];
uint8_t i_state[sizeof(s->block_state)];
RangeCoder pc, ic;
uint8_t *pbbak= s->c.bytestream;
uint8_t *pbbak_start= s->c.bytestream_start;
int score, score2, iscore, i_len, p_len, block_s, sum, base_bits;
const int w= s->b_width << s->block_max_depth;
const int h= s->b_height << s->block_max_depth;
const int rem_depth= s->block_max_depth - level;
const int index= (x + y*w) << rem_depth;
const int block_w= 1<<(LOG2_MB_SIZE - level);
int trx= (x+1)<<rem_depth;
int try= (y+1)<<rem_depth;
const BlockNode *left = x ? &s->block[index-1] : &null_block;
const BlockNode *top = y ? &s->block[index-w] : &null_block;
const BlockNode *right = trx<w ? &s->block[index+1] : &null_block;
const BlockNode *bottom= try<h ? &s->block[index+w] : &null_block;
const BlockNode *tl = y && x ? &s->block[index-w-1] : left;
const BlockNode *tr = y && trx<w && ((x&1)==0 || level==0) ? &s->block[index-w+(1<<rem_depth)] : tl; //FIXME use lt
int pl = left->color[0];
int pcb= left->color[1];
int pcr= left->color[2];
int pmx, pmy;
int mx=0, my=0;
int l,cr,cb;
const int stride= s->current_picture.linesize[0];
const int uvstride= s->current_picture.linesize[1];
uint8_t *current_data[3]= { s->input_picture.data[0] + (x + y* stride)*block_w,
s->input_picture.data[1] + (x + y*uvstride)*block_w/2,
s->input_picture.data[2] + (x + y*uvstride)*block_w/2};
int P[10][2];
int16_t last_mv[3][2];
int qpel= !!(s->avctx->flags & CODEC_FLAG_QPEL); //unused
const int shift= 1+qpel;
MotionEstContext *c= &s->m.me;
int ref_context= av_log2(2*left->ref) + av_log2(2*top->ref);
int mx_context= av_log2(2*FFABS(left->mx - top->mx));
int my_context= av_log2(2*FFABS(left->my - top->my));
int s_context= 2*left->level + 2*top->level + tl->level + tr->level;
int ref, best_ref, ref_score, ref_mx, ref_my;
assert(sizeof(s->block_state) >= 256);
if(s->keyframe){
set_blocks(s, level, x, y, pl, pcb, pcr, 0, 0, 0, BLOCK_INTRA);
return 0;
}
// clip predictors / edge ?
P_LEFT[0]= left->mx;
P_LEFT[1]= left->my;
P_TOP [0]= top->mx;
P_TOP [1]= top->my;
P_TOPRIGHT[0]= tr->mx;
P_TOPRIGHT[1]= tr->my;
last_mv[0][0]= s->block[index].mx;
last_mv[0][1]= s->block[index].my;
last_mv[1][0]= right->mx;
last_mv[1][1]= right->my;
last_mv[2][0]= bottom->mx;
last_mv[2][1]= bottom->my;
s->m.mb_stride=2;
s->m.mb_x=
s->m.mb_y= 0;
c->skip= 0;
assert(c-> stride == stride);
assert(c->uvstride == uvstride);
c->penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_cmp);
c->sub_penalty_factor= get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_sub_cmp);
c->mb_penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->mb_cmp);
c->current_mv_penalty= c->mv_penalty[s->m.f_code=1] + MAX_MV;
c->xmin = - x*block_w - 16+3;
c->ymin = - y*block_w - 16+3;
c->xmax = - (x+1)*block_w + (w<<(LOG2_MB_SIZE - s->block_max_depth)) + 16-3;
c->ymax = - (y+1)*block_w + (h<<(LOG2_MB_SIZE - s->block_max_depth)) + 16-3;
if(P_LEFT[0] > (c->xmax<<shift)) P_LEFT[0] = (c->xmax<<shift);
if(P_LEFT[1] > (c->ymax<<shift)) P_LEFT[1] = (c->ymax<<shift);
if(P_TOP[0] > (c->xmax<<shift)) P_TOP[0] = (c->xmax<<shift);
if(P_TOP[1] > (c->ymax<<shift)) P_TOP[1] = (c->ymax<<shift);
if(P_TOPRIGHT[0] < (c->xmin<<shift)) P_TOPRIGHT[0]= (c->xmin<<shift);
if(P_TOPRIGHT[0] > (c->xmax<<shift)) P_TOPRIGHT[0]= (c->xmax<<shift); //due to pmx no clip
if(P_TOPRIGHT[1] > (c->ymax<<shift)) P_TOPRIGHT[1]= (c->ymax<<shift);
P_MEDIAN[0]= mid_pred(P_LEFT[0], P_TOP[0], P_TOPRIGHT[0]);
P_MEDIAN[1]= mid_pred(P_LEFT[1], P_TOP[1], P_TOPRIGHT[1]);
if (!y) {
c->pred_x= P_LEFT[0];
c->pred_y= P_LEFT[1];
} else {
c->pred_x = P_MEDIAN[0];
c->pred_y = P_MEDIAN[1];
}
score= INT_MAX;
best_ref= 0;
for(ref=0; ref<s->ref_frames; ref++){
init_ref(c, current_data, s->last_picture[ref].data, NULL, block_w*x, block_w*y, 0);
ref_score= ff_epzs_motion_search(&s->m, &ref_mx, &ref_my, P, 0, /*ref_index*/ 0, last_mv,
(1<<16)>>shift, level-LOG2_MB_SIZE+4, block_w);
assert(ref_mx >= c->xmin);
assert(ref_mx <= c->xmax);
assert(ref_my >= c->ymin);
assert(ref_my <= c->ymax);
ref_score= c->sub_motion_search(&s->m, &ref_mx, &ref_my, ref_score, 0, 0, level-LOG2_MB_SIZE+4, block_w);
ref_score= ff_get_mb_score(&s->m, ref_mx, ref_my, 0, 0, level-LOG2_MB_SIZE+4, block_w, 0);
ref_score+= 2*av_log2(2*ref)*c->penalty_factor;
if(s->ref_mvs[ref]){
s->ref_mvs[ref][index][0]= ref_mx;
s->ref_mvs[ref][index][1]= ref_my;
s->ref_scores[ref][index]= ref_score;
}
if(score > ref_score){
score= ref_score;
best_ref= ref;
mx= ref_mx;
my= ref_my;
}
}
//FIXME if mb_cmp != SSE then intra cannot be compared currently and mb_penalty vs. lambda2
// subpel search
base_bits= get_rac_count(&s->c) - 8*(s->c.bytestream - s->c.bytestream_start);
pc= s->c;
pc.bytestream_start=
pc.bytestream= p_buffer; //FIXME end/start? and at the other stoo
memcpy(p_state, s->block_state, sizeof(s->block_state));
if(level!=s->block_max_depth)
put_rac(&pc, &p_state[4 + s_context], 1);
put_rac(&pc, &p_state[1 + left->type + top->type], 0);
if(s->ref_frames > 1)
put_symbol(&pc, &p_state[128 + 1024 + 32*ref_context], best_ref, 0);
pred_mv(s, &pmx, &pmy, best_ref, left, top, tr);
put_symbol(&pc, &p_state[128 + 32*(mx_context + 16*!!best_ref)], mx - pmx, 1);
put_symbol(&pc, &p_state[128 + 32*(my_context + 16*!!best_ref)], my - pmy, 1);
p_len= pc.bytestream - pc.bytestream_start;
score += (s->lambda2*(get_rac_count(&pc)-base_bits))>>FF_LAMBDA_SHIFT;
block_s= block_w*block_w;
sum = pix_sum(current_data[0], stride, block_w);
l= (sum + block_s/2)/block_s;
iscore = pix_norm1(current_data[0], stride, block_w) - 2*l*sum + l*l*block_s;
block_s= block_w*block_w>>2;
sum = pix_sum(current_data[1], uvstride, block_w>>1);
cb= (sum + block_s/2)/block_s;
// iscore += pix_norm1(&current_mb[1][0], uvstride, block_w>>1) - 2*cb*sum + cb*cb*block_s;
sum = pix_sum(current_data[2], uvstride, block_w>>1);
cr= (sum + block_s/2)/block_s;
// iscore += pix_norm1(&current_mb[2][0], uvstride, block_w>>1) - 2*cr*sum + cr*cr*block_s;
ic= s->c;
ic.bytestream_start=
ic.bytestream= i_buffer; //FIXME end/start? and at the other stoo
memcpy(i_state, s->block_state, sizeof(s->block_state));
if(level!=s->block_max_depth)
put_rac(&ic, &i_state[4 + s_context], 1);
put_rac(&ic, &i_state[1 + left->type + top->type], 1);
put_symbol(&ic, &i_state[32], l-pl , 1);
put_symbol(&ic, &i_state[64], cb-pcb, 1);
put_symbol(&ic, &i_state[96], cr-pcr, 1);
i_len= ic.bytestream - ic.bytestream_start;
iscore += (s->lambda2*(get_rac_count(&ic)-base_bits))>>FF_LAMBDA_SHIFT;
// assert(score==256*256*256*64-1);
assert(iscore < 255*255*256 + s->lambda2*10);
assert(iscore >= 0);
assert(l>=0 && l<=255);
assert(pl>=0 && pl<=255);
if(level==0){
int varc= iscore >> 8;
int vard= score >> 8;
if (vard <= 64 || vard < varc)
c->scene_change_score+= ff_sqrt(vard) - ff_sqrt(varc);
else
c->scene_change_score+= s->m.qscale;
}
if(level!=s->block_max_depth){
put_rac(&s->c, &s->block_state[4 + s_context], 0);
score2 = encode_q_branch(s, level+1, 2*x+0, 2*y+0);
score2+= encode_q_branch(s, level+1, 2*x+1, 2*y+0);
score2+= encode_q_branch(s, level+1, 2*x+0, 2*y+1);
score2+= encode_q_branch(s, level+1, 2*x+1, 2*y+1);
score2+= s->lambda2>>FF_LAMBDA_SHIFT; //FIXME exact split overhead
if(score2 < score && score2 < iscore)
return score2;
}
if(iscore < score){
pred_mv(s, &pmx, &pmy, 0, left, top, tr);
memcpy(pbbak, i_buffer, i_len);
s->c= ic;
s->c.bytestream_start= pbbak_start;
s->c.bytestream= pbbak + i_len;
set_blocks(s, level, x, y, l, cb, cr, pmx, pmy, 0, BLOCK_INTRA);
memcpy(s->block_state, i_state, sizeof(s->block_state));
return iscore;
}else{
memcpy(pbbak, p_buffer, p_len);
s->c= pc;
s->c.bytestream_start= pbbak_start;
s->c.bytestream= pbbak + p_len;
set_blocks(s, level, x, y, pl, pcb, pcr, mx, my, best_ref, 0);
memcpy(s->block_state, p_state, sizeof(s->block_state));
return score;
}
}
static void encode_q_branch2(SnowContext *s, int level, int x, int y){
const int w= s->b_width << s->block_max_depth;
const int rem_depth= s->block_max_depth - level;
const int index= (x + y*w) << rem_depth;
int trx= (x+1)<<rem_depth;
BlockNode *b= &s->block[index];
const BlockNode *left = x ? &s->block[index-1] : &null_block;
const BlockNode *top = y ? &s->block[index-w] : &null_block;
const BlockNode *tl = y && x ? &s->block[index-w-1] : left;
const BlockNode *tr = y && trx<w && ((x&1)==0 || level==0) ? &s->block[index-w+(1<<rem_depth)] : tl; //FIXME use lt
int pl = left->color[0];
int pcb= left->color[1];
int pcr= left->color[2];
int pmx, pmy;
int ref_context= av_log2(2*left->ref) + av_log2(2*top->ref);
int mx_context= av_log2(2*FFABS(left->mx - top->mx)) + 16*!!b->ref;
int my_context= av_log2(2*FFABS(left->my - top->my)) + 16*!!b->ref;
int s_context= 2*left->level + 2*top->level + tl->level + tr->level;
if(s->keyframe){
set_blocks(s, level, x, y, pl, pcb, pcr, 0, 0, 0, BLOCK_INTRA);
return;
}
if(level!=s->block_max_depth){
if(same_block(b,b+1) && same_block(b,b+w) && same_block(b,b+w+1)){
put_rac(&s->c, &s->block_state[4 + s_context], 1);
}else{
put_rac(&s->c, &s->block_state[4 + s_context], 0);
encode_q_branch2(s, level+1, 2*x+0, 2*y+0);
encode_q_branch2(s, level+1, 2*x+1, 2*y+0);
encode_q_branch2(s, level+1, 2*x+0, 2*y+1);
encode_q_branch2(s, level+1, 2*x+1, 2*y+1);
return;
}
}
if(b->type & BLOCK_INTRA){
pred_mv(s, &pmx, &pmy, 0, left, top, tr);
put_rac(&s->c, &s->block_state[1 + (left->type&1) + (top->type&1)], 1);
put_symbol(&s->c, &s->block_state[32], b->color[0]-pl , 1);
put_symbol(&s->c, &s->block_state[64], b->color[1]-pcb, 1);
put_symbol(&s->c, &s->block_state[96], b->color[2]-pcr, 1);
set_blocks(s, level, x, y, b->color[0], b->color[1], b->color[2], pmx, pmy, 0, BLOCK_INTRA);
}else{
pred_mv(s, &pmx, &pmy, b->ref, left, top, tr);
put_rac(&s->c, &s->block_state[1 + (left->type&1) + (top->type&1)], 0);
if(s->ref_frames > 1)
put_symbol(&s->c, &s->block_state[128 + 1024 + 32*ref_context], b->ref, 0);
put_symbol(&s->c, &s->block_state[128 + 32*mx_context], b->mx - pmx, 1);
put_symbol(&s->c, &s->block_state[128 + 32*my_context], b->my - pmy, 1);
set_blocks(s, level, x, y, pl, pcb, pcr, b->mx, b->my, b->ref, 0);
}
}
static int get_dc(SnowContext *s, int mb_x, int mb_y, int plane_index){
int i, x2, y2;
Plane *p= &s->plane[plane_index];
const int block_size = MB_SIZE >> s->block_max_depth;
const int block_w = plane_index ? block_size/2 : block_size;
const uint8_t *obmc = plane_index ? ff_obmc_tab[s->block_max_depth+1] : ff_obmc_tab[s->block_max_depth];
const int obmc_stride= plane_index ? block_size : 2*block_size;
const int ref_stride= s->current_picture.linesize[plane_index];
uint8_t *src= s-> input_picture.data[plane_index];
IDWTELEM *dst= (IDWTELEM*)s->m.obmc_scratchpad + plane_index*block_size*block_size*4; //FIXME change to unsigned
const int b_stride = s->b_width << s->block_max_depth;
const int w= p->width;
const int h= p->height;
int index= mb_x + mb_y*b_stride;
BlockNode *b= &s->block[index];
BlockNode backup= *b;
int ab=0;
int aa=0;
b->type|= BLOCK_INTRA;
b->color[plane_index]= 0;
memset(dst, 0, obmc_stride*obmc_stride*sizeof(IDWTELEM));
for(i=0; i<4; i++){
int mb_x2= mb_x + (i &1) - 1;
int mb_y2= mb_y + (i>>1) - 1;
int x= block_w*mb_x2 + block_w/2;
int y= block_w*mb_y2 + block_w/2;
add_yblock(s, 0, NULL, dst + ((i&1)+(i>>1)*obmc_stride)*block_w, NULL, obmc,
x, y, block_w, block_w, w, h, obmc_stride, ref_stride, obmc_stride, mb_x2, mb_y2, 0, 0, plane_index);
for(y2= FFMAX(y, 0); y2<FFMIN(h, y+block_w); y2++){
for(x2= FFMAX(x, 0); x2<FFMIN(w, x+block_w); x2++){
int index= x2-(block_w*mb_x - block_w/2) + (y2-(block_w*mb_y - block_w/2))*obmc_stride;
int obmc_v= obmc[index];
int d;
if(y<0) obmc_v += obmc[index + block_w*obmc_stride];
if(x<0) obmc_v += obmc[index + block_w];
if(y+block_w>h) obmc_v += obmc[index - block_w*obmc_stride];
if(x+block_w>w) obmc_v += obmc[index - block_w];
//FIXME precalculate this or simplify it somehow else
d = -dst[index] + (1<<(FRAC_BITS-1));
dst[index] = d;
ab += (src[x2 + y2*ref_stride] - (d>>FRAC_BITS)) * obmc_v;
aa += obmc_v * obmc_v; //FIXME precalculate this
}
}
}
*b= backup;
return av_clip(((ab<<LOG2_OBMC_MAX) + aa/2)/aa, 0, 255); //FIXME we should not need clipping
}
static inline int get_block_bits(SnowContext *s, int x, int y, int w){
const int b_stride = s->b_width << s->block_max_depth;
const int b_height = s->b_height<< s->block_max_depth;
int index= x + y*b_stride;
const BlockNode *b = &s->block[index];
const BlockNode *left = x ? &s->block[index-1] : &null_block;
const BlockNode *top = y ? &s->block[index-b_stride] : &null_block;
const BlockNode *tl = y && x ? &s->block[index-b_stride-1] : left;
const BlockNode *tr = y && x+w<b_stride ? &s->block[index-b_stride+w] : tl;
int dmx, dmy;
// int mx_context= av_log2(2*FFABS(left->mx - top->mx));
// int my_context= av_log2(2*FFABS(left->my - top->my));
if(x<0 || x>=b_stride || y>=b_height)
return 0;
/*
1 0 0
01X 1-2 1
001XX 3-6 2-3
0001XXX 7-14 4-7
00001XXXX 15-30 8-15
*/
//FIXME try accurate rate
//FIXME intra and inter predictors if surrounding blocks are not the same type
if(b->type & BLOCK_INTRA){
return 3+2*( av_log2(2*FFABS(left->color[0] - b->color[0]))
+ av_log2(2*FFABS(left->color[1] - b->color[1]))
+ av_log2(2*FFABS(left->color[2] - b->color[2])));
}else{
pred_mv(s, &dmx, &dmy, b->ref, left, top, tr);
dmx-= b->mx;
dmy-= b->my;
return 2*(1 + av_log2(2*FFABS(dmx)) //FIXME kill the 2* can be merged in lambda
+ av_log2(2*FFABS(dmy))
+ av_log2(2*b->ref));
}
}
static int get_block_rd(SnowContext *s, int mb_x, int mb_y, int plane_index, uint8_t (*obmc_edged)[MB_SIZE * 2]){
Plane *p= &s->plane[plane_index];
const int block_size = MB_SIZE >> s->block_max_depth;
const int block_w = plane_index ? block_size/2 : block_size;
const int obmc_stride= plane_index ? block_size : 2*block_size;
const int ref_stride= s->current_picture.linesize[plane_index];
uint8_t *dst= s->current_picture.data[plane_index];
uint8_t *src= s-> input_picture.data[plane_index];
IDWTELEM *pred= (IDWTELEM*)s->m.obmc_scratchpad + plane_index*block_size*block_size*4;
uint8_t *cur = s->scratchbuf;
uint8_t *tmp = s->emu_edge_buffer;
const int b_stride = s->b_width << s->block_max_depth;
const int b_height = s->b_height<< s->block_max_depth;
const int w= p->width;
const int h= p->height;
int distortion;
int rate= 0;
const int penalty_factor= get_penalty_factor(s->lambda, s->lambda2, s->avctx->me_cmp);
int sx= block_w*mb_x - block_w/2;
int sy= block_w*mb_y - block_w/2;
int x0= FFMAX(0,-sx);
int y0= FFMAX(0,-sy);
int x1= FFMIN(block_w*2, w-sx);
int y1= FFMIN(block_w*2, h-sy);
int i,x,y;
ff_snow_pred_block(s, cur, tmp, ref_stride, sx, sy, block_w*2, block_w*2, &s->block[mb_x + mb_y*b_stride], plane_index, w, h);
for(y=y0; y<y1; y++){
const uint8_t *obmc1= obmc_edged[y];
const IDWTELEM *pred1 = pred + y*obmc_stride;
uint8_t *cur1 = cur + y*ref_stride;
uint8_t *dst1 = dst + sx + (sy+y)*ref_stride;
for(x=x0; x<x1; x++){
#if FRAC_BITS >= LOG2_OBMC_MAX
int v = (cur1[x] * obmc1[x]) << (FRAC_BITS - LOG2_OBMC_MAX);
#else
int v = (cur1[x] * obmc1[x] + (1<<(LOG2_OBMC_MAX - FRAC_BITS-1))) >> (LOG2_OBMC_MAX - FRAC_BITS);
#endif
v = (v + pred1[x]) >> FRAC_BITS;
if(v&(~255)) v= ~(v>>31);
dst1[x] = v;
}
}
/* copy the regions where obmc[] = (uint8_t)256 */
if(LOG2_OBMC_MAX == 8
&& (mb_x == 0 || mb_x == b_stride-1)
&& (mb_y == 0 || mb_y == b_height-1)){
if(mb_x == 0)
x1 = block_w;
else
x0 = block_w;
if(mb_y == 0)
y1 = block_w;
else
y0 = block_w;
for(y=y0; y<y1; y++)
memcpy(dst + sx+x0 + (sy+y)*ref_stride, cur + x0 + y*ref_stride, x1-x0);
}
if(block_w==16){
/* FIXME rearrange dsputil to fit 32x32 cmp functions */
/* FIXME check alignment of the cmp wavelet vs the encoding wavelet */
/* FIXME cmps overlap but do not cover the wavelet's whole support.
* So improving the score of one block is not strictly guaranteed
* to improve the score of the whole frame, thus iterative motion
* estimation does not always converge. */
if(s->avctx->me_cmp == FF_CMP_W97)
distortion = ff_w97_32_c(&s->m, src + sx + sy*ref_stride, dst + sx + sy*ref_stride, ref_stride, 32);
else if(s->avctx->me_cmp == FF_CMP_W53)
distortion = ff_w53_32_c(&s->m, src + sx + sy*ref_stride, dst + sx + sy*ref_stride, ref_stride, 32);
else{
distortion = 0;
for(i=0; i<4; i++){
int off = sx+16*(i&1) + (sy+16*(i>>1))*ref_stride;
distortion += s->dsp.me_cmp[0](&s->m, src + off, dst + off, ref_stride, 16);
}
}
}else{
assert(block_w==8);
distortion = s->dsp.me_cmp[0](&s->m, src + sx + sy*ref_stride, dst + sx + sy*ref_stride, ref_stride, block_w*2);
}
if(plane_index==0){
for(i=0; i<4; i++){
/* ..RRr
* .RXx.
* rxx..
*/
rate += get_block_bits(s, mb_x + (i&1) - (i>>1), mb_y + (i>>1), 1);
}
if(mb_x == b_stride-2)
rate += get_block_bits(s, mb_x + 1, mb_y + 1, 1);
}
return distortion + rate*penalty_factor;
}
static int get_4block_rd(SnowContext *s, int mb_x, int mb_y, int plane_index){
int i, y2;
Plane *p= &s->plane[plane_index];
const int block_size = MB_SIZE >> s->block_max_depth;
const int block_w = plane_index ? block_size/2 : block_size;
const uint8_t *obmc = plane_index ? ff_obmc_tab[s->block_max_depth+1] : ff_obmc_tab[s->block_max_depth];
const int obmc_stride= plane_index ? block_size : 2*block_size;
const int ref_stride= s->current_picture.linesize[plane_index];
uint8_t *dst= s->current_picture.data[plane_index];
uint8_t *src= s-> input_picture.data[plane_index];
//FIXME zero_dst is const but add_yblock changes dst if add is 0 (this is never the case for dst=zero_dst
// const has only been removed from zero_dst to suppress a warning
static IDWTELEM zero_dst[4096]; //FIXME
const int b_stride = s->b_width << s->block_max_depth;
const int w= p->width;
const int h= p->height;
int distortion= 0;
int rate= 0;
const int penalty_factor= get_penalty_factor(s->lambda, s->lambda2, s->avctx->me_cmp);
for(i=0; i<9; i++){
int mb_x2= mb_x + (i%3) - 1;
int mb_y2= mb_y + (i/3) - 1;
int x= block_w*mb_x2 + block_w/2;
int y= block_w*mb_y2 + block_w/2;
add_yblock(s, 0, NULL, zero_dst, dst, obmc,
x, y, block_w, block_w, w, h, /*dst_stride*/0, ref_stride, obmc_stride, mb_x2, mb_y2, 1, 1, plane_index);
//FIXME find a cleaner/simpler way to skip the outside stuff
for(y2= y; y2<0; y2++)
memcpy(dst + x + y2*ref_stride, src + x + y2*ref_stride, block_w);
for(y2= h; y2<y+block_w; y2++)
memcpy(dst + x + y2*ref_stride, src + x + y2*ref_stride, block_w);
if(x<0){
for(y2= y; y2<y+block_w; y2++)
memcpy(dst + x + y2*ref_stride, src + x + y2*ref_stride, -x);
}
if(x+block_w > w){
for(y2= y; y2<y+block_w; y2++)
memcpy(dst + w + y2*ref_stride, src + w + y2*ref_stride, x+block_w - w);
}
assert(block_w== 8 || block_w==16);
distortion += s->dsp.me_cmp[block_w==8](&s->m, src + x + y*ref_stride, dst + x + y*ref_stride, ref_stride, block_w);
}
if(plane_index==0){
BlockNode *b= &s->block[mb_x+mb_y*b_stride];
int merged= same_block(b,b+1) && same_block(b,b+b_stride) && same_block(b,b+b_stride+1);
/* ..RRRr
* .RXXx.
* .RXXx.
* rxxx.
*/
if(merged)
rate = get_block_bits(s, mb_x, mb_y, 2);
for(i=merged?4:0; i<9; i++){
static const int dxy[9][2] = {{0,0},{1,0},{0,1},{1,1},{2,0},{2,1},{-1,2},{0,2},{1,2}};
rate += get_block_bits(s, mb_x + dxy[i][0], mb_y + dxy[i][1], 1);
}
}
return distortion + rate*penalty_factor;
}
static int encode_subband_c0run(SnowContext *s, SubBand *b, IDWTELEM *src, IDWTELEM *parent, int stride, int orientation){
const int w= b->width;
const int h= b->height;
int x, y;
if(1){
int run=0;
int *runs = s->run_buffer;
int run_index=0;
int max_index;
for(y=0; y<h; y++){
for(x=0; x<w; x++){
int v, p=0;
int /*ll=0, */l=0, lt=0, t=0, rt=0;
v= src[x + y*stride];
if(y){
t= src[x + (y-1)*stride];
if(x){
lt= src[x - 1 + (y-1)*stride];
}
if(x + 1 < w){
rt= src[x + 1 + (y-1)*stride];
}
}
if(x){
l= src[x - 1 + y*stride];
/*if(x > 1){
if(orientation==1) ll= src[y + (x-2)*stride];
else ll= src[x - 2 + y*stride];
}*/
}
if(parent){
int px= x>>1;
int py= y>>1;
if(px<b->parent->width && py<b->parent->height)
p= parent[px + py*2*stride];
}
if(!(/*ll|*/l|lt|t|rt|p)){
if(v){
runs[run_index++]= run;
run=0;
}else{
run++;
}
}
}
}
max_index= run_index;
runs[run_index++]= run;
run_index=0;
run= runs[run_index++];
put_symbol2(&s->c, b->state[30], max_index, 0);
if(run_index <= max_index)
put_symbol2(&s->c, b->state[1], run, 3);
for(y=0; y<h; y++){
if(s->c.bytestream_end - s->c.bytestream < w*40){
av_log(s->avctx, AV_LOG_ERROR, "encoded frame too large\n");
return -1;
}
for(x=0; x<w; x++){
int v, p=0;
int /*ll=0, */l=0, lt=0, t=0, rt=0;
v= src[x + y*stride];
if(y){
t= src[x + (y-1)*stride];
if(x){
lt= src[x - 1 + (y-1)*stride];
}
if(x + 1 < w){
rt= src[x + 1 + (y-1)*stride];
}
}
if(x){
l= src[x - 1 + y*stride];
/*if(x > 1){
if(orientation==1) ll= src[y + (x-2)*stride];
else ll= src[x - 2 + y*stride];
}*/
}
if(parent){
int px= x>>1;
int py= y>>1;
if(px<b->parent->width && py<b->parent->height)
p= parent[px + py*2*stride];
}
if(/*ll|*/l|lt|t|rt|p){
int context= av_log2(/*FFABS(ll) + */3*FFABS(l) + FFABS(lt) + 2*FFABS(t) + FFABS(rt) + FFABS(p));
put_rac(&s->c, &b->state[0][context], !!v);
}else{
if(!run){
run= runs[run_index++];
if(run_index <= max_index)
put_symbol2(&s->c, b->state[1], run, 3);
assert(v);
}else{
run--;
assert(!v);
}
}
if(v){
int context= av_log2(/*FFABS(ll) + */3*FFABS(l) + FFABS(lt) + 2*FFABS(t) + FFABS(rt) + FFABS(p));
int l2= 2*FFABS(l) + (l<0);
int t2= 2*FFABS(t) + (t<0);
put_symbol2(&s->c, b->state[context + 2], FFABS(v)-1, context-4);
put_rac(&s->c, &b->state[0][16 + 1 + 3 + ff_quant3bA[l2&0xFF] + 3*ff_quant3bA[t2&0xFF]], v<0);
}
}
}
}
return 0;
}
static int encode_subband(SnowContext *s, SubBand *b, IDWTELEM *src, IDWTELEM *parent, int stride, int orientation){
// encode_subband_qtree(s, b, src, parent, stride, orientation);
// encode_subband_z0run(s, b, src, parent, stride, orientation);
return encode_subband_c0run(s, b, src, parent, stride, orientation);
// encode_subband_dzr(s, b, src, parent, stride, orientation);
}
static av_always_inline int check_block(SnowContext *s, int mb_x, int mb_y, int p[3], int intra, uint8_t (*obmc_edged)[MB_SIZE * 2], int *best_rd){
const int b_stride= s->b_width << s->block_max_depth;
BlockNode *block= &s->block[mb_x + mb_y * b_stride];
BlockNode backup= *block;
unsigned value;
int rd, index;
assert(mb_x>=0 && mb_y>=0);
assert(mb_x<b_stride);
if(intra){
block->color[0] = p[0];
block->color[1] = p[1];
block->color[2] = p[2];
block->type |= BLOCK_INTRA;
}else{
index= (p[0] + 31*p[1]) & (ME_CACHE_SIZE-1);
value= s->me_cache_generation + (p[0]>>10) + (p[1]<<6) + (block->ref<<12);
if(s->me_cache[index] == value)
return 0;
s->me_cache[index]= value;
block->mx= p[0];
block->my= p[1];
block->type &= ~BLOCK_INTRA;
}
rd= get_block_rd(s, mb_x, mb_y, 0, obmc_edged);
//FIXME chroma
if(rd < *best_rd){
*best_rd= rd;
return 1;
}else{
*block= backup;
return 0;
}
}
/* special case for int[2] args we discard afterwards,
* fixes compilation problem with gcc 2.95 */
static av_always_inline int check_block_inter(SnowContext *s, int mb_x, int mb_y, int p0, int p1, uint8_t (*obmc_edged)[MB_SIZE * 2], int *best_rd){
int p[2] = {p0, p1};
return check_block(s, mb_x, mb_y, p, 0, obmc_edged, best_rd);
}
static av_always_inline int check_4block_inter(SnowContext *s, int mb_x, int mb_y, int p0, int p1, int ref, int *best_rd){
const int b_stride= s->b_width << s->block_max_depth;
BlockNode *block= &s->block[mb_x + mb_y * b_stride];
BlockNode backup[4];
unsigned value;
int rd, index;
/* We don't initialize backup[] during variable declaration, because
* that fails to compile on MSVC: "cannot convert from 'BlockNode' to
* 'int16_t'". */
backup[0] = block[0];
backup[1] = block[1];
backup[2] = block[b_stride];
backup[3] = block[b_stride + 1];
assert(mb_x>=0 && mb_y>=0);
assert(mb_x<b_stride);
assert(((mb_x|mb_y)&1) == 0);
index= (p0 + 31*p1) & (ME_CACHE_SIZE-1);
value= s->me_cache_generation + (p0>>10) + (p1<<6) + (block->ref<<12);
if(s->me_cache[index] == value)
return 0;
s->me_cache[index]= value;
block->mx= p0;
block->my= p1;
block->ref= ref;
block->type &= ~BLOCK_INTRA;
block[1]= block[b_stride]= block[b_stride+1]= *block;
rd= get_4block_rd(s, mb_x, mb_y, 0);
//FIXME chroma
if(rd < *best_rd){
*best_rd= rd;
return 1;
}else{
block[0]= backup[0];
block[1]= backup[1];
block[b_stride]= backup[2];
block[b_stride+1]= backup[3];
return 0;
}
}
static void iterative_me(SnowContext *s){
int pass, mb_x, mb_y;
const int b_width = s->b_width << s->block_max_depth;
const int b_height= s->b_height << s->block_max_depth;
const int b_stride= b_width;
int color[3];
{
RangeCoder r = s->c;
uint8_t state[sizeof(s->block_state)];
memcpy(state, s->block_state, sizeof(s->block_state));
for(mb_y= 0; mb_y<s->b_height; mb_y++)
for(mb_x= 0; mb_x<s->b_width; mb_x++)
encode_q_branch(s, 0, mb_x, mb_y);
s->c = r;
memcpy(s->block_state, state, sizeof(s->block_state));
}
for(pass=0; pass<25; pass++){
int change= 0;
for(mb_y= 0; mb_y<b_height; mb_y++){
for(mb_x= 0; mb_x<b_width; mb_x++){
int dia_change, i, j, ref;
int best_rd= INT_MAX, ref_rd;
BlockNode backup, ref_b;
const int index= mb_x + mb_y * b_stride;
BlockNode *block= &s->block[index];
BlockNode *tb = mb_y ? &s->block[index-b_stride ] : NULL;
BlockNode *lb = mb_x ? &s->block[index -1] : NULL;
BlockNode *rb = mb_x+1<b_width ? &s->block[index +1] : NULL;
BlockNode *bb = mb_y+1<b_height ? &s->block[index+b_stride ] : NULL;
BlockNode *tlb= mb_x && mb_y ? &s->block[index-b_stride-1] : NULL;
BlockNode *trb= mb_x+1<b_width && mb_y ? &s->block[index-b_stride+1] : NULL;
BlockNode *blb= mb_x && mb_y+1<b_height ? &s->block[index+b_stride-1] : NULL;
BlockNode *brb= mb_x+1<b_width && mb_y+1<b_height ? &s->block[index+b_stride+1] : NULL;
const int b_w= (MB_SIZE >> s->block_max_depth);
uint8_t obmc_edged[MB_SIZE * 2][MB_SIZE * 2];
if(pass && (block->type & BLOCK_OPT))
continue;
block->type |= BLOCK_OPT;
backup= *block;
if(!s->me_cache_generation)
memset(s->me_cache, 0, sizeof(s->me_cache));
s->me_cache_generation += 1<<22;
//FIXME precalculate
{
int x, y;
for (y = 0; y < b_w * 2; y++)
memcpy(obmc_edged[y], ff_obmc_tab[s->block_max_depth] + y * b_w * 2, b_w * 2);
if(mb_x==0)
for(y=0; y<b_w*2; y++)
memset(obmc_edged[y], obmc_edged[y][0] + obmc_edged[y][b_w-1], b_w);
if(mb_x==b_stride-1)
for(y=0; y<b_w*2; y++)
memset(obmc_edged[y]+b_w, obmc_edged[y][b_w] + obmc_edged[y][b_w*2-1], b_w);
if(mb_y==0){
for(x=0; x<b_w*2; x++)
obmc_edged[0][x] += obmc_edged[b_w-1][x];
for(y=1; y<b_w; y++)
memcpy(obmc_edged[y], obmc_edged[0], b_w*2);
}
if(mb_y==b_height-1){
for(x=0; x<b_w*2; x++)
obmc_edged[b_w*2-1][x] += obmc_edged[b_w][x];
for(y=b_w; y<b_w*2-1; y++)
memcpy(obmc_edged[y], obmc_edged[b_w*2-1], b_w*2);
}
}
//skip stuff outside the picture
if(mb_x==0 || mb_y==0 || mb_x==b_width-1 || mb_y==b_height-1){
uint8_t *src= s-> input_picture.data[0];
uint8_t *dst= s->current_picture.data[0];
const int stride= s->current_picture.linesize[0];
const int block_w= MB_SIZE >> s->block_max_depth;
const int sx= block_w*mb_x - block_w/2;
const int sy= block_w*mb_y - block_w/2;
const int w= s->plane[0].width;
const int h= s->plane[0].height;
int y;
for(y=sy; y<0; y++)
memcpy(dst + sx + y*stride, src + sx + y*stride, block_w*2);
for(y=h; y<sy+block_w*2; y++)
memcpy(dst + sx + y*stride, src + sx + y*stride, block_w*2);
if(sx<0){
for(y=sy; y<sy+block_w*2; y++)
memcpy(dst + sx + y*stride, src + sx + y*stride, -sx);
}
if(sx+block_w*2 > w){
for(y=sy; y<sy+block_w*2; y++)
memcpy(dst + w + y*stride, src + w + y*stride, sx+block_w*2 - w);
}
}
// intra(black) = neighbors' contribution to the current block
for(i=0; i<3; i++)
color[i]= get_dc(s, mb_x, mb_y, i);
// get previous score (cannot be cached due to OBMC)
if(pass > 0 && (block->type&BLOCK_INTRA)){
int color0[3]= {block->color[0], block->color[1], block->color[2]};
check_block(s, mb_x, mb_y, color0, 1, obmc_edged, &best_rd);
}else
check_block_inter(s, mb_x, mb_y, block->mx, block->my, obmc_edged, &best_rd);
ref_b= *block;
ref_rd= best_rd;
for(ref=0; ref < s->ref_frames; ref++){
int16_t (*mvr)[2]= &s->ref_mvs[ref][index];
if(s->ref_scores[ref][index] > s->ref_scores[ref_b.ref][index]*3/2) //FIXME tune threshold
continue;
block->ref= ref;
best_rd= INT_MAX;
check_block_inter(s, mb_x, mb_y, mvr[0][0], mvr[0][1], obmc_edged, &best_rd);
check_block_inter(s, mb_x, mb_y, 0, 0, obmc_edged, &best_rd);
if(tb)
check_block_inter(s, mb_x, mb_y, mvr[-b_stride][0], mvr[-b_stride][1], obmc_edged, &best_rd);
if(lb)
check_block_inter(s, mb_x, mb_y, mvr[-1][0], mvr[-1][1], obmc_edged, &best_rd);
if(rb)
check_block_inter(s, mb_x, mb_y, mvr[1][0], mvr[1][1], obmc_edged, &best_rd);
if(bb)
check_block_inter(s, mb_x, mb_y, mvr[b_stride][0], mvr[b_stride][1], obmc_edged, &best_rd);
/* fullpel ME */
//FIXME avoid subpel interpolation / round to nearest integer
do{
dia_change=0;
for(i=0; i<FFMAX(s->avctx->dia_size, 1); i++){
for(j=0; j<i; j++){
dia_change |= check_block_inter(s, mb_x, mb_y, block->mx+4*(i-j), block->my+(4*j), obmc_edged, &best_rd);
dia_change |= check_block_inter(s, mb_x, mb_y, block->mx-4*(i-j), block->my-(4*j), obmc_edged, &best_rd);
dia_change |= check_block_inter(s, mb_x, mb_y, block->mx+4*(i-j), block->my-(4*j), obmc_edged, &best_rd);
dia_change |= check_block_inter(s, mb_x, mb_y, block->mx-4*(i-j), block->my+(4*j), obmc_edged, &best_rd);
}
}
}while(dia_change);
/* subpel ME */
do{
static const int square[8][2]= {{+1, 0},{-1, 0},{ 0,+1},{ 0,-1},{+1,+1},{-1,-1},{+1,-1},{-1,+1},};
dia_change=0;
for(i=0; i<8; i++)
dia_change |= check_block_inter(s, mb_x, mb_y, block->mx+square[i][0], block->my+square[i][1], obmc_edged, &best_rd);
}while(dia_change);
//FIXME or try the standard 2 pass qpel or similar
mvr[0][0]= block->mx;
mvr[0][1]= block->my;
if(ref_rd > best_rd){
ref_rd= best_rd;
ref_b= *block;
}
}
best_rd= ref_rd;
*block= ref_b;
check_block(s, mb_x, mb_y, color, 1, obmc_edged, &best_rd);
//FIXME RD style color selection
if(!same_block(block, &backup)){
if(tb ) tb ->type &= ~BLOCK_OPT;
if(lb ) lb ->type &= ~BLOCK_OPT;
if(rb ) rb ->type &= ~BLOCK_OPT;
if(bb ) bb ->type &= ~BLOCK_OPT;
if(tlb) tlb->type &= ~BLOCK_OPT;
if(trb) trb->type &= ~BLOCK_OPT;
if(blb) blb->type &= ~BLOCK_OPT;
if(brb) brb->type &= ~BLOCK_OPT;
change ++;
}
}
}
av_log(s->avctx, AV_LOG_ERROR, "pass:%d changed:%d\n", pass, change);
if(!change)
break;
}
if(s->block_max_depth == 1){
int change= 0;
for(mb_y= 0; mb_y<b_height; mb_y+=2){
for(mb_x= 0; mb_x<b_width; mb_x+=2){
int i;
int best_rd, init_rd;
const int index= mb_x + mb_y * b_stride;
BlockNode *b[4];
b[0]= &s->block[index];
b[1]= b[0]+1;
b[2]= b[0]+b_stride;
b[3]= b[2]+1;
if(same_block(b[0], b[1]) &&
same_block(b[0], b[2]) &&
same_block(b[0], b[3]))
continue;
if(!s->me_cache_generation)
memset(s->me_cache, 0, sizeof(s->me_cache));
s->me_cache_generation += 1<<22;
init_rd= best_rd= get_4block_rd(s, mb_x, mb_y, 0);
//FIXME more multiref search?
check_4block_inter(s, mb_x, mb_y,
(b[0]->mx + b[1]->mx + b[2]->mx + b[3]->mx + 2) >> 2,
(b[0]->my + b[1]->my + b[2]->my + b[3]->my + 2) >> 2, 0, &best_rd);
for(i=0; i<4; i++)
if(!(b[i]->type&BLOCK_INTRA))
check_4block_inter(s, mb_x, mb_y, b[i]->mx, b[i]->my, b[i]->ref, &best_rd);
if(init_rd != best_rd)
change++;
}
}
av_log(s->avctx, AV_LOG_ERROR, "pass:4mv changed:%d\n", change*4);
}
}
static void encode_blocks(SnowContext *s, int search){
int x, y;
int w= s->b_width;
int h= s->b_height;
if(s->avctx->me_method == ME_ITER && !s->keyframe && search)
iterative_me(s);
for(y=0; y<h; y++){
if(s->c.bytestream_end - s->c.bytestream < w*MB_SIZE*MB_SIZE*3){ //FIXME nicer limit
av_log(s->avctx, AV_LOG_ERROR, "encoded frame too large\n");
return;
}
for(x=0; x<w; x++){
if(s->avctx->me_method == ME_ITER || !search)
encode_q_branch2(s, 0, x, y);
else
encode_q_branch (s, 0, x, y);
}
}
}
static void quantize(SnowContext *s, SubBand *b, IDWTELEM *dst, DWTELEM *src, int stride, int bias){
const int w= b->width;
const int h= b->height;
const int qlog= av_clip(s->qlog + b->qlog, 0, QROOT*16);
const int qmul= ff_qexp[qlog&(QROOT-1)]<<((qlog>>QSHIFT) + ENCODER_EXTRA_BITS);
int x,y, thres1, thres2;
if(s->qlog == LOSSLESS_QLOG){
for(y=0; y<h; y++)
for(x=0; x<w; x++)
dst[x + y*stride]= src[x + y*stride];
return;
}
bias= bias ? 0 : (3*qmul)>>3;
thres1= ((qmul - bias)>>QEXPSHIFT) - 1;
thres2= 2*thres1;
if(!bias){
for(y=0; y<h; y++){
for(x=0; x<w; x++){
int i= src[x + y*stride];
if((unsigned)(i+thres1) > thres2){
if(i>=0){
i<<= QEXPSHIFT;
i/= qmul; //FIXME optimize
dst[x + y*stride]= i;
}else{
i= -i;
i<<= QEXPSHIFT;
i/= qmul; //FIXME optimize
dst[x + y*stride]= -i;
}
}else
dst[x + y*stride]= 0;
}
}
}else{
for(y=0; y<h; y++){
for(x=0; x<w; x++){
int i= src[x + y*stride];
if((unsigned)(i+thres1) > thres2){
if(i>=0){
i<<= QEXPSHIFT;
i= (i + bias) / qmul; //FIXME optimize
dst[x + y*stride]= i;
}else{
i= -i;
i<<= QEXPSHIFT;
i= (i + bias) / qmul; //FIXME optimize
dst[x + y*stride]= -i;
}
}else
dst[x + y*stride]= 0;
}
}
}
}
static void dequantize(SnowContext *s, SubBand *b, IDWTELEM *src, int stride){
const int w= b->width;
const int h= b->height;
const int qlog= av_clip(s->qlog + b->qlog, 0, QROOT*16);
const int qmul= ff_qexp[qlog&(QROOT-1)]<<(qlog>>QSHIFT);
const int qadd= (s->qbias*qmul)>>QBIAS_SHIFT;
int x,y;
if(s->qlog == LOSSLESS_QLOG) return;
for(y=0; y<h; y++){
for(x=0; x<w; x++){
int i= src[x + y*stride];
if(i<0){
src[x + y*stride]= -((-i*qmul + qadd)>>(QEXPSHIFT)); //FIXME try different bias
}else if(i>0){
src[x + y*stride]= (( i*qmul + qadd)>>(QEXPSHIFT));
}
}
}
}
static void decorrelate(SnowContext *s, SubBand *b, IDWTELEM *src, int stride, int inverse, int use_median){
const int w= b->width;
const int h= b->height;
int x,y;
for(y=h-1; y>=0; y--){
for(x=w-1; x>=0; x--){
int i= x + y*stride;
if(x){
if(use_median){
if(y && x+1<w) src[i] -= mid_pred(src[i - 1], src[i - stride], src[i - stride + 1]);
else src[i] -= src[i - 1];
}else{
if(y) src[i] -= mid_pred(src[i - 1], src[i - stride], src[i - 1] + src[i - stride] - src[i - 1 - stride]);
else src[i] -= src[i - 1];
}
}else{
if(y) src[i] -= src[i - stride];
}
}
}
}
static void correlate(SnowContext *s, SubBand *b, IDWTELEM *src, int stride, int inverse, int use_median){
const int w= b->width;
const int h= b->height;
int x,y;
for(y=0; y<h; y++){
for(x=0; x<w; x++){
int i= x + y*stride;
if(x){
if(use_median){
if(y && x+1<w) src[i] += mid_pred(src[i - 1], src[i - stride], src[i - stride + 1]);
else src[i] += src[i - 1];
}else{
if(y) src[i] += mid_pred(src[i - 1], src[i - stride], src[i - 1] + src[i - stride] - src[i - 1 - stride]);
else src[i] += src[i - 1];
}
}else{
if(y) src[i] += src[i - stride];
}
}
}
}
static void encode_qlogs(SnowContext *s){
int plane_index, level, orientation;
for(plane_index=0; plane_index<2; plane_index++){
for(level=0; level<s->spatial_decomposition_count; level++){
for(orientation=level ? 1:0; orientation<4; orientation++){
if(orientation==2) continue;
put_symbol(&s->c, s->header_state, s->plane[plane_index].band[level][orientation].qlog, 1);
}
}
}
}
static void encode_header(SnowContext *s){
int plane_index, i;
uint8_t kstate[32];
memset(kstate, MID_STATE, sizeof(kstate));
put_rac(&s->c, kstate, s->keyframe);
if(s->keyframe || s->always_reset){
ff_snow_reset_contexts(s);
s->last_spatial_decomposition_type=
s->last_qlog=
s->last_qbias=
s->last_mv_scale=
s->last_block_max_depth= 0;
for(plane_index=0; plane_index<2; plane_index++){
Plane *p= &s->plane[plane_index];
p->last_htaps=0;
p->last_diag_mc=0;
memset(p->last_hcoeff, 0, sizeof(p->last_hcoeff));
}
}
if(s->keyframe){
put_symbol(&s->c, s->header_state, s->version, 0);
put_rac(&s->c, s->header_state, s->always_reset);
put_symbol(&s->c, s->header_state, s->temporal_decomposition_type, 0);
put_symbol(&s->c, s->header_state, s->temporal_decomposition_count, 0);
put_symbol(&s->c, s->header_state, s->spatial_decomposition_count, 0);
put_symbol(&s->c, s->header_state, s->colorspace_type, 0);
put_symbol(&s->c, s->header_state, s->chroma_h_shift, 0);
put_symbol(&s->c, s->header_state, s->chroma_v_shift, 0);
put_rac(&s->c, s->header_state, s->spatial_scalability);
// put_rac(&s->c, s->header_state, s->rate_scalability);
put_symbol(&s->c, s->header_state, s->max_ref_frames-1, 0);
encode_qlogs(s);
}
if(!s->keyframe){
int update_mc=0;
for(plane_index=0; plane_index<2; plane_index++){
Plane *p= &s->plane[plane_index];
update_mc |= p->last_htaps != p->htaps;
update_mc |= p->last_diag_mc != p->diag_mc;
update_mc |= !!memcmp(p->last_hcoeff, p->hcoeff, sizeof(p->hcoeff));
}
put_rac(&s->c, s->header_state, update_mc);
if(update_mc){
for(plane_index=0; plane_index<2; plane_index++){
Plane *p= &s->plane[plane_index];
put_rac(&s->c, s->header_state, p->diag_mc);
put_symbol(&s->c, s->header_state, p->htaps/2-1, 0);
for(i= p->htaps/2; i; i--)
put_symbol(&s->c, s->header_state, FFABS(p->hcoeff[i]), 0);
}
}
if(s->last_spatial_decomposition_count != s->spatial_decomposition_count){
put_rac(&s->c, s->header_state, 1);
put_symbol(&s->c, s->header_state, s->spatial_decomposition_count, 0);
encode_qlogs(s);
}else
put_rac(&s->c, s->header_state, 0);
}
put_symbol(&s->c, s->header_state, s->spatial_decomposition_type - s->last_spatial_decomposition_type, 1);
put_symbol(&s->c, s->header_state, s->qlog - s->last_qlog , 1);
put_symbol(&s->c, s->header_state, s->mv_scale - s->last_mv_scale, 1);
put_symbol(&s->c, s->header_state, s->qbias - s->last_qbias , 1);
put_symbol(&s->c, s->header_state, s->block_max_depth - s->last_block_max_depth, 1);
}
static void update_last_header_values(SnowContext *s){
int plane_index;
if(!s->keyframe){
for(plane_index=0; plane_index<2; plane_index++){
Plane *p= &s->plane[plane_index];
p->last_diag_mc= p->diag_mc;
p->last_htaps = p->htaps;
memcpy(p->last_hcoeff, p->hcoeff, sizeof(p->hcoeff));
}
}
s->last_spatial_decomposition_type = s->spatial_decomposition_type;
s->last_qlog = s->qlog;
s->last_qbias = s->qbias;
s->last_mv_scale = s->mv_scale;
s->last_block_max_depth = s->block_max_depth;
s->last_spatial_decomposition_count = s->spatial_decomposition_count;
}
static int qscale2qlog(int qscale){
return rint(QROOT*log2(qscale / (float)FF_QP2LAMBDA))
+ 61*QROOT/8; ///< 64 > 60
}
static int ratecontrol_1pass(SnowContext *s, AVFrame *pict)
{
/* Estimate the frame's complexity as a sum of weighted dwt coefficients.
* FIXME we know exact mv bits at this point,
* but ratecontrol isn't set up to include them. */
uint32_t coef_sum= 0;
int level, orientation, delta_qlog;
for(level=0; level<s->spatial_decomposition_count; level++){
for(orientation=level ? 1 : 0; orientation<4; orientation++){
SubBand *b= &s->plane[0].band[level][orientation];
IDWTELEM *buf= b->ibuf;
const int w= b->width;
const int h= b->height;
const int stride= b->stride;
const int qlog= av_clip(2*QROOT + b->qlog, 0, QROOT*16);
const int qmul= ff_qexp[qlog&(QROOT-1)]<<(qlog>>QSHIFT);
const int qdiv= (1<<16)/qmul;
int x, y;
//FIXME this is ugly
for(y=0; y<h; y++)
for(x=0; x<w; x++)
buf[x+y*stride]= b->buf[x+y*stride];
if(orientation==0)
decorrelate(s, b, buf, stride, 1, 0);
for(y=0; y<h; y++)
for(x=0; x<w; x++)
coef_sum+= abs(buf[x+y*stride]) * qdiv >> 16;
}
}
/* ugly, ratecontrol just takes a sqrt again */
coef_sum = (uint64_t)coef_sum * coef_sum >> 16;
assert(coef_sum < INT_MAX);
if(pict->pict_type == AV_PICTURE_TYPE_I){
s->m.current_picture.mb_var_sum= coef_sum;
s->m.current_picture.mc_mb_var_sum= 0;
}else{
s->m.current_picture.mc_mb_var_sum= coef_sum;
s->m.current_picture.mb_var_sum= 0;
}
pict->quality= ff_rate_estimate_qscale(&s->m, 1);
if (pict->quality < 0)
return INT_MIN;
s->lambda= pict->quality * 3/2;
delta_qlog= qscale2qlog(pict->quality) - s->qlog;
s->qlog+= delta_qlog;
return delta_qlog;
}
static void calculate_visual_weight(SnowContext *s, Plane *p){
int width = p->width;
int height= p->height;
int level, orientation, x, y;
for(level=0; level<s->spatial_decomposition_count; level++){
for(orientation=level ? 1 : 0; orientation<4; orientation++){
SubBand *b= &p->band[level][orientation];
IDWTELEM *ibuf= b->ibuf;
int64_t error=0;
memset(s->spatial_idwt_buffer, 0, sizeof(*s->spatial_idwt_buffer)*width*height);
ibuf[b->width/2 + b->height/2*b->stride]= 256*16;
ff_spatial_idwt(s->spatial_idwt_buffer, s->temp_idwt_buffer, width, height, width, s->spatial_decomposition_type, s->spatial_decomposition_count);
for(y=0; y<height; y++){
for(x=0; x<width; x++){
int64_t d= s->spatial_idwt_buffer[x + y*width]*16;
error += d*d;
}
}
b->qlog= (int)(log(352256.0/sqrt(error)) / log(pow(2.0, 1.0/QROOT))+0.5);
}
}
}
static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
const AVFrame *pict, int *got_packet)
{
SnowContext *s = avctx->priv_data;
RangeCoder * const c= &s->c;
AVFrame *pic = &s->new_picture;
const int width= s->avctx->width;
const int height= s->avctx->height;
int level, orientation, plane_index, i, y, ret;
uint8_t rc_header_bak[sizeof(s->header_state)];
uint8_t rc_block_bak[sizeof(s->block_state)];
if (!pkt->data &&
(ret = av_new_packet(pkt, s->b_width*s->b_height*MB_SIZE*MB_SIZE*3 + FF_MIN_BUFFER_SIZE)) < 0) {
av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
return ret;
}
ff_init_range_encoder(c, pkt->data, pkt->size);
ff_build_rac_states(c, 0.05*(1LL<<32), 256-8);
for(i=0; i<3; i++){
int shift= !!i;
for(y=0; y<(height>>shift); y++)
memcpy(&s->input_picture.data[i][y * s->input_picture.linesize[i]],
&pict->data[i][y * pict->linesize[i]],
width>>shift);
}
s->new_picture = *pict;
s->m.picture_number= avctx->frame_number;
if(avctx->flags&CODEC_FLAG_PASS2){
s->m.pict_type = pic->pict_type = s->m.rc_context.entry[avctx->frame_number].new_pict_type;
s->keyframe = pic->pict_type == AV_PICTURE_TYPE_I;
if(!(avctx->flags&CODEC_FLAG_QSCALE)) {
pic->quality = ff_rate_estimate_qscale(&s->m, 0);
if (pic->quality < 0)
return -1;
}
}else{
s->keyframe= avctx->gop_size==0 || avctx->frame_number % avctx->gop_size == 0;
s->m.pict_type = pic->pict_type = s->keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
}
if(s->pass1_rc && avctx->frame_number == 0)
pic->quality = 2*FF_QP2LAMBDA;
if (pic->quality) {
s->qlog = qscale2qlog(pic->quality);
s->lambda = pic->quality * 3/2;
}
if (s->qlog < 0 || (!pic->quality && (avctx->flags & CODEC_FLAG_QSCALE))) {
s->qlog= LOSSLESS_QLOG;
s->lambda = 0;
}//else keep previous frame's qlog until after motion estimation
ff_snow_frame_start(s);
s->m.current_picture_ptr= &s->m.current_picture;
s->m.last_picture.f.pts = s->m.current_picture.f.pts;
s->m.current_picture.f.pts = pict->pts;
if(pic->pict_type == AV_PICTURE_TYPE_P){
int block_width = (width +15)>>4;
int block_height= (height+15)>>4;
int stride= s->current_picture.linesize[0];
assert(s->current_picture.data[0]);
assert(s->last_picture[0].data[0]);
s->m.avctx= s->avctx;
s->m.current_picture.f.data[0] = s->current_picture.data[0];
s->m. last_picture.f.data[0] = s->last_picture[0].data[0];
s->m. new_picture.f.data[0] = s-> input_picture.data[0];
s->m. last_picture_ptr= &s->m. last_picture;
s->m.linesize=
s->m. last_picture.f.linesize[0] =
s->m. new_picture.f.linesize[0] =
s->m.current_picture.f.linesize[0] = stride;
s->m.uvlinesize= s->current_picture.linesize[1];
s->m.width = width;
s->m.height= height;
s->m.mb_width = block_width;
s->m.mb_height= block_height;
s->m.mb_stride= s->m.mb_width+1;
s->m.b8_stride= 2*s->m.mb_width+1;
s->m.f_code=1;
s->m.pict_type = pic->pict_type;
s->m.me_method= s->avctx->me_method;
s->m.me.scene_change_score=0;
s->m.flags= s->avctx->flags;
s->m.quarter_sample= (s->avctx->flags & CODEC_FLAG_QPEL)!=0;
s->m.out_format= FMT_H263;
s->m.unrestricted_mv= 1;
s->m.lambda = s->lambda;
s->m.qscale= (s->m.lambda*139 + FF_LAMBDA_SCALE*64) >> (FF_LAMBDA_SHIFT + 7);
s->lambda2= s->m.lambda2= (s->m.lambda*s->m.lambda + FF_LAMBDA_SCALE/2) >> FF_LAMBDA_SHIFT;
s->m.dsp= s->dsp; //move
ff_init_me(&s->m);
s->dsp= s->m.dsp;
}
if(s->pass1_rc){
memcpy(rc_header_bak, s->header_state, sizeof(s->header_state));
memcpy(rc_block_bak, s->block_state, sizeof(s->block_state));
}
redo_frame:
if (pic->pict_type == AV_PICTURE_TYPE_I)
s->spatial_decomposition_count= 5;
else
s->spatial_decomposition_count= 5;
s->m.pict_type = pic->pict_type;
s->qbias = pic->pict_type == AV_PICTURE_TYPE_P ? 2 : 0;
ff_snow_common_init_after_header(avctx);
if(s->last_spatial_decomposition_count != s->spatial_decomposition_count){
for(plane_index=0; plane_index<3; plane_index++){
calculate_visual_weight(s, &s->plane[plane_index]);
}
}
encode_header(s);
s->m.misc_bits = 8*(s->c.bytestream - s->c.bytestream_start);
encode_blocks(s, 1);
s->m.mv_bits = 8*(s->c.bytestream - s->c.bytestream_start) - s->m.misc_bits;
for(plane_index=0; plane_index<3; plane_index++){
Plane *p= &s->plane[plane_index];
int w= p->width;
int h= p->height;
int x, y;
// int bits= put_bits_count(&s->c.pb);
if (!s->memc_only) {
//FIXME optimize
if(pict->data[plane_index]) //FIXME gray hack
for(y=0; y<h; y++){
for(x=0; x<w; x++){
s->spatial_idwt_buffer[y*w + x]= pict->data[plane_index][y*pict->linesize[plane_index] + x]<<FRAC_BITS;
}
}
predict_plane(s, s->spatial_idwt_buffer, plane_index, 0);
if( plane_index==0
&& pic->pict_type == AV_PICTURE_TYPE_P
&& !(avctx->flags&CODEC_FLAG_PASS2)
&& s->m.me.scene_change_score > s->avctx->scenechange_threshold){
ff_init_range_encoder(c, pkt->data, pkt->size);
ff_build_rac_states(c, 0.05*(1LL<<32), 256-8);
pic->pict_type= AV_PICTURE_TYPE_I;
s->keyframe=1;
s->current_picture.key_frame=1;
goto redo_frame;
}
if(s->qlog == LOSSLESS_QLOG){
for(y=0; y<h; y++){
for(x=0; x<w; x++){
s->spatial_dwt_buffer[y*w + x]= (s->spatial_idwt_buffer[y*w + x] + (1<<(FRAC_BITS-1))-1)>>FRAC_BITS;
}
}
}else{
for(y=0; y<h; y++){
for(x=0; x<w; x++){
s->spatial_dwt_buffer[y*w + x]=s->spatial_idwt_buffer[y*w + x]<<ENCODER_EXTRA_BITS;
}
}
}
/* if(QUANTIZE2)
dwt_quantize(s, p, s->spatial_dwt_buffer, w, h, w, s->spatial_decomposition_type);
else*/
ff_spatial_dwt(s->spatial_dwt_buffer, s->temp_dwt_buffer, w, h, w, s->spatial_decomposition_type, s->spatial_decomposition_count);
if(s->pass1_rc && plane_index==0){
int delta_qlog = ratecontrol_1pass(s, pic);
if (delta_qlog <= INT_MIN)
return -1;
if(delta_qlog){
//reordering qlog in the bitstream would eliminate this reset
ff_init_range_encoder(c, pkt->data, pkt->size);
memcpy(s->header_state, rc_header_bak, sizeof(s->header_state));
memcpy(s->block_state, rc_block_bak, sizeof(s->block_state));
encode_header(s);
encode_blocks(s, 0);
}
}
for(level=0; level<s->spatial_decomposition_count; level++){
for(orientation=level ? 1 : 0; orientation<4; orientation++){
SubBand *b= &p->band[level][orientation];
if(!QUANTIZE2)
quantize(s, b, b->ibuf, b->buf, b->stride, s->qbias);
if(orientation==0)
decorrelate(s, b, b->ibuf, b->stride, pic->pict_type == AV_PICTURE_TYPE_P, 0);
encode_subband(s, b, b->ibuf, b->parent ? b->parent->ibuf : NULL, b->stride, orientation);
assert(b->parent==NULL || b->parent->stride == b->stride*2);
if(orientation==0)
correlate(s, b, b->ibuf, b->stride, 1, 0);
}
}
for(level=0; level<s->spatial_decomposition_count; level++){
for(orientation=level ? 1 : 0; orientation<4; orientation++){
SubBand *b= &p->band[level][orientation];
dequantize(s, b, b->ibuf, b->stride);
}
}
ff_spatial_idwt(s->spatial_idwt_buffer, s->temp_idwt_buffer, w, h, w, s->spatial_decomposition_type, s->spatial_decomposition_count);
if(s->qlog == LOSSLESS_QLOG){
for(y=0; y<h; y++){
for(x=0; x<w; x++){
s->spatial_idwt_buffer[y*w + x]<<=FRAC_BITS;
}
}
}
predict_plane(s, s->spatial_idwt_buffer, plane_index, 1);
}else{
//ME/MC only
if(pic->pict_type == AV_PICTURE_TYPE_I){
for(y=0; y<h; y++){
for(x=0; x<w; x++){
s->current_picture.data[plane_index][y*s->current_picture.linesize[plane_index] + x]=
pict->data[plane_index][y*pict->linesize[plane_index] + x];
}
}
}else{
memset(s->spatial_idwt_buffer, 0, sizeof(IDWTELEM)*w*h);
predict_plane(s, s->spatial_idwt_buffer, plane_index, 1);
}
}
if(s->avctx->flags&CODEC_FLAG_PSNR){
int64_t error= 0;
if(pict->data[plane_index]) //FIXME gray hack
for(y=0; y<h; y++){
for(x=0; x<w; x++){
int d= s->current_picture.data[plane_index][y*s->current_picture.linesize[plane_index] + x] - pict->data[plane_index][y*pict->linesize[plane_index] + x];
error += d*d;
}
}
s->avctx->error[plane_index] += error;
s->current_picture.error[plane_index] = error;
}
}
update_last_header_values(s);
ff_snow_release_buffer(avctx);
s->current_picture.coded_picture_number = avctx->frame_number;
s->current_picture.pict_type = pict->pict_type;
s->current_picture.quality = pict->quality;
s->m.frame_bits = 8*(s->c.bytestream - s->c.bytestream_start);
s->m.p_tex_bits = s->m.frame_bits - s->m.misc_bits - s->m.mv_bits;
s->m.current_picture.f.display_picture_number =
s->m.current_picture.f.coded_picture_number = avctx->frame_number;
s->m.current_picture.f.quality = pic->quality;
s->m.total_bits += 8*(s->c.bytestream - s->c.bytestream_start);
if(s->pass1_rc)
if (ff_rate_estimate_qscale(&s->m, 0) < 0)
return -1;
if(avctx->flags&CODEC_FLAG_PASS1)
ff_write_pass1_stats(&s->m);
s->m.last_pict_type = s->m.pict_type;
avctx->frame_bits = s->m.frame_bits;
avctx->mv_bits = s->m.mv_bits;
avctx->misc_bits = s->m.misc_bits;
avctx->p_tex_bits = s->m.p_tex_bits;
emms_c();
pkt->size = ff_rac_terminate(c);
if (avctx->coded_frame->key_frame)
pkt->flags |= AV_PKT_FLAG_KEY;
*got_packet = 1;
return 0;
}
static av_cold int encode_end(AVCodecContext *avctx)
{
SnowContext *s = avctx->priv_data;
ff_snow_common_end(s);
if (s->input_picture.data[0])
avctx->release_buffer(avctx, &s->input_picture);
av_free(avctx->stats_out);
return 0;
}
#define OFFSET(x) offsetof(SnowContext, x)
#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
{ "memc_only", "Only do ME/MC (I frames -> ref, P frame -> ME+MC).", OFFSET(memc_only), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE },
{ NULL },
};
static const AVClass snowenc_class = {
.class_name = "snow encoder",
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
};
AVCodec ff_snow_encoder = {
.name = "snow",
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_SNOW,
.priv_data_size = sizeof(SnowContext),
.init = encode_init,
.encode2 = encode_frame,
.close = encode_end,
.long_name = NULL_IF_CONFIG_SMALL("Snow"),
.priv_class = &snowenc_class,
};
......@@ -91,5 +91,8 @@
#ifndef FF_API_MMI
#define FF_API_MMI (LIBAVCODEC_VERSION_MAJOR < 55)
#endif
#ifndef FF_API_SNOW
#define FF_API_SNOW (LIBAVCODEC_VERSION_MAJOR < 55)
#endif
#endif /* AVCODEC_VERSION_H */
......@@ -32,7 +32,6 @@ MMX-OBJS += x86/dsputil_mmx.o \
x86/idct_sse2_xvid.o \
x86/simple_idct.o \
MMX-OBJS-$(CONFIG_DWT) += x86/snowdsp.o
MMX-OBJS-$(CONFIG_ENCODERS) += x86/dsputilenc_mmx.o \
x86/motion_est.o
MMX-OBJS-$(CONFIG_VC1_DECODER) += x86/vc1dsp_mmx.o
......
......@@ -466,7 +466,7 @@ void ff_dsputil_init_pix_mmx(DSPContext* c, AVCodecContext *avctx)
c->pix_abs[1][3] = sad8_xy2_mmxext;
}
}
if ((mm_flags & AV_CPU_FLAG_SSE2) && !(mm_flags & AV_CPU_FLAG_3DNOW) && avctx->codec_id != AV_CODEC_ID_SNOW) {
if ((mm_flags & AV_CPU_FLAG_SSE2) && !(mm_flags & AV_CPU_FLAG_3DNOW)) {
c->sad[0]= sad16_sse2;
}
#endif /* HAVE_INLINE_ASM */
......
/*
* MMX and SSE2 optimized snow DSP utils
* Copyright (c) 2005-2006 Robert Edele <yartrebo@earthlink.net>
*
* This file is part of Libav.
*
* Libav 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.
*
* Libav 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 Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/cpu.h"
#include "libavutil/x86/asm.h"
#include "libavcodec/avcodec.h"
#include "libavcodec/snow.h"
#include "libavcodec/dwt.h"
#include "dsputil_mmx.h"
#if HAVE_INLINE_ASM
static void ff_snow_horizontal_compose97i_sse2(IDWTELEM *b, IDWTELEM *temp, int width){
const int w2= (width+1)>>1;
const int w_l= (width>>1);
const int w_r= w2 - 1;
int i;
{ // Lift 0
IDWTELEM * const ref = b + w2 - 1;
IDWTELEM b_0 = b[0]; //By allowing the first entry in b[0] to be calculated twice
// (the first time erroneously), we allow the SSE2 code to run an extra pass.
// The savings in code and time are well worth having to store this value and
// calculate b[0] correctly afterwards.
i = 0;
__asm__ volatile(
"pcmpeqd %%xmm7, %%xmm7 \n\t"
"pcmpeqd %%xmm3, %%xmm3 \n\t"
"psllw $1, %%xmm3 \n\t"
"paddw %%xmm7, %%xmm3 \n\t"
"psllw $13, %%xmm3 \n\t"
::);
for(; i<w_l-15; i+=16){
__asm__ volatile(
"movdqu (%1), %%xmm1 \n\t"
"movdqu 16(%1), %%xmm5 \n\t"
"movdqu 2(%1), %%xmm2 \n\t"
"movdqu 18(%1), %%xmm6 \n\t"
"paddw %%xmm1, %%xmm2 \n\t"
"paddw %%xmm5, %%xmm6 \n\t"
"paddw %%xmm7, %%xmm2 \n\t"
"paddw %%xmm7, %%xmm6 \n\t"
"pmulhw %%xmm3, %%xmm2 \n\t"
"pmulhw %%xmm3, %%xmm6 \n\t"
"paddw (%0), %%xmm2 \n\t"
"paddw 16(%0), %%xmm6 \n\t"
"movdqa %%xmm2, (%0) \n\t"
"movdqa %%xmm6, 16(%0) \n\t"
:: "r"(&b[i]), "r"(&ref[i])
: "memory"
);
}
snow_horizontal_compose_lift_lead_out(i, b, b, ref, width, w_l, 0, W_DM, W_DO, W_DS);
b[0] = b_0 - ((W_DM * 2 * ref[1]+W_DO)>>W_DS);
}
{ // Lift 1
IDWTELEM * const dst = b+w2;
i = 0;
for(; (((x86_reg)&dst[i]) & 0x1F) && i<w_r; i++){
dst[i] = dst[i] - (b[i] + b[i + 1]);
}
for(; i<w_r-15; i+=16){
__asm__ volatile(
"movdqu (%1), %%xmm1 \n\t"
"movdqu 16(%1), %%xmm5 \n\t"
"movdqu 2(%1), %%xmm2 \n\t"
"movdqu 18(%1), %%xmm6 \n\t"
"paddw %%xmm1, %%xmm2 \n\t"
"paddw %%xmm5, %%xmm6 \n\t"
"movdqa (%0), %%xmm0 \n\t"
"movdqa 16(%0), %%xmm4 \n\t"
"psubw %%xmm2, %%xmm0 \n\t"
"psubw %%xmm6, %%xmm4 \n\t"
"movdqa %%xmm0, (%0) \n\t"
"movdqa %%xmm4, 16(%0) \n\t"
:: "r"(&dst[i]), "r"(&b[i])
: "memory"
);
}
snow_horizontal_compose_lift_lead_out(i, dst, dst, b, width, w_r, 1, W_CM, W_CO, W_CS);
}
{ // Lift 2
IDWTELEM * const ref = b+w2 - 1;
IDWTELEM b_0 = b[0];
i = 0;
__asm__ volatile(
"psllw $15, %%xmm7 \n\t"
"pcmpeqw %%xmm6, %%xmm6 \n\t"
"psrlw $13, %%xmm6 \n\t"
"paddw %%xmm7, %%xmm6 \n\t"
::);
for(; i<w_l-15; i+=16){
__asm__ volatile(
"movdqu (%1), %%xmm0 \n\t"
"movdqu 16(%1), %%xmm4 \n\t"
"movdqu 2(%1), %%xmm1 \n\t"
"movdqu 18(%1), %%xmm5 \n\t" //FIXME try aligned reads and shifts
"paddw %%xmm6, %%xmm0 \n\t"
"paddw %%xmm6, %%xmm4 \n\t"
"paddw %%xmm7, %%xmm1 \n\t"
"paddw %%xmm7, %%xmm5 \n\t"
"pavgw %%xmm1, %%xmm0 \n\t"
"pavgw %%xmm5, %%xmm4 \n\t"
"psubw %%xmm7, %%xmm0 \n\t"
"psubw %%xmm7, %%xmm4 \n\t"
"psraw $1, %%xmm0 \n\t"
"psraw $1, %%xmm4 \n\t"
"movdqa (%0), %%xmm1 \n\t"
"movdqa 16(%0), %%xmm5 \n\t"
"paddw %%xmm1, %%xmm0 \n\t"
"paddw %%xmm5, %%xmm4 \n\t"
"psraw $2, %%xmm0 \n\t"
"psraw $2, %%xmm4 \n\t"
"paddw %%xmm1, %%xmm0 \n\t"
"paddw %%xmm5, %%xmm4 \n\t"
"movdqa %%xmm0, (%0) \n\t"
"movdqa %%xmm4, 16(%0) \n\t"
:: "r"(&b[i]), "r"(&ref[i])
: "memory"
);
}
snow_horizontal_compose_liftS_lead_out(i, b, b, ref, width, w_l);
b[0] = b_0 + ((2 * ref[1] + W_BO-1 + 4 * b_0) >> W_BS);
}
{ // Lift 3
IDWTELEM * const src = b+w2;
i = 0;
for(; (((x86_reg)&temp[i]) & 0x1F) && i<w_r; i++){
temp[i] = src[i] - ((-W_AM*(b[i] + b[i+1]))>>W_AS);
}
for(; i<w_r-7; i+=8){
__asm__ volatile(
"movdqu 2(%1), %%xmm2 \n\t"
"movdqu 18(%1), %%xmm6 \n\t"
"paddw (%1), %%xmm2 \n\t"
"paddw 16(%1), %%xmm6 \n\t"
"movdqu (%0), %%xmm0 \n\t"
"movdqu 16(%0), %%xmm4 \n\t"
"paddw %%xmm2, %%xmm0 \n\t"
"paddw %%xmm6, %%xmm4 \n\t"
"psraw $1, %%xmm2 \n\t"
"psraw $1, %%xmm6 \n\t"
"paddw %%xmm0, %%xmm2 \n\t"
"paddw %%xmm4, %%xmm6 \n\t"
"movdqa %%xmm2, (%2) \n\t"
"movdqa %%xmm6, 16(%2) \n\t"
:: "r"(&src[i]), "r"(&b[i]), "r"(&temp[i])
: "memory"
);
}
snow_horizontal_compose_lift_lead_out(i, temp, src, b, width, w_r, 1, -W_AM, W_AO+1, W_AS);
}
{
snow_interleave_line_header(&i, width, b, temp);
for (; (i & 0x3E) != 0x3E; i-=2){
b[i+1] = temp[i>>1];
b[i] = b[i>>1];
}
for (i-=62; i>=0; i-=64){
__asm__ volatile(
"movdqa (%1), %%xmm0 \n\t"
"movdqa 16(%1), %%xmm2 \n\t"
"movdqa 32(%1), %%xmm4 \n\t"
"movdqa 48(%1), %%xmm6 \n\t"
"movdqa (%1), %%xmm1 \n\t"
"movdqa 16(%1), %%xmm3 \n\t"
"movdqa 32(%1), %%xmm5 \n\t"
"movdqa 48(%1), %%xmm7 \n\t"
"punpcklwd (%2), %%xmm0 \n\t"
"punpcklwd 16(%2), %%xmm2 \n\t"
"punpcklwd 32(%2), %%xmm4 \n\t"
"punpcklwd 48(%2), %%xmm6 \n\t"
"movdqa %%xmm0, (%0) \n\t"
"movdqa %%xmm2, 32(%0) \n\t"
"movdqa %%xmm4, 64(%0) \n\t"
"movdqa %%xmm6, 96(%0) \n\t"
"punpckhwd (%2), %%xmm1 \n\t"
"punpckhwd 16(%2), %%xmm3 \n\t"
"punpckhwd 32(%2), %%xmm5 \n\t"
"punpckhwd 48(%2), %%xmm7 \n\t"
"movdqa %%xmm1, 16(%0) \n\t"
"movdqa %%xmm3, 48(%0) \n\t"
"movdqa %%xmm5, 80(%0) \n\t"
"movdqa %%xmm7, 112(%0) \n\t"
:: "r"(&(b)[i]), "r"(&(b)[i>>1]), "r"(&(temp)[i>>1])
: "memory"
);
}
}
}
static void ff_snow_horizontal_compose97i_mmx(IDWTELEM *b, IDWTELEM *temp, int width){
const int w2= (width+1)>>1;
const int w_l= (width>>1);
const int w_r= w2 - 1;
int i;
{ // Lift 0
IDWTELEM * const ref = b + w2 - 1;
i = 1;
b[0] = b[0] - ((W_DM * 2 * ref[1]+W_DO)>>W_DS);
__asm__ volatile(
"pcmpeqw %%mm7, %%mm7 \n\t"
"pcmpeqw %%mm3, %%mm3 \n\t"
"psllw $1, %%mm3 \n\t"
"paddw %%mm7, %%mm3 \n\t"
"psllw $13, %%mm3 \n\t"
::);
for(; i<w_l-7; i+=8){
__asm__ volatile(
"movq (%1), %%mm2 \n\t"
"movq 8(%1), %%mm6 \n\t"
"paddw 2(%1), %%mm2 \n\t"
"paddw 10(%1), %%mm6 \n\t"
"paddw %%mm7, %%mm2 \n\t"
"paddw %%mm7, %%mm6 \n\t"
"pmulhw %%mm3, %%mm2 \n\t"
"pmulhw %%mm3, %%mm6 \n\t"
"paddw (%0), %%mm2 \n\t"
"paddw 8(%0), %%mm6 \n\t"
"movq %%mm2, (%0) \n\t"
"movq %%mm6, 8(%0) \n\t"
:: "r"(&b[i]), "r"(&ref[i])
: "memory"
);
}
snow_horizontal_compose_lift_lead_out(i, b, b, ref, width, w_l, 0, W_DM, W_DO, W_DS);
}
{ // Lift 1
IDWTELEM * const dst = b+w2;
i = 0;
for(; i<w_r-7; i+=8){
__asm__ volatile(
"movq (%1), %%mm2 \n\t"
"movq 8(%1), %%mm6 \n\t"
"paddw 2(%1), %%mm2 \n\t"
"paddw 10(%1), %%mm6 \n\t"
"movq (%0), %%mm0 \n\t"
"movq 8(%0), %%mm4 \n\t"
"psubw %%mm2, %%mm0 \n\t"
"psubw %%mm6, %%mm4 \n\t"
"movq %%mm0, (%0) \n\t"
"movq %%mm4, 8(%0) \n\t"
:: "r"(&dst[i]), "r"(&b[i])
: "memory"
);
}
snow_horizontal_compose_lift_lead_out(i, dst, dst, b, width, w_r, 1, W_CM, W_CO, W_CS);
}
{ // Lift 2
IDWTELEM * const ref = b+w2 - 1;
i = 1;
b[0] = b[0] + (((2 * ref[1] + W_BO) + 4 * b[0]) >> W_BS);
__asm__ volatile(
"psllw $15, %%mm7 \n\t"
"pcmpeqw %%mm6, %%mm6 \n\t"
"psrlw $13, %%mm6 \n\t"
"paddw %%mm7, %%mm6 \n\t"
::);
for(; i<w_l-7; i+=8){
__asm__ volatile(
"movq (%1), %%mm0 \n\t"
"movq 8(%1), %%mm4 \n\t"
"movq 2(%1), %%mm1 \n\t"
"movq 10(%1), %%mm5 \n\t"
"paddw %%mm6, %%mm0 \n\t"
"paddw %%mm6, %%mm4 \n\t"
"paddw %%mm7, %%mm1 \n\t"
"paddw %%mm7, %%mm5 \n\t"
"pavgw %%mm1, %%mm0 \n\t"
"pavgw %%mm5, %%mm4 \n\t"
"psubw %%mm7, %%mm0 \n\t"
"psubw %%mm7, %%mm4 \n\t"
"psraw $1, %%mm0 \n\t"
"psraw $1, %%mm4 \n\t"
"movq (%0), %%mm1 \n\t"
"movq 8(%0), %%mm5 \n\t"
"paddw %%mm1, %%mm0 \n\t"
"paddw %%mm5, %%mm4 \n\t"
"psraw $2, %%mm0 \n\t"
"psraw $2, %%mm4 \n\t"
"paddw %%mm1, %%mm0 \n\t"
"paddw %%mm5, %%mm4 \n\t"
"movq %%mm0, (%0) \n\t"
"movq %%mm4, 8(%0) \n\t"
:: "r"(&b[i]), "r"(&ref[i])
: "memory"
);
}
snow_horizontal_compose_liftS_lead_out(i, b, b, ref, width, w_l);
}
{ // Lift 3
IDWTELEM * const src = b+w2;
i = 0;
for(; i<w_r-7; i+=8){
__asm__ volatile(
"movq 2(%1), %%mm2 \n\t"
"movq 10(%1), %%mm6 \n\t"
"paddw (%1), %%mm2 \n\t"
"paddw 8(%1), %%mm6 \n\t"
"movq (%0), %%mm0 \n\t"
"movq 8(%0), %%mm4 \n\t"
"paddw %%mm2, %%mm0 \n\t"
"paddw %%mm6, %%mm4 \n\t"
"psraw $1, %%mm2 \n\t"
"psraw $1, %%mm6 \n\t"
"paddw %%mm0, %%mm2 \n\t"
"paddw %%mm4, %%mm6 \n\t"
"movq %%mm2, (%2) \n\t"
"movq %%mm6, 8(%2) \n\t"
:: "r"(&src[i]), "r"(&b[i]), "r"(&temp[i])
: "memory"
);
}
snow_horizontal_compose_lift_lead_out(i, temp, src, b, width, w_r, 1, -W_AM, W_AO+1, W_AS);
}
{
snow_interleave_line_header(&i, width, b, temp);
for (; (i & 0x1E) != 0x1E; i-=2){
b[i+1] = temp[i>>1];
b[i] = b[i>>1];
}
for (i-=30; i>=0; i-=32){
__asm__ volatile(
"movq (%1), %%mm0 \n\t"
"movq 8(%1), %%mm2 \n\t"
"movq 16(%1), %%mm4 \n\t"
"movq 24(%1), %%mm6 \n\t"
"movq (%1), %%mm1 \n\t"
"movq 8(%1), %%mm3 \n\t"
"movq 16(%1), %%mm5 \n\t"
"movq 24(%1), %%mm7 \n\t"
"punpcklwd (%2), %%mm0 \n\t"
"punpcklwd 8(%2), %%mm2 \n\t"
"punpcklwd 16(%2), %%mm4 \n\t"
"punpcklwd 24(%2), %%mm6 \n\t"
"movq %%mm0, (%0) \n\t"
"movq %%mm2, 16(%0) \n\t"
"movq %%mm4, 32(%0) \n\t"
"movq %%mm6, 48(%0) \n\t"
"punpckhwd (%2), %%mm1 \n\t"
"punpckhwd 8(%2), %%mm3 \n\t"
"punpckhwd 16(%2), %%mm5 \n\t"
"punpckhwd 24(%2), %%mm7 \n\t"
"movq %%mm1, 8(%0) \n\t"
"movq %%mm3, 24(%0) \n\t"
"movq %%mm5, 40(%0) \n\t"
"movq %%mm7, 56(%0) \n\t"
:: "r"(&b[i]), "r"(&b[i>>1]), "r"(&temp[i>>1])
: "memory"
);
}
}
}
#if HAVE_7REGS
#define snow_vertical_compose_sse2_load_add(op,r,t0,t1,t2,t3)\
""op" ("r",%%"REG_d"), %%"t0" \n\t"\
""op" 16("r",%%"REG_d"), %%"t1" \n\t"\
""op" 32("r",%%"REG_d"), %%"t2" \n\t"\
""op" 48("r",%%"REG_d"), %%"t3" \n\t"
#define snow_vertical_compose_sse2_load(r,t0,t1,t2,t3)\
snow_vertical_compose_sse2_load_add("movdqa",r,t0,t1,t2,t3)
#define snow_vertical_compose_sse2_add(r,t0,t1,t2,t3)\
snow_vertical_compose_sse2_load_add("paddw",r,t0,t1,t2,t3)
#define snow_vertical_compose_r2r_sub(s0,s1,s2,s3,t0,t1,t2,t3)\
"psubw %%"s0", %%"t0" \n\t"\
"psubw %%"s1", %%"t1" \n\t"\
"psubw %%"s2", %%"t2" \n\t"\
"psubw %%"s3", %%"t3" \n\t"
#define snow_vertical_compose_sse2_store(w,s0,s1,s2,s3)\
"movdqa %%"s0", ("w",%%"REG_d") \n\t"\
"movdqa %%"s1", 16("w",%%"REG_d") \n\t"\
"movdqa %%"s2", 32("w",%%"REG_d") \n\t"\
"movdqa %%"s3", 48("w",%%"REG_d") \n\t"
#define snow_vertical_compose_sra(n,t0,t1,t2,t3)\
"psraw $"n", %%"t0" \n\t"\
"psraw $"n", %%"t1" \n\t"\
"psraw $"n", %%"t2" \n\t"\
"psraw $"n", %%"t3" \n\t"
#define snow_vertical_compose_r2r_add(s0,s1,s2,s3,t0,t1,t2,t3)\
"paddw %%"s0", %%"t0" \n\t"\
"paddw %%"s1", %%"t1" \n\t"\
"paddw %%"s2", %%"t2" \n\t"\
"paddw %%"s3", %%"t3" \n\t"
#define snow_vertical_compose_r2r_pmulhw(s0,s1,s2,s3,t0,t1,t2,t3)\
"pmulhw %%"s0", %%"t0" \n\t"\
"pmulhw %%"s1", %%"t1" \n\t"\
"pmulhw %%"s2", %%"t2" \n\t"\
"pmulhw %%"s3", %%"t3" \n\t"
#define snow_vertical_compose_sse2_move(s0,s1,s2,s3,t0,t1,t2,t3)\
"movdqa %%"s0", %%"t0" \n\t"\
"movdqa %%"s1", %%"t1" \n\t"\
"movdqa %%"s2", %%"t2" \n\t"\
"movdqa %%"s3", %%"t3" \n\t"
static void ff_snow_vertical_compose97i_sse2(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, IDWTELEM *b3, IDWTELEM *b4, IDWTELEM *b5, int width){
x86_reg i = width;
while(i & 0x1F)
{
i--;
b4[i] -= (W_DM*(b3[i] + b5[i])+W_DO)>>W_DS;
b3[i] -= (W_CM*(b2[i] + b4[i])+W_CO)>>W_CS;
b2[i] += (W_BM*(b1[i] + b3[i])+4*b2[i]+W_BO)>>W_BS;
b1[i] += (W_AM*(b0[i] + b2[i])+W_AO)>>W_AS;
}
i+=i;
__asm__ volatile (
"jmp 2f \n\t"
"1: \n\t"
snow_vertical_compose_sse2_load("%4","xmm0","xmm2","xmm4","xmm6")
snow_vertical_compose_sse2_add("%6","xmm0","xmm2","xmm4","xmm6")
"pcmpeqw %%xmm0, %%xmm0 \n\t"
"pcmpeqw %%xmm2, %%xmm2 \n\t"
"paddw %%xmm2, %%xmm2 \n\t"
"paddw %%xmm0, %%xmm2 \n\t"
"psllw $13, %%xmm2 \n\t"
snow_vertical_compose_r2r_add("xmm0","xmm0","xmm0","xmm0","xmm1","xmm3","xmm5","xmm7")
snow_vertical_compose_r2r_pmulhw("xmm2","xmm2","xmm2","xmm2","xmm1","xmm3","xmm5","xmm7")
snow_vertical_compose_sse2_add("%5","xmm1","xmm3","xmm5","xmm7")
snow_vertical_compose_sse2_store("%5","xmm1","xmm3","xmm5","xmm7")
snow_vertical_compose_sse2_load("%4","xmm0","xmm2","xmm4","xmm6")
snow_vertical_compose_sse2_add("%3","xmm1","xmm3","xmm5","xmm7")
snow_vertical_compose_r2r_sub("xmm1","xmm3","xmm5","xmm7","xmm0","xmm2","xmm4","xmm6")
snow_vertical_compose_sse2_store("%4","xmm0","xmm2","xmm4","xmm6")
"pcmpeqw %%xmm7, %%xmm7 \n\t"
"pcmpeqw %%xmm5, %%xmm5 \n\t"
"psllw $15, %%xmm7 \n\t"
"psrlw $13, %%xmm5 \n\t"
"paddw %%xmm7, %%xmm5 \n\t"
snow_vertical_compose_r2r_add("xmm5","xmm5","xmm5","xmm5","xmm0","xmm2","xmm4","xmm6")
"movq (%2,%%"REG_d"), %%xmm1 \n\t"
"movq 8(%2,%%"REG_d"), %%xmm3 \n\t"
"paddw %%xmm7, %%xmm1 \n\t"
"paddw %%xmm7, %%xmm3 \n\t"
"pavgw %%xmm1, %%xmm0 \n\t"
"pavgw %%xmm3, %%xmm2 \n\t"
"movq 16(%2,%%"REG_d"), %%xmm1 \n\t"
"movq 24(%2,%%"REG_d"), %%xmm3 \n\t"
"paddw %%xmm7, %%xmm1 \n\t"
"paddw %%xmm7, %%xmm3 \n\t"
"pavgw %%xmm1, %%xmm4 \n\t"
"pavgw %%xmm3, %%xmm6 \n\t"
snow_vertical_compose_r2r_sub("xmm7","xmm7","xmm7","xmm7","xmm0","xmm2","xmm4","xmm6")
snow_vertical_compose_sra("1","xmm0","xmm2","xmm4","xmm6")
snow_vertical_compose_sse2_add("%3","xmm0","xmm2","xmm4","xmm6")
snow_vertical_compose_sra("2","xmm0","xmm2","xmm4","xmm6")
snow_vertical_compose_sse2_add("%3","xmm0","xmm2","xmm4","xmm6")
snow_vertical_compose_sse2_store("%3","xmm0","xmm2","xmm4","xmm6")
snow_vertical_compose_sse2_add("%1","xmm0","xmm2","xmm4","xmm6")
snow_vertical_compose_sse2_move("xmm0","xmm2","xmm4","xmm6","xmm1","xmm3","xmm5","xmm7")
snow_vertical_compose_sra("1","xmm0","xmm2","xmm4","xmm6")
snow_vertical_compose_r2r_add("xmm1","xmm3","xmm5","xmm7","xmm0","xmm2","xmm4","xmm6")
snow_vertical_compose_sse2_add("%2","xmm0","xmm2","xmm4","xmm6")
snow_vertical_compose_sse2_store("%2","xmm0","xmm2","xmm4","xmm6")
"2: \n\t"
"sub $64, %%"REG_d" \n\t"
"jge 1b \n\t"
:"+d"(i)
:"r"(b0),"r"(b1),"r"(b2),"r"(b3),"r"(b4),"r"(b5));
}
#define snow_vertical_compose_mmx_load_add(op,r,t0,t1,t2,t3)\
""op" ("r",%%"REG_d"), %%"t0" \n\t"\
""op" 8("r",%%"REG_d"), %%"t1" \n\t"\
""op" 16("r",%%"REG_d"), %%"t2" \n\t"\
""op" 24("r",%%"REG_d"), %%"t3" \n\t"
#define snow_vertical_compose_mmx_load(r,t0,t1,t2,t3)\
snow_vertical_compose_mmx_load_add("movq",r,t0,t1,t2,t3)
#define snow_vertical_compose_mmx_add(r,t0,t1,t2,t3)\
snow_vertical_compose_mmx_load_add("paddw",r,t0,t1,t2,t3)
#define snow_vertical_compose_mmx_store(w,s0,s1,s2,s3)\
"movq %%"s0", ("w",%%"REG_d") \n\t"\
"movq %%"s1", 8("w",%%"REG_d") \n\t"\
"movq %%"s2", 16("w",%%"REG_d") \n\t"\
"movq %%"s3", 24("w",%%"REG_d") \n\t"
#define snow_vertical_compose_mmx_move(s0,s1,s2,s3,t0,t1,t2,t3)\
"movq %%"s0", %%"t0" \n\t"\
"movq %%"s1", %%"t1" \n\t"\
"movq %%"s2", %%"t2" \n\t"\
"movq %%"s3", %%"t3" \n\t"
static void ff_snow_vertical_compose97i_mmx(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, IDWTELEM *b3, IDWTELEM *b4, IDWTELEM *b5, int width){
x86_reg i = width;
while(i & 15)
{
i--;
b4[i] -= (W_DM*(b3[i] + b5[i])+W_DO)>>W_DS;
b3[i] -= (W_CM*(b2[i] + b4[i])+W_CO)>>W_CS;
b2[i] += (W_BM*(b1[i] + b3[i])+4*b2[i]+W_BO)>>W_BS;
b1[i] += (W_AM*(b0[i] + b2[i])+W_AO)>>W_AS;
}
i+=i;
__asm__ volatile(
"jmp 2f \n\t"
"1: \n\t"
snow_vertical_compose_mmx_load("%4","mm1","mm3","mm5","mm7")
snow_vertical_compose_mmx_add("%6","mm1","mm3","mm5","mm7")
"pcmpeqw %%mm0, %%mm0 \n\t"
"pcmpeqw %%mm2, %%mm2 \n\t"
"paddw %%mm2, %%mm2 \n\t"
"paddw %%mm0, %%mm2 \n\t"
"psllw $13, %%mm2 \n\t"
snow_vertical_compose_r2r_add("mm0","mm0","mm0","mm0","mm1","mm3","mm5","mm7")
snow_vertical_compose_r2r_pmulhw("mm2","mm2","mm2","mm2","mm1","mm3","mm5","mm7")
snow_vertical_compose_mmx_add("%5","mm1","mm3","mm5","mm7")
snow_vertical_compose_mmx_store("%5","mm1","mm3","mm5","mm7")
snow_vertical_compose_mmx_load("%4","mm0","mm2","mm4","mm6")
snow_vertical_compose_mmx_add("%3","mm1","mm3","mm5","mm7")
snow_vertical_compose_r2r_sub("mm1","mm3","mm5","mm7","mm0","mm2","mm4","mm6")
snow_vertical_compose_mmx_store("%4","mm0","mm2","mm4","mm6")
"pcmpeqw %%mm7, %%mm7 \n\t"
"pcmpeqw %%mm5, %%mm5 \n\t"
"psllw $15, %%mm7 \n\t"
"psrlw $13, %%mm5 \n\t"
"paddw %%mm7, %%mm5 \n\t"
snow_vertical_compose_r2r_add("mm5","mm5","mm5","mm5","mm0","mm2","mm4","mm6")
"movq (%2,%%"REG_d"), %%mm1 \n\t"
"movq 8(%2,%%"REG_d"), %%mm3 \n\t"
"paddw %%mm7, %%mm1 \n\t"
"paddw %%mm7, %%mm3 \n\t"
"pavgw %%mm1, %%mm0 \n\t"
"pavgw %%mm3, %%mm2 \n\t"
"movq 16(%2,%%"REG_d"), %%mm1 \n\t"
"movq 24(%2,%%"REG_d"), %%mm3 \n\t"
"paddw %%mm7, %%mm1 \n\t"
"paddw %%mm7, %%mm3 \n\t"
"pavgw %%mm1, %%mm4 \n\t"
"pavgw %%mm3, %%mm6 \n\t"
snow_vertical_compose_r2r_sub("mm7","mm7","mm7","mm7","mm0","mm2","mm4","mm6")
snow_vertical_compose_sra("1","mm0","mm2","mm4","mm6")
snow_vertical_compose_mmx_add("%3","mm0","mm2","mm4","mm6")
snow_vertical_compose_sra("2","mm0","mm2","mm4","mm6")
snow_vertical_compose_mmx_add("%3","mm0","mm2","mm4","mm6")
snow_vertical_compose_mmx_store("%3","mm0","mm2","mm4","mm6")
snow_vertical_compose_mmx_add("%1","mm0","mm2","mm4","mm6")
snow_vertical_compose_mmx_move("mm0","mm2","mm4","mm6","mm1","mm3","mm5","mm7")
snow_vertical_compose_sra("1","mm0","mm2","mm4","mm6")
snow_vertical_compose_r2r_add("mm1","mm3","mm5","mm7","mm0","mm2","mm4","mm6")
snow_vertical_compose_mmx_add("%2","mm0","mm2","mm4","mm6")
snow_vertical_compose_mmx_store("%2","mm0","mm2","mm4","mm6")
"2: \n\t"
"sub $32, %%"REG_d" \n\t"
"jge 1b \n\t"
:"+d"(i)
:"r"(b0),"r"(b1),"r"(b2),"r"(b3),"r"(b4),"r"(b5));
}
#endif //HAVE_7REGS
#define snow_inner_add_yblock_sse2_header \
IDWTELEM * * dst_array = sb->line + src_y;\
x86_reg tmp;\
__asm__ volatile(\
"mov %7, %%"REG_c" \n\t"\
"mov %6, %2 \n\t"\
"mov %4, %%"REG_S" \n\t"\
"pxor %%xmm7, %%xmm7 \n\t" /* 0 */\
"pcmpeqd %%xmm3, %%xmm3 \n\t"\
"psllw $15, %%xmm3 \n\t"\
"psrlw $12, %%xmm3 \n\t" /* FRAC_BITS >> 1 */\
"1: \n\t"\
"mov %1, %%"REG_D" \n\t"\
"mov (%%"REG_D"), %%"REG_D" \n\t"\
"add %3, %%"REG_D" \n\t"
#define snow_inner_add_yblock_sse2_start_8(out_reg1, out_reg2, ptr_offset, s_offset)\
"mov "PTR_SIZE"*"ptr_offset"(%%"REG_a"), %%"REG_d"; \n\t"\
"movq (%%"REG_d"), %%"out_reg1" \n\t"\
"movq (%%"REG_d", %%"REG_c"), %%"out_reg2" \n\t"\
"punpcklbw %%xmm7, %%"out_reg1" \n\t"\
"punpcklbw %%xmm7, %%"out_reg2" \n\t"\
"movq "s_offset"(%%"REG_S"), %%xmm0 \n\t"\
"movq "s_offset"+16(%%"REG_S"), %%xmm4 \n\t"\
"punpcklbw %%xmm7, %%xmm0 \n\t"\
"punpcklbw %%xmm7, %%xmm4 \n\t"\
"pmullw %%xmm0, %%"out_reg1" \n\t"\
"pmullw %%xmm4, %%"out_reg2" \n\t"
#define snow_inner_add_yblock_sse2_start_16(out_reg1, out_reg2, ptr_offset, s_offset)\
"mov "PTR_SIZE"*"ptr_offset"(%%"REG_a"), %%"REG_d"; \n\t"\
"movq (%%"REG_d"), %%"out_reg1" \n\t"\
"movq 8(%%"REG_d"), %%"out_reg2" \n\t"\
"punpcklbw %%xmm7, %%"out_reg1" \n\t"\
"punpcklbw %%xmm7, %%"out_reg2" \n\t"\
"movq "s_offset"(%%"REG_S"), %%xmm0 \n\t"\
"movq "s_offset"+8(%%"REG_S"), %%xmm4 \n\t"\
"punpcklbw %%xmm7, %%xmm0 \n\t"\
"punpcklbw %%xmm7, %%xmm4 \n\t"\
"pmullw %%xmm0, %%"out_reg1" \n\t"\
"pmullw %%xmm4, %%"out_reg2" \n\t"
#define snow_inner_add_yblock_sse2_accum_8(ptr_offset, s_offset) \
snow_inner_add_yblock_sse2_start_8("xmm2", "xmm6", ptr_offset, s_offset)\
"paddusw %%xmm2, %%xmm1 \n\t"\
"paddusw %%xmm6, %%xmm5 \n\t"
#define snow_inner_add_yblock_sse2_accum_16(ptr_offset, s_offset) \
snow_inner_add_yblock_sse2_start_16("xmm2", "xmm6", ptr_offset, s_offset)\
"paddusw %%xmm2, %%xmm1 \n\t"\
"paddusw %%xmm6, %%xmm5 \n\t"
#define snow_inner_add_yblock_sse2_end_common1\
"add $32, %%"REG_S" \n\t"\
"add %%"REG_c", %0 \n\t"\
"add %%"REG_c", "PTR_SIZE"*3(%%"REG_a");\n\t"\
"add %%"REG_c", "PTR_SIZE"*2(%%"REG_a");\n\t"\
"add %%"REG_c", "PTR_SIZE"*1(%%"REG_a");\n\t"\
"add %%"REG_c", (%%"REG_a") \n\t"
#define snow_inner_add_yblock_sse2_end_common2\
"jnz 1b \n\t"\
:"+m"(dst8),"+m"(dst_array),"=&r"(tmp)\
:\
"rm"((x86_reg)(src_x<<1)),"m"(obmc),"a"(block),"m"(b_h),"m"(src_stride):\
"%"REG_c"","%"REG_S"","%"REG_D"","%"REG_d"");
#define snow_inner_add_yblock_sse2_end_8\
"sal $1, %%"REG_c" \n\t"\
"addl $"PTR_SIZE"*2, %1 \n\t"\
snow_inner_add_yblock_sse2_end_common1\
"sar $1, %%"REG_c" \n\t"\
"sub $2, %2 \n\t"\
snow_inner_add_yblock_sse2_end_common2
#define snow_inner_add_yblock_sse2_end_16\
"addl $"PTR_SIZE"*1, %1 \n\t"\
snow_inner_add_yblock_sse2_end_common1\
"dec %2 \n\t"\
snow_inner_add_yblock_sse2_end_common2
static void inner_add_yblock_bw_8_obmc_16_bh_even_sse2(const uint8_t *obmc, const x86_reg obmc_stride, uint8_t * * block, int b_w, x86_reg b_h,
int src_x, int src_y, x86_reg src_stride, slice_buffer * sb, int add, uint8_t * dst8){
snow_inner_add_yblock_sse2_header
snow_inner_add_yblock_sse2_start_8("xmm1", "xmm5", "3", "0")
snow_inner_add_yblock_sse2_accum_8("2", "8")
snow_inner_add_yblock_sse2_accum_8("1", "128")
snow_inner_add_yblock_sse2_accum_8("0", "136")
"mov %0, %%"REG_d" \n\t"
"movdqa (%%"REG_D"), %%xmm0 \n\t"
"movdqa %%xmm1, %%xmm2 \n\t"
"punpckhwd %%xmm7, %%xmm1 \n\t"
"punpcklwd %%xmm7, %%xmm2 \n\t"
"paddd %%xmm2, %%xmm0 \n\t"
"movdqa 16(%%"REG_D"), %%xmm2 \n\t"
"paddd %%xmm1, %%xmm2 \n\t"
"paddd %%xmm3, %%xmm0 \n\t"
"paddd %%xmm3, %%xmm2 \n\t"
"mov %1, %%"REG_D" \n\t"
"mov "PTR_SIZE"(%%"REG_D"), %%"REG_D";\n\t"
"add %3, %%"REG_D" \n\t"
"movdqa (%%"REG_D"), %%xmm4 \n\t"
"movdqa %%xmm5, %%xmm6 \n\t"
"punpckhwd %%xmm7, %%xmm5 \n\t"
"punpcklwd %%xmm7, %%xmm6 \n\t"
"paddd %%xmm6, %%xmm4 \n\t"
"movdqa 16(%%"REG_D"), %%xmm6 \n\t"
"paddd %%xmm5, %%xmm6 \n\t"
"paddd %%xmm3, %%xmm4 \n\t"
"paddd %%xmm3, %%xmm6 \n\t"
"psrad $8, %%xmm0 \n\t" /* FRAC_BITS. */
"psrad $8, %%xmm2 \n\t" /* FRAC_BITS. */
"packssdw %%xmm2, %%xmm0 \n\t"
"packuswb %%xmm7, %%xmm0 \n\t"
"movq %%xmm0, (%%"REG_d") \n\t"
"psrad $8, %%xmm4 \n\t" /* FRAC_BITS. */
"psrad $8, %%xmm6 \n\t" /* FRAC_BITS. */
"packssdw %%xmm6, %%xmm4 \n\t"
"packuswb %%xmm7, %%xmm4 \n\t"
"movq %%xmm4, (%%"REG_d",%%"REG_c");\n\t"
snow_inner_add_yblock_sse2_end_8
}
static void inner_add_yblock_bw_16_obmc_32_sse2(const uint8_t *obmc, const x86_reg obmc_stride, uint8_t * * block, int b_w, x86_reg b_h,
int src_x, int src_y, x86_reg src_stride, slice_buffer * sb, int add, uint8_t * dst8){
snow_inner_add_yblock_sse2_header
snow_inner_add_yblock_sse2_start_16("xmm1", "xmm5", "3", "0")
snow_inner_add_yblock_sse2_accum_16("2", "16")
snow_inner_add_yblock_sse2_accum_16("1", "512")
snow_inner_add_yblock_sse2_accum_16("0", "528")
"mov %0, %%"REG_d" \n\t"
"psrlw $4, %%xmm1 \n\t"
"psrlw $4, %%xmm5 \n\t"
"paddw (%%"REG_D"), %%xmm1 \n\t"
"paddw 16(%%"REG_D"), %%xmm5 \n\t"
"paddw %%xmm3, %%xmm1 \n\t"
"paddw %%xmm3, %%xmm5 \n\t"
"psraw $4, %%xmm1 \n\t" /* FRAC_BITS. */
"psraw $4, %%xmm5 \n\t" /* FRAC_BITS. */
"packuswb %%xmm5, %%xmm1 \n\t"
"movdqu %%xmm1, (%%"REG_d") \n\t"
snow_inner_add_yblock_sse2_end_16
}
#define snow_inner_add_yblock_mmx_header \
IDWTELEM * * dst_array = sb->line + src_y;\
x86_reg tmp;\
__asm__ volatile(\
"mov %7, %%"REG_c" \n\t"\
"mov %6, %2 \n\t"\
"mov %4, %%"REG_S" \n\t"\
"pxor %%mm7, %%mm7 \n\t" /* 0 */\
"pcmpeqd %%mm3, %%mm3 \n\t"\
"psllw $15, %%mm3 \n\t"\
"psrlw $12, %%mm3 \n\t" /* FRAC_BITS >> 1 */\
"1: \n\t"\
"mov %1, %%"REG_D" \n\t"\
"mov (%%"REG_D"), %%"REG_D" \n\t"\
"add %3, %%"REG_D" \n\t"
#define snow_inner_add_yblock_mmx_start(out_reg1, out_reg2, ptr_offset, s_offset, d_offset)\
"mov "PTR_SIZE"*"ptr_offset"(%%"REG_a"), %%"REG_d"; \n\t"\
"movd "d_offset"(%%"REG_d"), %%"out_reg1" \n\t"\
"movd "d_offset"+4(%%"REG_d"), %%"out_reg2" \n\t"\
"punpcklbw %%mm7, %%"out_reg1" \n\t"\
"punpcklbw %%mm7, %%"out_reg2" \n\t"\
"movd "s_offset"(%%"REG_S"), %%mm0 \n\t"\
"movd "s_offset"+4(%%"REG_S"), %%mm4 \n\t"\
"punpcklbw %%mm7, %%mm0 \n\t"\
"punpcklbw %%mm7, %%mm4 \n\t"\
"pmullw %%mm0, %%"out_reg1" \n\t"\
"pmullw %%mm4, %%"out_reg2" \n\t"
#define snow_inner_add_yblock_mmx_accum(ptr_offset, s_offset, d_offset) \
snow_inner_add_yblock_mmx_start("mm2", "mm6", ptr_offset, s_offset, d_offset)\
"paddusw %%mm2, %%mm1 \n\t"\
"paddusw %%mm6, %%mm5 \n\t"
#define snow_inner_add_yblock_mmx_mix(read_offset, write_offset)\
"mov %0, %%"REG_d" \n\t"\
"psrlw $4, %%mm1 \n\t"\
"psrlw $4, %%mm5 \n\t"\
"paddw "read_offset"(%%"REG_D"), %%mm1 \n\t"\
"paddw "read_offset"+8(%%"REG_D"), %%mm5 \n\t"\
"paddw %%mm3, %%mm1 \n\t"\
"paddw %%mm3, %%mm5 \n\t"\
"psraw $4, %%mm1 \n\t"\
"psraw $4, %%mm5 \n\t"\
"packuswb %%mm5, %%mm1 \n\t"\
"movq %%mm1, "write_offset"(%%"REG_d") \n\t"
#define snow_inner_add_yblock_mmx_end(s_step)\
"add $"s_step", %%"REG_S" \n\t"\
"add %%"REG_c", "PTR_SIZE"*3(%%"REG_a");\n\t"\
"add %%"REG_c", "PTR_SIZE"*2(%%"REG_a");\n\t"\
"add %%"REG_c", "PTR_SIZE"*1(%%"REG_a");\n\t"\
"add %%"REG_c", (%%"REG_a") \n\t"\
"add"OPSIZE " $"PTR_SIZE"*1, %1 \n\t"\
"add %%"REG_c", %0 \n\t"\
"dec %2 \n\t"\
"jnz 1b \n\t"\
:"+m"(dst8),"+m"(dst_array),"=&r"(tmp)\
:\
"rm"((x86_reg)(src_x<<1)),"m"(obmc),"a"(block),"m"(b_h),"m"(src_stride):\
"%"REG_c"","%"REG_S"","%"REG_D"","%"REG_d"");
static void inner_add_yblock_bw_8_obmc_16_mmx(const uint8_t *obmc, const x86_reg obmc_stride, uint8_t * * block, int b_w, x86_reg b_h,
int src_x, int src_y, x86_reg src_stride, slice_buffer * sb, int add, uint8_t * dst8){
snow_inner_add_yblock_mmx_header
snow_inner_add_yblock_mmx_start("mm1", "mm5", "3", "0", "0")
snow_inner_add_yblock_mmx_accum("2", "8", "0")
snow_inner_add_yblock_mmx_accum("1", "128", "0")
snow_inner_add_yblock_mmx_accum("0", "136", "0")
snow_inner_add_yblock_mmx_mix("0", "0")
snow_inner_add_yblock_mmx_end("16")
}
static void inner_add_yblock_bw_16_obmc_32_mmx(const uint8_t *obmc, const x86_reg obmc_stride, uint8_t * * block, int b_w, x86_reg b_h,
int src_x, int src_y, x86_reg src_stride, slice_buffer * sb, int add, uint8_t * dst8){
snow_inner_add_yblock_mmx_header
snow_inner_add_yblock_mmx_start("mm1", "mm5", "3", "0", "0")
snow_inner_add_yblock_mmx_accum("2", "16", "0")
snow_inner_add_yblock_mmx_accum("1", "512", "0")
snow_inner_add_yblock_mmx_accum("0", "528", "0")
snow_inner_add_yblock_mmx_mix("0", "0")
snow_inner_add_yblock_mmx_start("mm1", "mm5", "3", "8", "8")
snow_inner_add_yblock_mmx_accum("2", "24", "8")
snow_inner_add_yblock_mmx_accum("1", "520", "8")
snow_inner_add_yblock_mmx_accum("0", "536", "8")
snow_inner_add_yblock_mmx_mix("16", "8")
snow_inner_add_yblock_mmx_end("32")
}
static void ff_snow_inner_add_yblock_sse2(const uint8_t *obmc, const int obmc_stride, uint8_t * * block, int b_w, int b_h,
int src_x, int src_y, int src_stride, slice_buffer * sb, int add, uint8_t * dst8){
if (b_w == 16)
inner_add_yblock_bw_16_obmc_32_sse2(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8);
else if (b_w == 8 && obmc_stride == 16) {
if (!(b_h & 1))
inner_add_yblock_bw_8_obmc_16_bh_even_sse2(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8);
else
inner_add_yblock_bw_8_obmc_16_mmx(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8);
} else
ff_snow_inner_add_yblock(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8);
}
static void ff_snow_inner_add_yblock_mmx(const uint8_t *obmc, const int obmc_stride, uint8_t * * block, int b_w, int b_h,
int src_x, int src_y, int src_stride, slice_buffer * sb, int add, uint8_t * dst8){
if (b_w == 16)
inner_add_yblock_bw_16_obmc_32_mmx(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8);
else if (b_w == 8 && obmc_stride == 16)
inner_add_yblock_bw_8_obmc_16_mmx(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8);
else
ff_snow_inner_add_yblock(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8);
}
#endif /* HAVE_INLINE_ASM */
void ff_dwt_init_x86(DWTContext *c)
{
#if HAVE_INLINE_ASM
int mm_flags = av_get_cpu_flags();
if (mm_flags & AV_CPU_FLAG_MMX) {
if(mm_flags & AV_CPU_FLAG_SSE2 & 0){
c->horizontal_compose97i = ff_snow_horizontal_compose97i_sse2;
#if HAVE_7REGS
c->vertical_compose97i = ff_snow_vertical_compose97i_sse2;
#endif
c->inner_add_yblock = ff_snow_inner_add_yblock_sse2;
}
else{
if (mm_flags & AV_CPU_FLAG_MMXEXT) {
c->horizontal_compose97i = ff_snow_horizontal_compose97i_mmx;
#if HAVE_7REGS
c->vertical_compose97i = ff_snow_vertical_compose97i_mmx;
#endif
}
c->inner_add_yblock = ff_snow_inner_add_yblock_mmx;
}
}
#endif /* HAVE_INLINE_ASM */
}
......@@ -76,7 +76,6 @@ const CodecTags ff_mkv_codec_tags[]={
{"V_REAL/RV20" , AV_CODEC_ID_RV20},
{"V_REAL/RV30" , AV_CODEC_ID_RV30},
{"V_REAL/RV40" , AV_CODEC_ID_RV40},
{"V_SNOW" , AV_CODEC_ID_SNOW},
{"V_THEORA" , AV_CODEC_ID_THEORA},
{"V_UNCOMPRESSED" , AV_CODEC_ID_RAWVIDEO},
{"V_VP8" , AV_CODEC_ID_VP8},
......
......@@ -231,7 +231,6 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_TRUEMOTION1, MKTAG('P', 'V', 'E', 'Z') },
{ AV_CODEC_ID_MSZH, MKTAG('M', 'S', 'Z', 'H') },
{ AV_CODEC_ID_ZLIB, MKTAG('Z', 'L', 'I', 'B') },
{ AV_CODEC_ID_SNOW, MKTAG('S', 'N', 'O', 'W') },
{ AV_CODEC_ID_4XM, MKTAG('4', 'X', 'M', 'V') },
{ AV_CODEC_ID_FLV1, MKTAG('F', 'L', 'V', '1') },
{ AV_CODEC_ID_FLASHSV, MKTAG('F', 'S', 'V', '1') },
......
......@@ -89,8 +89,6 @@ FATE_SEEK_VSYNTH2-$(call ENCDEC, RAWVIDEO, AVI) += rgb
FATE_SEEK_VSYNTH2-$(call ENCDEC, ROQ, ROQ) += roqvideo
FATE_SEEK_VSYNTH2-$(call ENCDEC, RV10, RM) += rv10
FATE_SEEK_VSYNTH2-$(call ENCDEC, RV20, RM) += rv20
FATE_SEEK_VSYNTH2-$(call ENCDEC, SNOW, AVI) += snow
FATE_SEEK_VSYNTH2-$(call ENCDEC, SNOW, AVI) += snow-ll
FATE_SEEK_VSYNTH2-$(call ENCDEC, SVQ1, MOV) += svq1
FATE_SEEK_VSYNTH2-$(call ENCDEC, WMV1, AVI) += wmv1
FATE_SEEK_VSYNTH2-$(call ENCDEC, WMV2, AVI) += wmv2
......
......@@ -208,18 +208,6 @@ FATE_VCODEC-$(call ENCDEC, RV20, RM) += rv20
fate-vsynth%-rv20: ENCOPTS = -qscale 10
fate-vsynth%-rv20: FMT = rm
FATE_VCODEC-$(call ENCDEC, SNOW, AVI) += snow snow-hpel snow-ll
fate-vsynth%-snow: ENCOPTS = -strict -2 -qscale 2 -flags +qpel \
-me_method iter -dia_size 2 \
-cmp 12 -subcmp 12 -s 128x64
fate-vsynth%-snow-hpel: ENCOPTS = -strict -2 -qscale 2 \
-me_method iter -dia_size 2 \
-cmp 12 -subcmp 12 -s 128x64
fate-vsynth%-snow-ll: ENCOPTS = -strict -2 -qscale .001 -pred 1 \
-flags +mv4+qpel
FATE_VCODEC-$(call ENCDEC, SVQ1, MOV) += svq1
fate-vsynth%-svq1: ENCOPTS = -qscale 3 -pix_fmt yuv410p
fate-vsynth%-svq1: FMT = mov
......
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 3035
ret: 0 st:-1 flags:0 ts:-1.000000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 3035
ret: 0 st:-1 flags:1 ts: 1.894167
ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 39714 size: 3640
ret: 0 st: 0 flags:0 ts: 0.800000
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 27434 size: 3494
ret:-1 st: 0 flags:1 ts:-0.320000
ret:-1 st:-1 flags:0 ts: 2.576668
ret: 0 st:-1 flags:1 ts: 1.470835
ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 39714 size: 3640
ret: 0 st: 0 flags:0 ts: 0.360000
ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 16124 size: 3244
ret:-1 st: 0 flags:1 ts:-0.760000
ret:-1 st:-1 flags:0 ts: 2.153336
ret: 0 st:-1 flags:1 ts: 1.047503
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 27434 size: 3494
ret: 0 st: 0 flags:0 ts:-0.040000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 3035
ret: 0 st: 0 flags:1 ts: 2.840000
ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 52604 size: 3582
ret: 0 st:-1 flags:0 ts: 1.730004
ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 52604 size: 3582
ret: 0 st:-1 flags:1 ts: 0.624171
ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 16124 size: 3244
ret: 0 st: 0 flags:0 ts:-0.480000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 3035
ret: 0 st: 0 flags:1 ts: 2.400000
ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 52604 size: 3582
ret: 0 st:-1 flags:0 ts: 1.306672
ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 39714 size: 3640
ret: 0 st:-1 flags:1 ts: 0.200839
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 3035
ret: 0 st: 0 flags:0 ts:-0.920000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 3035
ret: 0 st: 0 flags:1 ts: 2.000000
ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 52604 size: 3582
ret: 0 st:-1 flags:0 ts: 0.883340
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 27434 size: 3494
ret:-1 st:-1 flags:1 ts:-0.222493
ret:-1 st: 0 flags:0 ts: 2.680000
ret: 0 st: 0 flags:1 ts: 1.560000
ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 39714 size: 3640
ret: 0 st:-1 flags:0 ts: 0.460008
ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 16124 size: 3244
ret:-1 st:-1 flags:1 ts:-0.645825
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 72476
ret: 0 st:-1 flags:0 ts:-1.000000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 72476
ret: 0 st:-1 flags:1 ts: 1.894167
ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:1902788 size: 78837
ret: 0 st: 0 flags:0 ts: 0.800000
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:1239090 size: 74994
ret:-1 st: 0 flags:1 ts:-0.320000
ret:-1 st:-1 flags:0 ts: 2.576668
ret: 0 st:-1 flags:1 ts: 1.470835
ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:1902788 size: 78837
ret: 0 st: 0 flags:0 ts: 0.360000
ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 605628 size: 71059
ret:-1 st: 0 flags:1 ts:-0.760000
ret:-1 st:-1 flags:0 ts: 2.153336
ret: 0 st:-1 flags:1 ts: 1.047503
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:1239090 size: 74994
ret: 0 st: 0 flags:0 ts:-0.040000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 72476
ret: 0 st: 0 flags:1 ts: 2.840000
ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:2585614 size: 79731
ret: 0 st:-1 flags:0 ts: 1.730004
ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:2585614 size: 79731
ret: 0 st:-1 flags:1 ts: 0.624171
ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 605628 size: 71059
ret: 0 st: 0 flags:0 ts:-0.480000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 72476
ret: 0 st: 0 flags:1 ts: 2.400000
ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:2585614 size: 79731
ret: 0 st:-1 flags:0 ts: 1.306672
ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:1902788 size: 78837
ret: 0 st:-1 flags:1 ts: 0.200839
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 72476
ret: 0 st: 0 flags:0 ts:-0.920000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 72476
ret: 0 st: 0 flags:1 ts: 2.000000
ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:2585614 size: 79731
ret: 0 st:-1 flags:0 ts: 0.883340
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:1239090 size: 74994
ret:-1 st:-1 flags:1 ts:-0.222493
ret:-1 st: 0 flags:0 ts: 2.680000
ret: 0 st: 0 flags:1 ts: 1.560000
ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:1902788 size: 78837
ret: 0 st:-1 flags:0 ts: 0.460008
ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 605628 size: 71059
ret:-1 st:-1 flags:1 ts:-0.645825
44fed844eb715fba0cc2433e7d7713bb *tests/data/fate/vsynth1-snow.avi
136076 tests/data/fate/vsynth1-snow.avi
91021b7d6d7908648fe78cc1975af8c4 *tests/data/fate/vsynth1-snow.out.rawvideo
stddev: 22.77 PSNR: 20.98 MAXDIFF: 172 bytes: 7603200/ 7603200
f60c8cb8f41b66bc38df87e9bdb84b34 *tests/data/fate/vsynth1-snow-hpel.avi
138700 tests/data/fate/vsynth1-snow-hpel.avi
d6845c8f1310e041afdcebc6bbfc449b *tests/data/fate/vsynth1-snow-hpel.out.rawvideo
stddev: 22.74 PSNR: 20.99 MAXDIFF: 171 bytes: 7603200/ 7603200
bdc7a025cd306f3da0d377b06bbe909b *tests/data/fate/vsynth1-snow-ll.avi
3419968 tests/data/fate/vsynth1-snow-ll.avi
c5ccac874dbf808e9088bc3107860042 *tests/data/fate/vsynth1-snow-ll.out.rawvideo
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
4b6236e23ae4a52655f2c24c5a09380a *tests/data/fate/vsynth2-snow.avi
57688 tests/data/fate/vsynth2-snow.avi
8890189af71a0dd3447c4e8424c9a76b *tests/data/fate/vsynth2-snow.out.rawvideo
stddev: 10.47 PSNR: 27.72 MAXDIFF: 119 bytes: 7603200/ 7603200
9872032345c33cf8e8fc26ab655be3d3 *tests/data/fate/vsynth2-snow-hpel.avi
61760 tests/data/fate/vsynth2-snow-hpel.avi
8680d40905f423999d65b996c4dcb984 *tests/data/fate/vsynth2-snow-hpel.out.rawvideo
stddev: 10.45 PSNR: 27.74 MAXDIFF: 123 bytes: 7603200/ 7603200
30b40e0bf64f92b23d6f94056c0c6da5 *tests/data/fate/vsynth2-snow-ll.avi
2721746 tests/data/fate/vsynth2-snow-ll.avi
dde5895817ad9d219f79a52d0bdfb001 *tests/data/fate/vsynth2-snow-ll.out.rawvideo
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment