X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=fecdec_filter.c;h=1b95ea4c5fd76ca926e8caec733243947254c7ca;hp=ca7c7dd3522eae673469baee46e7a7471e7fac72;hb=4adde8dae3317fa83b81e7a860c9ed9133e99bb0;hpb=a694ab16b6ff43b545ccd530360b7224433a5b76 diff --git a/fecdec_filter.c b/fecdec_filter.c index ca7c7dd3..1b95ea4c 100644 --- a/fecdec_filter.c +++ b/fecdec_filter.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Andre Noll + * Copyright (C) 2009 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -8,12 +8,11 @@ #include -#include #include "para.h" #include "error.h" #include "list.h" #include "sched.h" -#include "ggo.h" +#include "buffer_tree.h" #include "filter.h" #include "string.h" #include "portable_io.h" @@ -29,18 +28,13 @@ */ #define NUM_FEC_GROUPS 3 -/** Default size of the output buffer of the fecdec filter. */ -#define FECDEC_DEFAULT_OUTBUF_SIZE (3 * 1024) -/** Maximal size of the output buffer of the fecdec filter. */ -#define FECDEC_MAX_OUTBUF_SIZE (1024 * 1024) - /** 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; @@ -52,7 +46,7 @@ struct fec_header { uint16_t slice_bytes; /** Non-zero if this group is the beginning of the stream. */ uint8_t bos; - /** Non-zero if this stream embedds audio headers into fec groups. */ + /** Non-zero if this stream embeds audio headers into fec groups. */ uint8_t header_stream; }; @@ -64,6 +58,8 @@ struct fecdec_group { struct fec_header h; /** How many slices received so far. */ int num_received_slices; + /** Bitmap of received slices. */ + uint8_t received_slices[32]; /** The size of the \a idx and the \a data arrays below. */ int num_slices; /** Array of indices of the received slices. */ @@ -84,6 +80,7 @@ struct private_fecdec_data { int have_header; /** Points to the first received group. */ struct fecdec_group *first_complete_group; + struct btr_pool *btrp; }; /** Iterate over all fecdec groups. */ @@ -104,18 +101,11 @@ static void clear_group(struct fecdec_group *fg) { int i; - for (i = 0; i < fg->num_slices; i++) { + for (i = 0; i < fg->num_slices; i++) free(fg->data[i]); - fg->data[i] = NULL; - 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; + memset(fg, 0, sizeof(*fg)); } static int find_group(struct fec_header *h, @@ -180,7 +170,7 @@ static struct fecdec_group *free_oldest_group(struct private_fecdec_data *pfd) oldest = fg; } if (!group_complete(oldest) && !group_empty(oldest)) - PARA_WARNING_LOG("Clearing incomplete group %d " + PARA_WARNING_LOG("Clearing incomplete group %u " "(contains %d slices)\n", oldest->h.group_num, oldest->num_received_slices); if (oldest == pfd->first_complete_group) @@ -215,29 +205,40 @@ success: return ret; } +static bool test_and_set_slice_bit(struct fecdec_group *fg, uint8_t slice_num) +{ + uint8_t *p = fg->received_slices + slice_num / 8, old = *p; + + *p |= 1 << (slice_num % 8); + return old == *p; +} + /* * returns 1 if slice was added, zero otherwise (because the group was already - * complete). In any case the number of received slices is being increased by - * one. + * complete or a slice has been received twice). */ static int add_slice(char *buf, struct fecdec_group *fg) { - int r, slice_num; + int r; + uint8_t slice_num = fg->h.slice_num; if (group_complete(fg)) { - PARA_DEBUG_LOG("group %d complete, ignoring slice %d\n", - fg->h.group_num, fg->h.slice_num); - fg->num_received_slices++; + PARA_DEBUG_LOG("group %u complete, ignoring slice %d\n", + fg->h.group_num, slice_num); return 0; } - slice_num = fg->h.slice_num; if (fg->num_slices == 0) { fg->num_slices = fg->h.slices_per_group; 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 *)); + fg->data = para_calloc(fg->num_slices * sizeof(unsigned char *)); } r = fg->num_received_slices; + /* Check if we already have this slice. */ + if (test_and_set_slice_bit(fg, slice_num)) { + PARA_INFO_LOG("ignoring duplicate slice %u:%d\n", fg->h.group_num, + slice_num); + return 0; + } fg->idx[r] = slice_num; fg->data[r] = para_malloc(fg->h.slice_bytes); memcpy(fg->data[r], buf, fg->h.slice_bytes); @@ -288,12 +289,13 @@ static int decode_group(struct fecdec_group *fg, struct filter_node *fn) 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; if (u == FEC_GROUP_UNUSABLE) { - PARA_INFO_LOG("dropping unusable group %d\n", fg->h.group_num); + PARA_INFO_LOG("dropping unusable group %u\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 %u (%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) @@ -301,21 +303,16 @@ static int decode_group(struct fecdec_group *fg, struct filter_node *fn) pfd->have_header = 1; i = 0; if (u == FEC_GROUP_USABLE_SKIP_HEADER) { - i = ROUND_UP(fg->h.audio_header_size, fg->h.slice_bytes) - / fg->h.slice_bytes; + i = DIV_ROUND_UP(fg->h.audio_header_size, fg->h.slice_bytes); PARA_DEBUG_LOG("skipping %d header slices\n", i); } - PARA_DEBUG_LOG("writing group %d (%d/%d decoded data bytes)\n", + PARA_DEBUG_LOG("writing group %u (%u/%d decoded data bytes)\n", fg->h.group_num, fg->h.group_bytes, fg->h.data_slices_per_group * sb); - need = fn->loaded + (fg->h.data_slices_per_group - i)* sb; - if (need > fn->bufsize) { - fn->bufsize = PARA_MAX(fn->bufsize * 2, need); - if (fn->bufsize > FECDEC_MAX_OUTBUF_SIZE) - return -E_FECDEC_OVERRUN; - PARA_INFO_LOG("increasing fec buf to %zu\n", fn->bufsize); - fn->buf = para_realloc(fn->buf, fn->bufsize); - } + 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); if (u == FEC_GROUP_USABLE_WITH_HEADER) { PARA_INFO_LOG("writing audio file header\n"); written = 0; @@ -325,8 +322,7 @@ static int decode_group(struct fecdec_group *fg, struct filter_node *fn) 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; + btr_copy(fg->data[i], n, pfd->btrp, fn->btrn); written += n; } } @@ -335,8 +331,7 @@ static int decode_group(struct fecdec_group *fg, struct filter_node *fn) size_t n = sb; if (n + written > fg->h.group_bytes) n = fg->h.group_bytes - written; - memcpy(fn->buf + fn->loaded, fg->data[i], n); - fn->loaded += n; + btr_copy(fg->data[i], n, pfd->btrp, fn->btrn); written += n; } return 0; @@ -383,8 +378,10 @@ static int dispatch_slice(char *buf, size_t len, struct fec_header *h, 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; @@ -411,6 +408,7 @@ static int dispatch_slice(char *buf, size_t len, struct fec_header *h, ret = fec_new(k, n, &pfd->fec); if (ret < 0) return ret; + pfd->btrp = btr_pool_new("fecdec", 128 * 1024); /* decode and clear the first group */ ret = decode_group(pfd->first_complete_group, fn); if (ret < 0) @@ -424,58 +422,67 @@ decode: return 1; } -static ssize_t fecdec(char *buf, size_t len, struct filter_node *fn) +static void fecdec_close(struct filter_node *fn) { + struct private_fecdec_data *pfd = fn->private_data; + struct fecdec_group *fg; + + FOR_EACH_FECDEC_GROUP(fg, pfd) + clear_group(fg); + fec_free(pfd->fec); + btr_pool_free(pfd->btrp); + free(fn->private_data); + fn->private_data = NULL; +} + +static int fecdec_post_select(__a_unused struct sched *s, void *context) +{ + struct filter_node *fn = context; + 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) - return ret; + goto out; + ret = -E_BAD_SLICE_SIZE; if (!h.slice_bytes) - return -E_BAD_SLICE_SIZE; + goto out; + ret = -E_BAD_SLICE_NUM; if (h.slice_num > h.slices_per_group) - return -E_BAD_SLICE_NUM; + 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) - return ret; - return FEC_HEADER_SIZE + h.slice_bytes; -} - -static void fecdec_close(struct filter_node *fn) -{ - struct private_fecdec_data *pfd = fn->private_data; - struct fecdec_group *fg; - - 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; + goto out; + btr_consume(btrn, FEC_HEADER_SIZE + h.slice_bytes); + goto next_buffer; +out: + if (ret < 0) + btr_remove_node(&fn->btrn); + return ret; } static void fecdec_open(struct filter_node *fn) { struct private_fecdec_data *pfd; - fn->bufsize = FECDEC_DEFAULT_OUTBUF_SIZE; - fn->buf = para_malloc(fn->bufsize); pfd = para_calloc(sizeof(*pfd)); fn->private_data = pfd; - fn->loaded = 0; + fn->min_iqs = FEC_HEADER_SIZE; } -/** - * The init function of the fecdec filter. - * - * \param f struct to initialize. - */ -void fecdec_filter_init(struct filter *f) -{ - f->convert = fecdec; - f->close = fecdec_close; - f->open = fecdec_open; -} +const struct filter lsg_filter_cmd_com_fecdec_user_data = { + .open = fecdec_open, + .pre_select = generic_filter_pre_select, + .post_select = fecdec_post_select, + .close = fecdec_close, +};