tvheadend/src/parsers.c
2009-11-30 22:33:19 +00:00

1177 lines
26 KiB
C

/*
* Packet parsing functions
* Copyright (C) 2007 Andreas Öman
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "tvhead.h"
#include "parsers.h"
#include "parser_h264.h"
#include "parser_latm.h"
#include "bitstream.h"
#include "packet.h"
#include "transports.h"
#include "streaming.h"
#define PTS_MASK 0x1ffffffffLL
//#define PTS_MASK 0x7ffffLL
static const AVRational mpeg_tc = {1, 90000};
#define getu32(b, l) ({ \
uint32_t x = (b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3]); \
b+=4; \
l-=4; \
x; \
})
#define getu16(b, l) ({ \
uint16_t x = (b[0] << 8 | b[1]); \
b+=2; \
l-=2; \
x; \
})
#define getu8(b, l) ({ \
uint8_t x = b[0]; \
b+=1; \
l-=1; \
x; \
})
#define getpts(b, l) ({ \
int64_t _pts; \
_pts = (int64_t)((getu8(b, l) >> 1) & 0x07) << 30; \
_pts |= (int64_t)(getu16(b, l) >> 1) << 15; \
_pts |= (int64_t)(getu16(b, l) >> 1); \
_pts; \
})
static int parse_mpeg2video(th_transport_t *t, th_stream_t *st, size_t len,
uint32_t next_startcode, int sc_offset);
static int parse_h264(th_transport_t *t, th_stream_t *st, size_t len,
uint32_t next_startcode, int sc_offset);
typedef int (vparser_t)(th_transport_t *t, th_stream_t *st, size_t len,
uint32_t next_startcode, int sc_offset);
typedef void (aparser_t)(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt);
static void parse_video(th_transport_t *t, th_stream_t *st, uint8_t *data,
int len, vparser_t *vp);
static void parse_audio_with_lavc(th_transport_t *t, th_stream_t *st,
uint8_t *data, int len, aparser_t *ap);
static void parse_audio(th_transport_t *t, th_stream_t *st, uint8_t *data,
int len, int start, aparser_t *vp);
static void parse_aac(th_transport_t *t, th_stream_t *st, uint8_t *data,
int len, int start);
static void parse_subtitles(th_transport_t *t, th_stream_t *st, uint8_t *data,
int len, int start);
static void parse_mpegaudio(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt);
static void parse_ac3(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt);
static void parse_compute_pts(th_transport_t *t, th_stream_t *st,
th_pkt_t *pkt);
static void parser_deliver(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt,
int checkts);
static int parse_pes_header(th_transport_t *t, th_stream_t *st, uint8_t *buf,
size_t len);
static void parser_compute_duration(th_transport_t *t, th_stream_t *st,
th_pktref_t *pr);
/**
* Parse raw mpeg data
*/
void
parse_mpeg_ts(th_transport_t *t, th_stream_t *st, uint8_t *data,
int len, int start, int err)
{
switch(st->st_type) {
case SCT_MPEG2VIDEO:
parse_video(t, st, data, len, parse_mpeg2video);
break;
case SCT_H264:
parse_video(t, st, data, len, parse_h264);
break;
case SCT_MPEG2AUDIO:
parse_audio(t, st, data, len, start, parse_mpegaudio);
break;
case SCT_AC3:
parse_audio(t, st, data, len, start, parse_ac3);
break;
case SCT_SUBTITLES:
parse_subtitles(t, st, data, len, start);
break;
case SCT_AAC:
if(0) // not yet
parse_aac(t, st, data, len, start);
break;
default:
break;
}
}
/**
* Parse program stream, as from V4L2, etc.
*
* Note: data does not include startcode and packet length
*/
void
parse_mpeg_ps(th_transport_t *t, th_stream_t *st, uint8_t *data, int len)
{
int hlen;
hlen = parse_pes_header(t, st, data, len);
#if 0
int i;
for(i = 0; i < 16; i++)
printf("%02x.", data[i]);
printf(" %d\n", hlen);
#endif
data += hlen;
len -= hlen;
if(len < 1)
return;
switch(st->st_type) {
case SCT_MPEG2AUDIO:
parse_audio_with_lavc(t, st, data, len, parse_mpegaudio);
break;
case SCT_MPEG2VIDEO:
parse_video(t, st, data, len, parse_mpeg2video);
break;
default:
break;
}
}
/**
* Parse AAC LATM
*/
static void
parse_aac(th_transport_t *t, th_stream_t *st, uint8_t *data,
int len, int start)
{
int l, muxlen, p;
if(start) {
int i;
if(0)for(i = 0; i < st->st_buffer_ptr - 2; i++) {
if(st->st_buffer[i] == 0x56 && (st->st_buffer[i + 1] & 0xe0) == 0xe0) {
muxlen = (st->st_buffer[i + 1] & 0x1f) << 8 |
st->st_buffer[i + 2];
printf("AAC Sync at %8d: %8d bytes, next at %d\n", i, muxlen + 3,
i + muxlen + 3);
}
}
/* Payload unit start */
st->st_parser_state = 1;
st->st_buffer_ptr = 0;
st->st_parser_ptr = 0;
}
if(st->st_parser_state == 0)
return;
if(st->st_buffer == NULL) {
st->st_buffer_size = 4000;
st->st_buffer = malloc(st->st_buffer_size);
}
if(st->st_buffer_ptr + len >= st->st_buffer_size) {
st->st_buffer_size += len * 4;
st->st_buffer = realloc(st->st_buffer, st->st_buffer_size);
}
memcpy(st->st_buffer + st->st_buffer_ptr, data, len);
st->st_buffer_ptr += len;
if(st->st_parser_ptr == 0) {
int hlen;
if(st->st_buffer_ptr < 9)
return;
hlen = parse_pes_header(t, st, st->st_buffer + 6, st->st_buffer_ptr - 6);
if(hlen < 0)
return;
st->st_parser_ptr += 6 + hlen;
}
p = st->st_parser_ptr;
while((l = st->st_buffer_ptr - p) > 3) {
if(st->st_buffer[p] == 0x56 && (st->st_buffer[p + 1] & 0xe0) == 0xe0) {
muxlen = (st->st_buffer[p + 1] & 0x1f) << 8 |
st->st_buffer[p + 2];
if(l < muxlen + 3)
break;
parse_latm_audio_mux_element(t, st, st->st_buffer + p + 3, muxlen);
p += muxlen + 3;
} else {
printf("skip\n");
p++;
}
}
st->st_parser_ptr = p;
}
/**
* Generic video parser
*
* We scan for startcodes a'la 0x000001xx and let a specific parser
* derive further information.
*/
static void
parse_video(th_transport_t *t, th_stream_t *st, uint8_t *data, int len,
vparser_t *vp)
{
uint32_t sc;
int i, r;
sc = st->st_startcond;
if(st->st_buffer == NULL) {
st->st_buffer_size = 4000;
st->st_buffer = malloc(st->st_buffer_size);
}
if(st->st_buffer_ptr + len + 4 >= st->st_buffer_size) {
st->st_buffer_size += len * 4;
st->st_buffer = realloc(st->st_buffer, st->st_buffer_size);
}
for(i = 0; i < len; i++) {
st->st_buffer[st->st_buffer_ptr++] = data[i];
sc = sc << 8 | data[i];
if((sc & 0xffffff00) != 0x00000100)
continue;
r = st->st_buffer_ptr - 4;
if(r > 0 && st->st_startcode != 0) {
r = vp(t, st, r, sc, st->st_startcode_offset);
} else {
r = 1;
}
if(r) {
/* Reset packet parser upon length error or if parser
tells us so */
st->st_buffer_ptr = 0;
st->st_buffer[st->st_buffer_ptr++] = sc >> 24;
st->st_buffer[st->st_buffer_ptr++] = sc >> 16;
st->st_buffer[st->st_buffer_ptr++] = sc >> 8;
st->st_buffer[st->st_buffer_ptr++] = sc >> 0;
}
st->st_startcode = sc;
st->st_startcode_offset = st->st_buffer_ptr - 4;
}
st->st_startcond = sc;
}
/**
* Generic audio parser
*
* We trust 'start' to be set where a new frame starts, thats where we
* can expect to find the system start code.
*
* We then trust ffmpeg to parse and extract packets for use
*/
static void
parse_audio(th_transport_t *t, th_stream_t *st, uint8_t *data,
int len, int start, aparser_t *ap)
{
int hlen;
if(start) {
/* Payload unit start */
st->st_parser_state = 1;
st->st_buffer_ptr = 0;
}
if(st->st_parser_state == 0)
return;
if(st->st_parser_state == 1) {
if(st->st_buffer == NULL)
st->st_buffer = malloc(1000);
if(st->st_buffer_ptr + len >= 1000)
return;
memcpy(st->st_buffer + st->st_buffer_ptr, data, len);
st->st_buffer_ptr += len;
if(st->st_buffer_ptr < 9)
return;
if((hlen = parse_pes_header(t, st, st->st_buffer + 6,
st->st_buffer_ptr - 6)) < 0)
return;
data = st->st_buffer + hlen + 6;
len = st->st_buffer_ptr - hlen - 6;
st->st_parser_state = 2;
assert(len >= 0);
if(len == 0)
return;
}
parse_audio_with_lavc(t, st, data, len, ap);
}
/**
* Use libavcodec's parsers for audio parsing
*/
static void
parse_audio_with_lavc(th_transport_t *t, th_stream_t *st, uint8_t *data,
int len, aparser_t *ap)
{
uint8_t *outbuf;
int outlen, rlen;
th_pkt_t *pkt;
int64_t dts;
while(len > 0) {
rlen = av_parser_parse(st->st_parser, st->st_ctx,
&outbuf, &outlen, data, len,
st->st_curpts, st->st_curdts);
st->st_curdts = AV_NOPTS_VALUE;
st->st_curpts = AV_NOPTS_VALUE;
if(outlen) {
dts = st->st_parser->dts;
if(dts == AV_NOPTS_VALUE)
dts = st->st_nextdts;
pkt = pkt_alloc(outbuf, outlen, dts, dts);
pkt->pkt_commercial = t->tht_tt_commercial_advice;
ap(t, st, pkt);
}
data += rlen;
len -= rlen;
}
}
/**
* Mpeg audio parser
*/
const static int mpegaudio_freq_tab[4] = {44100, 48000, 32000, 0};
static void
parse_mpegaudio(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt)
{
uint8_t *buf = pkt->pkt_payload;
uint32_t header;
int sample_rate, duration;
header = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3]);
sample_rate = mpegaudio_freq_tab[(header >> 10) & 3];
if(sample_rate == 0) {
pkt_ref_dec(pkt);
return;
}
duration = 90000 * 1152 / sample_rate;
pkt->pkt_duration = duration;
st->st_nextdts = pkt->pkt_dts + duration;
parser_deliver(t, st, pkt, 1);
}
/**
* AC3 audio parser
*/
const static int ac3_freq_tab[4] = {48000, 44100, 32000, 0};
const static uint16_t ac3_frame_size_tab[38][3] = {
{ 64, 69, 96 },
{ 64, 70, 96 },
{ 80, 87, 120 },
{ 80, 88, 120 },
{ 96, 104, 144 },
{ 96, 105, 144 },
{ 112, 121, 168 },
{ 112, 122, 168 },
{ 128, 139, 192 },
{ 128, 140, 192 },
{ 160, 174, 240 },
{ 160, 175, 240 },
{ 192, 208, 288 },
{ 192, 209, 288 },
{ 224, 243, 336 },
{ 224, 244, 336 },
{ 256, 278, 384 },
{ 256, 279, 384 },
{ 320, 348, 480 },
{ 320, 349, 480 },
{ 384, 417, 576 },
{ 384, 418, 576 },
{ 448, 487, 672 },
{ 448, 488, 672 },
{ 512, 557, 768 },
{ 512, 558, 768 },
{ 640, 696, 960 },
{ 640, 697, 960 },
{ 768, 835, 1152 },
{ 768, 836, 1152 },
{ 896, 975, 1344 },
{ 896, 976, 1344 },
{ 1024, 1114, 1536 },
{ 1024, 1115, 1536 },
{ 1152, 1253, 1728 },
{ 1152, 1254, 1728 },
{ 1280, 1393, 1920 },
{ 1280, 1394, 1920 },
};
static void
parse_ac3(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt)
{
uint8_t *buf = pkt->pkt_payload;
uint32_t src, fsc;
int sample_rate, frame_size, duration, bsid;
src = buf[4] >> 6;
fsc = buf[4] & 0x3f;
bsid = (buf[5] & 0xf) - 8;
if(bsid < 0)
bsid = 0;
sample_rate = ac3_freq_tab[src] >> bsid;
if(sample_rate == 0) {
pkt_ref_dec(pkt);
return;
}
frame_size = ac3_frame_size_tab[fsc][src] * 2;
duration = 90000 * 1536 / sample_rate;
pkt->pkt_duration = duration;
st->st_nextdts = pkt->pkt_dts + duration;
parser_deliver(t, st, pkt, 1);
}
/**
* PES header parser
*
* Extract DTS and PTS and update current values in stream
*/
static int
parse_pes_header(th_transport_t *t, th_stream_t *st, uint8_t *buf, size_t len)
{
int64_t dts, pts;
int hdr, flags, hlen;
hdr = getu8(buf, len);
flags = getu8(buf, len);
hlen = getu8(buf, len);
if(len < hlen || (hdr & 0xc0) != 0x80)
return -1;
if((flags & 0xc0) == 0xc0) {
if(hlen < 10)
return -1;
pts = getpts(buf, len);
dts = getpts(buf, len);
} else if((flags & 0xc0) == 0x80) {
if(hlen < 5)
return -1;
dts = pts = getpts(buf, len);
} else
return hlen + 3;
st->st_curdts = dts & PTS_MASK;
st->st_curpts = pts & PTS_MASK;
return hlen + 3;
}
/**
* MPEG2VIDEO frame duration table (in 90kHz clock domain)
*/
const unsigned int mpeg2video_framedurations[16] = {
0,
3753,
3750,
3600,
3003,
3000,
1800,
1501,
1500,
};
/**
* Parse mpeg2video picture start
*/
static int
parse_mpeg2video_pic_start(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt,
bitstream_t *bs)
{
int v, pct;
if(bs->len < 29)
return 1;
skip_bits(bs, 10); /* temporal reference */
pct = read_bits(bs, 3);
if(pct < PKT_I_FRAME || pct > PKT_B_FRAME)
return 1; /* Illegal picture_coding_type */
pkt->pkt_frametype = pct;
/* If this is the first I-frame seen, set dts_start as a reference
offset */
if(pct == PKT_I_FRAME && t->tht_dts_start == AV_NOPTS_VALUE)
t->tht_dts_start = st->st_curdts;
v = read_bits(bs, 16); /* vbv_delay */
if(v == 0xffff)
st->st_vbv_delay = -1;
else
st->st_vbv_delay = av_rescale_q(v, st->st_tb, AV_TIME_BASE_Q);
return 0;
}
/**
* Parse mpeg2video sequence start
*/
static int
parse_mpeg2video_seq_start(th_transport_t *t, th_stream_t *st,
bitstream_t *bs)
{
int v;
if(bs->len < 61)
return 1;
skip_bits(bs, 12);
skip_bits(bs, 12);
skip_bits(bs, 4);
st->st_frame_duration = mpeg2video_framedurations[read_bits(bs, 4)];
v = read_bits(bs, 18) * 400;
skip_bits(bs, 1);
v = read_bits(bs, 10) * 16 * 1024 / 8;
st->st_vbv_size = v;
return 0;
}
/**
* MPEG2VIDEO specific reassembly
*
* Process all startcodes (also the system ones)
*
* Extract framerate (or duration to be more specific)
*
* 'steal' the st->st_buffer and use it as 'pkt' buffer
*
*/
static int
parse_mpeg2video(th_transport_t *t, th_stream_t *st, size_t len,
uint32_t next_startcode, int sc_offset)
{
uint8_t *buf = st->st_buffer + sc_offset;
bitstream_t bs;
th_pkt_t pkt0; /* Fake temporary packet */
init_bits(&bs, buf + 4, (len - 4) * 8);
switch(st->st_startcode) {
case 0x000001e0 ... 0x000001ef:
/* System start codes for video */
if(len >= 9)
parse_pes_header(t, st, buf + 6, len - 6);
return 1;
case 0x00000100:
/* Picture start code */
if(st->st_frame_duration == 0 || st->st_curdts == AV_NOPTS_VALUE)
return 1;
if(parse_mpeg2video_pic_start(t, st, &pkt0, &bs))
return 1;
if(st->st_curpkt != NULL)
pkt_ref_dec(st->st_curpkt);
st->st_curpkt = pkt_alloc(NULL, 0, st->st_curpts, st->st_curdts);
st->st_curpkt->pkt_frametype = pkt0.pkt_frametype;
st->st_curpkt->pkt_duration = st->st_frame_duration;
st->st_curpkt->pkt_commercial = t->tht_tt_commercial_advice;
break;
case 0x000001b3:
/* Sequence start code */
if(parse_mpeg2video_seq_start(t, st, &bs))
return 1;
break;
case 0x000001b5:
if(len < 5)
return 1;
switch(buf[4] >> 4) {
case 0x1:
/* sequence extension */
// printf("Sequence extension, len = %d\n", len);
if(len < 10)
return 1;
// printf("Profile = %d\n", buf[4] & 0x7);
// printf(" Level = %d\n", buf[5] >> 4);
break;
}
break;
case 0x00000101 ... 0x000001af:
/* Slices */
if(next_startcode == 0x100 || next_startcode > 0x1af) {
/* Last picture slice (because next not a slice) */
if(st->st_curpkt == NULL) {
/* no packet, may've been discarded by sanity checks here */
return 1;
}
st->st_curpkt->pkt_payload = st->st_buffer;
st->st_curpkt->pkt_payloadlen = st->st_buffer_ptr - 4;
st->st_curpkt->pkt_duration = st->st_frame_duration;
parse_compute_pts(t, st, st->st_curpkt);
st->st_curpkt = NULL;
st->st_buffer = malloc(st->st_buffer_size);
/* If we know the frame duration, increase DTS accordingly */
st->st_curdts += st->st_frame_duration;
/* PTS cannot be extrapolated (it's not linear) */
st->st_curpts = AV_NOPTS_VALUE;
return 1;
}
break;
default:
break;
}
return 0;
}
/**
* H.264 parser
*/
static int
parse_h264(th_transport_t *t, th_stream_t *st, size_t len,
uint32_t next_startcode, int sc_offset)
{
uint8_t *buf = st->st_buffer + sc_offset;
uint32_t sc = st->st_startcode;
int64_t d;
int l2, pkttype, l;
bitstream_t bs;
if(sc == 0x10c) {
/* RBSP padding, we don't want this */
l = len - sc_offset;
memcpy(buf, buf + l, 4); /* Move down new start code */
st->st_buffer_ptr -= l; /* Drop buffer */
}
if(sc >= 0x000001e0 && sc <= 0x000001ef) {
/* System start codes for video */
if(len >= 9)
parse_pes_header(t, st, buf + 6, len - 6);
if(st->st_prevdts != AV_NOPTS_VALUE) {
d = (st->st_curdts - st->st_prevdts) & 0x1ffffffffLL;
if(d < 90000)
st->st_frame_duration = d;
}
st->st_prevdts = st->st_curdts;
return 1;
}
bs.data = NULL;
switch(sc & 0x1f) {
case 7:
h264_nal_deescape(&bs, buf + 3, len - 3);
if(h264_decode_seq_parameter_set(st, &bs)) {
free(bs.data);
return 1;
}
break;
case 8:
h264_nal_deescape(&bs, buf + 3, len - 3);
if(h264_decode_pic_parameter_set(st, &bs)) {
free(bs.data);
return 1;
}
break;
case 5: /* IDR+SLICE */
case 1:
if(st->st_curpkt != NULL || st->st_frame_duration == 0 ||
st->st_curdts == AV_NOPTS_VALUE)
break;
if(t->tht_dts_start == AV_NOPTS_VALUE)
t->tht_dts_start = st->st_curdts;
l2 = len - 3 > 64 ? 64 : len - 3;
h264_nal_deescape(&bs, buf + 3, len); /* we just the first stuff */
if(h264_decode_slice_header(st, &bs, &pkttype)) {
free(bs.data);
return 1;
}
st->st_curpkt = pkt_alloc(NULL, 0, st->st_curpts, st->st_curdts);
st->st_curpkt->pkt_frametype = pkttype;
st->st_curpkt->pkt_duration = st->st_frame_duration;
st->st_curpkt->pkt_commercial = t->tht_tt_commercial_advice;
break;
default:
break;
}
free(bs.data);
if(next_startcode >= 0x000001e0 && next_startcode <= 0x000001ef) {
/* Complete frame */
if(st->st_curpkt == NULL)
return 1;
st->st_curpkt->pkt_payload = st->st_buffer;
st->st_curpkt->pkt_payloadlen = st->st_buffer_ptr;
parser_deliver(t, st, st->st_curpkt, 1);
st->st_curpkt = NULL;
st->st_buffer = malloc(st->st_buffer_size);
return 1;
}
return 0;
}
/**
* http://broadcasting.ru/pdf-standard-specifications/subtitling/dvb-sub/en300743.v1.2.1.pdf
*/
static void
parse_subtitles(th_transport_t *t, th_stream_t *st, uint8_t *data,
int len, int start)
{
th_pkt_t *pkt;
int psize, hlen;
uint8_t *buf;
if(start) {
/* Payload unit start */
st->st_parser_state = 1;
st->st_buffer_ptr = 0;
}
if(st->st_parser_state == 0)
return;
if(st->st_buffer == NULL) {
st->st_buffer_size = 4000;
st->st_buffer = malloc(st->st_buffer_size);
}
if(st->st_buffer_ptr + len >= st->st_buffer_size) {
st->st_buffer_size += len * 4;
st->st_buffer = realloc(st->st_buffer, st->st_buffer_size);
}
memcpy(st->st_buffer + st->st_buffer_ptr, data, len);
st->st_buffer_ptr += len;
if(st->st_buffer_ptr < 6)
return;
psize = st->st_buffer[4] << 8 | st->st_buffer[5];
if(st->st_buffer_ptr != psize + 6)
return;
st->st_parser_state = 0;
hlen = parse_pes_header(t, st, st->st_buffer + 6, st->st_buffer_ptr - 6);
if(hlen < 0)
return;
psize -= 6 + hlen;
buf = st->st_buffer + 6 + hlen;
if(psize < 2 || buf[0] != 0x20 || buf[1] != 0x00)
return;
psize -= 2;
buf += 2;
if(psize >= 6) {
pkt = pkt_alloc(buf, psize, st->st_curpts, st->st_curdts);
pkt->pkt_commercial = t->tht_tt_commercial_advice;
parser_deliver(t, st, pkt, 0);
}
}
/**
* Compute PTS (if not known)
*
* We do this by placing packets on a queue and wait for next I/P
* frame to appear
*/
static void
parse_compute_pts(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt)
{
th_pktref_t *pr;
int validpts = pkt->pkt_pts != AV_NOPTS_VALUE && st->st_ptsq_len == 0;
/* PTS known and no other packets in queue, deliver at once */
if(validpts && pkt->pkt_duration)
return parser_deliver(t, st, pkt, 1);
/* Reference count is transfered to queue */
pr = malloc(sizeof(th_pktref_t));
pr->pr_pkt = pkt;
if(validpts)
return parser_compute_duration(t, st, pr);
TAILQ_INSERT_TAIL(&st->st_ptsq, pr, pr_link);
st->st_ptsq_len++;
/* */
while((pr = TAILQ_FIRST(&st->st_ptsq)) != NULL) {
pkt = pr->pr_pkt;
switch(pkt->pkt_frametype) {
case PKT_B_FRAME:
/* B-frames have same PTS as DTS, pass them on */
pkt->pkt_pts = pkt->pkt_dts;
break;
case PKT_I_FRAME:
case PKT_P_FRAME:
/* Presentation occures at DTS of next I or P frame,
try to find it */
pr = TAILQ_NEXT(pr, pr_link);
while(1) {
if(pr == NULL)
return; /* not arrived yet, wait */
if(pr->pr_pkt->pkt_frametype <= PKT_P_FRAME) {
pkt->pkt_pts = pr->pr_pkt->pkt_dts;
break;
}
pr = TAILQ_NEXT(pr, pr_link);
}
break;
}
pr = TAILQ_FIRST(&st->st_ptsq);
TAILQ_REMOVE(&st->st_ptsq, pr, pr_link);
st->st_ptsq_len--;
if(pkt->pkt_duration == 0) {
parser_compute_duration(t, st, pr);
} else {
parser_deliver(t, st, pkt, 1);
free(pr);
}
}
}
/**
* Compute duration of a packet, we do this by keeping a packet
* until the next one arrives, then we release it
*/
static void
parser_compute_duration(th_transport_t *t, th_stream_t *st, th_pktref_t *pr)
{
th_pktref_t *next;
int64_t d;
TAILQ_INSERT_TAIL(&st->st_durationq, pr, pr_link);
pr = TAILQ_FIRST(&st->st_durationq);
if((next = TAILQ_NEXT(pr, pr_link)) == NULL)
return;
d = next->pr_pkt->pkt_dts - pr->pr_pkt->pkt_dts;
TAILQ_REMOVE(&st->st_durationq, pr, pr_link);
if(d < 10) {
pkt_ref_dec(pr->pr_pkt);
} else {
pr->pr_pkt->pkt_duration = d;
parser_deliver(t, st, pr->pr_pkt, 1);
}
free(pr);
}
/**
* De-wrap and normalize PTS/DTS to 1MHz clock domain
*/
static void
parser_deliver(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt,
int checkts)
{
int64_t dts, pts, ptsoff, d;
assert(pkt->pkt_dts != AV_NOPTS_VALUE);
assert(pkt->pkt_pts != AV_NOPTS_VALUE);
if(t->tht_dts_start == AV_NOPTS_VALUE) {
pkt_ref_dec(pkt);
return;
}
dts = pkt->pkt_dts;
pts = pkt->pkt_pts;
/* Compute delta between PTS and DTS (and watch out for 33 bit wrap) */
ptsoff = (pts - dts) & PTS_MASK;
/* Subtract the transport wide start offset */
dts -= t->tht_dts_start;
if(st->st_last_dts == AV_NOPTS_VALUE) {
if(dts < 0) {
/* Early packet with negative time stamp, drop those */
pkt_ref_dec(pkt);
return;
}
} else if(checkts) {
d = dts + st->st_dts_epoch - st->st_last_dts;
if(d < 0 || d > 90000) {
if(d < -PTS_MASK || d > -PTS_MASK + 180000) {
st->st_bad_dts++;
if(st->st_bad_dts < 5) {
tvhlog(LOG_ERR, "parser",
"transport %s stream %s, DTS discontinuity. "
"DTS = %" PRId64 ", last = %" PRId64,
t->tht_identifier, streaming_component_type2txt(st->st_type),
dts, st->st_last_dts);
}
} else {
/* DTS wrapped, increase upper bits */
printf("Wrap detected\n");
st->st_dts_epoch += PTS_MASK + 1;
st->st_bad_dts = 0;
}
} else {
st->st_bad_dts = 0;
}
}
st->st_bad_dts++;
dts += st->st_dts_epoch;
st->st_last_dts = dts;
pts = dts + ptsoff;
/* Rescale to tvheadned internal 1MHz clock */
pkt->pkt_dts =av_rescale_q(dts, st->st_tb, AV_TIME_BASE_Q);
pkt->pkt_pts =av_rescale_q(pts, st->st_tb, AV_TIME_BASE_Q);
pkt->pkt_duration=av_rescale_q(pkt->pkt_duration, st->st_tb, AV_TIME_BASE_Q);
#if 0
printf("%-12s %d %10"PRId64" %10"PRId64" %10d %10d\n",
streaming_component_type2txt(st->st_type),
pkt->pkt_frametype,
pkt->pkt_dts,
pkt->pkt_pts,
pkt->pkt_duration,
pkt->pkt_payloadlen);
#endif
avgstat_add(&st->st_rate, pkt->pkt_payloadlen, dispatch_clock);
/**
* Input is ok
*/
transport_set_feed_status(t, TRANSPORT_FEED_VALID_PACKETS);
/* Forward packet */
pkt->pkt_componentindex = st->st_index;
streaming_message_t *sm = streaming_msg_create_pkt(pkt);
streaming_pad_deliver(&t->tht_streaming_pad, sm);
streaming_msg_free(sm);
/* Decrease our own reference to the packet */
pkt_ref_dec(pkt);
}
/**
* Receive whole frames
*
* Analyze them as much as we need to and patch up PTS and duration
* if needed
*/
void
parser_enqueue_packet(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt)
{
uint8_t *buf = pkt->pkt_payload;
uint32_t sc = 0xffffffff;
int i, err = 0, rem;
bitstream_t bs;
assert(pkt->pkt_dts != AV_NOPTS_VALUE); /* We require DTS to be set */
pkt->pkt_duration = 0;
/* Per stream type analysis */
switch(st->st_type) {
case SCT_MPEG2VIDEO:
for(i = 0; i < pkt->pkt_payloadlen && err == 0; i++) {
sc = (sc << 8) | buf[i];
if((sc & 0xffffff00) != 0x00000100)
continue;
if(sc >= 0x101 && sc <= 0x1af)
break; /* slices, dont scan further */
rem = pkt->pkt_payloadlen - i - 1;
init_bits(&bs, buf + i + 1, rem);
switch(sc) {
case 0x00000100: /* Picture start code */
err = parse_mpeg2video_pic_start(t, st, pkt, &bs);
break;
case 0x000001b3: /* Sequence start code */
if(t->tht_dts_start == AV_NOPTS_VALUE)
t->tht_dts_start = pkt->pkt_dts;
err = parse_mpeg2video_seq_start(t, st, &bs);
break;
}
}
break;
default:
pkt->pkt_pts = pkt->pkt_dts;
break;
}
if(err) {
pkt_ref_dec(pkt);
return;
}
parse_compute_pts(t, st, pkt);
}