1#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)))) {
27		printk(KERN_WARNING "Couldn't allocate memory for ipack\n");
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
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}
404