Add btr support to the oggdec filter.
[paraslash.git] / fecdec_filter.c
index 2c63fc6b00ac6d671f74142ac74060bacece8bed..901a91694b3f22c71e3ead710da95d0faed0391b 100644 (file)
@@ -7,6 +7,7 @@
 /** \file fecdec_filter.c A filter that fec-decodes an audio stream. */
 
 #include <regex.h>
+#include <stdbool.h>
 
 #include <dirent.h>
 #include "para.h"
@@ -14,6 +15,7 @@
 #include "list.h"
 #include "sched.h"
 #include "ggo.h"
+#include "buffer_tree.h"
 #include "filter.h"
 #include "string.h"
 #include "portable_io.h"
@@ -40,7 +42,7 @@ struct fec_header {
        uint8_t slices_per_group;
        /** Number of slices needed to start decoding. */
        uint8_t data_slices_per_group;
-       /** Size of the ogg vorbis header (zero for mp3, aac). */
+       /** Size of the ogg vorbis/wma header (zero for mp3, aac). */
        uint32_t audio_header_size;
        /** Number of the FEC group this slice belongs to. */
        uint32_t group_num;
@@ -72,20 +74,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,8 +84,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;
 };
@@ -126,7 +112,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 +165,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 +185,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;
 }
@@ -260,10 +247,21 @@ static int add_slice(char *buf, struct fecdec_group *fg)
        return 1;
 }
 
+/**
+ * The different states of a complete FEC group.
+ *
+ * Even if a FEC group has been received successfully, it probably can not be
+ * used right away because some streams (ogg, wma) need to receive an audio
+ * file header before decoding can start.
+ */
 enum fec_group_usability {
+       /** Drop the group (because we did not receive the header yet). */
        FEC_GROUP_UNUSABLE,
+       /** Use all data in the group. */
        FEC_GROUP_USABLE,
+       /** Use the group, but drop its audio file header. */
        FEC_GROUP_USABLE_SKIP_HEADER,
+       /** Use the group, including its header. */
        FEC_GROUP_USABLE_WITH_HEADER
 };
 
@@ -392,41 +390,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;
 }
 
@@ -470,7 +466,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;
 }