blob: 699ef8b5b99ac9ac3ea720419777ffaa2b5e8dcf [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#include "dvb_filter.h"
2#include "av7110_ipack.h"
3#include <linux/string.h> /* for memcpy() */
4#include <linux/vmalloc.h>
5
6
7void av7110_ipack_reset(struct ipack *p)
8{
9 p->found = 0;
10 p->cid = 0;
11 p->plength = 0;
12 p->flag1 = 0;
13 p->flag2 = 0;
14 p->hlength = 0;
15 p->mpeg = 0;
16 p->check = 0;
17 p->which = 0;
18 p->done = 0;
19 p->count = 0;
20}
21
22
23int av7110_ipack_init(struct ipack *p, int size,
24 void (*func)(u8 *buf, int size, void *priv))
25{
26 if (!(p->buf = vmalloc(size*sizeof(u8)))) {
Christophe Lucas80887a52005-07-07 17:58:03 -070027 printk(KERN_WARNING "Couldn't allocate memory for ipack\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070028 return -ENOMEM;
29 }
30 p->size = size;
31 p->func = func;
32 p->repack_subids = 0;
33 av7110_ipack_reset(p);
34 return 0;
35}
36
37
38void av7110_ipack_free(struct ipack *p)
39{
40 vfree(p->buf);
41}
42
43
44static void send_ipack(struct ipack *p)
45{
46 int off;
47 struct dvb_audio_info ai;
48 int ac3_off = 0;
49 int streamid = 0;
50 int nframes = 0;
51 int f = 0;
52
53 switch (p->mpeg) {
54 case 2:
55 if (p->count < 10)
56 return;
57 p->buf[3] = p->cid;
58 p->buf[4] = (u8)(((p->count - 6) & 0xff00) >> 8);
59 p->buf[5] = (u8)((p->count - 6) & 0x00ff);
60 if (p->repack_subids && p->cid == PRIVATE_STREAM1) {
61 off = 9 + p->buf[8];
62 streamid = p->buf[off];
63 if ((streamid & 0xf8) == 0x80) {
64 ai.off = 0;
65 ac3_off = ((p->buf[off + 2] << 8)|
66 p->buf[off + 3]);
67 if (ac3_off < p->count)
68 f = dvb_filter_get_ac3info(p->buf + off + 3 + ac3_off,
69 p->count - ac3_off, &ai, 0);
70 if (!f) {
71 nframes = (p->count - off - 3 - ac3_off) /
72 ai.framesize + 1;
73 p->buf[off + 2] = (ac3_off >> 8) & 0xff;
74 p->buf[off + 3] = (ac3_off) & 0xff;
75 p->buf[off + 1] = nframes;
76 ac3_off += nframes * ai.framesize - p->count;
77 }
78 }
79 }
80 p->func(p->buf, p->count, p->data);
81
82 p->buf[6] = 0x80;
83 p->buf[7] = 0x00;
84 p->buf[8] = 0x00;
85 p->count = 9;
86 if (p->repack_subids && p->cid == PRIVATE_STREAM1
87 && (streamid & 0xf8) == 0x80) {
88 p->count += 4;
89 p->buf[9] = streamid;
90 p->buf[10] = (ac3_off >> 8) & 0xff;
91 p->buf[11] = (ac3_off) & 0xff;
92 p->buf[12] = 0;
93 }
94 break;
95
96 case 1:
97 if (p->count < 8)
98 return;
99 p->buf[3] = p->cid;
100 p->buf[4] = (u8)(((p->count - 6) & 0xff00) >> 8);
101 p->buf[5] = (u8)((p->count - 6) & 0x00ff);
102 p->func(p->buf, p->count, p->data);
103
104 p->buf[6] = 0x0f;
105 p->count = 7;
106 break;
107 }
108}
109
110
111void av7110_ipack_flush(struct ipack *p)
112{
113 if (p->plength != MMAX_PLENGTH - 6 || p->found <= 6)
114 return;
115 p->plength = p->found - 6;
116 p->found = 0;
117 send_ipack(p);
118 av7110_ipack_reset(p);
119}
120
121
122static void write_ipack(struct ipack *p, const u8 *data, int count)
123{
124 u8 headr[3] = { 0x00, 0x00, 0x01 };
125
126 if (p->count < 6) {
127 memcpy(p->buf, headr, 3);
128 p->count = 6;
129 }
130
131 if (p->count + count < p->size){
132 memcpy(p->buf+p->count, data, count);
133 p->count += count;
134 } else {
135 int rest = p->size - p->count;
136 memcpy(p->buf+p->count, data, rest);
137 p->count += rest;
138 send_ipack(p);
139 if (count - rest > 0)
140 write_ipack(p, data + rest, count - rest);
141 }
142}
143
144
145int av7110_ipack_instant_repack (const u8 *buf, int count, struct ipack *p)
146{
147 int l;
148 int c = 0;
149
150 while (c < count && (p->mpeg == 0 ||
151 (p->mpeg == 1 && p->found < 7) ||
152 (p->mpeg == 2 && p->found < 9))
153 && (p->found < 5 || !p->done)) {
154 switch (p->found) {
155 case 0:
156 case 1:
157 if (buf[c] == 0x00)
158 p->found++;
159 else
160 p->found = 0;
161 c++;
162 break;
163 case 2:
164 if (buf[c] == 0x01)
165 p->found++;
166 else if (buf[c] == 0)
167 p->found = 2;
168 else
169 p->found = 0;
170 c++;
171 break;
172 case 3:
173 p->cid = 0;
174 switch (buf[c]) {
175 case PROG_STREAM_MAP:
176 case PRIVATE_STREAM2:
177 case PROG_STREAM_DIR:
178 case ECM_STREAM :
179 case EMM_STREAM :
180 case PADDING_STREAM :
181 case DSM_CC_STREAM :
182 case ISO13522_STREAM:
183 p->done = 1;
184 /* fall through */
185 case PRIVATE_STREAM1:
186 case VIDEO_STREAM_S ... VIDEO_STREAM_E:
187 case AUDIO_STREAM_S ... AUDIO_STREAM_E:
188 p->found++;
189 p->cid = buf[c];
190 c++;
191 break;
192 default:
193 p->found = 0;
194 break;
195 }
196 break;
197
198 case 4:
199 if (count-c > 1) {
200 p->plen[0] = buf[c];
201 c++;
202 p->plen[1] = buf[c];
203 c++;
204 p->found += 2;
205 p->plength = (p->plen[0] << 8) | p->plen[1];
206 } else {
207 p->plen[0] = buf[c];
208 p->found++;
209 return count;
210 }
211 break;
212 case 5:
213 p->plen[1] = buf[c];
214 c++;
215 p->found++;
216 p->plength = (p->plen[0] << 8) | p->plen[1];
217 break;
218 case 6:
219 if (!p->done) {
220 p->flag1 = buf[c];
221 c++;
222 p->found++;
223 if ((p->flag1 & 0xc0) == 0x80)
224 p->mpeg = 2;
225 else {
226 p->hlength = 0;
227 p->which = 0;
228 p->mpeg = 1;
229 p->flag2 = 0;
230 }
231 }
232 break;
233
234 case 7:
235 if (!p->done && p->mpeg == 2) {
236 p->flag2 = buf[c];
237 c++;
238 p->found++;
239 }
240 break;
241
242 case 8:
243 if (!p->done && p->mpeg == 2) {
244 p->hlength = buf[c];
245 c++;
246 p->found++;
247 }
248 break;
249 }
250 }
251
252 if (c == count)
253 return count;
254
255 if (!p->plength)
256 p->plength = MMAX_PLENGTH - 6;
257
258 if (p->done || ((p->mpeg == 2 && p->found >= 9) ||
259 (p->mpeg == 1 && p->found >= 7))) {
260 switch (p->cid) {
261 case AUDIO_STREAM_S ... AUDIO_STREAM_E:
262 case VIDEO_STREAM_S ... VIDEO_STREAM_E:
263 case PRIVATE_STREAM1:
264 if (p->mpeg == 2 && p->found == 9) {
265 write_ipack(p, &p->flag1, 1);
266 write_ipack(p, &p->flag2, 1);
267 write_ipack(p, &p->hlength, 1);
268 }
269
270 if (p->mpeg == 1 && p->found == 7)
271 write_ipack(p, &p->flag1, 1);
272
273 if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) &&
274 p->found < 14) {
275 while (c < count && p->found < 14) {
276 p->pts[p->found - 9] = buf[c];
277 write_ipack(p, buf + c, 1);
278 c++;
279 p->found++;
280 }
281 if (c == count)
282 return count;
283 }
284
285 if (p->mpeg == 1 && p->which < 2000) {
286
287 if (p->found == 7) {
288 p->check = p->flag1;
289 p->hlength = 1;
290 }
291
292 while (!p->which && c < count &&
293 p->check == 0xff){
294 p->check = buf[c];
295 write_ipack(p, buf + c, 1);
296 c++;
297 p->found++;
298 p->hlength++;
299 }
300
301 if (c == count)
302 return count;
303
304 if ((p->check & 0xc0) == 0x40 && !p->which) {
305 p->check = buf[c];
306 write_ipack(p, buf + c, 1);
307 c++;
308 p->found++;
309 p->hlength++;
310
311 p->which = 1;
312 if (c == count)
313 return count;
314 p->check = buf[c];
315 write_ipack(p, buf + c, 1);
316 c++;
317 p->found++;
318 p->hlength++;
319 p->which = 2;
320 if (c == count)
321 return count;
322 }
323
324 if (p->which == 1) {
325 p->check = buf[c];
326 write_ipack(p, buf + c, 1);
327 c++;
328 p->found++;
329 p->hlength++;
330 p->which = 2;
331 if (c == count)
332 return count;
333 }
334
335 if ((p->check & 0x30) && p->check != 0xff) {
336 p->flag2 = (p->check & 0xf0) << 2;
337 p->pts[0] = p->check;
338 p->which = 3;
339 }
340
341 if (c == count)
342 return count;
343 if (p->which > 2){
344 if ((p->flag2 & PTS_DTS_FLAGS) == PTS_ONLY) {
345 while (c < count && p->which < 7) {
346 p->pts[p->which - 2] = buf[c];
347 write_ipack(p, buf + c, 1);
348 c++;
349 p->found++;
350 p->which++;
351 p->hlength++;
352 }
353 if (c == count)
354 return count;
355 } else if ((p->flag2 & PTS_DTS_FLAGS) == PTS_DTS) {
356 while (c < count && p->which < 12) {
357 if (p->which < 7)
358 p->pts[p->which - 2] = buf[c];
359 write_ipack(p, buf + c, 1);
360 c++;
361 p->found++;
362 p->which++;
363 p->hlength++;
364 }
365 if (c == count)
366 return count;
367 }
368 p->which = 2000;
369 }
370
371 }
372
373 while (c < count && p->found < p->plength + 6) {
374 l = count - c;
375 if (l + p->found > p->plength + 6)
376 l = p->plength + 6 - p->found;
377 write_ipack(p, buf + c, l);
378 p->found += l;
379 c += l;
380 }
381 break;
382 }
383
384
385 if (p->done) {
386 if (p->found + count - c < p->plength + 6) {
387 p->found += count - c;
388 c = count;
389 } else {
390 c += p->plength + 6 - p->found;
391 p->found = p->plength + 6;
392 }
393 }
394
395 if (p->plength && p->found == p->plength + 6) {
396 send_ipack(p);
397 av7110_ipack_reset(p);
398 if (c < count)
399 av7110_ipack_instant_repack(buf + c, count - c, p);
400 }
401 }
402 return count;
403}