fecdec: Wait until the second FEC group is complete.
authorAndre Noll <maan@systemlinux.org>
Mon, 30 Nov 2009 22:50:48 +0000 (23:50 +0100)
committerAndre Noll <maan@systemlinux.org>
Mon, 30 Nov 2009 22:50:48 +0000 (23:50 +0100)
Currently the fecdec filter starts writing output as soon as the first slice of the
second group arrives. This makes the logic in fecdec_filter.c quite convoluted
and does not help much to avoid buffer underruns.

Waiting for completion of the second group simplifies the code quite a bit and
adds more more buffering to the fecdec filter which should make buffer underruns
less likely.

fecdec_filter.c

index 18dcb34..a6218e4 100644 (file)
@@ -70,20 +70,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.
  */
@@ -94,8 +80,6 @@ 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;
 };
@@ -175,8 +159,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;
@@ -196,8 +179,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;
 }
@@ -390,41 +373,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) {
-                       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;
 }
 
@@ -468,7 +449,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;
 }