X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=fecdec_filter.c;h=ca9dcd739e23c6fe7e89d4ff67cec41686906318;hp=daecee7e5fc50bcb61f8cad8c481efb4e006a2b3;hb=bb6721e17e741b7ea52fbf88661d2b177bed72c3;hpb=e0acbd356abf4d9f1b693065b1ff23c57c53ab1e;ds=sidebyside diff --git a/fecdec_filter.c b/fecdec_filter.c index daecee7e..ca9dcd73 100644 --- a/fecdec_filter.c +++ b/fecdec_filter.c @@ -4,7 +4,9 @@ * Licensed under the GPL v2. For licencing details see COPYING. */ -/** \file fecdec_filter.c A filter fec-decodes an audio stream. */ +/** \file fecdec_filter.c A filter that fec-decodes an audio stream. */ + +#include #include #include "para.h" @@ -27,8 +29,10 @@ */ #define NUM_FEC_GROUPS 3 -/** Size of the output buffer of the fecdec filter. */ -#define FECDEC_OUTBUF_SIZE (1024 * 1024) /* FIXME: This has to depend on the fec params */ +/** Default size of the output buffer of the fecdec filter. */ +#define FECDEC_DEFAULT_OUTBUF_SIZE (3 * 1024) +/** Maximal size of the output buffer of the fecdec filter. */ +#define FECDEC_MAX_OUTBUF_SIZE (1024 * 1024) /** Data read from the header of a slice. */ struct fec_header { @@ -68,6 +72,20 @@ struct fecdec_group { unsigned char **data; }; +/** + * The fecdec filter defers decoding of the first group until the first slice + * of the next group was received. This avoids buffer underruns in subsequent + * filters of the filter chain. + */ +enum group_completion_status { + /** No complete group received so far. */ + GCS_NO_COMPLETE_GROUP, + /** First group received, but not yet decoded. */ + GCS_FIRST_GROUP_COMPLETE, + /** At least one complete group decoded. */ + GCS_FIRST_GROUP_DECODED, +}; + /** * Data private to the fecdec filter. */ @@ -76,7 +94,12 @@ struct private_fecdec_data { struct fec_parms *fec; /** Keeps track of what was received so far. */ struct fecdec_group groups[NUM_FEC_GROUPS]; + /** Whether an audio file header was already received. */ int have_header; + /** See \ref group_completion_status. */ + unsigned completion_status; + /** Points to the first received group. */ + struct fecdec_group *first_complete_group; }; /** Iterate over all fecdec groups. */ @@ -150,6 +173,13 @@ static struct fecdec_group *try_to_free_group(struct private_fecdec_data *pfd) FOR_EACH_FECDEC_GROUP(fg, pfd) { if (!group_complete(fg)) continue; + /* + * Don't clear the first complete group if it has not yet been + * decoded. + */ + if (pfd->completion_status == GCS_FIRST_GROUP_COMPLETE + && pfd->first_complete_group == fg) + continue; clear_group(fg); return fg; } @@ -168,6 +198,8 @@ static struct fecdec_group *free_oldest_group(struct private_fecdec_data *pfd) PARA_WARNING_LOG("Clearing incomplete group %d " "(contains %d slices)\n", oldest->h.group_num, oldest->num_received_slices); + assert(pfd->completion_status != GCS_FIRST_GROUP_COMPLETE + || oldest != pfd->first_complete_group); clear_group(oldest); return oldest; } @@ -208,8 +240,8 @@ static int add_slice(char *buf, struct fecdec_group *fg) int r, slice_num; if (group_complete(fg)) { - PARA_DEBUG_LOG("group complete, ignoring slice %d\n", - fg->h.slice_num); + PARA_DEBUG_LOG("group %d complete, ignoring slice %d\n", + fg->h.group_num, fg->h.slice_num); fg->num_received_slices++; return 0; } @@ -256,7 +288,7 @@ static enum fec_group_usability group_is_usable(struct fecdec_group *fg, static int decode_group(struct fecdec_group *fg, struct filter_node *fn) { int i, ret, sb = fg->h.slice_bytes; - size_t written = 0; + size_t written = 0, need; struct private_fecdec_data *pfd = fn->private_data; enum fec_group_usability u = group_is_usable(fg, pfd); @@ -264,7 +296,7 @@ static int decode_group(struct fecdec_group *fg, struct filter_node *fn) PARA_INFO_LOG("dropping unusable group %d\n", fg->h.group_num); return 0; } - PARA_DEBUG_LOG("decoding group %d %d slices\n", fg->h.group_num, + PARA_DEBUG_LOG("decoding group %d (%d slices)\n", fg->h.group_num, fg->h.data_slices_per_group); ret = fec_decode(pfd->fec, fg->data, fg->idx, sb); if (ret < 0) @@ -279,12 +311,18 @@ static int decode_group(struct fecdec_group *fg, struct filter_node *fn) PARA_DEBUG_LOG("writing group %d (%d/%d decoded data bytes)\n", fg->h.group_num, fg->h.group_bytes, fg->h.data_slices_per_group * sb); + need = fn->loaded + (fg->h.data_slices_per_group - i)* sb; + if (need > fn->bufsize) { + fn->bufsize = PARA_MAX(fn->bufsize * 2, need); + if (fn->bufsize > FECDEC_MAX_OUTBUF_SIZE) + return -E_FECDEC_OVERRUN; + PARA_INFO_LOG("increasing fec buf to %zu\n", fn->bufsize); + fn->buf = para_realloc(fn->buf, fn->bufsize); + } for (; i < fg->h.data_slices_per_group; i++) { size_t n = sb; if (n + written > fg->h.group_bytes) n = fg->h.group_bytes - written; - if (fn->loaded + n > fn->bufsize) - return -E_FECDEC_OVERRUN; memcpy(fn->buf + fn->loaded, fg->data[i], n); fn->loaded += n; written += n; @@ -330,7 +368,7 @@ static int dispatch_slice(char *buf, size_t len, struct fec_header *h, struct filter_node *fn) { struct fecdec_group *fg; - int ret; + int ret, k, n; struct private_fecdec_data *pfd = fn->private_data; if (h->slice_bytes > len) /* can not use the thing, try to read more */ @@ -341,17 +379,34 @@ static int dispatch_slice(char *buf, size_t len, struct fec_header *h, if (!add_slice(buf, fg)) return 1; if (group_complete(fg)) { - if (!pfd->fec) { - int k = h->data_slices_per_group, n = h->slices_per_group; - PARA_NOTICE_LOG("init fec (%d, %d)\n", k, n); - ret = fec_new(k, n, &pfd->fec); - if (ret < 0) - return ret; + if (pfd->completion_status == GCS_NO_COMPLETE_GROUP) { + pfd->completion_status = GCS_FIRST_GROUP_COMPLETE; + pfd->first_complete_group = fg; + return 1; } + assert(pfd->fec); ret = decode_group(fg, fn); if (ret < 0) return ret; + return 1; } + if (pfd->completion_status == GCS_NO_COMPLETE_GROUP) + return 1; + if (pfd->completion_status == GCS_FIRST_GROUP_DECODED) + return 1; + if (fg == pfd->first_complete_group) + return 1; + assert(!pfd->fec); + k = h->data_slices_per_group; + n = h->slices_per_group; + PARA_NOTICE_LOG("init fec (%d, %d)\n", k, n); + ret = fec_new(k, n, &pfd->fec); + if (ret < 0) + return ret; + ret = decode_group(pfd->first_complete_group, fn); + if (ret < 0) + return ret; + pfd->completion_status = GCS_FIRST_GROUP_DECODED; return 1; } @@ -391,9 +446,12 @@ static void fecdec_close(struct filter_node *fn) static void fecdec_open(struct filter_node *fn) { - fn->bufsize = FECDEC_OUTBUF_SIZE; + struct private_fecdec_data *pfd; + fn->bufsize = FECDEC_DEFAULT_OUTBUF_SIZE; fn->buf = para_malloc(fn->bufsize); - fn->private_data = para_calloc(sizeof(struct private_fecdec_data)); + pfd = para_calloc(sizeof(*pfd)); + pfd->completion_status = GCS_NO_COMPLETE_GROUP; + fn->private_data = pfd; fn->loaded = 0; }