]> git.sesse.net Git - ffmpeg/blob - libavcodec/i386/mpegvideo_mmx_template.c
mpeg4 mpeg quantizer encoding
[ffmpeg] / libavcodec / i386 / mpegvideo_mmx_template.c
1 /*
2  * MPEG video MMX templates
3  *
4  * Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #undef SPREADW
21 #undef PMAXW
22 #ifdef HAVE_MMX2
23 #define SPREADW(a) "pshufw $0, " #a ", " #a " \n\t"
24 #define PMAXW(a,b) "pmaxsw " #a ", " #b " \n\t"
25
26 #else
27 #define SPREADW(a) \
28         "punpcklwd " #a ", " #a " \n\t"\
29         "punpcklwd " #a ", " #a " \n\t"
30 #define PMAXW(a,b) \
31         "psubusw " #a ", " #b " \n\t"\
32         "paddw " #a ", " #b " \n\t"
33 #endif
34
35 static int RENAME(dct_quantize)(MpegEncContext *s,
36                             DCTELEM *block, int n,
37                             int qscale, int *overflow)
38 {
39     int level=0, last_non_zero_p1, q; //=0 is cuz gcc says uninitalized ...
40     const UINT16 *qmat, *bias;
41     static __align8 INT16 temp_block[64];
42
43     av_fdct (block);
44
45     if (s->mb_intra) {
46         int dummy;
47         if (n < 4)
48             q = s->y_dc_scale;
49         else
50             q = s->c_dc_scale;
51         /* note: block[0] is assumed to be positive */
52         if (!s->h263_aic) {
53 #if 1
54         asm volatile (
55                 "xorl %%edx, %%edx      \n\t"
56                 "mul %%ecx              \n\t"
57                 : "=d" (level), "=a"(dummy)
58                 : "a" (block[0] + (q >> 1)), "c" (inverse[q])
59         );
60 #else
61         asm volatile (
62                 "xorl %%edx, %%edx      \n\t"
63                 "divw %%cx              \n\t"
64                 "movzwl %%ax, %%eax     \n\t"
65                 : "=a" (level)
66                 : "a" (block[0] + (q >> 1)), "c" (q)
67                 : "%edx"
68         );
69 #endif
70         } else
71             /* For AIC we skip quant/dequant of INTRADC */
72             level = block[0];
73             
74         block[0]=0; //avoid fake overflow
75 //        temp_block[0] = (block[0] + (q >> 1)) / q;
76         last_non_zero_p1 = 1;
77         bias = s->q_intra_matrix16_bias[qscale];
78         qmat = s->q_intra_matrix16[qscale];
79     } else {
80         last_non_zero_p1 = 0;
81         bias = s->q_inter_matrix16_bias[qscale];
82         qmat = s->q_inter_matrix16[qscale];
83     }
84
85     if(s->out_format == FMT_H263 && s->mpeg_quant==0){
86     
87         asm volatile(
88             "movd %%eax, %%mm3                  \n\t" // last_non_zero_p1
89             SPREADW(%%mm3)
90             "pxor %%mm7, %%mm7                  \n\t" // 0
91             "pxor %%mm4, %%mm4                  \n\t" // 0
92             "movq (%2), %%mm5                   \n\t" // qmat[0]
93             "pxor %%mm6, %%mm6                  \n\t"
94             "psubw (%3), %%mm6                  \n\t" // -bias[0]
95             "movl $-128, %%eax                  \n\t"
96             ".balign 16                         \n\t"
97             "1:                                 \n\t"
98             "pxor %%mm1, %%mm1                  \n\t" // 0
99             "movq (%1, %%eax), %%mm0            \n\t" // block[i]
100             "pcmpgtw %%mm0, %%mm1               \n\t" // block[i] <= 0 ? 0xFF : 0x00
101             "pxor %%mm1, %%mm0                  \n\t" 
102             "psubw %%mm1, %%mm0                 \n\t" // ABS(block[i])
103             "psubusw %%mm6, %%mm0               \n\t" // ABS(block[i]) + bias[0]
104             "pmulhw %%mm5, %%mm0                \n\t" // (ABS(block[i])*qmat[0] - bias[0]*qmat[0])>>16
105             "por %%mm0, %%mm4                   \n\t" 
106             "pxor %%mm1, %%mm0                  \n\t" 
107             "psubw %%mm1, %%mm0                 \n\t" // out=((ABS(block[i])*qmat[0] - bias[0]*qmat[0])>>16)*sign(block[i])
108             "movq %%mm0, (%5, %%eax)            \n\t"
109             "pcmpeqw %%mm7, %%mm0               \n\t" // out==0 ? 0xFF : 0x00
110             "movq (%4, %%eax), %%mm1            \n\t" 
111             "movq %%mm7, (%1, %%eax)            \n\t" // 0
112             "pandn %%mm1, %%mm0                 \n\t"
113             PMAXW(%%mm0, %%mm3)
114             "addl $8, %%eax                     \n\t"
115             " js 1b                             \n\t"
116             "movq %%mm3, %%mm0                  \n\t"
117             "psrlq $32, %%mm3                   \n\t"
118             PMAXW(%%mm0, %%mm3)
119             "movq %%mm3, %%mm0                  \n\t"
120             "psrlq $16, %%mm3                   \n\t"
121             PMAXW(%%mm0, %%mm3)
122             "movd %%mm3, %%eax                  \n\t"
123             "movzbl %%al, %%eax                 \n\t" // last_non_zero_p1
124             : "+a" (last_non_zero_p1)
125             : "r" (block+64), "r" (qmat), "r" (bias),
126               "r" (inv_zigzag_direct16+64), "r" (temp_block+64)
127         );
128         // note the asm is split cuz gcc doesnt like that many operands ...
129         asm volatile(
130             "movd %1, %%mm1                     \n\t" // max_qcoeff
131             SPREADW(%%mm1)
132             "psubusw %%mm1, %%mm4               \n\t" 
133             "packuswb %%mm4, %%mm4              \n\t"
134             "movd %%mm4, %0                     \n\t" // *overflow
135         : "=g" (*overflow)
136         : "g" (s->max_qcoeff)
137         );
138     }else{ // FMT_H263
139         asm volatile(
140             "movd %%eax, %%mm3                  \n\t" // last_non_zero_p1
141             SPREADW(%%mm3)
142             "pxor %%mm7, %%mm7                  \n\t" // 0
143             "pxor %%mm4, %%mm4                  \n\t" // 0
144             "movl $-128, %%eax                  \n\t"
145             ".balign 16                         \n\t"
146             "1:                                 \n\t"
147             "pxor %%mm1, %%mm1                  \n\t" // 0
148             "movq (%1, %%eax), %%mm0            \n\t" // block[i]
149             "pcmpgtw %%mm0, %%mm1               \n\t" // block[i] <= 0 ? 0xFF : 0x00
150             "pxor %%mm1, %%mm0                  \n\t" 
151             "psubw %%mm1, %%mm0                 \n\t" // ABS(block[i])
152             "movq (%3, %%eax), %%mm6            \n\t" // bias[0]
153             "paddusw %%mm6, %%mm0               \n\t" // ABS(block[i]) + bias[0]
154             "movq (%2, %%eax), %%mm5            \n\t" // qmat[i]
155             "pmulhw %%mm5, %%mm0                \n\t" // (ABS(block[i])*qmat[0] + bias[0]*qmat[0])>>16
156             "por %%mm0, %%mm4                   \n\t" 
157             "pxor %%mm1, %%mm0                  \n\t" 
158             "psubw %%mm1, %%mm0                 \n\t" // out=((ABS(block[i])*qmat[0] - bias[0]*qmat[0])>>16)*sign(block[i])
159             "movq %%mm0, (%5, %%eax)            \n\t"
160             "pcmpeqw %%mm7, %%mm0               \n\t" // out==0 ? 0xFF : 0x00
161             "movq (%4, %%eax), %%mm1            \n\t" 
162             "movq %%mm7, (%1, %%eax)            \n\t" // 0
163             "pandn %%mm1, %%mm0                 \n\t"
164             PMAXW(%%mm0, %%mm3)
165             "addl $8, %%eax                     \n\t"
166             " js 1b                             \n\t"
167             "movq %%mm3, %%mm0                  \n\t"
168             "psrlq $32, %%mm3                   \n\t"
169             PMAXW(%%mm0, %%mm3)
170             "movq %%mm3, %%mm0                  \n\t"
171             "psrlq $16, %%mm3                   \n\t"
172             PMAXW(%%mm0, %%mm3)
173             "movd %%mm3, %%eax                  \n\t"
174             "movzbl %%al, %%eax                 \n\t" // last_non_zero_p1
175             : "+a" (last_non_zero_p1)
176             : "r" (block+64), "r" (qmat+64), "r" (bias+64),
177               "r" (inv_zigzag_direct16+64), "r" (temp_block+64)
178         );
179         // note the asm is split cuz gcc doesnt like that many operands ...
180         asm volatile(
181             "movd %1, %%mm1                     \n\t" // max_qcoeff
182             SPREADW(%%mm1)
183             "psubusw %%mm1, %%mm4               \n\t" 
184             "packuswb %%mm4, %%mm4              \n\t"
185             "movd %%mm4, %0                     \n\t" // *overflow
186         : "=g" (*overflow)
187         : "g" (s->max_qcoeff)
188         );
189     }
190
191     if(s->mb_intra) temp_block[0]= level; //FIXME move afer permute
192         
193 // last_non_zero_p1=64;       
194     /* permute for IDCT */
195     asm volatile(
196         "movl %0, %%eax                 \n\t"
197         "pushl %%ebp                    \n\t"
198         "movl %%esp, " MANGLE(esp_temp) "\n\t"
199         "1:                             \n\t"
200         "movzbl (%1, %%eax), %%ebx      \n\t"
201         "movzbl 1(%1, %%eax), %%ebp     \n\t"
202         "movw (%2, %%ebx, 2), %%cx      \n\t"
203         "movw (%2, %%ebp, 2), %%sp      \n\t"
204         "movzbl " MANGLE(permutation) "(%%ebx), %%ebx\n\t"
205         "movzbl " MANGLE(permutation) "(%%ebp), %%ebp\n\t"
206         "movw %%cx, (%3, %%ebx, 2)      \n\t"
207         "movw %%sp, (%3, %%ebp, 2)      \n\t"
208         "addl $2, %%eax                 \n\t"
209         " js 1b                         \n\t"
210         "movl " MANGLE(esp_temp) ", %%esp\n\t"
211         "popl %%ebp                     \n\t"
212         : 
213         : "g" (-last_non_zero_p1), "d" (zigzag_direct_noperm+last_non_zero_p1), "S" (temp_block), "D" (block)
214         : "%eax", "%ebx", "%ecx"
215         );
216 /*
217     for(i=0; i<last_non_zero_p1; i++)
218     {
219        int j= zigzag_direct_noperm[i];
220        block[block_permute_op(j)]= temp_block[j];
221     }
222 */
223 //block_permute(block);
224
225     return last_non_zero_p1 - 1;
226 }