From c0876c7471af8dc8c677e8c98e58d2715b21929e Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Sat, 12 Sep 2009 18:16:56 +0200 Subject: [PATCH] FEC timing improvements. Currently we compute the time of a FEC group as the number of containing chunks times the chunk time. The time between sending two slices therefore depends only on the number of chunks the group contains. Groups containing many slices are sent with larger delays than groups containing few slices. This approach is not optimal for the following reason: Consider a group containing only few slices which is followed by a group containing many slices. This happens frequently at the end of VBR MP3 files which contain some seconds of silence or applause at the end because this last part is often encoded at a lower bitrate than the preceding part. In this scenario buffer underruns in the receiving application can easily occur if the previous FEC group has been decoded and completely fed to the writer before enough slices of the next group have arrived to decode the second group. This patch changes the timing of FEC groups such that all but the first group use the duration of the _previous_ group as the basis for the timing. --- vss.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/vss.c b/vss.c index 400df846..babcd24c 100644 --- a/vss.c +++ b/vss.c @@ -232,6 +232,17 @@ static int num_slices(long unsigned bytes, struct fec_client *fc, uint8_t *resul return 1; } +static void set_slice_duration(struct fec_client *fc, struct fec_group *g) +{ + struct timeval group_duration, *chunk_tv = vss_chunk_time(); + + tv_scale(g->num_chunks, chunk_tv, &group_duration); + tv_divide(fc->fcp->slices_per_group + fc->num_extra_slices, + &group_duration, &g->slice_duration); + PARA_DEBUG_LOG("durations (group/chunk/slice): %lu/%lu/%lu\n", + tv2ms(&group_duration), tv2ms(chunk_tv), tv2ms(&g->slice_duration)); +} + static int setup_next_fec_group(struct fec_client *fc, struct vss_task *vsst) { int ret, i, k, data_slices; @@ -275,6 +286,8 @@ static int setup_next_fec_group(struct fec_client *fc, struct vss_task *vsst) g->first_chunk = mmd->current_chunk; g->num = 0; } else { + /* use duration of the previous group for the timing of this group */ + set_slice_duration(fc, g); g->first_chunk += g->num_chunks; g->num++; } @@ -301,6 +314,8 @@ static int setup_next_fec_group(struct fec_client *fc, struct vss_task *vsst) g->num_chunks = i - g->first_chunk; assert(g->num_chunks); fc->current_slice_num = 0; + if (g->num == 0) + set_slice_duration(fc, g); /* setup header slices */ buf = vsst->header_buf; @@ -332,21 +347,15 @@ static int setup_next_fec_group(struct fec_client *fc, struct vss_task *vsst) for (; i < k; i++) fc->src_data[i] = (const unsigned char *)buf; } - - /* setup group timing */ - tv_scale(g->first_chunk - fc->first_stream_chunk, chunk_tv, &tmp); - tv_add(&fc->stream_start, &tmp, &g->start); - tv_scale(g->num_chunks, chunk_tv, &tmp); /* group duration */ - tv_divide(fc->fcp->slices_per_group + fc->num_extra_slices, - &tmp, &g->slice_duration); - - PARA_DEBUG_LOG("FEC group %d: %d chunks (%d - %d), %d header slices, %d data slices\n", + PARA_DEBUG_LOG("FEC group %d: %d chunks (%d - %d), " + "%d header slices, %d data slices\n", g->num, g->num_chunks, g->first_chunk, g->first_chunk + g->num_chunks - 1, g->num_header_slices, data_slices ); - PARA_DEBUG_LOG("durations (group/chunk/slice): %lu/%lu/%lu\n", - tv2ms(&tmp), tv2ms(chunk_tv), tv2ms(&g->slice_duration)); + /* set group start */ + tv_scale(g->first_chunk - fc->first_stream_chunk, chunk_tv, &tmp); + tv_add(&fc->stream_start, &tmp, &g->start); return 1; } -- 2.39.2