X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=fecdec_filter.c;h=8ccc2ee2b344371e369e0c2df5c792616f5d2374;hp=5f37f1a81f9199f6080b6669cd455d706a96af06;hb=e7e55d0ad711a46e4768066be197bb41caa5c5eb;hpb=345e7b4adce741621a412c3845712e8540b572ad diff --git a/fecdec_filter.c b/fecdec_filter.c index 5f37f1a8..8ccc2ee2 100644 --- a/fecdec_filter.c +++ b/fecdec_filter.c @@ -4,7 +4,10 @@ * 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 #include "para.h" @@ -12,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" @@ -27,16 +31,13 @@ */ #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 */ - /** Data read from the header of a slice. */ struct fec_header { /** Total number of slices in this group. */ 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; @@ -76,12 +77,16 @@ 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; + /** Points to the first received group. */ + struct fecdec_group *first_complete_group; + struct btr_pool *btrp; }; /** 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) { @@ -103,7 +108,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; @@ -150,6 +157,12 @@ 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 (fg == pfd->first_complete_group) + continue; clear_group(fg); return fg; } @@ -168,6 +181,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); + if (oldest == pfd->first_complete_group) + pfd->first_complete_group = NULL; clear_group(oldest); return oldest; } @@ -208,30 +223,42 @@ 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; } 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; } +/** + * 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 }; static enum fec_group_usability group_is_usable(struct fecdec_group *fg, @@ -249,22 +276,23 @@ 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; + size_t written, need; struct private_fecdec_data *pfd = fn->private_data; enum fec_group_usability u = group_is_usable(fg, pfd); + char *buf = NULL, *p; if (u == FEC_GROUP_UNUSABLE) { 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,16 +307,34 @@ 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 = (fg->h.data_slices_per_group - i) * sb; + if (need > btr_pool_unused(pfd->btrp)) + return -E_FECDEC_OVERRUN; + btr_pool_get_buffer(pfd->btrp, &buf); + p = buf; + 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; + btr_copy(fg->data[i], n, pfd->btrp, fn->btrn); + written += n; + } + p += written; + } + written = 0; 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; + btr_copy(fg->data[i], n, pfd->btrp, fn->btrn); written += n; } + p += written; return 0; } @@ -330,49 +376,51 @@ 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 */ + if (h->slice_bytes > len) { /* can not use the thing, try to read more */ + fn->min_iqs = h->slice_bytes + FEC_HEADER_SIZE; return 0; + } 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)) + 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; + pfd->first_complete_group = fg; /* remember it */ 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; - } - ret = decode_group(fg, fn); - if (ret < 0) - return ret; } - return 1; -} - -static ssize_t fecdec(char *buf, size_t len, struct filter_node *fn) -{ - int ret; - struct fec_header h; - - ret = read_fec_header(buf, len, &h); - if (ret <= 0) + /* 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; - if (!h.slice_bytes || h.slice_bytes > fn->bufsize) - return -E_BAD_SLICE_SIZE; - if (h.slice_num > h.slices_per_group) - return -E_BAD_SLICE_NUM; - ret = dispatch_slice(buf + FEC_HEADER_SIZE, len - FEC_HEADER_SIZE, - &h, fn); - //PARA_INFO_LOG("ret: %d, len: %d, slice_bytes: %d\n", ret, len, h.slice_bytes); - if (ret <= 0) + pfd->btrp = btr_pool_new("fecdec", 20 * k * h->slice_bytes); + /* decode and clear the first group */ + ret = decode_group(pfd->first_complete_group, fn); + if (ret < 0) return ret; - return FEC_HEADER_SIZE + h.slice_bytes; + clear_group(pfd->first_complete_group); + pfd->first_complete_group = NULL; +decode: + ret = decode_group(fg, fn); + if (ret < 0) + return ret; + return 1; } static void fecdec_close(struct filter_node *fn) @@ -382,29 +430,65 @@ static void fecdec_close(struct filter_node *fn) FOR_EACH_FECDEC_GROUP(fg, pfd) clear_group(fg); - free(fn->buf); - fn->buf = NULL; fec_free(pfd->fec); free(fn->private_data); fn->private_data = NULL; } +static void fecdec_post_select(__a_unused struct sched *s, struct task *t) +{ + struct filter_node *fn = container_of(t, struct filter_node, task); + struct btr_node *btrn = fn->btrn; + int ret; + struct fec_header h; + char *buf; + size_t len; + +next_buffer: + ret = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL); + if (ret <= 0) + goto out; + btr_merge(btrn, fn->min_iqs); + len = btr_next_buffer(btrn, &buf); + ret = read_fec_header(buf, len, &h); + if (ret <= 0) + goto out; + ret = -E_BAD_SLICE_SIZE; + if (!h.slice_bytes) + goto out; + ret = -E_BAD_SLICE_NUM; + if (h.slice_num > h.slices_per_group) + goto out; + ret = dispatch_slice(buf + FEC_HEADER_SIZE, len - FEC_HEADER_SIZE, + &h, fn); + //PARA_INFO_LOG("ret: %d, len: %d, slice_bytes: %d\n", ret, len, h.slice_bytes); + if (ret <= 0) + goto out; + btr_consume(btrn, FEC_HEADER_SIZE + h.slice_bytes); + goto next_buffer; +out: + t->error = ret; + if (ret < 0) + btr_remove_node(btrn); +} + static void fecdec_open(struct filter_node *fn) { - fn->bufsize = FECDEC_OUTBUF_SIZE; - fn->buf = para_malloc(fn->bufsize); - fn->private_data = para_calloc(sizeof(struct private_fecdec_data)); - fn->loaded = 0; + struct private_fecdec_data *pfd; + pfd = para_calloc(sizeof(*pfd)); + fn->private_data = pfd; + fn->min_iqs = FEC_HEADER_SIZE; } /** * The init function of the fecdec filter. * - * \param f struct to initialize. + * \param f Struct to initialize. */ void fecdec_filter_init(struct filter *f) { - f->convert = fecdec; f->close = fecdec_close; f->open = fecdec_open; + f->pre_select = generic_filter_pre_select; + f->post_select = fecdec_post_select; }