|
0 |
/*
|
|
1 |
* Squeezelite - lightweight headless squeezebox emulator
|
|
2 |
*
|
|
3 |
* (c) Adrian Smith 2012, 2013, triode1@btinternet.com
|
|
4 |
*
|
|
5 |
* This program is free software: you can redistribute it and/or modify
|
|
6 |
* it under the terms of the GNU General Public License as published by
|
|
7 |
* the Free Software Foundation, either version 3 of the License, or
|
|
8 |
* (at your option) any later version.
|
|
9 |
*
|
|
10 |
* This program is distributed in the hope that it will be useful,
|
|
11 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13 |
* GNU General Public License for more details.
|
|
14 |
*
|
|
15 |
* You should have received a copy of the GNU General Public License
|
|
16 |
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17 |
*
|
|
18 |
*/
|
|
19 |
|
|
20 |
#include "squeezelite.h"
|
|
21 |
|
|
22 |
#if FFMPEG
|
|
23 |
|
|
24 |
#include <libavformat/avformat.h>
|
|
25 |
#include <libavcodec/avcodec.h>
|
|
26 |
|
|
27 |
// we try to load a range of ffmpeg library versions
|
|
28 |
// note that this file must be compiled with header files of the same major version as the library loaded
|
|
29 |
// (as structs accessed may change between major versions)
|
|
30 |
|
|
31 |
#define LIBAVUTIL "libavutil.so"
|
|
32 |
#define LIBAVUTIL_MAX 52
|
|
33 |
#define LIBAVUTIL_MIN 51
|
|
34 |
|
|
35 |
#define LIBAVCODEC "libavcodec.so"
|
|
36 |
#define LIBAVCODEC_MAX 55
|
|
37 |
#define LIBAVCODEC_MIN 53
|
|
38 |
|
|
39 |
#define LIBAVFORMAT "libavformat.so"
|
|
40 |
#define LIBAVFORMAT_MAX 55
|
|
41 |
#define LIBAVFORMAT_MIN 53
|
|
42 |
|
|
43 |
|
|
44 |
#define READ_SIZE 4096 * 4 // this is large enough to ensure ffmpeg always gets new data when decode is called
|
|
45 |
#define WRITE_SIZE 256 * 1024 // FIXME - make smaller, but still to absorb max wma output
|
|
46 |
|
|
47 |
// FIXME - do we need to align these params as per ffmpeg on i386?
|
|
48 |
#define attribute_align_arg
|
|
49 |
|
|
50 |
struct ff_s {
|
|
51 |
// state for ffmpeg decoder
|
|
52 |
bool wma;
|
|
53 |
u8_t wma_mmsh;
|
|
54 |
u8_t wma_playstream;
|
|
55 |
u8_t wma_metadatastream;
|
|
56 |
u8_t *readbuf;
|
|
57 |
bool end_of_stream;
|
|
58 |
AVInputFormat *input_format;
|
|
59 |
AVFormatContext *formatC;
|
|
60 |
AVCodecContext *codecC;
|
|
61 |
AVFrame *frame;
|
|
62 |
AVPacket *avpkt;
|
|
63 |
unsigned mmsh_bytes_left;
|
|
64 |
unsigned mmsh_bytes_pad;
|
|
65 |
unsigned mmsh_packet_len;
|
|
66 |
// library versions
|
|
67 |
unsigned avcodec_v, avformat_v, avutil_v;
|
|
68 |
// ffmpeg symbols to be dynamically loaded from libavcodec
|
|
69 |
unsigned (* avcodec_version)(void);
|
|
70 |
AVCodec * (* avcodec_find_decoder)(int);
|
|
71 |
int attribute_align_arg (* avcodec_open2)(AVCodecContext *, const AVCodec *, AVDictionary **);
|
|
72 |
AVFrame * (* avcodec_alloc_frame)(void);
|
|
73 |
void (* avcodec_free_frame)(AVFrame *);
|
|
74 |
int attribute_align_arg (* avcodec_decode_audio4)(AVCodecContext *, AVFrame *, int *, const AVPacket *);
|
|
75 |
// ffmpeg symbols to be dynamically loaded from libavformat
|
|
76 |
unsigned (* avformat_version)(void);
|
|
77 |
AVFormatContext * (* avformat_alloc_context)(void);
|
|
78 |
void (* avformat_free_context)(AVFormatContext *);
|
|
79 |
int (* avformat_open_input)(AVFormatContext **, const char *, AVInputFormat *, AVDictionary **);
|
|
80 |
int (* avformat_find_stream_info)(AVFormatContext *, AVDictionary **);
|
|
81 |
AVIOContext * (* avio_alloc_context)(unsigned char *, int, int, void *,
|
|
82 |
int (*read_packet)(void *, uint8_t *, int), int (*write_packet)(void *, uint8_t *, int), int64_t (*seek)(void *, int64_t, int));
|
|
83 |
void (* av_init_packet)(AVPacket *);
|
|
84 |
void (* av_free_packet)(AVPacket *);
|
|
85 |
int (* av_read_frame)(AVFormatContext *, AVPacket *);
|
|
86 |
AVInputFormat * (* av_find_input_format)(const char *);
|
|
87 |
void (* av_register_all)(void);
|
|
88 |
// ffmpeg symbols to be dynamically loaded from libavutil
|
|
89 |
unsigned (* avutil_version)(void);
|
|
90 |
void (* av_log_set_callback)(void (*)(void*, int, const char*, va_list));
|
|
91 |
void (* av_log_set_level)(int);
|
|
92 |
int (* av_strerror)(int, char *, size_t);
|
|
93 |
void * (* av_malloc)(size_t);
|
|
94 |
void (* av_free)(void *);
|
|
95 |
};
|
|
96 |
|
|
97 |
static struct ff_s *ff;
|
|
98 |
|
|
99 |
extern log_level loglevel;
|
|
100 |
|
|
101 |
extern struct buffer *streambuf;
|
|
102 |
extern struct buffer *outputbuf;
|
|
103 |
extern struct streamstate stream;
|
|
104 |
extern struct outputstate output;
|
|
105 |
extern struct decodestate decode;
|
|
106 |
extern struct processstate process;
|
|
107 |
|
|
108 |
#define LOCK_S mutex_lock(streambuf->mutex)
|
|
109 |
#define UNLOCK_S mutex_unlock(streambuf->mutex)
|
|
110 |
#define LOCK_O mutex_lock(outputbuf->mutex)
|
|
111 |
#define UNLOCK_O mutex_unlock(outputbuf->mutex)
|
|
112 |
#if PROCESS
|
|
113 |
#define LOCK_O_direct if (decode.direct) mutex_lock(outputbuf->mutex)
|
|
114 |
#define UNLOCK_O_direct if (decode.direct) mutex_unlock(outputbuf->mutex)
|
|
115 |
#define IF_DIRECT(x) if (decode.direct) { x }
|
|
116 |
#define IF_PROCESS(x) if (!decode.direct) { x }
|
|
117 |
#else
|
|
118 |
#define LOCK_O_direct mutex_lock(outputbuf->mutex)
|
|
119 |
#define UNLOCK_O_direct mutex_unlock(outputbuf->mutex)
|
|
120 |
#define IF_DIRECT(x) { x }
|
|
121 |
#define IF_PROCESS(x)
|
|
122 |
#endif
|
|
123 |
|
|
124 |
// our own version of useful error function not included in earlier ffmpeg versions
|
|
125 |
static char *av__err2str(errnum) {
|
|
126 |
static char buf[64];
|
|
127 |
ff->av_strerror(errnum, buf, 64);
|
|
128 |
return buf;
|
|
129 |
}
|
|
130 |
|
|
131 |
// parser to extract asf data packet length from asf header
|
|
132 |
const u8_t header_guid[16] = { 0x30, 0x26, 0xB2, 0x75, 0x8E, 0x66, 0xCF, 0x11, 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C };
|
|
133 |
const u8_t file_props_guid[16] = { 0xA1, 0xDC, 0xAB, 0x8C, 0x47, 0xA9, 0xCF, 0x11, 0x8E, 0xE4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 };
|
|
134 |
|
|
135 |
static int _parse_packlen(void) {
|
|
136 |
int bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf));
|
|
137 |
u8_t *ptr = streambuf->readp;
|
|
138 |
int remain = 1;
|
|
139 |
|
|
140 |
while (bytes >= 24 && remain > 0) {
|
|
141 |
u32_t len = *(ptr+16) | *(ptr+17) << 8 | *(ptr+18) << 16 | *(ptr+19) << 24; // assume msb 32 bits are 0
|
|
142 |
if (!memcmp(ptr, header_guid, 16) && bytes >= 30) {
|
|
143 |
ptr += 30;
|
|
144 |
bytes -= 30;
|
|
145 |
remain = len - 30;
|
|
146 |
continue;
|
|
147 |
}
|
|
148 |
if (!memcmp(ptr, file_props_guid, 16) && len == 104) {
|
|
149 |
u32_t packlen = *(ptr+92) | *(ptr+93) << 8 | *(ptr+94) << 16 | *(ptr+95) << 24;
|
|
150 |
LOG_INFO("asf packet len: %u", packlen);
|
|
151 |
return packlen;
|
|
152 |
}
|
|
153 |
ptr += len;
|
|
154 |
bytes -= len;
|
|
155 |
remain -= len;
|
|
156 |
}
|
|
157 |
|
|
158 |
LOG_WARN("could not parse packet length");
|
|
159 |
return 0;
|
|
160 |
}
|
|
161 |
|
|
162 |
static int _read_data(void *opaque, u8_t *buffer, int buf_size) {
|
|
163 |
LOCK_S;
|
|
164 |
|
|
165 |
size_t bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf));
|
|
166 |
ff->end_of_stream = (stream.state <= DISCONNECT && bytes == 0);
|
|
167 |
bytes = min(bytes, buf_size);
|
|
168 |
|
|
169 |
// for chunked wma extract asf header and data frames from framing structure
|
|
170 |
// pad asf data frames to size of packet extracted from asf header
|
|
171 |
if (ff->wma_mmsh) {
|
|
172 |
unsigned chunk_type = 0, chunk_len = 0;
|
|
173 |
|
|
174 |
if (ff->mmsh_bytes_left) {
|
|
175 |
// bytes remaining from previous frame
|
|
176 |
if (bytes >= ff->mmsh_bytes_left) {
|
|
177 |
bytes = ff->mmsh_bytes_left;
|
|
178 |
ff->mmsh_bytes_left = 0;
|
|
179 |
} else {
|
|
180 |
ff->mmsh_bytes_left -= bytes;
|
|
181 |
}
|
|
182 |
} else if (ff->mmsh_bytes_pad) {
|
|
183 |
// add padding for previous frame
|
|
184 |
bytes = min(ff->mmsh_bytes_pad, buf_size);
|
|
185 |
memset(buffer, 0, bytes);
|
|
186 |
ff->mmsh_bytes_pad -= bytes;
|
|
187 |
UNLOCK_S;
|
|
188 |
return bytes;
|
|
189 |
} else if (bytes >= 12) {
|
|
190 |
// new chunk header
|
|
191 |
chunk_type = (*(streambuf->readp) & 0x7f) | *(streambuf->readp + 1) << 8;
|
|
192 |
chunk_len = *(streambuf->readp + 2) | *(streambuf->readp + 3) << 8;
|
|
193 |
_buf_inc_readp(streambuf, 12);
|
|
194 |
bytes -= 12;
|
|
195 |
} else if (_buf_used(streambuf) >= 12) {
|
|
196 |
// new chunk header split over end of streambuf, read in two
|
|
197 |
u8_t header[12];
|
|
198 |
memcpy(header, streambuf->readp, bytes);
|
|
199 |
_buf_inc_readp(streambuf, bytes);
|
|
200 |
memcpy(header + bytes, streambuf->readp, 12 - bytes);
|
|
201 |
_buf_inc_readp(streambuf, 12 - bytes);
|
|
202 |
chunk_type = (header[0] & 0x7f) | header[1] << 8;
|
|
203 |
chunk_len = header[2] | header[3] << 8;
|
|
204 |
bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf));
|
|
205 |
bytes = min(bytes, buf_size);
|
|
206 |
} else {
|
|
207 |
// should not get here...
|
|
208 |
LOG_ERROR("chunk parser stalled bytes: %u %u", bytes, _buf_used(streambuf));
|
|
209 |
UNLOCK_S;
|
|
210 |
return 0;
|
|
211 |
}
|
|
212 |
|
|
213 |
if (chunk_type && chunk_len) {
|
|
214 |
if (chunk_type == 0x4824) {
|
|
215 |
// asf header - parse packet length
|
|
216 |
ff->mmsh_packet_len = _parse_packlen();
|
|
217 |
ff->mmsh_bytes_pad = 0;
|
|
218 |
} else if (chunk_type == 0x4424 && ff->mmsh_packet_len) {
|
|
219 |
// asf data packet - add padding
|
|
220 |
ff->mmsh_bytes_pad = ff->mmsh_packet_len - chunk_len + 8;
|
|
221 |
} else {
|
|
222 |
LOG_INFO("unknown chunk: %04x", chunk_type);
|
|
223 |
// other packet - no padding
|
|
224 |
ff->mmsh_bytes_pad = 0;
|
|
225 |
}
|
|
226 |
|
|
227 |
if (chunk_len - 8 <= bytes) {
|
|
228 |
bytes = chunk_len - 8;
|
|
229 |
ff->mmsh_bytes_left = 0;
|
|
230 |
} else {
|
|
231 |
ff->mmsh_bytes_left = chunk_len - 8 - bytes;
|
|
232 |
}
|
|
233 |
}
|
|
234 |
|
|
235 |
}
|
|
236 |
|
|
237 |
memcpy(buffer, streambuf->readp, bytes);
|
|
238 |
|
|
239 |
_buf_inc_readp(streambuf, bytes);
|
|
240 |
|
|
241 |
if (ff->mmsh_bytes_pad && bytes + ff->mmsh_bytes_pad < buf_size) {
|
|
242 |
memset(buffer + bytes, 0, ff->mmsh_bytes_pad);
|
|
243 |
bytes += ff->mmsh_bytes_pad;
|
|
244 |
ff->mmsh_bytes_pad = 0;
|
|
245 |
}
|
|
246 |
|
|
247 |
UNLOCK_S;
|
|
248 |
|
|
249 |
return bytes;
|
|
250 |
}
|
|
251 |
|
|
252 |
static decode_state ff_decode(void) {
|
|
253 |
int r, len, got_frame;
|
|
254 |
AVPacket pkt_c;
|
|
255 |
s32_t *optr = NULL;
|
|
256 |
|
|
257 |
if (decode.new_stream) {
|
|
258 |
|
|
259 |
AVIOContext *avio;
|
|
260 |
AVStream *av_stream;
|
|
261 |
AVCodec *codec;
|
|
262 |
int o;
|
|
263 |
int audio_stream = -1;
|
|
264 |
|
|
265 |
ff->mmsh_bytes_left = ff->mmsh_bytes_pad = ff->mmsh_packet_len = 0;
|
|
266 |
|
|
267 |
if (!ff->readbuf) {
|
|
268 |
ff->readbuf = ff->av_malloc(READ_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
|
|
269 |
}
|
|
270 |
|
|
271 |
avio = ff->avio_alloc_context(ff->readbuf, READ_SIZE, 0, NULL, _read_data, NULL, NULL);
|
|
272 |
avio->seekable = 0;
|
|
273 |
|
|
274 |
ff->formatC = ff->avformat_alloc_context();
|
|
275 |
if (ff->formatC == NULL) {
|
|
276 |
LOG_ERROR("null context");
|
|
277 |
return DECODE_ERROR;
|
|
278 |
}
|
|
279 |
|
|
280 |
ff->formatC->pb = avio;
|
|
281 |
ff->formatC->flags |= AVFMT_FLAG_CUSTOM_IO | AVFMT_FLAG_NOPARSE;
|
|
282 |
|
|
283 |
o = ff->avformat_open_input(&ff->formatC, "", ff->input_format, NULL);
|
|
284 |
if (o < 0) {
|
|
285 |
LOG_WARN("avformat_open_input: %d %s", o, av__err2str(o));
|
|
286 |
return DECODE_ERROR;
|
|
287 |
}
|
|
288 |
|
|
289 |
LOG_INFO("format: name:%s lname:%s", ff->formatC->iformat->name, ff->formatC->iformat->long_name);
|
|
290 |
|
|
291 |
o = ff->avformat_find_stream_info(ff->formatC, NULL);
|
|
292 |
if (o < 0) {
|
|
293 |
LOG_WARN("avformat_find_stream_info: %d %s", o, av__err2str(o));
|
|
294 |
return DECODE_ERROR;
|
|
295 |
}
|
|
296 |
|
|
297 |
if (ff->wma && ff->wma_playstream < ff->formatC->nb_streams) {
|
|
298 |
if (ff->formatC->streams[ff->wma_playstream]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
|
|
299 |
LOG_INFO("using wma stream sent from server: %i", ff->wma_playstream);
|
|
300 |
audio_stream = ff->wma_playstream;
|
|
301 |
}
|
|
302 |
}
|
|
303 |
|
|
304 |
if (audio_stream == -1) {
|
|
305 |
int i;
|
|
306 |
for (i = 0; i < ff->formatC->nb_streams; ++i) {
|
|
307 |
if (ff->formatC->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
|
|
308 |
audio_stream = i;
|
|
309 |
LOG_INFO("found stream: %i", i);
|
|
310 |
break;
|
|
311 |
}
|
|
312 |
}
|
|
313 |
}
|
|
314 |
|
|
315 |
if (audio_stream == -1) {
|
|
316 |
LOG_WARN("no audio stream found");
|
|
317 |
return DECODE_ERROR;
|
|
318 |
}
|
|
319 |
|
|
320 |
av_stream = ff->formatC->streams[audio_stream];
|
|
321 |
|
|
322 |
ff->codecC = av_stream->codec;
|
|
323 |
|
|
324 |
codec = ff->avcodec_find_decoder(ff->codecC->codec_id);
|
|
325 |
|
|
326 |
ff->avcodec_open2(ff->codecC, codec, NULL);
|
|
327 |
|
|
328 |
ff->frame = ff->avcodec_alloc_frame();
|
|
329 |
|
|
330 |
ff->avpkt = ff->av_malloc(sizeof(AVPacket));
|
|
331 |
if (ff->avpkt == NULL) {
|
|
332 |
LOG_ERROR("can't allocate avpkt");
|
|
333 |
return DECODE_ERROR;
|
|
334 |
}
|
|
335 |
|
|
336 |
ff->av_init_packet(ff->avpkt);
|
|
337 |
ff->avpkt->data = NULL;
|
|
338 |
ff->avpkt->size = 0;
|
|
339 |
|
|
340 |
LOCK_O;
|
|
341 |
LOG_INFO("setting track_start");
|
|
342 |
output.next_sample_rate = decode_newstream(ff->codecC->sample_rate, output.max_sample_rate);
|
|
343 |
output.track_start = outputbuf->writep;
|
|
344 |
if (output.fade_mode) _checkfade(true);
|
|
345 |
decode.new_stream = false;
|
|
346 |
UNLOCK_O;
|
|
347 |
}
|
|
348 |
|
|
349 |
got_frame = 0;
|
|
350 |
|
|
351 |
if ((r = ff->av_read_frame(ff->formatC, ff->avpkt)) < 0) {
|
|
352 |
if (r == AVERROR_EOF) {
|
|
353 |
if (ff->end_of_stream) {
|
|
354 |
LOG_INFO("decode complete");
|
|
355 |
return DECODE_COMPLETE;
|
|
356 |
} else {
|
|
357 |
LOG_INFO("codec end of file");
|
|
358 |
}
|
|
359 |
} else {
|
|
360 |
LOG_ERROR("av_read_frame error: %i %s", r, av__err2str(r));
|
|
361 |
}
|
|
362 |
return DECODE_RUNNING;
|
|
363 |
}
|
|
364 |
|
|
365 |
// clone packet as we are adjusting it
|
|
366 |
pkt_c = *ff->avpkt;
|
|
367 |
|
|
368 |
IF_PROCESS(
|
|
369 |
optr = (s32_t *)process.inbuf;
|
|
370 |
process.in_frames = 0;
|
|
371 |
);
|
|
372 |
|
|
373 |
while (pkt_c.size > 0 || got_frame) {
|
|
374 |
|
|
375 |
len = ff->avcodec_decode_audio4(ff->codecC, ff->frame, &got_frame, &pkt_c);
|
|
376 |
if (len < 0) {
|
|
377 |
LOG_ERROR("avcodec_decode_audio4 error: %i %s", len, av__err2str(len));
|
|
378 |
return DECODE_RUNNING;
|
|
379 |
}
|
|
380 |
|
|
381 |
pkt_c.data += len;
|
|
382 |
pkt_c.size -= len;
|
|
383 |
|
|
384 |
if (got_frame) {
|
|
385 |
|
|
386 |
s16_t *iptr16 = (s16_t *)ff->frame->data[0];
|
|
387 |
s32_t *iptr32 = (s32_t *)ff->frame->data[0];
|
|
388 |
s16_t *iptr16l = (s16_t *)ff->frame->data[0];
|
|
389 |
s16_t *iptr16r = (s16_t *)ff->frame->data[1];
|
|
390 |
s32_t *iptr32l = (s32_t *)ff->frame->data[0];
|
|
391 |
s32_t *iptr32r = (s32_t *)ff->frame->data[1];
|
|
392 |
float *iptrfl = (float *)ff->frame->data[0];
|
|
393 |
float *iptrfr = (float *)ff->frame->data[1];
|
|
394 |
|
|
395 |
frames_t frames = ff->frame->nb_samples;
|
|
396 |
|
|
397 |
LOG_SDEBUG("got audio channels: %u samples: %u format: %u", ff->codecC->channels, ff->frame->nb_samples,
|
|
398 |
ff->codecC->sample_fmt);
|
|
399 |
|
|
400 |
LOCK_O_direct;
|
|
401 |
|
|
402 |
while (frames > 0) {
|
|
403 |
frames_t count;
|
|
404 |
frames_t f;
|
|
405 |
|
|
406 |
IF_DIRECT(
|
|
407 |
optr = (s32_t *)outputbuf->writep;
|
|
408 |
f = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / BYTES_PER_FRAME;
|
|
409 |
f = min(f, frames);
|
|
410 |
);
|
|
411 |
|
|
412 |
IF_PROCESS(
|
|
413 |
if (process.in_frames + frames > process.max_in_frames) {
|
|
414 |
LOG_WARN("exceeded process buffer size - dropping frames");
|
|
415 |
break;
|
|
416 |
}
|
|
417 |
f = frames;
|
|
418 |
);
|
|
419 |
|
|
420 |
count = f;
|
|
421 |
|
|
422 |
if (ff->codecC->channels == 2) {
|
|
423 |
if (ff->codecC->sample_fmt == AV_SAMPLE_FMT_S16) {
|
|
424 |
while (count--) {
|
|
425 |
*optr++ = *iptr16++ << 16;
|
|
426 |
*optr++ = *iptr16++ << 16;
|
|
427 |
}
|
|
428 |
} else if (ff->codecC->sample_fmt == AV_SAMPLE_FMT_S32) {
|
|
429 |
while (count--) {
|
|
430 |
*optr++ = *iptr32++;
|
|
431 |
*optr++ = *iptr32++;
|
|
432 |
}
|
|
433 |
} else if (ff->codecC->sample_fmt == AV_SAMPLE_FMT_S16P) {
|
|
434 |
while (count--) {
|
|
435 |
*optr++ = *iptr16l++ << 16;
|
|
436 |
*optr++ = *iptr16r++ << 16;
|
|
437 |
}
|
|
438 |
} else if (ff->codecC->sample_fmt == AV_SAMPLE_FMT_S32P) {
|
|
439 |
while (count--) {
|
|
440 |
*optr++ = *iptr32l++;
|
|
441 |
*optr++ = *iptr32r++;
|
|
442 |
}
|
|
443 |
} else if (ff->codecC->sample_fmt == AV_SAMPLE_FMT_FLTP) {
|
|
444 |
while (count--) {
|
|
445 |
double scaledl = *iptrfl++ * 0x7fffffff;
|
|
446 |
double scaledr = *iptrfr++ * 0x7fffffff;
|
|
447 |
if (scaledl > 2147483647.0) scaledl = 2147483647.0;
|
|
448 |
if (scaledl < -2147483648.0) scaledl = -2147483648.0;
|
|
449 |
if (scaledr > 2147483647.0) scaledr = 2147483647.0;
|
|
450 |
if (scaledr < -2147483648.0) scaledr = -2147483648.0;
|
|
451 |
*optr++ = (s32_t)scaledl;
|
|
452 |
*optr++ = (s32_t)scaledr;
|
|
453 |
}
|
|
454 |
} else {
|
|
455 |
LOG_WARN("unsupported sample format: %u", ff->codecC->sample_fmt);
|
|
456 |
}
|
|
457 |
} else if (ff->codecC->channels == 1) {
|
|
458 |
if (ff->codecC->sample_fmt == AV_SAMPLE_FMT_S16) {
|
|
459 |
while (count--) {
|
|
460 |
*optr++ = *iptr16 << 16;
|
|
461 |
*optr++ = *iptr16++ << 16;
|
|
462 |
}
|
|
463 |
} else if (ff->codecC->sample_fmt == AV_SAMPLE_FMT_S32) {
|
|
464 |
while (count--) {
|
|
465 |
*optr++ = *iptr32;
|
|
466 |
*optr++ = *iptr32++;
|
|
467 |
}
|
|
468 |
} else if (ff->codecC->sample_fmt == AV_SAMPLE_FMT_S16P) {
|
|
469 |
while (count--) {
|
|
470 |
*optr++ = *iptr16l << 16;
|
|
471 |
*optr++ = *iptr16l++ << 16;
|
|
472 |
}
|
|
473 |
} else if (ff->codecC->sample_fmt == AV_SAMPLE_FMT_S32P) {
|
|
474 |
while (count--) {
|
|
475 |
*optr++ = *iptr32l;
|
|
476 |
*optr++ = *iptr32l++;
|
|
477 |
}
|
|
478 |
} else if (ff->codecC->sample_fmt == AV_SAMPLE_FMT_FLTP) {
|
|
479 |
while (count--) {
|
|
480 |
double scaled = *iptrfl++ * 0x7fffffff;
|
|
481 |
if (scaled > 2147483647.0) scaled = 2147483647.0;
|
|
482 |
if (scaled < -2147483648.0) scaled = -2147483648.0;
|
|
483 |
*optr++ = (s32_t)scaled;
|
|
484 |
*optr++ = (s32_t)scaled;
|
|
485 |
}
|
|
486 |
} else {
|
|
487 |
LOG_WARN("unsupported sample format: %u", ff->codecC->sample_fmt);
|
|
488 |
}
|
|
489 |
} else {
|
|
490 |
LOG_WARN("unsupported number of channels");
|
|
491 |
}
|
|
492 |
|
|
493 |
frames -= f;
|
|
494 |
|
|
495 |
IF_DIRECT(
|
|
496 |
_buf_inc_writep(outputbuf, f * BYTES_PER_FRAME);
|
|
497 |
);
|
|
498 |
|
|
499 |
IF_PROCESS(
|
|
500 |
process.in_frames += f;
|
|
501 |
);
|
|
502 |
}
|
|
503 |
|
|
504 |
UNLOCK_O_direct;
|
|
505 |
}
|
|
506 |
}
|
|
507 |
|
|
508 |
ff->av_free_packet(ff->avpkt);
|
|
509 |
|
|
510 |
return DECODE_RUNNING;
|
|
511 |
}
|
|
512 |
|
|
513 |
static void _free_ff_data(void) {
|
|
514 |
if (ff->formatC) {
|
|
515 |
if (ff->formatC->pb) ff->av_free(ff->formatC->pb);
|
|
516 |
ff->avformat_free_context(ff->formatC);
|
|
517 |
ff->formatC = NULL;
|
|
518 |
}
|
|
519 |
|
|
520 |
if (ff->frame) {
|
|
521 |
// ffmpeg version dependant free function
|
|
522 |
ff->avcodec_free_frame ? ff->avcodec_free_frame(ff->frame) : ff->av_free(ff->frame);
|
|
523 |
ff->frame = NULL;
|
|
524 |
}
|
|
525 |
|
|
526 |
if (ff->avpkt) {
|
|
527 |
ff->av_free_packet(ff->avpkt);
|
|
528 |
ff->av_free(ff->avpkt);
|
|
529 |
ff->avpkt = NULL;
|
|
530 |
}
|
|
531 |
}
|
|
532 |
|
|
533 |
static void ff_open_wma(u8_t size, u8_t rate, u8_t chan, u8_t endianness) {
|
|
534 |
_free_ff_data();
|
|
535 |
|
|
536 |
ff->input_format = ff->av_find_input_format("asf");
|
|
537 |
if (ff->input_format == NULL) {
|
|
538 |
LOG_ERROR("asf format not supported by ffmpeg library");
|
|
539 |
}
|
|
540 |
|
|
541 |
ff->wma = true;
|
|
542 |
ff->wma_mmsh = size - '0';
|
|
543 |
ff->wma_playstream = rate - 1;
|
|
544 |
ff->wma_metadatastream = chan != '?' ? chan : 0;
|
|
545 |
|
|
546 |
LOG_INFO("open wma chunking: %u playstream: %u metadatastream: %u", ff->wma_mmsh, ff->wma_playstream, ff->wma_metadatastream);
|
|
547 |
}
|
|
548 |
|
|
549 |
static void ff_open_alac(u8_t size, u8_t rate, u8_t chan, u8_t endianness) {
|
|
550 |
_free_ff_data();
|
|
551 |
|
|
552 |
ff->input_format = ff->av_find_input_format("mp4");
|
|
553 |
if (ff->input_format == NULL) {
|
|
554 |
LOG_ERROR("mp4 format not supported by ffmpeg library");
|
|
555 |
}
|
|
556 |
|
|
557 |
ff->wma = false;
|
|
558 |
ff->wma_mmsh = 0;
|
|
559 |
|
|
560 |
LOG_INFO("open alac");
|
|
561 |
}
|
|
562 |
|
|
563 |
static void ff_close(void) {
|
|
564 |
_free_ff_data();
|
|
565 |
|
|
566 |
if (ff->readbuf) {
|
|
567 |
ff->av_free(ff->readbuf);
|
|
568 |
ff->readbuf = NULL;
|
|
569 |
}
|
|
570 |
}
|
|
571 |
|
|
572 |
static bool load_ff() {
|
|
573 |
void *handle_codec = NULL, *handle_format = NULL, *handle_util = NULL;
|
|
574 |
char name[30];
|
|
575 |
char *err;
|
|
576 |
int i;
|
|
577 |
|
|
578 |
// attempt to load newest known versions of libraries first
|
|
579 |
for (i = LIBAVCODEC_MAX; i >= LIBAVCODEC_MIN && !handle_codec; --i) {
|
|
580 |
sprintf(name, "%s.%d", LIBAVCODEC, i);
|
|
581 |
handle_codec = dlopen(name, RTLD_NOW);
|
|
582 |
}
|
|
583 |
if (!handle_codec) {
|
|
584 |
LOG_INFO("dlerror: %s", dlerror());
|
|
585 |
return false;
|
|
586 |
}
|
|
587 |
|
|
588 |
for (i = LIBAVFORMAT_MAX; i >= LIBAVFORMAT_MIN && !handle_format; --i) {
|
|
589 |
sprintf(name, "%s.%d", LIBAVFORMAT, i);
|
|
590 |
handle_format = dlopen(name, RTLD_NOW);
|
|
591 |
}
|
|
592 |
if (!handle_format) {
|
|
593 |
LOG_INFO("dlerror: %s", dlerror());
|
|
594 |
return false;
|
|
595 |
}
|
|
596 |
|
|
597 |
for (i = LIBAVUTIL_MAX; i >= LIBAVUTIL_MIN && !handle_util; --i) {
|
|
598 |
sprintf(name, "%s.%d", LIBAVUTIL, i);
|
|
599 |
handle_util = dlopen(name, RTLD_NOW);
|
|
600 |
}
|
|
601 |
if (!handle_util) {
|
|
602 |
LOG_INFO("dlerror: %s", dlerror());
|
|
603 |
return false;
|
|
604 |
}
|
|
605 |
|
|
606 |
ff = malloc(sizeof(struct ff_s));
|
|
607 |
memset(ff, 0, sizeof(struct ff_s));
|
|
608 |
|
|
609 |
ff->avcodec_version = dlsym(handle_codec, "avcodec_version");
|
|
610 |
ff->avcodec_find_decoder = dlsym(handle_codec, "avcodec_find_decoder");
|
|
611 |
ff->avcodec_open2 = dlsym(handle_codec, "avcodec_open2");
|
|
612 |
ff->avcodec_alloc_frame = dlsym(handle_codec, "avcodec_alloc_frame");
|
|
613 |
ff->avcodec_free_frame = dlsym(handle_codec, "avcodec_free_frame");
|
|
614 |
ff->avcodec_decode_audio4 = dlsym(handle_codec, "avcodec_decode_audio4");
|
|
615 |
|
|
616 |
if ((err = dlerror()) != NULL) {
|
|
617 |
LOG_INFO("dlerror: %s", err);
|
|
618 |
return false;
|
|
619 |
}
|
|
620 |
|
|
621 |
ff->avcodec_v = ff->avcodec_version();
|
|
622 |
LOG_INFO("loaded "LIBAVCODEC" (%u.%u.%u)", ff->avcodec_v >> 16, (ff->avcodec_v >> 8) & 0xff, ff->avcodec_v & 0xff);
|
|
623 |
if (ff->avcodec_v >> 16 != LIBAVCODEC_VERSION_MAJOR) {
|
|
624 |
LOG_WARN("error: library major version (%u) differs from build headers (%u)", ff->avcodec_v >> 16, LIBAVCODEC_VERSION_MAJOR);
|
|
625 |
return false;
|
|
626 |
}
|
|
627 |
|
|
628 |
ff->avformat_version = dlsym(handle_format, "avformat_version");
|
|
629 |
ff->avformat_alloc_context = dlsym(handle_format, "avformat_alloc_context");
|
|
630 |
ff->avformat_free_context = dlsym(handle_format, "avformat_free_context");
|
|
631 |
ff->avformat_open_input = dlsym(handle_format, "avformat_open_input");
|
|
632 |
ff->avformat_find_stream_info = dlsym(handle_format, "avformat_find_stream_info");
|
|
633 |
ff->avio_alloc_context = dlsym(handle_format, "avio_alloc_context");
|
|
634 |
ff->av_init_packet = dlsym(handle_format, "av_init_packet");
|
|
635 |
ff->av_free_packet = dlsym(handle_format, "av_free_packet");
|
|
636 |
ff->av_read_frame = dlsym(handle_format, "av_read_frame");
|
|
637 |
ff->av_find_input_format= dlsym(handle_format, "av_find_input_format");
|
|
638 |
ff->av_register_all = dlsym(handle_format, "av_register_all");
|
|
639 |
|
|
640 |
if ((err = dlerror()) != NULL) {
|
|
641 |
LOG_INFO("dlerror: %s", err);
|
|
642 |
return false;
|
|
643 |
}
|
|
644 |
|
|
645 |
ff->avformat_v = ff->avformat_version();
|
|
646 |
LOG_INFO("loaded "LIBAVFORMAT" (%u.%u.%u)", ff->avformat_v >> 16, (ff->avformat_v >> 8) & 0xff, ff->avformat_v & 0xff);
|
|
647 |
if (ff->avformat_v >> 16 != LIBAVFORMAT_VERSION_MAJOR) {
|
|
648 |
LOG_WARN("error: library major version (%u) differs from build headers (%u)", ff->avformat_v >> 16, LIBAVFORMAT_VERSION_MAJOR);
|
|
649 |
return false;
|
|
650 |
}
|
|
651 |
|
|
652 |
ff->avutil_version = dlsym(handle_util, "avutil_version");
|
|
653 |
ff->av_log_set_callback = dlsym(handle_util, "av_log_set_callback");
|
|
654 |
ff->av_log_set_level = dlsym(handle_util, "av_log_set_level");
|
|
655 |
ff->av_strerror = dlsym(handle_util, "av_strerror");
|
|
656 |
ff->av_malloc = dlsym(handle_util, "av_malloc");
|
|
657 |
ff->av_free = dlsym(handle_util, "av_free");
|
|
658 |
|
|
659 |
if ((err = dlerror()) != NULL) {
|
|
660 |
LOG_INFO("dlerror: %s", err);
|
|
661 |
return false;
|
|
662 |
}
|
|
663 |
|
|
664 |
ff->avutil_v = ff->avutil_version();
|
|
665 |
LOG_INFO("loaded "LIBAVUTIL" (%u.%u.%u)", ff->avutil_v >> 16, (ff->avutil_v >> 8) & 0xff, ff->avutil_v & 0xff);
|
|
666 |
if (ff->avutil_v >> 16 != LIBAVUTIL_VERSION_MAJOR) {
|
|
667 |
LOG_WARN("error: library major version (%u) differs from build headers (%u)", ff->avutil_v >> 16, LIBAVUTIL_VERSION_MAJOR);
|
|
668 |
return false;
|
|
669 |
}
|
|
670 |
|
|
671 |
return true;
|
|
672 |
}
|
|
673 |
|
|
674 |
static int ff_log_level = 0;
|
|
675 |
|
|
676 |
void av_err_callback(void *avcl, int level, const char *fmt, va_list vl) {
|
|
677 |
if (level > ff_log_level) return;
|
|
678 |
fprintf(stderr, "%s ffmpeg: ", logtime());
|
|
679 |
vfprintf(stderr, fmt, vl);
|
|
680 |
fflush(stderr);
|
|
681 |
}
|
|
682 |
|
|
683 |
static bool registered = false;
|
|
684 |
|
|
685 |
struct codec *register_ff(const char *codec) {
|
|
686 |
if (!registered) {
|
|
687 |
|
|
688 |
if (!load_ff()) {
|
|
689 |
return NULL;
|
|
690 |
}
|
|
691 |
|
|
692 |
switch (loglevel) {
|
|
693 |
case lERROR:
|
|
694 |
ff_log_level = AV_LOG_ERROR; break;
|
|
695 |
case lWARN:
|
|
696 |
ff_log_level = AV_LOG_WARNING; break;
|
|
697 |
case lINFO:
|
|
698 |
ff_log_level = AV_LOG_INFO; break;
|
|
699 |
case lDEBUG:
|
|
700 |
ff_log_level = AV_LOG_VERBOSE; break;
|
|
701 |
default: break;
|
|
702 |
}
|
|
703 |
|
|
704 |
ff->av_log_set_callback(av_err_callback);
|
|
705 |
|
|
706 |
ff->av_register_all();
|
|
707 |
|
|
708 |
registered = true;
|
|
709 |
}
|
|
710 |
|
|
711 |
if (!strcmp(codec, "wma")) {
|
|
712 |
|
|
713 |
static struct codec ret = {
|
|
714 |
'w', // id
|
|
715 |
"wma,wmap,wmal", // types
|
|
716 |
READ_SIZE, // min read
|
|
717 |
WRITE_SIZE, // min space
|
|
718 |
ff_open_wma, // open
|
|
719 |
ff_close, // close
|
|
720 |
ff_decode, // decode
|
|
721 |
};
|
|
722 |
|
|
723 |
return &ret;
|
|
724 |
}
|
|
725 |
|
|
726 |
if (!strcmp(codec, "alc")) {
|
|
727 |
|
|
728 |
static struct codec ret = {
|
|
729 |
'l', // id
|
|
730 |
"alc", // types
|
|
731 |
READ_SIZE, // min read
|
|
732 |
WRITE_SIZE, // min space
|
|
733 |
ff_open_alac,// open
|
|
734 |
ff_close, // close
|
|
735 |
ff_decode, // decode
|
|
736 |
};
|
|
737 |
|
|
738 |
return &ret;
|
|
739 |
}
|
|
740 |
|
|
741 |
return NULL;
|
|
742 |
}
|
|
743 |
|
|
744 |
#endif
|