2 * Copyright (C) 2009 Andre Noll <maan@systemlinux.org>
4 * Licensed under the GPL v2. For licencing details see COPYING.
7 /** \file fecdev_filter.c A filter fec-decodes an audio stream. */
17 #include "portable_io.h"
21 #define NUM_FEC_GROUPS 3
22 #define INPUT_BUFFER_SIZE 16384
24 /** size of the output buffer */
25 #define FECDEC_OUTBUF_SIZE 81920
28 uint8_t slices_per_group
;
29 uint8_t data_slices_per_group
;
30 uint32_t audio_header_size
;
41 int num_received_slices
;
47 struct private_fecdec_data
{
48 struct fec_parms
*fec
;
49 struct fec_group groups
[NUM_FEC_GROUPS
];
52 #define FOR_EACH_FEC_GROUP(g, d) for (g = (d)->groups; \
53 (g) - (d)->groups < NUM_FEC_GROUPS; (g)++)
55 #define UNUSED_GROUP_NUM 0xffffffff
57 static int group_complete(struct fec_group
*fg
)
59 if (fg
->h
.group_num
== UNUSED_GROUP_NUM
)
61 //PARA_INFO_LOG("received slices: %u, slices per group: %u\n", fg->num_received_slices, fg->h.data_slices_per_group);
62 return fg
->num_received_slices
>= fg
->h
.data_slices_per_group
;
65 static int group_empty(struct fec_group
*fg
)
67 return fg
->num_received_slices
== 0;
70 static void clear_group(struct fec_group
*fg
)
74 if (!group_complete(fg
) && !group_empty(fg
))
75 PARA_WARNING_LOG("Clearing incomplete group %d "
76 "(contains %d slices)\n", fg
->h
.group_num
,
77 fg
->num_received_slices
);
78 for (i
= 0; i
< fg
->num_slices
; i
++) {
86 memset(&fg
->h
, 0, sizeof(struct fec_header
));
87 fg
->num_received_slices
= 0;
88 fg
->h
.group_num
= UNUSED_GROUP_NUM
;
91 static int find_group(struct fec_header
*h
,
92 struct private_fecdec_data
*pfd
, struct fec_group
**result
)
96 FOR_EACH_FEC_GROUP(fg
, pfd
) {
97 if (fg
->h
.group_num
!= h
->group_num
)
105 static struct fec_group
*find_unused_group(struct private_fecdec_data
*pfd
)
107 struct fec_group
*fg
;
109 FOR_EACH_FEC_GROUP(fg
, pfd
) {
110 if (fg
->num_received_slices
== 0)
116 static struct fec_group
*try_to_free_group(struct private_fecdec_data
*pfd
)
118 struct fec_group
*fg
;
120 FOR_EACH_FEC_GROUP(fg
, pfd
) {
121 if (!group_complete(fg
))
129 static struct fec_group
*free_oldest_group(struct private_fecdec_data
*pfd
)
131 struct fec_group
*fg
, *oldest
= NULL
;
133 FOR_EACH_FEC_GROUP(fg
, pfd
) {
134 if (!oldest
|| oldest
->h
.group_num
> fg
->h
.group_num
)
141 static int get_group(struct fec_header
*h
, struct private_fecdec_data
*pfd
,
142 struct fec_group
**result
)
144 struct fec_group
*fg
;
145 int ret
= find_group(h
, pfd
, &fg
);
149 if (ret
> 0) /* found group */
151 /* group not found */
152 fg
= find_unused_group(pfd
);
155 fg
= try_to_free_group(pfd
);
158 fg
= free_oldest_group(pfd
);
166 static int add_slice(char *buf
, struct fec_group
*fg
)
170 if (group_complete(fg
))
172 slice_num
= fg
->h
.slice_num
;
173 if (fg
->num_slices
== 0) {
174 fg
->num_slices
= fg
->h
.slices_per_group
;
175 fg
->idx
= malloc(fg
->num_slices
* sizeof(int));
176 fg
->data
= malloc(fg
->num_slices
* sizeof(unsigned char *));
177 memset(fg
->data
, 0, fg
->num_slices
* sizeof(unsigned char *));
179 r
= fg
->num_received_slices
;
180 fg
->idx
[r
] = slice_num
;
181 fg
->data
[r
] = malloc(fg
->h
.slice_bytes
);
182 memcpy(fg
->data
[r
], buf
, fg
->h
.slice_bytes
);
183 fg
->num_received_slices
++;
187 static int decode_group(struct fec_group
*fg
, struct filter_node
*fn
)
189 int i
, ret
, sb
= fg
->h
.slice_bytes
;
191 struct private_fecdec_data
*pfd
= fn
->private_data
;
193 ret
= fec_decode(pfd
->fec
, fg
->data
, fg
->idx
, sb
);
196 PARA_DEBUG_LOG("writing group %d (%d/%d decoded data bytes)\n",
197 fg
->h
.group_num
, fg
->h
.group_bytes
,
198 fg
->h
.data_slices_per_group
* sb
);
199 for (i
= 0; i
< fg
->h
.data_slices_per_group
; i
++) {
201 if (n
+ written
> fg
->h
.group_bytes
)
202 n
= fg
->h
.group_bytes
- written
;
203 if (fn
->loaded
+ n
> fn
->bufsize
)
204 return -E_FECDEC_OVERRUN
;
205 memcpy(fn
->buf
+ fn
->loaded
, fg
->data
[i
], n
);
213 * Read a fec header from a buffer.
215 * \param buf The buffer to write to.
216 * \param h The fec header to write.
218 static int read_fec_header(char *buf
, size_t len
, struct fec_header
*h
)
222 if (len
< FEC_HEADER_SIZE
)
224 magic
= read_u32(buf
);
225 if (magic
!= FEC_MAGIC
)
226 return -E_BAD_FEC_HEADER
;
227 h
->slices_per_group
= read_u8(buf
+ 4);
228 h
->data_slices_per_group
= read_u8(buf
+ 5);
229 h
->audio_header_size
= read_u32(buf
+ 6);
231 h
->group_num
= read_u32(buf
+ 10);
232 h
->group_bytes
= read_u32(buf
+ 14);
234 h
->slice_num
= read_u8(buf
+ 18);
235 h
->slice_bytes
= read_u16(buf
+ 20);
236 if (!h
->group_bytes
&& & h
->slice_bytes
)
237 return -E_FECDEC_EOF
;
238 // PARA_DEBUG_LOG("group %u, slize %u, slices per group: %u\n",
239 // h->group_num, h->slice_num, h->slices_per_group);
243 static int dispatch_slice(char *buf
, size_t len
, struct fec_header
*h
,
244 struct filter_node
*fn
)
246 struct fec_group
*fg
;
248 struct private_fecdec_data
*pfd
= fn
->private_data
;
250 if (h
->slice_bytes
> len
) /* can not use the thing, try to read more */
252 ret
= get_group(h
, pfd
, &fg
);
255 if (group_complete(fg
)) {
256 PARA_DEBUG_LOG("group complete, ignoring slice %d\n",
261 ret
= add_slice(buf
, fg
);
264 if (group_complete(fg
)) {
266 int k
= h
->data_slices_per_group
, n
= h
->slices_per_group
;
267 PARA_NOTICE_LOG("init fec (%d, %d)\n", k
, n
);
268 ret
= fec_new(k
, n
, &pfd
->fec
);
272 ret
= decode_group(fg
, fn
);
279 static int fecdec(char *buf
, size_t len
, struct filter_node
*fn
)
284 ret
= read_fec_header(buf
, len
, &h
);
287 if (h
.slice_bytes
> INPUT_BUFFER_SIZE
)
288 return -E_BAD_SLICE_SIZE
;
289 if (h
.slice_num
> h
.slices_per_group
)
290 return -E_BAD_SLICE_NUM
;
291 ret
= dispatch_slice(buf
+ FEC_HEADER_SIZE
, len
- FEC_HEADER_SIZE
,
293 //PARA_INFO_LOG("ret: %d, len: %d, slice_bytes: %d\n", ret, len, h.slice_bytes);
296 return FEC_HEADER_SIZE
+ h
.slice_bytes
;
299 static void fecdec_close(struct filter_node
*fn
)
301 struct private_fecdec_data
*pfd
= fn
->private_data
;
302 struct fec_group
*fg
;
304 FOR_EACH_FEC_GROUP(fg
, pfd
)
308 free(fn
->private_data
);
309 fn
->private_data
= NULL
;
312 static void fecdec_open(struct filter_node
*fn
)
314 fn
->bufsize
= FECDEC_OUTBUF_SIZE
;
315 fn
->buf
= para_malloc(fn
->bufsize
);
316 fn
->private_data
= para_calloc(sizeof(struct private_fecdec_data
));
321 * The init function of the fecdec filter.
323 * \param f struct to initialize.
325 void fecdec_filter_init(struct filter
*f
)
328 f
->close
= fecdec_close
;
329 f
->open
= fecdec_open
;