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