Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | #include "dvb_filter.h" |
2 | #include "av7110_ipack.h" | |
3 | #include <linux/string.h> /* for memcpy() */ | |
4 | #include <linux/vmalloc.h> | |
5 | ||
6 | ||
7 | void 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 | ||
23 | int 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)))) { | |
80887a59 | 27 | printk(KERN_WARNING "Couldn't allocate memory for ipack\n"); |
1da177e4 LT |
28 | 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 | ||
38 | void av7110_ipack_free(struct ipack *p) | |
39 | { | |
40 | vfree(p->buf); | |
41 | } | |
42 | ||
43 | ||
44 | static 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 | ||
111 | void 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 | ||
122 | static 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 | ||
145 | int 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 | } |