]> git.tuebingen.mpg.de Git - paraslash.git/blob - aacdec_filter.c
Merge topic branch t/sf_float into pu
[paraslash.git] / aacdec_filter.c
1 /* Copyright (C) 2006 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
2 /*
3  * based in parts on libfaad, Copyright (C) 2003-2005 M. Bakker,
4  * Ahead Software AG
5  */
6
7 /** \file aacdec_filter.c paraslash's aac (m4a) decoder. */
8
9 #include <regex.h>
10 #include <neaacdec.h>
11
12 #include "para.h"
13 #include "portable_io.h"
14 #include "list.h"
15 #include "sched.h"
16 #include "buffer_tree.h"
17 #include "filter.h"
18 #include "error.h"
19 #include "string.h"
20
21 /** Give up decoding after that many errors. */
22 #define MAX_ERRORS 20
23
24 /**
25  * data specific to the aacdec filter
26  *
27  * \sa \ref filter, \ref filter_node.
28  */
29 struct private_aacdec_data {
30         /** the return value of aac_open */
31         NeAACDecHandle handle;
32         /** whether this instance of the aac decoder is already initialized */
33         bool initialized;
34         /** number of times the decoder returned an error */
35         unsigned error_count;
36         /** number of bytes already consumed from the imput stream */
37         size_t consumed_total;
38         /** The number of channels of the current stream. */
39         unsigned int channels;
40         /** Current sample rate in Hz. */
41         unsigned int sample_rate;
42 };
43
44 static int aacdec_execute(const struct btr_node *btrn, const char *cmd,
45                 char **result)
46 {
47         struct filter_node *fn = btr_context(btrn);
48         struct private_aacdec_data *padd = fn->private_data;
49
50         return decoder_execute(cmd, padd->sample_rate, padd->channels, result);
51 }
52
53 static void aacdec_open(struct filter_node *fn)
54 {
55         NeAACDecConfigurationPtr c;
56         struct private_aacdec_data *padd = zalloc(sizeof(*padd));
57
58         padd->handle = NeAACDecOpen();
59         c = NeAACDecGetCurrentConfiguration(padd->handle);
60         c->defObjectType = LC;
61         c->outputFormat = FAAD_FMT_16BIT;
62         c->downMatrix = 0;
63         NeAACDecSetConfiguration(padd->handle, c);
64
65         fn->private_data = padd;
66         fn->min_iqs = 2048;
67 }
68
69 static void aacdec_close(struct filter_node *fn)
70 {
71         struct private_aacdec_data *padd = fn->private_data;
72
73         NeAACDecClose(padd->handle);
74         free(padd);
75         fn->private_data = NULL;
76 }
77
78 static int aacdec_post_monitor(__a_unused struct sched *s, void *context)
79 {
80         struct filter_node *fn = context;
81         struct btr_node *btrn = fn->btrn;
82         struct private_aacdec_data *padd = fn->private_data;
83         int i, ret;
84         char *inbuf, *outbuf, *btrbuf;
85         size_t len, consumed, loaded = 0;
86         NeAACDecFrameInfo frame_info;
87
88 next_buffer:
89         ret = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL);
90         if (ret < 0)
91                 goto err;
92         if (ret == 0)
93                 return 0;
94         btr_merge(btrn, fn->min_iqs);
95         len = btr_next_buffer(btrn, &inbuf);
96         len = PARA_MIN(len, (size_t)8192);
97         consumed = 0;
98         if (!padd->initialized) {
99                 unsigned long rate = 0;
100                 unsigned char channels = 0;
101                 ret = NeAACDecInit(padd->handle, (unsigned char *)inbuf,
102                         len, &rate, &channels);
103                 PARA_INFO_LOG("decoder init: %d\n", ret);
104                 if (ret < 0) {
105                         ret = -E_AACDEC_INIT;
106                         goto err;
107                 }
108                 consumed = ret;
109                 padd->sample_rate = rate;
110                 padd->channels = channels;
111                 PARA_INFO_LOG("rate: %u, channels: %u\n",
112                         padd->sample_rate, padd->channels);
113                 padd->initialized = true;
114         }
115         if (consumed >= len)
116                 goto success;
117         //PARA_CRIT_LOG("consumed: %zu (%zu + %zu), have: %zu\n", padd->consumed_total + consumed,
118         //      padd->consumed_total, consumed, len - consumed);
119         outbuf = NeAACDecDecode(padd->handle, &frame_info,
120                 (unsigned char *)inbuf + consumed, len - consumed);
121         if (frame_info.error) {
122                 int err = frame_info.error;
123                 ret = -E_AAC_DECODE;
124                 if (padd->error_count++ > MAX_ERRORS)
125                         goto err;
126                 PARA_NOTICE_LOG("error #%u: (%s)\n", padd->error_count,
127                         NeAACDecGetErrorMessage(err));
128                 PARA_NOTICE_LOG("consumed (total, buffer, frame): "
129                         "%zu, %zu, %lu\n",
130                         padd->consumed_total, consumed,
131                         frame_info.bytesconsumed);
132                 consumed++; /* just eat one byte and hope for the best */
133                 goto success;
134         }
135         padd->error_count = 0;
136         //PARA_CRIT_LOG("decoder ate %lu\n", frame_info.bytesconsumed);
137         consumed += frame_info.bytesconsumed;
138         if (!frame_info.samples)
139                 goto success;
140         btrbuf = arr_alloc(2, frame_info.samples);
141         for (i = 0; i < frame_info.samples; i++) {
142                 short sh = ((short *)outbuf)[i];
143                 write_int16_host_endian(btrbuf + loaded, sh);
144                 loaded += 2;
145         }
146         btr_add_output(btrbuf, loaded, btrn);
147 success:
148         btr_consume(btrn, consumed);
149         padd->consumed_total += consumed;
150         if (loaded == 0)
151                 goto next_buffer;
152         return 1;
153 err:
154         assert(ret < 0);
155         btr_remove_node(&fn->btrn);
156         return ret;
157 }
158
159 const struct filter lsg_filter_cmd_com_aacdec_user_data = {
160         .open = aacdec_open,
161         .close = aacdec_close,
162         .pre_monitor = generic_filter_pre_monitor,
163         .post_monitor = aacdec_post_monitor,
164         .execute = aacdec_execute
165 };