moving libs around
[platform/upstream/gstreamer.git] / libs / gst / getbits / getbits.c
1
2 #include "config.h"
3
4 #include "gstgetbits.h"
5
6 /* Defined in gstgetbits_i386.s */
7 extern unsigned long _gst_get1bit_i386(gst_getbits_t *gb, unsigned long bits);
8 extern unsigned long _gst_getbits_i386(gst_getbits_t *gb, unsigned long bits);
9 extern unsigned long _gst_getbits_fast_i386(gst_getbits_t *gb, unsigned long bits);
10 extern unsigned long _gst_showbits_i386(gst_getbits_t *gb, unsigned long bits);
11 extern void _gst_flushbits_i386(gst_getbits_t *gb, unsigned long bits);
12 extern void _gst_getbits_back_i386(gst_getbits_t *gb, unsigned long bits);
13
14 /* Defined in gstgetbits_generic.c */
15 extern unsigned long _gst_getbits_int_cb(gst_getbits_t *gb, unsigned long bits);
16 extern unsigned long _gst_get1bit_int(gst_getbits_t *gb, unsigned long bits);
17 extern unsigned long _gst_getbits_int(gst_getbits_t *gb, unsigned long bits);
18 extern unsigned long _gst_getbits_fast_int(gst_getbits_t *gb, unsigned long bits);
19 extern unsigned long _gst_showbits_int(gst_getbits_t *gb, unsigned long bits);
20 extern void _gst_flushbits_int(gst_getbits_t *gb, unsigned long bits);
21 extern void _gst_getbits_back_int(gst_getbits_t *gb, unsigned long bits);
22
23
24 unsigned long gst_getbits_nBitMask[] = { 
25   0x00000000, 0x80000000, 0xc0000000, 0xe0000000,
26   0xf0000000, 0xf8000000, 0xfc000000, 0xfe000000,
27   0xff000000, 0xff800000, 0xffc00000, 0xffe00000,
28   0xfff00000, 0xfff80000, 0xfffc0000, 0xfffe0000,
29   0xffff0000, 0xffff8000, 0xffffc000, 0xffffe000,
30   0xfffff000, 0xfffff800, 0xfffffc00, 0xfffffe00,
31   0xffffff00, 0xffffff80, 0xffffffc0, 0xffffffe0,
32   0xfffffff0, 0xfffffff8, 0xfffffffc, 0xfffffffe};
33
34 unsigned long _getbits_masks[] = {
35   0x00000000,
36   0x00000001, 0x00000003, 0x00000007, 0x0000000f,
37   0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
38   0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
39   0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
40   0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
41   0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
42   0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
43   0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff,
44 };
45
46 #ifdef HAVE_LIBMMX
47 unsigned long _getbits_64_minus_index[] = {
48   64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,
49   40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,
50   16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1 };
51
52 /* this routine taken from Intel AppNote AP-527:
53    "Using MMX[tm] Instructions to Get Bits From a Data Stream"
54    written in C with libmmx to *closely* mimic Intel's ASM implementation
55
56    this isn't as cycle-efficient, due to the simple fact that I must call
57    emms() at the end.  all state must be kept in *gb, not in registers */
58 unsigned long _gst_getbits_mmx(gst_getbits_t *gb,unsigned long bits) {
59   signed long remaining;
60   unsigned long result;
61
62   /* NOTE: this is a code-size optimization Intel seems to have missed!
63      according to the MMX Programmer's Reference Manual, Chapter 5,
64      neither movd nor movq have any effect on the flags.  that means you
65      can put them before the sub and jl in their code, which I've done
66      symbolically in this C code.  gcc is probably going to lose horribly,
67      I'll do an inline asm version later.  I've a point to prove ;-) */
68   /* find the right shift value, put it in mm3 */
69   movd_m2r(_getbits_64_minus_index[bits],mm3);
70   /* load the current quadword into mm0 */
71   movq_m2r(gb->qword,mm0);
72   /* copy it to mm2 */
73   movq_r2r(mm0,mm2);
74
75   remaining = gb->bits - bits;
76
77   if (remaining <= 0) {
78     unsigned long dword1,dword2;
79
80     /* shift the pointer by 64 bits (8 bytes) */
81     gb->ptr += 8;
82     /* add 64 to bits remaining, to bring it positive */
83     remaining += 64;
84
85     /* grab the first 32 bits from the buffer and swap them around */
86     dword1 = swab32(*(gb->ptr-8));
87     /* grab the second 32 bits, swap */
88     dword2 = swab32(*(gb->ptr-4));
89
90     /* put second dword in mm4 */
91     movd_m2r(dword2,mm4);
92     /* shift mm2 over to make room for new bits */
93     psrlq_r2r(mm3,mm2);
94
95     /* put first dword in mm1 */
96     movd_m2r(dword1,mm1);
97     /* shift second dword up 32 bits */
98     psrlq_i2r(32,mm4);
99
100     /* put the shift counter in mm3 */
101     movd_m2r(remaining,mm3);
102     /* combine the swapped data in mm4 */
103     por_r2r(mm1,mm4);
104
105     /* save off the bits in mm4 to mm0 */
106     movq_r2r(mm4,mm0);
107     /* get the new low-order bits in mm4, shifted by 'mm3' */
108     psrlq_r2r(mm3,mm4);
109
110     /* save off new remaining bits */
111     gb->bits = remaining;
112     /* combine bits into mm2 */
113     por_r2r(mm2,mm4);
114
115     /* save off the result */
116     movd_r2m(mm2,result);
117     /* get rid of the bits we just read */
118     psllq_r2r(mm1,mm0);
119
120     /* save off mm0 */
121     movq_r2m(mm0,gb->qword);
122
123     /* finished with MMX */
124     emms();
125
126     /* we have what we came for */
127     return(result);
128   } else {
129     /* load the number of bits requested into mm1 */
130     movd_m2r(bits,mm1);
131     /* shift the quadword in mm2 by 'mm3' bits */
132     psrlq_r2r(mm3,mm2);
133
134     /* update the number of valid bits */
135     gb->bits = remaining;
136
137     /* save off the remaining bits */
138     movd_r2m(mm2,result);
139     /* discard those bits in mm0 */
140     psllq_r2r(mm1,mm0);
141
142     /* save off mm0 */
143     movq_r2m(mm0,gb->qword);
144     /* finished with MMX */
145     emms();
146
147     /* we have what we came for */
148     return(result);
149   }
150 }
151 #endif /* HAVE_LIBMMX */
152
153 unsigned long _gst_getbyte(gst_getbits_t *gb, unsigned long bits) {
154   return *gb->ptr++;
155 }
156
157 /* initialize the getbits structure with the proper getbits func */
158 void gst_getbits_init(gst_getbits_t *gb, GstGetbitsCallback callback, void *data) {
159   gb->ptr = NULL;
160   gb->bits = 0;
161   gb->callback = callback;
162   gb->data = data;
163
164 #ifdef HAVE_LIBMMX
165   if (1) {
166     gb->getbits = _gst_getbits_mmx;
167 //    gb->backbits = _gst_getbits_back_mmx;
168 //    gb->backbytes = _gst_getbits_byteback_mmx;
169 //    printf("gstgetbits: using MMX optimized versions\n");
170   } else
171 #endif /* HAVE_LIBMMX */
172   {
173     if (gb->callback) {
174       gb->getbits = _gst_getbits_int_cb;
175       gb->showbits = _gst_showbits_int;
176       gb->flushbits = _gst_flushbits_int;
177       gb->backbits = _gst_getbits_back_int;
178 //      printf("gstgetbits: using callback versions\n");
179     }
180     else {
181 #ifdef HAVE_CPU_I386
182       gb->get1bit = _gst_get1bit_i386;
183       gb->getbits = _gst_getbits_i386;
184       gb->getbits_fast = _gst_getbits_fast_i386;
185       gb->getbyte = _gst_getbyte;
186       gb->show1bit = _gst_showbits_i386;
187       gb->showbits = _gst_showbits_i386;
188       gb->flushbits = _gst_flushbits_i386;
189       gb->backbits = _gst_getbits_back_i386;
190 //      printf("gstgetbits: using i386 optimized versions\n");
191 #else
192       gb->get1bit = _gst_get1bit_int;
193       gb->getbits = _gst_getbits_int;
194       gb->getbits_fast = _gst_getbits_fast_int;
195       gb->getbyte = _gst_getbyte;
196       gb->show1bit = _gst_showbits_int;
197       gb->showbits = _gst_showbits_int;
198       gb->flushbits = _gst_flushbits_int;
199       gb->backbits = _gst_getbits_back_int;
200 //      printf("gstgetbits: using normal versions\n");
201 #endif
202     }
203   }
204 }
205
206 /* set up the getbits structure with a new buffer */
207 void gst_getbits_newbuf(gst_getbits_t *gb,unsigned char *buffer, unsigned long len) {
208   gb->ptr = buffer;
209   gb->endptr = buffer+len;
210   gb->bits = 0;
211 #ifdef HAVE_LIBMMX
212 //  gb->qword = 0;
213 #endif /* HAVE_LIBMMX */
214 }