X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=fecdec_filter.c;h=5f37f1a81f9199f6080b6669cd455d706a96af06;hp=721fc09443011c7bfcc53e2f655f171e9cef3d8c;hb=44c5fe64eebb185ecc7a406c3db26721834dbea4;hpb=625c5cd993d07a63061a0788f174e12fa1c221e0 diff --git a/fecdec_filter.c b/fecdec_filter.c index 721fc094..5f37f1a8 100644 --- a/fecdec_filter.c +++ b/fecdec_filter.c @@ -4,7 +4,7 @@ * Licensed under the GPL v2. For licencing details see COPYING. */ -/** \file fecdev_filter.c A filter fec-decodes an audio stream. */ +/** \file fecdec_filter.c A filter fec-decodes an audio stream. */ #include #include "para.h" @@ -18,63 +18,85 @@ #include "fec.h" #include "fd.h" +/** + * How many FEC groups to store in memory. + * + * Packet reordering requires to keep more than one FEC group in memory because + * slices belonging to the next FEC group may arrive before the current FEC group + * is complete. + */ #define NUM_FEC_GROUPS 3 -#define INPUT_BUFFER_SIZE 16384 -/** size of the output buffer */ -#define FECDEC_OUTBUF_SIZE 81920 +/** 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). */ uint32_t audio_header_size; - + /** Number of the FEC group this slice belongs to. */ uint32_t group_num; + /** Size of the data in this FEC group. */ uint32_t group_bytes; - + /** Number of this slice in the group. */ uint8_t slice_num; + /** Used data bytes of this slice. */ 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. */ + uint8_t header_stream; }; -struct fec_group { +/** + * The status of one partially received FEC group. + */ +struct fecdec_group { + /** The header read from the last slice. */ struct fec_header h; + /** How many slices received so far. */ int num_received_slices; + /** The size of the \a idx and the \a data arrays below. */ int num_slices; + /** Array of indices of the received slices. */ int *idx; + /** Content of the received slices. */ unsigned char **data; }; +/** + * Data private to the fecdec filter. + */ struct private_fecdec_data { + /** Used by the fec core code. */ struct fec_parms *fec; - struct fec_group groups[NUM_FEC_GROUPS]; + /** Keeps track of what was received so far. */ + struct fecdec_group groups[NUM_FEC_GROUPS]; + int have_header; }; -#define FOR_EACH_FEC_GROUP(g, d) for (g = (d)->groups; \ +/** Iterate over all fecdec groups. */ +#define FOR_EACH_FECDEC_GROUP(g, d) for (g = (d)->groups; \ (g) - (d)->groups < NUM_FEC_GROUPS; (g)++) -#define UNUSED_GROUP_NUM 0xffffffff - -static int group_complete(struct fec_group *fg) +static int group_complete(struct fecdec_group *fg) { - if (fg->h.group_num == UNUSED_GROUP_NUM) - return 0; - //PARA_INFO_LOG("received slices: %u, slices per group: %u\n", fg->num_received_slices, fg->h.data_slices_per_group); return fg->num_received_slices >= fg->h.data_slices_per_group; } -static int group_empty(struct fec_group *fg) +static int group_empty(struct fecdec_group *fg) { return fg->num_received_slices == 0; } -static void clear_group(struct fec_group *fg) +static void clear_group(struct fecdec_group *fg) { int i; - if (!group_complete(fg) && !group_empty(fg)) - PARA_WARNING_LOG("Clearing incomplete group %d " - "(contains %d slices)\n", fg->h.group_num, - fg->num_received_slices); for (i = 0; i < fg->num_slices; i++) { free(fg->data[i]); fg->data[i] = NULL; @@ -85,39 +107,47 @@ static void clear_group(struct fec_group *fg) fg->num_slices = 0; memset(&fg->h, 0, sizeof(struct fec_header)); fg->num_received_slices = 0; - fg->h.group_num = UNUSED_GROUP_NUM; } static int find_group(struct fec_header *h, - struct private_fecdec_data *pfd, struct fec_group **result) + struct private_fecdec_data *pfd, struct fecdec_group **result) { - struct fec_group *fg; + struct fecdec_group *fg; - FOR_EACH_FEC_GROUP(fg, pfd) { + FOR_EACH_FECDEC_GROUP(fg, pfd) { if (fg->h.group_num != h->group_num) continue; + if (fg->num_received_slices == 0) + goto success; + if (fg->h.slices_per_group != h->slices_per_group) + return -E_BAD_FEC_HEADER; + if (fg->h.data_slices_per_group != h->data_slices_per_group) + return -E_BAD_FEC_HEADER; + if (fg->h.group_bytes != h->group_bytes) + return -E_BAD_FEC_HEADER; +success: *result = fg; return 1; } return 0; } -static struct fec_group *find_unused_group(struct private_fecdec_data *pfd) +static struct fecdec_group *find_unused_group(struct private_fecdec_data *pfd) { - struct fec_group *fg; + struct fecdec_group *fg; - FOR_EACH_FEC_GROUP(fg, pfd) { + FOR_EACH_FECDEC_GROUP(fg, pfd) { if (fg->num_received_slices == 0) return fg; } return NULL; } -static struct fec_group *try_to_free_group(struct private_fecdec_data *pfd) +static struct fecdec_group *try_to_free_group(struct private_fecdec_data *pfd) { - struct fec_group *fg; + struct fecdec_group *fg; - FOR_EACH_FEC_GROUP(fg, pfd) { + FOR_EACH_FECDEC_GROUP(fg, pfd) { if (!group_complete(fg)) continue; clear_group(fg); @@ -126,22 +156,27 @@ static struct fec_group *try_to_free_group(struct private_fecdec_data *pfd) return NULL; } -static struct fec_group *free_oldest_group(struct private_fecdec_data *pfd) +static struct fecdec_group *free_oldest_group(struct private_fecdec_data *pfd) { - struct fec_group *fg, *oldest = NULL; + struct fecdec_group *fg, *oldest = NULL; - FOR_EACH_FEC_GROUP(fg, pfd) { + FOR_EACH_FECDEC_GROUP(fg, pfd) { if (!oldest || oldest->h.group_num > fg->h.group_num) oldest = fg; } + if (!group_complete(oldest) && !group_empty(oldest)) + PARA_WARNING_LOG("Clearing incomplete group %d " + "(contains %d slices)\n", oldest->h.group_num, + oldest->num_received_slices); clear_group(oldest); return oldest; } +/* returns 1 if the group was found, 0 if not, negative on errors */ static int get_group(struct fec_header *h, struct private_fecdec_data *pfd, - struct fec_group **result) + struct fecdec_group **result) { - struct fec_group *fg; + struct fecdec_group *fg; int ret = find_group(h, pfd, &fg); if (ret < 0) @@ -151,24 +186,33 @@ static int get_group(struct fec_header *h, struct private_fecdec_data *pfd, /* group not found */ fg = find_unused_group(pfd); if (fg) - goto update_header; + goto success; fg = try_to_free_group(pfd); if (fg) - goto update_header; + goto success; fg = free_oldest_group(pfd); -update_header: - fg->h = *h; + ret = 0; success: + fg->h = *h; *result = fg; - return 1; + return ret; } -static int add_slice(char *buf, struct fec_group *fg) +/* + * 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. + */ +static int add_slice(char *buf, struct fecdec_group *fg) { int r, slice_num; - if (group_complete(fg)) + if (group_complete(fg)) { + PARA_DEBUG_LOG("group complete, ignoring slice %d\n", + 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; @@ -184,19 +228,58 @@ static int add_slice(char *buf, struct fec_group *fg) return 1; } -static int decode_group(struct fec_group *fg, struct filter_node *fn) +enum fec_group_usability { + FEC_GROUP_UNUSABLE, + FEC_GROUP_USABLE, + FEC_GROUP_USABLE_SKIP_HEADER, +}; + +static enum fec_group_usability group_is_usable(struct fecdec_group *fg, + struct private_fecdec_data *pfd) +{ + struct fec_header *h = &fg->h; + + if (!h->header_stream) + return FEC_GROUP_USABLE; + if (pfd->have_header) { + if (h->audio_header_size) + return FEC_GROUP_USABLE_SKIP_HEADER; + return FEC_GROUP_USABLE; + } + if (fg->h.bos) + return FEC_GROUP_USABLE; + if (fg->h.audio_header_size) + return FEC_GROUP_USABLE; + 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; struct private_fecdec_data *pfd = fn->private_data; + enum fec_group_usability u = group_is_usable(fg, pfd); + 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, + fg->h.data_slices_per_group); ret = fec_decode(pfd->fec, fg->data, fg->idx, sb); if (ret < 0) return ret; + 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; + PARA_DEBUG_LOG("skipping %d header slices\n", i); + } 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); - for (i = 0; i < fg->h.data_slices_per_group; i++) { + 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; @@ -233,17 +316,20 @@ static int read_fec_header(char *buf, size_t len, struct fec_header *h) h->slice_num = read_u8(buf + 18); h->slice_bytes = read_u16(buf + 20); - if (!h->group_bytes && & h->slice_bytes) + h->bos = read_u8(buf + 22); + h->header_stream = read_u8(buf + 23); + if (!memcmp(buf, FEC_EOF_PACKET, FEC_EOF_PACKET_LEN)) return -E_FECDEC_EOF; // PARA_DEBUG_LOG("group %u, slize %u, slices per group: %u\n", // h->group_num, h->slice_num, h->slices_per_group); return 1; } +/* returns 1 if we used the buffer, 0 if we didn't, negative on errors */ static int dispatch_slice(char *buf, size_t len, struct fec_header *h, struct filter_node *fn) { - struct fec_group *fg; + struct fecdec_group *fg; int ret; struct private_fecdec_data *pfd = fn->private_data; @@ -252,15 +338,8 @@ 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 (group_complete(fg)) { - PARA_DEBUG_LOG("group complete, ignoring slice %d\n", - h->slice_num); + if (!add_slice(buf, fg)) return 1; - } - fg->h = *h; - ret = add_slice(buf, fg); - if (ret < 0) - return ret; if (group_complete(fg)) { if (!pfd->fec) { int k = h->data_slices_per_group, n = h->slices_per_group; @@ -276,7 +355,7 @@ static int dispatch_slice(char *buf, size_t len, struct fec_header *h, return 1; } -static int fecdec(char *buf, size_t len, struct filter_node *fn) +static ssize_t fecdec(char *buf, size_t len, struct filter_node *fn) { int ret; struct fec_header h; @@ -284,7 +363,7 @@ static int fecdec(char *buf, size_t len, struct filter_node *fn) ret = read_fec_header(buf, len, &h); if (ret <= 0) return ret; - if (h.slice_bytes > INPUT_BUFFER_SIZE) + 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; @@ -299,12 +378,13 @@ static int 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 fec_group *fg; + struct fecdec_group *fg; - FOR_EACH_FEC_GROUP(fg, pfd) + 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; }