linux/drivers/media/pci/ttpci/av7110_ipack.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include "dvb_filter.h"
   3#include "av7110_ipack.h"
   4#include <linux/string.h>       /* for memcpy() */
   5#include <linux/vmalloc.h>
   6
   7
   8void av7110_ipack_reset(struct ipack *p)
   9{
  10        p->found = 0;
  11        p->cid = 0;
  12        p->plength = 0;
  13        p->flag1 = 0;
  14        p->flag2 = 0;
  15        p->hlength = 0;
  16        p->mpeg = 0;
  17        p->check = 0;
  18        p->which = 0;
  19        p->done = 0;
  20        p->count = 0;
  21}
  22
  23
  24int av7110_ipack_init(struct ipack *p, int size,
  25                      void (*func)(u8 *buf, int size, void *priv))
  26{
  27        if (!(p->buf = vmalloc(size))) {
  28                printk(KERN_WARNING "Couldn't allocate memory for ipack\n");
  29                return -ENOMEM;
  30        }
  31        p->size = size;
  32        p->func = func;
  33        p->repack_subids = 0;
  34        av7110_ipack_reset(p);
  35        return 0;
  36}
  37
  38
  39void av7110_ipack_free(struct ipack *p)
  40{
  41        vfree(p->buf);
  42}
  43
  44
  45static void send_ipack(struct ipack *p)
  46{
  47        int off;
  48        struct dvb_audio_info ai;
  49        int ac3_off = 0;
  50        int streamid = 0;
  51        int nframes = 0;
  52        int f = 0;
  53
  54        switch (p->mpeg) {
  55        case 2:
  56                if (p->count < 10)
  57                        return;
  58                p->buf[3] = p->cid;
  59                p->buf[4] = (u8)(((p->count - 6) & 0xff00) >> 8);
  60                p->buf[5] = (u8)((p->count - 6) & 0x00ff);
  61                if (p->repack_subids && p->cid == PRIVATE_STREAM1) {
  62                        off = 9 + p->buf[8];
  63                        streamid = p->buf[off];
  64                        if ((streamid & 0xf8) == 0x80) {
  65                                ai.off = 0;
  66                                ac3_off = ((p->buf[off + 2] << 8)|
  67                                           p->buf[off + 3]);
  68                                if (ac3_off < p->count)
  69                                        f = dvb_filter_get_ac3info(p->buf + off + 3 + ac3_off,
  70                                                                   p->count - ac3_off, &ai, 0);
  71                                if (!f) {
  72                                        nframes = (p->count - off - 3 - ac3_off) /
  73                                                ai.framesize + 1;
  74                                        p->buf[off + 2] = (ac3_off >> 8) & 0xff;
  75                                        p->buf[off + 3] = (ac3_off) & 0xff;
  76                                        p->buf[off + 1] = nframes;
  77                                        ac3_off +=  nframes * ai.framesize - p->count;
  78                                }
  79                        }
  80                }
  81                p->func(p->buf, p->count, p->data);
  82
  83                p->buf[6] = 0x80;
  84                p->buf[7] = 0x00;
  85                p->buf[8] = 0x00;
  86                p->count = 9;
  87                if (p->repack_subids && p->cid == PRIVATE_STREAM1
  88                    && (streamid & 0xf8) == 0x80) {
  89                        p->count += 4;
  90                        p->buf[9] = streamid;
  91                        p->buf[10] = (ac3_off >> 8) & 0xff;
  92                        p->buf[11] = (ac3_off) & 0xff;
  93                        p->buf[12] = 0;
  94                }
  95                break;
  96
  97        case 1:
  98                if (p->count < 8)
  99                        return;
 100                p->buf[3] = p->cid;
 101                p->buf[4] = (u8)(((p->count - 6) & 0xff00) >> 8);
 102                p->buf[5] = (u8)((p->count - 6) & 0x00ff);
 103                p->func(p->buf, p->count, p->data);
 104
 105                p->buf[6] = 0x0f;
 106                p->count = 7;
 107                break;
 108        }
 109}
 110
 111
 112void av7110_ipack_flush(struct ipack *p)
 113{
 114        if (p->plength != MMAX_PLENGTH - 6 || p->found <= 6)
 115                return;
 116        p->plength = p->found - 6;
 117        p->found = 0;
 118        send_ipack(p);
 119        av7110_ipack_reset(p);
 120}
 121
 122
 123static void write_ipack(struct ipack *p, const u8 *data, int count)
 124{
 125        u8 headr[3] = { 0x00, 0x00, 0x01 };
 126
 127        if (p->count < 6) {
 128                memcpy(p->buf, headr, 3);
 129                p->count = 6;
 130        }
 131
 132        if (p->count + count < p->size){
 133                memcpy(p->buf+p->count, data, count);
 134                p->count += count;
 135        } else {
 136                int rest = p->size - p->count;
 137                memcpy(p->buf+p->count, data, rest);
 138                p->count += rest;
 139                send_ipack(p);
 140                if (count - rest > 0)
 141                        write_ipack(p, data + rest, count - rest);
 142        }
 143}
 144
 145
 146int av7110_ipack_instant_repack (const u8 *buf, int count, struct ipack *p)
 147{
 148        int l;
 149        int c = 0;
 150
 151        while (c < count && (p->mpeg == 0 ||
 152                             (p->mpeg == 1 && p->found < 7) ||
 153                             (p->mpeg == 2 && p->found < 9))
 154               &&  (p->found < 5 || !p->done)) {
 155                switch (p->found) {
 156                case 0:
 157                case 1:
 158                        if (buf[c] == 0x00)
 159                                p->found++;
 160                        else
 161                                p->found = 0;
 162                        c++;
 163                        break;
 164                case 2:
 165                        if (buf[c] == 0x01)
 166                                p->found++;
 167                        else if (buf[c] == 0)
 168                                p->found = 2;
 169                        else
 170                                p->found = 0;
 171                        c++;
 172                        break;
 173                case 3:
 174                        p->cid = 0;
 175                        switch (buf[c]) {
 176                        case PROG_STREAM_MAP:
 177                        case PRIVATE_STREAM2:
 178                        case PROG_STREAM_DIR:
 179                        case ECM_STREAM     :
 180                        case EMM_STREAM     :
 181                        case PADDING_STREAM :
 182                        case DSM_CC_STREAM  :
 183                        case ISO13522_STREAM:
 184                                p->done = 1;
 185                                /* fall through */
 186                        case PRIVATE_STREAM1:
 187                        case VIDEO_STREAM_S ... VIDEO_STREAM_E:
 188                        case AUDIO_STREAM_S ... AUDIO_STREAM_E:
 189                                p->found++;
 190                                p->cid = buf[c];
 191                                c++;
 192                                break;
 193                        default:
 194                                p->found = 0;
 195                                break;
 196                        }
 197                        break;
 198
 199                case 4:
 200                        if (count-c > 1) {
 201                                p->plen[0] = buf[c];
 202                                c++;
 203                                p->plen[1] = buf[c];
 204                                c++;
 205                                p->found += 2;
 206                                p->plength = (p->plen[0] << 8) | p->plen[1];
 207                        } else {
 208                                p->plen[0] = buf[c];
 209                                p->found++;
 210                                return count;
 211                        }
 212                        break;
 213                case 5:
 214                        p->plen[1] = buf[c];
 215                        c++;
 216                        p->found++;
 217                        p->plength = (p->plen[0] << 8) | p->plen[1];
 218                        break;
 219                case 6:
 220                        if (!p->done) {
 221                                p->flag1 = buf[c];
 222                                c++;
 223                                p->found++;
 224                                if ((p->flag1 & 0xc0) == 0x80)
 225                                        p->mpeg = 2;
 226                                else {
 227                                        p->hlength = 0;
 228                                        p->which = 0;
 229                                        p->mpeg = 1;
 230                                        p->flag2 = 0;
 231                                }
 232                        }
 233                        break;
 234
 235                case 7:
 236                        if (!p->done && p->mpeg == 2) {
 237                                p->flag2 = buf[c];
 238                                c++;
 239                                p->found++;
 240                        }
 241                        break;
 242
 243                case 8:
 244                        if (!p->done && p->mpeg == 2) {
 245                                p->hlength = buf[c];
 246                                c++;
 247                                p->found++;
 248                        }
 249                        break;
 250                }
 251        }
 252
 253        if (c == count)
 254                return count;
 255
 256        if (!p->plength)
 257                p->plength = MMAX_PLENGTH - 6;
 258
 259        if (p->done || ((p->mpeg == 2 && p->found >= 9) ||
 260                        (p->mpeg == 1 && p->found >= 7))) {
 261                switch (p->cid) {
 262                case AUDIO_STREAM_S ... AUDIO_STREAM_E:
 263                case VIDEO_STREAM_S ... VIDEO_STREAM_E:
 264                case PRIVATE_STREAM1:
 265                        if (p->mpeg == 2 && p->found == 9) {
 266                                write_ipack(p, &p->flag1, 1);
 267                                write_ipack(p, &p->flag2, 1);
 268                                write_ipack(p, &p->hlength, 1);
 269                        }
 270
 271                        if (p->mpeg == 1 && p->found == 7)
 272                                write_ipack(p, &p->flag1, 1);
 273
 274                        if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) &&
 275                            p->found < 14) {
 276                                while (c < count && p->found < 14) {
 277                                        p->pts[p->found - 9] = buf[c];
 278                                        write_ipack(p, buf + c, 1);
 279                                        c++;
 280                                        p->found++;
 281                                }
 282                                if (c == count)
 283                                        return count;
 284                        }
 285
 286                        if (p->mpeg == 1 && p->which < 2000) {
 287
 288                                if (p->found == 7) {
 289                                        p->check = p->flag1;
 290                                        p->hlength = 1;
 291                                }
 292
 293                                while (!p->which && c < count &&
 294                                       p->check == 0xff){
 295                                        p->check = buf[c];
 296                                        write_ipack(p, buf + c, 1);
 297                                        c++;
 298                                        p->found++;
 299                                        p->hlength++;
 300                                }
 301
 302                                if (c == count)
 303                                        return count;
 304
 305                                if ((p->check & 0xc0) == 0x40 && !p->which) {
 306                                        p->check = buf[c];
 307                                        write_ipack(p, buf + c, 1);
 308                                        c++;
 309                                        p->found++;
 310                                        p->hlength++;
 311
 312                                        p->which = 1;
 313                                        if (c == count)
 314                                                return count;
 315                                        p->check = buf[c];
 316                                        write_ipack(p, buf + c, 1);
 317                                        c++;
 318                                        p->found++;
 319                                        p->hlength++;
 320                                        p->which = 2;
 321                                        if (c == count)
 322                                                return count;
 323                                }
 324
 325                                if (p->which == 1) {
 326                                        p->check = buf[c];
 327                                        write_ipack(p, buf + c, 1);
 328                                        c++;
 329                                        p->found++;
 330                                        p->hlength++;
 331                                        p->which = 2;
 332                                        if (c == count)
 333                                                return count;
 334                                }
 335
 336                                if ((p->check & 0x30) && p->check != 0xff) {
 337                                        p->flag2 = (p->check & 0xf0) << 2;
 338                                        p->pts[0] = p->check;
 339                                        p->which = 3;
 340                                }
 341
 342                                if (c == count)
 343                                        return count;
 344                                if (p->which > 2){
 345                                        if ((p->flag2 & PTS_DTS_FLAGS) == PTS_ONLY) {
 346                                                while (c < count && p->which < 7) {
 347                                                        p->pts[p->which - 2] = buf[c];
 348                                                        write_ipack(p, buf + c, 1);
 349                                                        c++;
 350                                                        p->found++;
 351                                                        p->which++;
 352                                                        p->hlength++;
 353                                                }
 354                                                if (c == count)
 355                                                        return count;
 356                                        } else if ((p->flag2 & PTS_DTS_FLAGS) == PTS_DTS) {
 357                                                while (c < count && p->which < 12) {
 358                                                        if (p->which < 7)
 359                                                                p->pts[p->which - 2] = buf[c];
 360                                                        write_ipack(p, buf + c, 1);
 361                                                        c++;
 362                                                        p->found++;
 363                                                        p->which++;
 364                                                        p->hlength++;
 365                                                }
 366                                                if (c == count)
 367                                                        return count;
 368                                        }
 369                                        p->which = 2000;
 370                                }
 371
 372                        }
 373
 374                        while (c < count && p->found < p->plength + 6) {
 375                                l = count - c;
 376                                if (l + p->found > p->plength + 6)
 377                                        l = p->plength + 6 - p->found;
 378                                write_ipack(p, buf + c, l);
 379                                p->found += l;
 380                                c += l;
 381                        }
 382                        break;
 383                }
 384
 385
 386                if (p->done) {
 387                        if (p->found + count - c < p->plength + 6) {
 388                                p->found += count - c;
 389                                c = count;
 390                        } else {
 391                                c += p->plength + 6 - p->found;
 392                                p->found = p->plength + 6;
 393                        }
 394                }
 395
 396                if (p->plength && p->found == p->plength + 6) {
 397                        send_ipack(p);
 398                        av7110_ipack_reset(p);
 399                        if (c < count)
 400                                av7110_ipack_instant_repack(buf + c, count - c, p);
 401                }
 402        }
 403        return count;
 404}
 405