Add ability to parse whole frames (without the reassembly stuff)

This commit is contained in:
Andreas Öman 2008-02-06 21:50:58 +00:00
parent 4226af5abb
commit e873fc7677
2 changed files with 125 additions and 32 deletions

155
parsers.c
View file

@ -465,6 +465,62 @@ const static unsigned int mpeg2video_framedurations[16] = {
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 < 6 * 8)
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 */
/* 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 < 11 * 8)
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
*
@ -481,7 +537,7 @@ parse_mpeg2video(th_transport_t *t, th_stream_t *st, size_t len,
{
uint8_t *buf = st->st_buffer + sc_offset;
bitstream_t bs;
int v, pct;
th_pkt_t pkt0; /* Fake temporary packet */
init_bits(&bs, buf + 4, (len - 4) * 8);
@ -497,31 +553,14 @@ parse_mpeg2video(th_transport_t *t, th_stream_t *st, size_t len,
if(st->st_frame_duration == 0 || st->st_curdts == AV_NOPTS_VALUE)
return 1;
if(len < 6)
if(parse_mpeg2video_pic_start(t, st, &pkt0, &bs))
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 */
/* 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);
if(st->st_curpkt != NULL)
pkt_deref(st->st_curpkt);
st->st_curpkt = pkt_alloc(NULL, 0, st->st_curpts, st->st_curdts);
st->st_curpkt->pkt_frametype = pct;
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;
@ -529,18 +568,9 @@ parse_mpeg2video(th_transport_t *t, th_stream_t *st, size_t len,
case 0x000001b3:
/* Sequence start code */
if(len < 11)
if(parse_mpeg2video_seq_start(t, st, &bs))
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;
break;
case 0x000001b5:
@ -747,8 +777,6 @@ parser_compute_duration(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt)
d = next->pkt_dts - pkt->pkt_dts;
TAILQ_REMOVE(&st->st_durationq, pkt, pkt_queue_link);
if(d < 10) {
printf("%s: duration is %lld, pkt dropped\n",
htstvstreamtype2txt(st->st_type), d);
pkt_deref(pkt);
return;
}
@ -817,6 +845,8 @@ parser_deliver(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt)
#endif
pkt->pkt_stream = st;
avgstat_add(&st->st_rate, pkt->pkt_payloadlen, dispatch_clock);
/* Alert all muxers tied to us that a new packet has arrived */
LIST_FOREACH(tm, &t->tht_muxers, tm_transport_link)
@ -827,3 +857,64 @@ parser_deliver(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt)
pkt_deref(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 HTSTV_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_deref(pkt);
return;
}
parse_compute_pts(t, st, pkt);
}

View file

@ -27,4 +27,6 @@ void parser_compute_duration(th_transport_t *t, th_stream_t *st,
void parse_compute_pts(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt);
void parser_enqueue_packet(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt);
#endif /* PARSERS_H */