X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=fecdec_filter.c;h=139a86fa1b7bf69ff832ca7a3fac755b68de5304;hp=ca9dcd739e23c6fe7e89d4ff67cec41686906318;hb=fae6ed3cc6d240eefcc111bdd04f637e3cda5dd0;hpb=72f7d7aca73e7848bcf6b841046893bf5e69f6b5 diff --git a/fecdec_filter.c b/fecdec_filter.c index ca9dcd73..139a86fa 100644 --- a/fecdec_filter.c +++ b/fecdec_filter.c @@ -72,20 +72,6 @@ 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. */ @@ -96,15 +82,13 @@ struct private_fecdec_data { 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. */ #define FOR_EACH_FECDEC_GROUP(g, d) for (g = (d)->groups; \ - (g) - (d)->groups < NUM_FEC_GROUPS; (g)++) + (g) < (d)->groups + NUM_FEC_GROUPS; (g)++) static int group_complete(struct fecdec_group *fg) { @@ -126,7 +110,9 @@ static void clear_group(struct fecdec_group *fg) fg->idx[i] = -1; } free(fg->data); + fg->data = NULL; free(fg->idx); + fg->idx = NULL; fg->num_slices = 0; memset(&fg->h, 0, sizeof(struct fec_header)); fg->num_received_slices = 0; @@ -177,8 +163,7 @@ static struct fecdec_group *try_to_free_group(struct private_fecdec_data *pfd) * 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) + if (fg == pfd->first_complete_group) continue; clear_group(fg); return fg; @@ -198,8 +183,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); + if (oldest == pfd->first_complete_group) + pfd->first_complete_group = NULL; clear_group(oldest); return oldest; } @@ -248,13 +233,13 @@ static int add_slice(char *buf, struct fecdec_group *fg) slice_num = fg->h.slice_num; if (fg->num_slices == 0) { fg->num_slices = fg->h.slices_per_group; - fg->idx = malloc(fg->num_slices * sizeof(int)); - fg->data = malloc(fg->num_slices * sizeof(unsigned char *)); + fg->idx = para_malloc(fg->num_slices * sizeof(int)); + fg->data = para_malloc(fg->num_slices * sizeof(unsigned char *)); memset(fg->data, 0, fg->num_slices * sizeof(unsigned char *)); } r = fg->num_received_slices; fg->idx[r] = slice_num; - fg->data[r] = malloc(fg->h.slice_bytes); + fg->data[r] = para_malloc(fg->h.slice_bytes); memcpy(fg->data[r], buf, fg->h.slice_bytes); fg->num_received_slices++; return 1; @@ -264,6 +249,7 @@ enum fec_group_usability { FEC_GROUP_UNUSABLE, FEC_GROUP_USABLE, FEC_GROUP_USABLE_SKIP_HEADER, + FEC_GROUP_USABLE_WITH_HEADER }; static enum fec_group_usability group_is_usable(struct fecdec_group *fg, @@ -281,14 +267,14 @@ static enum fec_group_usability group_is_usable(struct fecdec_group *fg, if (fg->h.bos) return FEC_GROUP_USABLE; if (fg->h.audio_header_size) - return FEC_GROUP_USABLE; + return FEC_GROUP_USABLE_WITH_HEADER; return FEC_GROUP_UNUSABLE; } static int decode_group(struct fecdec_group *fg, struct filter_node *fn) { int i, ret, sb = fg->h.slice_bytes; - size_t written = 0, need; + size_t written, need; struct private_fecdec_data *pfd = fn->private_data; enum fec_group_usability u = group_is_usable(fg, pfd); @@ -319,6 +305,21 @@ static int decode_group(struct fecdec_group *fg, struct filter_node *fn) PARA_INFO_LOG("increasing fec buf to %zu\n", fn->bufsize); fn->buf = para_realloc(fn->buf, fn->bufsize); } + if (u == FEC_GROUP_USABLE_WITH_HEADER) { + PARA_INFO_LOG("writing audio file header\n"); + written = 0; + for (i = 0; i < fg->h.data_slices_per_group; i++) { + size_t n = sb; + if (written >= fg->h.audio_header_size) + break; + if (sb + written > fg->h.audio_header_size) + n = fg->h.audio_header_size - written; + memcpy(fn->buf + fn->loaded, fg->data[i], n); + fn->loaded += n; + written += n; + } + } + written = 0; for (; i < fg->h.data_slices_per_group; i++) { size_t n = sb; if (n + written > fg->h.group_bytes) @@ -376,37 +377,39 @@ static int dispatch_slice(char *buf, size_t len, struct fec_header *h, ret = get_group(h, pfd, &fg); if (ret < 0) return ret; - if (!add_slice(buf, fg)) + if (!add_slice(buf, fg)) /* group already complete */ return 1; - if (group_complete(fg)) { - if (pfd->completion_status == GCS_NO_COMPLETE_GROUP) { - pfd->completion_status = GCS_FIRST_GROUP_COMPLETE; - pfd->first_complete_group = fg; + if (!group_complete(fg)) + return 1; + /* this slice completed the group */ + if (pfd->fec) + goto decode; + /* it's either the first or the second complete group */ + if (!pfd->first_complete_group) { /* it's the first group */ + enum fec_group_usability u = group_is_usable(fg, pfd); + assert(u != FEC_GROUP_USABLE_SKIP_HEADER); + if (u == FEC_GROUP_UNUSABLE) /* forget it */ return 1; - } - assert(pfd->fec); - ret = decode_group(fg, fn); - if (ret < 0) - return ret; + pfd->first_complete_group = fg; /* remember it */ 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); + /* we have two complete groups, let's go */ 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; + /* decode and clear the first group */ ret = decode_group(pfd->first_complete_group, fn); if (ret < 0) return ret; - pfd->completion_status = GCS_FIRST_GROUP_DECODED; + clear_group(pfd->first_complete_group); + pfd->first_complete_group = NULL; +decode: + ret = decode_group(fg, fn); + if (ret < 0) + return ret; return 1; } @@ -450,7 +453,6 @@ static void fecdec_open(struct filter_node *fn) fn->bufsize = FECDEC_DEFAULT_OUTBUF_SIZE; fn->buf = para_malloc(fn->bufsize); pfd = para_calloc(sizeof(*pfd)); - pfd->completion_status = GCS_NO_COMPLETE_GROUP; fn->private_data = pfd; fn->loaded = 0; }