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.
*/
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;
};
* 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;
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;
}
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) {
- enum fec_group_usability u = group_is_usable(fg, pfd);
- assert(u != FEC_GROUP_USABLE_SKIP_HEADER);
- if (u == FEC_GROUP_UNUSABLE)
- return 1;
- 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;
}
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;
}