MythTV  0.26-pre
m2ts_demux.c
Go to the documentation of this file.
00001 /*
00002  * This file is part of libbluray
00003  * Copyright (C) 2010  hpi1
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Lesser General Public
00007  * License as published by the Free Software Foundation; either
00008  * version 2.1 of the License, or (at your option) any later version.
00009  *
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Lesser General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Lesser General Public
00016  * License along with this library. If not, see
00017  * <http://www.gnu.org/licenses/>.
00018  */
00019 
00020 #include "m2ts_demux.h"
00021 #include "pes_buffer.h"
00022 
00023 #include "util/logging.h"
00024 #include "util/macro.h"
00025 
00026 #include <stdlib.h>
00027 #include <string.h>
00028 
00029 /*#define M2TS_TRACE(...) BD_DEBUG(DBG_CRIT,__VA_ARGS__)*/
00030 #define M2TS_TRACE(...) do {} while(0)
00031 
00032 /*
00033  *
00034  */
00035 
00036 struct m2ts_demux_s
00037 {
00038     uint16_t    pid;
00039     uint32_t    pes_length;
00040     PES_BUFFER *buf;
00041 };
00042 
00043 M2TS_DEMUX *m2ts_demux_init(uint16_t pid)
00044 {
00045     M2TS_DEMUX *p = calloc(1, sizeof(*p));
00046 
00047     if (p) {
00048         p->pid = pid;
00049     }
00050 
00051     return p;
00052 }
00053 
00054 void m2ts_demux_free(M2TS_DEMUX **p)
00055 {
00056     if (p && *p) {
00057         pes_buffer_free(&(*p)->buf);
00058         X_FREE(*p);
00059     }
00060 }
00061 
00062 static int64_t _parse_timestamp(uint8_t *p)
00063 {
00064     int64_t ts;
00065     ts  = ((int64_t)(p[0] & 0x0E)) << 29;
00066     ts |=  p[1]         << 22;
00067     ts |= (p[2] & 0xFE) << 14;
00068     ts |=  p[3]         <<  7;
00069     ts |= (p[4] & 0xFE) >>  1;
00070     return ts;
00071 }
00072 
00073 /*
00074  * _add_ts()
00075  * - add ts payload to buffer.
00076  * - parse PES header if pusi is set.
00077  * - return:
00078  *   < 0   error (incorrect PES header)
00079  *   = 0   PES packet continue
00080  *   > 0   PES packet payload length from PES header
00081  */
00082 static int _add_ts(PES_BUFFER *p, unsigned pusi, uint8_t *buf, unsigned len)
00083 {
00084     int result = 0;
00085 
00086     if (pusi) {
00087         // Parse PES header
00088         unsigned pes_length = buf[4] << 8 | buf[5];
00089         unsigned pts_exists = buf[7] & 0x80;
00090         unsigned dts_exists = buf[7] & 0x40;
00091         unsigned hdr_len    = buf[8] + 9;
00092 
00093         if (buf[0] || buf[1] || buf[2] != 1) {
00094             BD_DEBUG(DBG_DECODE, "invalid PES header (00 00 01)");
00095             return -1;
00096         }
00097 
00098         if (len < hdr_len) {
00099             BD_DEBUG(DBG_DECODE, "invalid BDAV TS (PES header not in single TS packet)\n");
00100             return -1;
00101         }
00102 
00103         if (pts_exists) {
00104             p->pts = _parse_timestamp(buf + 9);
00105         }
00106         if (dts_exists) {
00107             p->dts = _parse_timestamp(buf + 14);
00108         }
00109 
00110         buf += hdr_len;
00111         len -= hdr_len;
00112 
00113         result = pes_length + 6 - hdr_len;
00114     }
00115 
00116     // realloc
00117     if (p->size < p->len + len) {
00118         p->size *= 2;
00119         p->buf   = realloc(p->buf, p->size);
00120     }
00121 
00122     // append
00123     memcpy(p->buf + p->len, buf, len);
00124     p->len += len;
00125 
00126     return result;
00127 }
00128 
00129 PES_BUFFER *m2ts_demux(M2TS_DEMUX *p, uint8_t *buf)
00130 {
00131     uint8_t   *end = buf + 6144;
00132     PES_BUFFER *result = NULL;
00133 
00134     if (!buf) {
00135         // flush
00136         result = p->buf;
00137         p->buf = NULL;
00138         return result;
00139     }
00140 
00141     for (; buf < end; buf += 192) {
00142 
00143         unsigned tp_error       = buf[4+1] & 0x80;
00144         unsigned pusi           = buf[4+1] & 0x40;
00145         uint16_t pid            = ((buf[4+1] & 0x1f) << 8) | buf[4+2];
00146         unsigned payload_exists = buf[4+3] & 0x10;
00147         int      payload_offset = (buf[4+3] & 0x20) ? buf[4+4] + 5 : 4;
00148 
00149         if (buf[4] != 0x47) {
00150             BD_DEBUG(DBG_DECODE, "missing sync byte. scrambled data ?\n");
00151             return NULL;
00152         }
00153         if (pid != p->pid) {
00154             M2TS_TRACE("skipping packet (pid %d)\n", pid);
00155             continue;
00156         }
00157         if (tp_error) {
00158             BD_DEBUG(DBG_DECODE, "skipping packet (transport error)\n");
00159             continue;
00160         }
00161         if (!payload_exists) {
00162             M2TS_TRACE("skipping packet (no payload)\n");
00163             continue;
00164         }
00165         if (payload_offset >= 188) {
00166             BD_DEBUG(DBG_DECODE, "skipping packet (invalid payload start address)\n");
00167             continue;
00168         }
00169 
00170         if (pusi) {
00171             if (p->buf) {
00172                 BD_DEBUG(DBG_DECODE, "PES length mismatch: have %d, expected %d\n",
00173                       p->buf->len, p->pes_length);
00174                 pes_buffer_free(&p->buf);
00175             }
00176             p->buf = pes_buffer_alloc(0xffff);
00177         }
00178 
00179         if (!p->buf) {
00180             BD_DEBUG(DBG_DECODE, "skipping packet (no pusi seen)\n");
00181             continue;
00182         }
00183 
00184         int r = _add_ts(p->buf, pusi, buf + 4 + payload_offset, 188 - payload_offset);
00185         if (r) {
00186             if (r < 0) {
00187                 BD_DEBUG(DBG_DECODE, "skipping block (PES header error)\n");
00188                 pes_buffer_free(&p->buf);
00189                 continue;
00190             }
00191             p->pes_length = r;
00192         }
00193 
00194         if (p->buf->len == p->pes_length) {
00195             M2TS_TRACE("PES complete (%d bytes)\n", p->pes_length);
00196             pes_buffer_append(&result, p->buf);
00197             p->buf = NULL;
00198         }
00199     }
00200 
00201     return result;
00202 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends