From e873fc76773c28b1d59f73f1a54b6820fa17d334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96man?= Date: Wed, 6 Feb 2008 21:50:58 +0000 Subject: [PATCH] Add ability to parse whole frames (without the reassembly stuff) --- parsers.c | 155 +++++++++++++++++++++++++++++++++++++++++++----------- parsers.h | 2 + 2 files changed, 125 insertions(+), 32 deletions(-) diff --git a/parsers.c b/parsers.c index 399f035a..345425b7 100644 --- a/parsers.c +++ b/parsers.c @@ -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); +} diff --git a/parsers.h b/parsers.h index d9a73792..2f6c9488 100644 --- a/parsers.h +++ b/parsers.h @@ -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 */