Logo Search packages:      
Sourcecode: linux version File versions  Download package

av7110_ipack.c

#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;
}

Generated by  Doxygen 1.6.0   Back to index