Extract h264 frame duration from bitstream instead of measuring intra packet time

This commit is contained in:
Andreas Öman 2010-06-15 10:51:44 +00:00
parent 478fa53b1c
commit 5b56688ebe
5 changed files with 65 additions and 57 deletions

View file

@ -90,10 +90,15 @@ static const int h264_lev2cpbsize[][2] = {
typedef struct h264_private {
struct {
int frame_duration;
int cbpsize;
int16_t width;
int16_t height;
int16_t max_frame_num_bits;
char mbs_only_flag;
char aff;
char fixed_rate;
int units_in_tick;
int time_scale;
} sps[256];
struct {
@ -106,13 +111,8 @@ typedef struct h264_private {
static int
decode_vui(th_stream_t *st, bitstream_t *bs, int spsid)
decode_vui(h264_private_t *p, bitstream_t *bs, int sps_id)
{
int units_in_tick;
int time_scale;
int fixed_rate;
return 0;
if(read_bits1(bs)) {
if(read_bits(bs, 8) == 255) {
read_bits(bs, 16);
@ -140,16 +140,12 @@ decode_vui(th_stream_t *st, bitstream_t *bs, int spsid)
}
if(!read_bits1(bs)) /* We need timing info */
return -1;
return 0;
units_in_tick = read_bits(bs, 32);
time_scale = read_bits(bs, 32);
fixed_rate = read_bits1(bs);
#if 0
printf("units_in_tick = %d\n", units_in_tick);
printf("time_scale = %d\n", time_scale);
printf("fixed_rate = %d\n", fixed_rate);
#endif
p->sps[sps_id].units_in_tick = read_bits(bs, 32);
p->sps[sps_id].time_scale = read_bits(bs, 32);
p->sps[sps_id].fixed_rate = read_bits1(bs);
return 0;
}
@ -229,7 +225,7 @@ h264_decode_seq_parameter_set(th_stream_t *st, bitstream_t *bs)
}
}
tmp = read_golomb_ue(bs); /* max frame num */
p->sps[sps_id].max_frame_num_bits = read_golomb_ue(bs) + 4;
poc_type= read_golomb_ue(bs);
if(poc_type == 0){ //FIXME #define
@ -257,8 +253,9 @@ h264_decode_seq_parameter_set(th_stream_t *st, bitstream_t *bs)
p->sps[sps_id].width = width * 16;
p->sps[sps_id].height = height * 16;
if(!read_bits1(bs))
read_bits1(bs);
p->sps[sps_id].mbs_only_flag = read_bits1(bs);
if(!p->sps[sps_id].mbs_only_flag)
p->sps[sps_id].aff = read_bits1(bs);
read_bits1(bs);
@ -271,7 +268,7 @@ h264_decode_seq_parameter_set(th_stream_t *st, bitstream_t *bs)
}
if(read_bits1(bs)) {
decode_vui(st, bs, sps_id);
decode_vui(p, bs, sps_id);
return 0;
} else {
return -1;
@ -296,10 +293,11 @@ h264_decode_pic_parameter_set(th_stream_t *st, bitstream_t *bs)
int
h264_decode_slice_header(th_stream_t *st, bitstream_t *bs, int *pkttype)
h264_decode_slice_header(th_stream_t *st, bitstream_t *bs, int *pkttype,
int *duration)
{
h264_private_t *p;
int slice_type, pps_id, sps_id;
int slice_type, pps_id, sps_id, fnum;
if((p = st->st_priv) == NULL)
return -1;
@ -326,11 +324,39 @@ h264_decode_slice_header(th_stream_t *st, bitstream_t *bs, int *pkttype)
pps_id = read_golomb_ue(bs);
sps_id = p->pps[pps_id].sps;
if(p->sps[sps_id].cbpsize == 0)
if(p->sps[sps_id].max_frame_num_bits == 0)
return -1;
st->st_vbv_size = p->sps[sps_id].cbpsize;
fnum = read_bits(bs, p->sps[sps_id].max_frame_num_bits);
int structure;
int timebase = 180000;
if(p->sps[sps_id].mbs_only_flag) {
structure = 0;
} else {
if(read_bits1(bs)) {
read_bits1(bs); // bottom field
structure = 1;
} else {
structure = 2;
}
}
if(p->sps[sps_id].time_scale != 0) {
int d = timebase * p->sps[sps_id].units_in_tick / p->sps[sps_id].time_scale;
*duration = d;
} else {
*duration = 0;
}
if(p->sps[sps_id].cbpsize != 0)
st->st_vbv_size = p->sps[sps_id].cbpsize;
st->st_vbv_delay = -1;
parser_set_stream_meta(st, p->sps[sps_id].width, p->sps[sps_id].height, 0);
if(p->sps[sps_id].width && p->sps[sps_id].height)
parser_set_stream_vsize(st, p->sps[sps_id].width, p->sps[sps_id].height);
return 0;
}

View file

@ -27,6 +27,7 @@ int h264_decode_seq_parameter_set(th_stream_t *st, bitstream_t *bs);
int h264_decode_pic_parameter_set(th_stream_t *st, bitstream_t *bs);
int h264_decode_slice_header(th_stream_t *st, bitstream_t *bs, int *pkttype);
int h264_decode_slice_header(th_stream_t *st, bitstream_t *bs, int *pkttype,
int *duration);
#endif /* PARSER_H264_H_ */

View file

@ -630,17 +630,15 @@ parse_mpeg2video_pic_start(th_transport_t *t, th_stream_t *st, int *frametype,
*
*/
void
parser_set_stream_meta(th_stream_t *st, int width, int height, int d)
parser_set_stream_vsize(th_stream_t *st, int width, int height)
{
int need_save = 0;
if(st->st_frame_duration == 0 && st->st_width == 0 && st->st_height == 0) {
if(st->st_width == 0 && st->st_height == 0) {
need_save = 1;
st->st_meta_change = 0;
} else if((d && st->st_frame_duration != d) ||
st->st_width != width ||
st->st_height != height) {
} else if(st->st_width != width || st->st_height != height) {
st->st_meta_change++;
if(st->st_meta_change == 2)
@ -651,8 +649,6 @@ parser_set_stream_meta(th_stream_t *st, int width, int height, int d)
}
if(need_save) {
if(d)
st->st_frame_duration = d;
st->st_width = width;
st->st_height = height;
transport_request_save(st->st_transport, 1);
@ -667,7 +663,7 @@ static int
parse_mpeg2video_seq_start(th_transport_t *t, th_stream_t *st,
bitstream_t *bs)
{
int v, width, height, d;
int v, width, height;
if(bs->len < 61)
return 1;
@ -675,7 +671,7 @@ parse_mpeg2video_seq_start(th_transport_t *t, th_stream_t *st,
width = read_bits(bs, 12);
height = read_bits(bs, 12);
skip_bits(bs, 4);
d = mpeg2video_framedurations[read_bits(bs, 4)];
st->st_frame_duration = mpeg2video_framedurations[read_bits(bs, 4)];
v = read_bits(bs, 18) * 400;
skip_bits(bs, 1);
@ -683,7 +679,7 @@ parse_mpeg2video_seq_start(th_transport_t *t, th_stream_t *st,
v = read_bits(bs, 10) * 16 * 1024 / 8;
st->st_vbv_size = v;
parser_set_stream_meta(st, width, height, d);
parser_set_stream_vsize(st, width, height);
return 0;
}
@ -835,7 +831,7 @@ parse_h264(th_transport_t *t, th_stream_t *st, size_t len,
uint8_t *buf = st->st_buffer + sc_offset;
uint32_t sc = st->st_startcode;
int64_t d;
int l2, pkttype;
int l2, pkttype, duration;
bitstream_t bs;
int ret = 0;
@ -892,14 +888,16 @@ parse_h264(th_transport_t *t, th_stream_t *st, size_t len,
l2 = len - 3 > 64 ? 64 : len - 3;
h264_nal_deescape(&bs, buf + 3, l2); /* we just want the first stuff */
if(h264_decode_slice_header(st, &bs, &pkttype)) {
duration = 0;
if(h264_decode_slice_header(st, &bs, &pkttype, &duration)) {
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_duration = duration ?: st->st_frame_duration;
st->st_curpkt->pkt_commercial = t->tht_tt_commercial_advice;
break;

View file

@ -28,7 +28,7 @@ void parse_mpeg_ps(th_transport_t *t, th_stream_t *st, uint8_t *data, int len);
void parser_enqueue_packet(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt);
void parser_set_stream_meta(th_stream_t *st, int width, int height, int d);
void parser_set_stream_vsize(th_stream_t *st, int width, int height);
extern const unsigned int mpeg2video_framedurations[16];

View file

@ -422,7 +422,6 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid,
streaming_component_type_t hts_stream_type;
th_stream_t *st, *next;
char lang[4];
int frameduration;
int update = 0;
int had_components;
int composition_id;
@ -502,7 +501,6 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid,
ptr += 5;
len -= 5;
frameduration = 0;
hts_stream_type = SCT_UNKNOWN;
memset(lang, 0, 4);
composition_id = -1;
@ -551,10 +549,6 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid,
hts_stream_type = SCT_AC3;
break;
case DVB_DESC_VIDEO_STREAM:
frameduration = mpeg2video_framedurations[(ptr[0] >> 3) & 0xf];
break;
case DVB_DESC_LANGUAGE:
memcpy(lang, ptr, 3);
break;
@ -618,11 +612,6 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid,
memcpy(st->st_lang, lang, 4);
}
if(st->st_frame_duration == 0 && frameduration != 0) {
st->st_frame_duration = frameduration;
update |= PMT_UPDATE_FRAME_DURATION;
}
if(composition_id != -1 && st->st_composition_id != composition_id) {
st->st_composition_id = composition_id;
update |= PMT_UPDATE_COMPOSITION_ID;
@ -980,9 +969,6 @@ psi_save_transport_settings(htsmsg_t *m, th_transport_t *t)
if(st->st_type == SCT_TEXTSUB)
htsmsg_add_u32(sub, "parentpid", st->st_parent_pid);
if(st->st_frame_duration)
htsmsg_add_u32(sub, "frameduration", st->st_frame_duration);
if(st->st_type == SCT_MPEG2VIDEO || st->st_type == SCT_H264) {
if(st->st_width && st->st_height) {
htsmsg_add_u32(sub, "width", st->st_width);
@ -1106,9 +1092,6 @@ psi_load_transport_settings(htsmsg_t *m, th_transport_t *t)
if((v = htsmsg_get_str(c, "language")) != NULL)
av_strlcpy(st->st_lang, v, 4);
if(!htsmsg_get_u32(c, "frameduration", &u32))
st->st_frame_duration = u32;
if(!htsmsg_get_u32(c, "position", &u32))
st->st_position = u32;