#define PTS_MASK 0x1ffffffffLL
//#define PTS_MASK 0x7ffffLL
+/* parser states */
+#define PARSER_APPEND 0
+#define PARSER_RESET 1
+#define PARSER_DROP 2
+#define PARSER_SKIP 3
+#define PARSER_HEADER 4
+
static int64_t
getpts(const uint8_t *p)
{
typedef void (aparser_t)(service_t *t, elementary_stream_t *st, th_pkt_t *pkt);
-static void parse_sc(service_t *t, elementary_stream_t *st, const uint8_t *data,
- int len, packet_parser_t *vp);
+static void parse_pes(service_t *t, elementary_stream_t *st, const uint8_t *data,
+ int len, int start, packet_parser_t *vp);
static void parse_mp4a_data(service_t *t, elementary_stream_t *st, int skip_next_check);
switch(st->es_type) {
case SCT_MPEG2VIDEO:
- parse_sc(t, st, data, len, parse_mpeg2video);
+ parse_pes(t, st, data, len, start, parse_mpeg2video);
break;
case SCT_H264:
- parse_sc(t, st, data, len, parse_h264);
+ parse_pes(t, st, data, len, start, parse_h264);
break;
case SCT_MPEG2AUDIO:
- parse_sc(t, st, data, len, parse_mpa);
+ parse_pes(t, st, data, len, start, parse_mpa);
break;
case SCT_AC3:
- parse_sc(t, st, data, len, parse_ac3);
+ parse_pes(t, st, data, len, start, parse_ac3);
break;
case SCT_EAC3:
- parse_sc(t, st, data, len, parse_eac3);
+ parse_pes(t, st, data, len, start, parse_eac3);
break;
case SCT_MP4A:
- parse_sc(t, st, data, len, parse_mp4a);
+ parse_pes(t, st, data, len, start, parse_mp4a);
break;
case SCT_DVBSUB:
/**
- * Generic video parser
+ * Generic PES parser
*
* We scan for startcodes a'la 0x000001xx and let a specific parser
* derive further information.
*/
static void
-parse_sc(service_t *t, elementary_stream_t *st, const uint8_t *data, int len,
- packet_parser_t *vp)
+parse_pes(service_t *t, elementary_stream_t *st, const uint8_t *data, int len,
+ int start, packet_parser_t *vp)
{
- uint32_t sc = st->es_startcond;
- int i, r;
- sbuf_alloc(&st->es_buf, len);
+ uint_fast32_t sc = st->es_startcond;
+ uint16_t plen;
+ int i, j, r, hlen, tmp, off;
- for(i = 0; i < len; i++) {
- if(st->es_ssc_intercept == 1) {
- if(st->es_ssc_ptr < sizeof(st->es_ssc_buf))
- st->es_ssc_buf[st->es_ssc_ptr] = data[i];
+ if (start) {
+ st->es_parser_state = 1;
+ if (data[0] != 0 && data[1] != 0 && data[2] != 1)
+ if (tvhlog_limit(&st->es_pes_log, 10))
+ tvhwarn("TS", "%s: Invalid start code %02x:%02x:%02x",
+ service_component_nicename(st),
+ data[0], data[1], data[2]);
+ st->es_incomplete = 0;
+ if (st->es_header_mode) {
+ st->es_buf.sb_ptr = st->es_header_offset;
+ st->es_header_mode = 0;
+ }
+ }
- st->es_ssc_ptr++;
+ if(st->es_parser_state == 0)
+ return;
- if(st->es_ssc_ptr < 5)
- continue;
+ for(i = 0; i < len; ) {
+
+ if(st->es_header_mode) {
+ r = len - i;
+ off = st->es_header_offset;
+ j = st->es_buf.sb_ptr - off;
+ if (j < 5) {
+ tmp = MIN(r, 5 - j);
+ sbuf_append(&st->es_buf, data + i, tmp);
+ j += tmp;
+ r -= tmp;
+ i += tmp;
+ }
+ if (j < 5)
+ break;
- uint16_t plen = st->es_ssc_buf[0] << 8 | st->es_ssc_buf[1];
+ plen = st->es_buf.sb_data[off] << 8 | st->es_buf.sb_data[off+1];
st->es_incomplete = plen >= 0xffdf;
- int hlen = st->es_ssc_buf[4];
-
- if(st->es_ssc_ptr < hlen + 5)
- continue;
+ hlen = st->es_buf.sb_data[off+4];
+
+ if(j < hlen + 5) {
+ tmp = MIN(r, hlen);
+ sbuf_append(&st->es_buf, data + i, tmp);
+ j += tmp;
+ r -= tmp;
+ i += tmp;
+ }
+ if(j < hlen + 5)
+ break;
- parse_pes_header(t, st, st->es_ssc_buf + 2, hlen + 3);
- st->es_ssc_intercept = 0;
+ r = parse_pes_header(t, st, st->es_buf.sb_data + off + 2, hlen + 3);
- if(st->es_buf.sb_ptr > 2)
- sc = st->es_buf.sb_data[st->es_buf.sb_ptr-3] << 16 |
- st->es_buf.sb_data[st->es_buf.sb_ptr-2] << 8 |
- st->es_buf.sb_data[st->es_buf.sb_ptr-1];
+ st->es_header_mode = 0;
+ st->es_buf.sb_ptr = off;
+ if(off > 2)
+ sc = st->es_buf.sb_data[off-3] << 16 |
+ st->es_buf.sb_data[off-2] << 8 |
+ st->es_buf.sb_data[off-1];
continue;
}
- st->es_buf.sb_data[st->es_buf.sb_ptr++] = data[i];
- sc = sc << 8 | data[i];
- if((sc & 0xffffff00) != 0x00000100)
- continue;
+ /* quick loop to find startcode */
+ j = i;
+ do {
+ sc = (sc << 8) | data[i++];
+ if((sc & 0xffffff00) == 0x00000100)
+ goto found;
+ } while (i < len);
+ sbuf_append(&st->es_buf, data + j, len - j);
+ break;
- if(sc == 0x100 && (len-i)>3) {
- uint32_t tempsc = data[i+1] << 16 | data[i+2] << 8 | data[i+3];
+found:
+ sbuf_append(&st->es_buf, data + j, i - j);
- if(tempsc == 0x1e0)
+ if(sc == 0x100 && (len-i)>2) {
+ if (data[0] == 0 && data[i+1] == 0x01 && data[i+2] == 0xe0)
continue;
}
r = st->es_buf.sb_ptr - st->es_startcode_offset - 4;
if(r > 0 && st->es_startcode != 0) {
r = vp(t, st, r, sc, st->es_startcode_offset);
-
- if(r == 3)
+
+ if(r == PARSER_SKIP)
continue;
- if(r == 4) {
+ if(r == PARSER_HEADER) {
st->es_buf.sb_ptr -= 4;
- st->es_ssc_intercept = 1;
- st->es_ssc_ptr = 0;
+ st->es_header_mode = 1;
+ st->es_header_offset = st->es_buf.sb_ptr;
sc = -1;
continue;
}
} else
- r = 1;
+ r = PARSER_RESET;
+
+ if(r == PARSER_DROP) {
- if(r == 2) {
assert(st->es_buf.sb_data != NULL);
- // Drop packet
+ /* Drop packet */
st->es_buf.sb_ptr = st->es_startcode_offset;
-
- st->es_buf.sb_data[st->es_buf.sb_ptr++] = sc >> 24;
- st->es_buf.sb_data[st->es_buf.sb_ptr++] = sc >> 16;
- st->es_buf.sb_data[st->es_buf.sb_ptr++] = sc >> 8;
- st->es_buf.sb_data[st->es_buf.sb_ptr++] = sc;
+ sbuf_put_be32(&st->es_buf, sc);
st->es_startcode = sc;
- } else {
- if(r == 1) {
+ } else /* APPEND or RESET */ {
+
+ if(r == PARSER_RESET) {
/* Reset packet parser upon length error or if parser
tells us so */
parser_deliver_error(t, st);
sbuf_reset_and_alloc(&st->es_buf, 256);
- st->es_buf.sb_data[st->es_buf.sb_ptr++] = sc >> 24;
- st->es_buf.sb_data[st->es_buf.sb_ptr++] = sc >> 16;
- st->es_buf.sb_data[st->es_buf.sb_ptr++] = sc >> 8;
- st->es_buf.sb_data[st->es_buf.sb_ptr++] = sc;
+ sbuf_put_be32(&st->es_buf, sc);
}
assert(st->es_buf.sb_data != NULL);
st->es_startcode = sc;
st->es_startcode_offset = st->es_buf.sb_ptr - 4;
+
}
}
+
st->es_startcond = sc;
}
int hlen, plen;
if((sc != 0x1bd && (sc & ~0x1f) != 0x1c0) || len < 9)
- return 1;
+ return PARSER_RESET;
plen = (buf[4] << 8) | buf[5];
if(plen + 6 > len)
- return 3;
+ return PARSER_SKIP;
if(plen + 6 < len)
- return 1;
+ return PARSER_RESET;
buf += 6;
len -= 6;
hlen = parse_pes_header(t, st, buf, len);
if(hlen < 0)
- return 1;
+ return PARSER_RESET;
buf += hlen;
len -= hlen;
st->es_buf_a.sb_err = st->es_buf.sb_err;
sbuf_append(&st->es_buf_a, buf, len);
- return 0;
+ return PARSER_APPEND;
}
return r;
parse_mp4a_data(t, st, 0);
- return 1;
+ return PARSER_RESET;
}
const static int mpa_br[16] = {
}
}
}
- return 1;
+ return PARSER_RESET;
}
/**
{
int r;
- if((r = depacketize(t, st, ilen, next_startcode, sc_offset)) != 0)
+ if((r = depacketize(t, st, ilen, next_startcode, sc_offset)) != PARSER_APPEND)
return r;
return parse_mpa2(t, st);
}
int i, len;
const uint8_t *buf;
- if((i = depacketize(t, st, ilen, next_startcode, sc_offset)) != 0)
+ if((i = depacketize(t, st, ilen, next_startcode, sc_offset)) != PARSER_APPEND)
return i;
again:
}
}
}
- return 1;
+ return PARSER_RESET;
}
int i, len;
const uint8_t *buf;
- if((i = depacketize(t, st, ilen, next_startcode, sc_offset)) != 0)
+ if((i = depacketize(t, st, ilen, next_startcode, sc_offset)) != PARSER_APPEND)
return i;
again:
}
}
}
- return 1;
+ return PARSER_RESET;
}
int v, pct;
if(bs->len < 29)
- return 1;
+ return PARSER_RESET;
skip_bits(bs, 10); /* temporal reference */
int frametype;
if(next_startcode == 0x1e0)
- return 4;
+ return PARSER_HEADER;
init_rbits(&bs, buf + 4, (len - 4) * 8);
case 0x000001e0 ... 0x000001ef:
/* System start codes for video */
if(len < 9)
- return 1;
+ return PARSER_RESET;
parse_pes_header(t, st, buf + 6, len - 6);
return 1;
case 0x00000100:
/* Picture start code */
if(st->es_frame_duration == 0)
- return 1;
+ return PARSER_RESET;
- if(parse_mpeg2video_pic_start(t, st, &frametype, &bs))
- return 1;
+ if(parse_mpeg2video_pic_start(t, st, &frametype, &bs) != PARSER_APPEND)
+ return PARSER_RESET;
if(st->es_curpkt != NULL)
pkt_ref_dec(st->es_curpkt);
/* Sequence start code */
if(!st->es_buf.sb_err) {
if(parse_mpeg2video_seq_start(t, st, &bs))
- return 1;
+ return PARSER_RESET;
parser_global_data_move(st, buf, len);
}
- return 2;
+ return PARSER_DROP;
case 0x000001b5:
if(len < 5)
// Sequence Extension
if(!st->es_buf.sb_err)
parser_global_data_move(st, buf, len);
- return 2;
+ return PARSER_DROP;
case 0x2:
// Sequence Display Extension
if(!st->es_buf.sb_err)
parser_global_data_move(st, buf, len);
- return 2;
+ return PARSER_DROP;
}
break;
parser_deliver(t, st, pkt);
st->es_curpkt = NULL;
- return 1;
+ return PARSER_RESET;
}
break;
// GOP header
if(!st->es_buf.sb_err)
parser_global_data_move(st, buf, len);
- return 2;
+ return PARSER_DROP;
case 0x000001b2:
// User data
break;
}
- return 0;
+ return PARSER_APPEND;
}
pkt_ref_dec(st->es_curpkt);
st->es_curpkt = NULL;
}
- return 1;
+ return PARSER_RESET;
}
if(sc >= 0x000001e0 && sc <= 0x000001ef) {
}
}
st->es_prevdts = st->es_curdts;
- return 1;
+ return PARSER_RESET;
}
if(sc == 0x10c) {
// Padding
st->es_buf.sb_ptr -= len;
- ret = 2;
+ ret = PARSER_DROP;
} else {
free(f);
parser_global_data_move(st, buf, len);
}
- ret = 2;
+ ret = PARSER_DROP;
break;
case 8:
free(f);
parser_global_data_move(st, buf, len);
}
- ret = 2;
+ ret = PARSER_DROP;
break;
case 5: /* IDR+SLICE */
if(h264_decode_slice_header(st, &bs, &pkttype, &isfield)) {
free(f);
- return 1;
+ return PARSER_RESET;
}
free(f);
(next_startcode & 0x1f) == 9) {
/* Complete frame - new start code or delimiter */
if (st->es_incomplete)
- return 4;
+ return PARSER_HEADER;
th_pkt_t *pkt = st->es_curpkt;
size_t metalen = 0;
sbuf_steal_data(&st->es_buf);
}
}
- return 1;
+ return PARSER_RESET;
}
return ret;
int psize, hlen;
const uint8_t *buf;
const uint8_t *d;
+
if(start) {
/* Payload unit start */
st->es_parser_state = 1;
int psize, hlen;
const uint8_t *buf;
const uint8_t *d;
+
if(start) {
st->es_parser_state = 1;
st->es_parser_ptr = 0;