Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
av7110_ipack.c
Go to the documentation of this file.
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)))) {
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;
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);
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:
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) {
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);
398  if (c < count)
399  av7110_ipack_instant_repack(buf + c, count - c, p);
400  }
401  }
402  return count;
403 }