#include "dvb_filter.h" #include "av7110_ipack.h" #include <linux/string.h> /* for memcpy() */ #include <linux/vmalloc.h> void av7110_ipack_reset(struct ipack *p) { p->found = 0; p->cid = 0; p->plength = 0; p->flag1 = 0; p->flag2 = 0; p->hlength = 0; p->mpeg = 0; p->check = 0; p->which = 0; p->done = 0; p->count = 0; } int av7110_ipack_init(struct ipack *p, int size, void (*func)(u8 *buf, int size, void *priv)) { if (!(p->buf = vmalloc(size*sizeof(u8)))) { printk(KERN_WARNING "Couldn't allocate memory for ipack\n"); return -ENOMEM; } p->size = size; p->func = func; p->repack_subids = 0; av7110_ipack_reset(p); return 0; } void av7110_ipack_free(struct ipack *p) { vfree(p->buf); } static void send_ipack(struct ipack *p) { int off; struct dvb_audio_info ai; int ac3_off = 0; int streamid = 0; int nframes = 0; int f = 0; switch (p->mpeg) { case 2: if (p->count < 10) return; p->buf[3] = p->cid; p->buf[4] = (u8)(((p->count - 6) & 0xff00) >> 8); p->buf[5] = (u8)((p->count - 6) & 0x00ff); if (p->repack_subids && p->cid == PRIVATE_STREAM1) { off = 9 + p->buf[8]; streamid = p->buf[off]; if ((streamid & 0xf8) == 0x80) { ai.off = 0; ac3_off = ((p->buf[off + 2] << 8)| p->buf[off + 3]); if (ac3_off < p->count) f = dvb_filter_get_ac3info(p->buf + off + 3 + ac3_off, p->count - ac3_off, &ai, 0); if (!f) { nframes = (p->count - off - 3 - ac3_off) / ai.framesize + 1; p->buf[off + 2] = (ac3_off >> 8) & 0xff; p->buf[off + 3] = (ac3_off) & 0xff; p->buf[off + 1] = nframes; ac3_off += nframes * ai.framesize - p->count; } } } p->func(p->buf, p->count, p->data); p->buf[6] = 0x80; p->buf[7] = 0x00; p->buf[8] = 0x00; p->count = 9; if (p->repack_subids && p->cid == PRIVATE_STREAM1 && (streamid & 0xf8) == 0x80) { p->count += 4; p->buf[9] = streamid; p->buf[10] = (ac3_off >> 8) & 0xff; p->buf[11] = (ac3_off) & 0xff; p->buf[12] = 0; } break; case 1: if (p->count < 8) return; p->buf[3] = p->cid; p->buf[4] = (u8)(((p->count - 6) & 0xff00) >> 8); p->buf[5] = (u8)((p->count - 6) & 0x00ff); p->func(p->buf, p->count, p->data); p->buf[6] = 0x0f; p->count = 7; break; } } void av7110_ipack_flush(struct ipack *p) { if (p->plength != MMAX_PLENGTH - 6 || p->found <= 6) return; p->plength = p->found - 6; p->found = 0; send_ipack(p); av7110_ipack_reset(p); } static void write_ipack(struct ipack *p, const u8 *data, int count) { u8 headr[3] = { 0x00, 0x00, 0x01 }; if (p->count < 6) { memcpy(p->buf, headr, 3); p->count = 6; } if (p->count + count < p->size){ memcpy(p->buf+p->count, data, count); p->count += count; } else { int rest = p->size - p->count; memcpy(p->buf+p->count, data, rest); p->count += rest; send_ipack(p); if (count - rest > 0) write_ipack(p, data + rest, count - rest); } } int av7110_ipack_instant_repack (const u8 *buf, int count, struct ipack *p) { int l; int c = 0; while (c < count && (p->mpeg == 0 || (p->mpeg == 1 && p->found < 7) || (p->mpeg == 2 && p->found < 9)) && (p->found < 5 || !p->done)) { switch (p->found) { case 0: case 1: if (buf[c] == 0x00) p->found++; else p->found = 0; c++; break; case 2: if (buf[c] == 0x01) p->found++; else if (buf[c] == 0) p->found = 2; else p->found = 0; c++; break; case 3: p->cid = 0; switch (buf[c]) { case PROG_STREAM_MAP: case PRIVATE_STREAM2: case PROG_STREAM_DIR: case ECM_STREAM : case EMM_STREAM : case PADDING_STREAM : case DSM_CC_STREAM : case ISO13522_STREAM: p->done = 1; /* fall through */ case PRIVATE_STREAM1: case VIDEO_STREAM_S ... VIDEO_STREAM_E: case AUDIO_STREAM_S ... AUDIO_STREAM_E: p->found++; p->cid = buf[c]; c++; break; default: p->found = 0; break; } break; case 4: if (count-c > 1) { p->plen[0] = buf[c]; c++; p->plen[1] = buf[c]; c++; p->found += 2; p->plength = (p->plen[0] << 8) | p->plen[1]; } else { p->plen[0] = buf[c]; p->found++; return count; } break; case 5: p->plen[1] = buf[c]; c++; p->found++; p->plength = (p->plen[0] << 8) | p->plen[1]; break; case 6: if (!p->done) { p->flag1 = buf[c]; c++; p->found++; if ((p->flag1 & 0xc0) == 0x80) p->mpeg = 2; else { p->hlength = 0; p->which = 0; p->mpeg = 1; p->flag2 = 0; } } break; case 7: if (!p->done && p->mpeg == 2) { p->flag2 = buf[c]; c++; p->found++; } break; case 8: if (!p->done && p->mpeg == 2) { p->hlength = buf[c]; c++; p->found++; } break; } } if (c == count) return count; if (!p->plength) p->plength = MMAX_PLENGTH - 6; if (p->done || ((p->mpeg == 2 && p->found >= 9) || (p->mpeg == 1 && p->found >= 7))) { switch (p->cid) { case AUDIO_STREAM_S ... AUDIO_STREAM_E: case VIDEO_STREAM_S ... VIDEO_STREAM_E: case PRIVATE_STREAM1: if (p->mpeg == 2 && p->found == 9) { write_ipack(p, &p->flag1, 1); write_ipack(p, &p->flag2, 1); write_ipack(p, &p->hlength, 1); } if (p->mpeg == 1 && p->found == 7) write_ipack(p, &p->flag1, 1); if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) && p->found < 14) { while (c < count && p->found < 14) { p->pts[p->found - 9] = buf[c]; write_ipack(p, buf + c, 1); c++; p->found++; } if (c == count) return count; } if (p->mpeg == 1 && p->which < 2000) { if (p->found == 7) { p->check = p->flag1; p->hlength = 1; } while (!p->which && c < count && p->check == 0xff){ p->check = buf[c]; write_ipack(p, buf + c, 1); c++; p->found++; p->hlength++; } if (c == count) return count; if ((p->check & 0xc0) == 0x40 && !p->which) { p->check = buf[c]; write_ipack(p, buf + c, 1); c++; p->found++; p->hlength++; p->which = 1; if (c == count) return count; p->check = buf[c]; write_ipack(p, buf + c, 1); c++; p->found++; p->hlength++; p->which = 2; if (c == count) return count; } if (p->which == 1) { p->check = buf[c]; write_ipack(p, buf + c, 1); c++; p->found++; p->hlength++; p->which = 2; if (c == count) return count; } if ((p->check & 0x30) && p->check != 0xff) { p->flag2 = (p->check & 0xf0) << 2; p->pts[0] = p->check; p->which = 3; } if (c == count) return count; if (p->which > 2){ if ((p->flag2 & PTS_DTS_FLAGS) == PTS_ONLY) { while (c < count && p->which < 7) { p->pts[p->which - 2] = buf[c]; write_ipack(p, buf + c, 1); c++; p->found++; p->which++; p->hlength++; } if (c == count) return count; } else if ((p->flag2 & PTS_DTS_FLAGS) == PTS_DTS) { while (c < count && p->which < 12) { if (p->which < 7) p->pts[p->which - 2] = buf[c]; write_ipack(p, buf + c, 1); c++; p->found++; p->which++; p->hlength++; } if (c == count) return count; } p->which = 2000; } } while (c < count && p->found < p->plength + 6) { l = count - c; if (l + p->found > p->plength + 6) l = p->plength + 6 - p->found; write_ipack(p, buf + c, l); p->found += l; c += l; } break; } if (p->done) { if (p->found + count - c < p->plength + 6) { p->found += count - c; c = count; } else { c += p->plength + 6 - p->found; p->found = p->plength + 6; } } if (p->plength && p->found == p->plength + 6) { send_ipack(p); av7110_ipack_reset(p); if (c < count) av7110_ipack_instant_repack(buf + c, count - c, p); } } return count; }