/src/vlc/modules/codec/opus.c
Line | Count | Source |
1 | | /***************************************************************************** |
2 | | * opus.c: opus decoder/encoder module making use of libopus. |
3 | | ***************************************************************************** |
4 | | * Copyright (C) 2003-2009, 2012 VLC authors and VideoLAN |
5 | | * |
6 | | * Authors: Gregory Maxwell <greg@xiph.org> |
7 | | * Based on speex.c by: Gildas Bazin <gbazin@videolan.org> |
8 | | * |
9 | | * This program is free software; you can redistribute it and/or modify it |
10 | | * under the terms of the GNU Lesser General Public License as published by |
11 | | * the Free Software Foundation; either version 2.1 of the License, or |
12 | | * (at your option) any later version. |
13 | | * |
14 | | * This program is distributed in the hope that it will be useful, |
15 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | | * GNU Lesser General Public License for more details. |
18 | | * |
19 | | * You should have received a copy of the GNU Lesser General Public License |
20 | | * along with this program; if not, write to the Free Software Foundation, |
21 | | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
22 | | *****************************************************************************/ |
23 | | |
24 | | /***************************************************************************** |
25 | | * Preamble |
26 | | *****************************************************************************/ |
27 | | #ifdef HAVE_CONFIG_H |
28 | | # include "config.h" |
29 | | #endif |
30 | | |
31 | | #include <vlc_common.h> |
32 | | #include <vlc_plugin.h> |
33 | | #include <vlc_codec.h> |
34 | | #include <vlc_aout.h> |
35 | | #include "../demux/xiph.h" |
36 | | |
37 | | #include <ogg/ogg.h> |
38 | | #include <opus.h> |
39 | | #include <opus_multistream.h> |
40 | | #ifdef OPUS_HAVE_OPUS_PROJECTION_H |
41 | | # include <opus_projection.h> /* from 1.3.0 */ |
42 | | #endif |
43 | | |
44 | | #include "opus_header.h" |
45 | | |
46 | | #ifndef OPUS_SET_GAIN |
47 | | #include <math.h> |
48 | | #endif |
49 | | |
50 | | /***************************************************************************** |
51 | | * Module descriptor |
52 | | *****************************************************************************/ |
53 | | static int OpenDecoder ( vlc_object_t * ); |
54 | | static void CloseDecoder ( vlc_object_t * ); |
55 | | #ifdef ENABLE_SOUT |
56 | | static int OpenEncoder ( vlc_object_t * ); |
57 | | static void CloseEncoder ( encoder_t * ); |
58 | | #endif |
59 | | |
60 | 116 | vlc_module_begin () |
61 | 58 | set_subcategory( SUBCAT_INPUT_ACODEC ) |
62 | | |
63 | 58 | set_description( N_("Opus audio decoder") ) |
64 | 58 | set_capability( "audio decoder", 100 ) |
65 | 58 | set_shortname( N_("Opus") ) |
66 | 116 | set_callbacks( OpenDecoder, CloseDecoder ) |
67 | | |
68 | 58 | #ifdef ENABLE_SOUT |
69 | 58 | add_submodule () |
70 | 58 | set_description( N_("Opus audio encoder") ) |
71 | 58 | set_capability( "audio encoder", 150 ) |
72 | 58 | set_shortname( N_("Opus") ) |
73 | 58 | set_callback( OpenEncoder ) |
74 | 58 | #endif |
75 | | |
76 | 58 | vlc_module_end () |
77 | | |
78 | | /***************************************************************************** |
79 | | * decoder_sys_t : opus decoder descriptor |
80 | | *****************************************************************************/ |
81 | | typedef struct |
82 | | { |
83 | | /* |
84 | | * Input properties |
85 | | */ |
86 | | bool b_has_headers; |
87 | | |
88 | | /* |
89 | | * Opus properties |
90 | | */ |
91 | | OpusHeader header; |
92 | | OpusMSDecoder *p_st; |
93 | | #ifdef OPUS_HAVE_OPUS_PROJECTION_H |
94 | | OpusProjectionDecoder *p_pr; |
95 | | #endif |
96 | | |
97 | | /* |
98 | | * Common properties |
99 | | */ |
100 | | date_t end_date; |
101 | | } decoder_sys_t; |
102 | | |
103 | | static const int pi_channels_maps[9] = |
104 | | { |
105 | | 0, |
106 | | AOUT_CHAN_CENTER, |
107 | | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT, |
108 | | AOUT_CHAN_CENTER | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT, |
109 | | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT |
110 | | | AOUT_CHAN_REARRIGHT, |
111 | | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER |
112 | | | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT, |
113 | | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER |
114 | | | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE, |
115 | | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER |
116 | | | AOUT_CHAN_REARCENTER | AOUT_CHAN_MIDDLELEFT |
117 | | | AOUT_CHAN_MIDDLERIGHT | AOUT_CHAN_LFE, |
118 | | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
119 | | | AOUT_CHAN_REARRIGHT | AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT |
120 | | | AOUT_CHAN_LFE, |
121 | | }; |
122 | | |
123 | | /* |
124 | | ** channel order as defined in http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9 |
125 | | */ |
126 | | |
127 | | /* recommended vorbis channel order for 8 channels */ |
128 | | static const uint32_t pi_8channels_in[] = |
129 | | { AOUT_CHAN_LEFT, AOUT_CHAN_CENTER, AOUT_CHAN_RIGHT, |
130 | | AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT, |
131 | | AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,AOUT_CHAN_LFE, 0 }; |
132 | | |
133 | | /* recommended vorbis channel order for 7 channels */ |
134 | | static const uint32_t pi_7channels_in[] = |
135 | | { AOUT_CHAN_LEFT, AOUT_CHAN_CENTER, AOUT_CHAN_RIGHT, |
136 | | AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT, |
137 | | AOUT_CHAN_REARCENTER, AOUT_CHAN_LFE, 0 }; |
138 | | |
139 | | /* recommended vorbis channel order for 6 channels */ |
140 | | static const uint32_t pi_6channels_in[] = |
141 | | { AOUT_CHAN_LEFT, AOUT_CHAN_CENTER, AOUT_CHAN_RIGHT, |
142 | | AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, AOUT_CHAN_LFE, 0 }; |
143 | | |
144 | | /* recommended vorbis channel order for 5 channels */ |
145 | | static const uint32_t pi_5channels_in[] = |
146 | | { AOUT_CHAN_LEFT, AOUT_CHAN_CENTER, AOUT_CHAN_RIGHT, |
147 | | AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, 0 }; |
148 | | |
149 | | /* recommended vorbis channel order for 4 channels */ |
150 | | static const uint32_t pi_4channels_in[] = |
151 | | { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, 0 }; |
152 | | |
153 | | /* recommended vorbis channel order for 3 channels */ |
154 | | static const uint32_t pi_3channels_in[] = |
155 | | { AOUT_CHAN_LEFT, AOUT_CHAN_CENTER, AOUT_CHAN_RIGHT, 0 }; |
156 | | |
157 | | /**************************************************************************** |
158 | | * Local prototypes |
159 | | ****************************************************************************/ |
160 | | |
161 | | static int DecodeAudio ( decoder_t *, block_t * ); |
162 | | static void Flush( decoder_t * ); |
163 | | static int ProcessHeaders( decoder_t * ); |
164 | | static int ProcessInitialHeader ( decoder_t *, ogg_packet * ); |
165 | | static block_t *ProcessPacket( decoder_t *, ogg_packet *, block_t * ); |
166 | | |
167 | | static block_t *DecodePacket( decoder_t *, ogg_packet *, int, vlc_tick_t ); |
168 | | /***************************************************************************** |
169 | | * Implementation Wrappers |
170 | | *****************************************************************************/ |
171 | | |
172 | | static void DecoderDestroy( decoder_sys_t *p_sys ) |
173 | 459 | { |
174 | 459 | #ifdef OPUS_HAVE_OPUS_PROJECTION_H |
175 | 459 | if( p_sys->p_pr ) |
176 | 0 | { |
177 | 0 | opus_projection_decoder_destroy( p_sys->p_pr ); |
178 | 0 | p_sys->p_pr = NULL; |
179 | 0 | } |
180 | 459 | else |
181 | 459 | #endif |
182 | 459 | if( p_sys->p_st ) |
183 | 232 | { |
184 | 232 | opus_multistream_decoder_destroy( p_sys->p_st ); |
185 | 232 | p_sys->p_st = NULL; |
186 | 232 | } |
187 | 459 | } |
188 | | |
189 | | #ifdef OPUS_SET_GAIN |
190 | | static int SetDecoderGain( decoder_sys_t *p_sys, int gain ) |
191 | 232 | { |
192 | 232 | # ifdef OPUS_HAVE_OPUS_PROJECTION_H |
193 | 232 | if( p_sys->p_pr ) |
194 | 0 | { |
195 | 0 | if( opus_projection_decoder_ctl( |
196 | 0 | p_sys->p_pr, OPUS_SET_GAIN(gain) ) != OPUS_OK ) |
197 | 0 | return VLC_EGENERIC; |
198 | 0 | } |
199 | 232 | else |
200 | 232 | # endif |
201 | 232 | { |
202 | 232 | if( opus_multistream_decoder_ctl( |
203 | 232 | p_sys->p_st, OPUS_SET_GAIN(gain) ) != OPUS_OK ) |
204 | 0 | return VLC_EGENERIC; |
205 | 232 | } |
206 | 232 | return VLC_SUCCESS; |
207 | 232 | } |
208 | | #endif |
209 | | |
210 | | static int DecoderDecodeFloat( decoder_sys_t *p_sys, const ogg_packet *p_oggpacket, |
211 | | int spp, block_t *out ) |
212 | 0 | { |
213 | 0 | #ifdef OPUS_HAVE_OPUS_PROJECTION_H |
214 | 0 | if( p_sys->p_pr ) |
215 | 0 | return opus_projection_decode_float(p_sys->p_pr, p_oggpacket->packet, |
216 | 0 | p_oggpacket->bytes, |
217 | 0 | (float *)out->p_buffer, spp, 0); |
218 | 0 | else |
219 | 0 | #endif |
220 | 0 | return opus_multistream_decode_float(p_sys->p_st, p_oggpacket->packet, |
221 | 0 | p_oggpacket->bytes, |
222 | 0 | (float *)out->p_buffer, spp, 0); |
223 | 0 | } |
224 | | |
225 | | static int DecoderCreate( decoder_sys_t *p_sys ) |
226 | 4.25k | { |
227 | 4.25k | int err; |
228 | 4.25k | const OpusHeader *p_header = &p_sys->header; |
229 | 4.25k | #ifdef OPUS_HAVE_OPUS_PROJECTION_H |
230 | 4.25k | if( p_header->channel_mapping == 3 ) |
231 | 0 | { |
232 | 0 | p_sys->p_pr = opus_projection_decoder_create( 48000, p_header->channels, |
233 | 0 | p_header->nb_streams, p_header->nb_coupled, |
234 | 0 | p_header->dmatrix, p_header->dmatrix_size, &err ); |
235 | 0 | } |
236 | 4.25k | else |
237 | 4.25k | #endif |
238 | 4.25k | { |
239 | 4.25k | const unsigned char* p_stream_map = p_header->stream_map; |
240 | 4.25k | unsigned char new_stream_map[8]; |
241 | 4.25k | if ( p_header->channel_mapping <= 1 ) |
242 | 232 | { |
243 | 232 | if( p_header->channels > 2 ) |
244 | 33 | { |
245 | 33 | static const uint32_t *pi_ch[6] = { pi_3channels_in, pi_4channels_in, |
246 | 33 | pi_5channels_in, pi_6channels_in, |
247 | 33 | pi_7channels_in, pi_8channels_in }; |
248 | 33 | uint8_t pi_chan_table[AOUT_CHAN_MAX]; |
249 | | |
250 | 33 | aout_CheckChannelReorder( pi_ch[p_header->channels-3], NULL, |
251 | 33 | pi_channels_maps[p_header->channels], |
252 | 33 | pi_chan_table ); |
253 | 227 | for( int i=0;i<p_header->channels;i++ ) |
254 | 194 | new_stream_map[pi_chan_table[i]] = p_header->stream_map[i]; |
255 | | |
256 | 33 | p_stream_map = new_stream_map; |
257 | 33 | } |
258 | 232 | } |
259 | | |
260 | 4.25k | p_sys->p_st = opus_multistream_decoder_create( 48000, p_header->channels, |
261 | 4.25k | p_header->nb_streams, p_header->nb_coupled, |
262 | 4.25k | p_stream_map, &err ); |
263 | 4.25k | } |
264 | 4.25k | return err == OPUS_OK ? VLC_SUCCESS : VLC_EGENERIC; |
265 | 4.25k | } |
266 | | |
267 | | /***************************************************************************** |
268 | | * OpenDecoder: probe the decoder and return score |
269 | | *****************************************************************************/ |
270 | | static int OpenDecoder( vlc_object_t *p_this ) |
271 | 701k | { |
272 | 701k | decoder_t *p_dec = (decoder_t*)p_this; |
273 | 701k | decoder_sys_t *p_sys; |
274 | | |
275 | 701k | if( p_dec->fmt_in->i_codec != VLC_CODEC_OPUS ) |
276 | 700k | return VLC_EGENERIC; |
277 | | |
278 | | /* Allocate the memory needed to store the decoder's structure */ |
279 | 459 | if( ( p_dec->p_sys = p_sys = malloc(sizeof(decoder_sys_t)) ) == NULL ) |
280 | 0 | return VLC_ENOMEM; |
281 | 459 | p_sys->b_has_headers = false; |
282 | 459 | opus_header_init(&p_sys->header); |
283 | | |
284 | 459 | date_Set( &p_sys->end_date, VLC_TICK_INVALID ); |
285 | | |
286 | | /* Set output properties */ |
287 | 459 | p_dec->fmt_out.i_codec = VLC_CODEC_FL32; |
288 | | |
289 | 459 | p_dec->pf_decode = DecodeAudio; |
290 | 459 | p_dec->pf_flush = Flush; |
291 | | |
292 | 459 | p_sys->p_st = NULL; |
293 | 459 | #ifdef OPUS_HAVE_OPUS_PROJECTION_H |
294 | 459 | p_sys->p_pr = NULL; |
295 | 459 | #endif |
296 | | |
297 | 459 | return VLC_SUCCESS; |
298 | 459 | } |
299 | | |
300 | | /**************************************************************************** |
301 | | * DecodeBlock: the whole thing |
302 | | **************************************************************************** |
303 | | * This function must be fed with ogg packets. |
304 | | ****************************************************************************/ |
305 | | static block_t *DecodeBlock( decoder_t *p_dec, block_t *p_block ) |
306 | 679k | { |
307 | 679k | decoder_sys_t *p_sys = p_dec->p_sys; |
308 | 679k | ogg_packet oggpacket; |
309 | | |
310 | | /* Block to Ogg packet */ |
311 | 679k | oggpacket.packet = p_block->p_buffer; |
312 | 679k | oggpacket.bytes = p_block->i_buffer; |
313 | | |
314 | 679k | oggpacket.granulepos = -1; |
315 | 679k | oggpacket.b_o_s = 0; |
316 | 679k | oggpacket.e_o_s = 0; |
317 | 679k | oggpacket.packetno = 0; |
318 | | |
319 | | /* Check for headers */ |
320 | 679k | if( !p_sys->b_has_headers ) |
321 | 24.8k | { |
322 | 24.8k | if( ProcessHeaders( p_dec ) ) |
323 | 24.6k | { |
324 | 24.6k | block_Release( p_block ); |
325 | 24.6k | return NULL; |
326 | 24.6k | } |
327 | 232 | p_sys->b_has_headers = true; |
328 | 232 | } |
329 | | |
330 | 654k | return ProcessPacket( p_dec, &oggpacket, p_block ); |
331 | 679k | } |
332 | | |
333 | | static int DecodeAudio( decoder_t *p_dec, block_t *p_block ) |
334 | 1.39M | { |
335 | 1.39M | if( p_block == NULL ) /* No Drain */ |
336 | 710k | return VLCDEC_SUCCESS; |
337 | | |
338 | 679k | p_block = DecodeBlock( p_dec, p_block ); |
339 | 679k | if( p_block != NULL ) |
340 | 0 | decoder_QueueAudio( p_dec, p_block ); |
341 | 679k | return VLCDEC_SUCCESS; |
342 | 1.39M | } |
343 | | |
344 | | /***************************************************************************** |
345 | | * ProcessHeaders: process Opus headers. |
346 | | *****************************************************************************/ |
347 | | static int ProcessHeaders( decoder_t *p_dec ) |
348 | 24.8k | { |
349 | 24.8k | decoder_sys_t *p_sys = p_dec->p_sys; |
350 | 24.8k | ogg_packet oggpacket; |
351 | | |
352 | 24.8k | size_t pi_size[XIPH_MAX_HEADER_COUNT]; |
353 | 24.8k | const void *pp_data[XIPH_MAX_HEADER_COUNT]; |
354 | 24.8k | size_t i_count; |
355 | | |
356 | 24.8k | size_t i_extra = p_dec->fmt_in->i_extra; |
357 | 24.8k | const uint8_t *p_extra = p_dec->fmt_in->p_extra; |
358 | 24.8k | uint8_t *p_alloc = NULL; |
359 | | |
360 | | /* Xiph headers as extradata */ |
361 | 24.8k | if( i_extra > 21 && !memcmp( &p_extra[2], "OpusHead", 8 ) ) |
362 | 4.62k | { |
363 | 4.62k | if( xiph_SplitHeaders( pi_size, pp_data, &i_count, |
364 | 4.62k | i_extra, p_extra ) || i_count < 2 ) |
365 | 0 | { |
366 | | /* Borked Xiph headers */ |
367 | 0 | free( p_alloc ); |
368 | 0 | return VLC_EGENERIC; |
369 | 0 | } |
370 | | |
371 | 4.62k | oggpacket.bytes = pi_size[0]; |
372 | 4.62k | oggpacket.packet = (unsigned char *) pp_data[0]; |
373 | 4.62k | } |
374 | | /* If we have no header (e.g. from RTP), make one. */ |
375 | 20.2k | else if( i_extra < 19 || memcmp( p_extra, "OpusHead", 8 ) ) |
376 | 20.2k | { |
377 | 20.2k | OpusHeader header; |
378 | 20.2k | opus_header_init(&header); |
379 | | |
380 | 20.2k | opus_prepare_header( p_dec->fmt_in->audio.i_channels ? p_dec->fmt_in->audio.i_channels : 2, |
381 | 20.2k | p_dec->fmt_in->audio.i_rate ? p_dec->fmt_in->audio.i_rate : 48000, |
382 | 20.2k | &header ); |
383 | | |
384 | | /* This is the only case where opus_write_header will try to read header.stream_map */ |
385 | 20.2k | if( header.channel_mapping == 1 ) |
386 | 33 | { |
387 | | /* default mapping */ |
388 | 33 | static const unsigned char map[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; |
389 | 33 | memcpy(header.stream_map, map, sizeof(map)); |
390 | 33 | } |
391 | | |
392 | 20.2k | int ret = opus_write_header( &p_alloc, &i_extra, &header, |
393 | 20.2k | opus_get_version_string() ); |
394 | 20.2k | opus_header_clean(&header); |
395 | 20.2k | if(ret != 0 || i_extra < 21) |
396 | 0 | { |
397 | 0 | free( p_alloc ); |
398 | 0 | return VLC_ENOMEM; |
399 | 0 | } |
400 | 20.2k | oggpacket.bytes = p_alloc[1]; /* Xiph header is type8/size8 */ |
401 | 20.2k | oggpacket.packet = (unsigned char *) p_alloc + 2; /* Point directly to opus header start */ |
402 | 20.2k | } |
403 | 11 | else /* raw header in extradata */ |
404 | 11 | { |
405 | 11 | oggpacket.bytes = i_extra; |
406 | 11 | oggpacket.packet = (unsigned char *) p_extra; |
407 | 11 | } |
408 | | |
409 | | /* Take care of the initial Opus header */ |
410 | 24.8k | oggpacket.granulepos = -1; |
411 | 24.8k | oggpacket.e_o_s = 0; |
412 | 24.8k | oggpacket.packetno = 0; |
413 | 24.8k | oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */ |
414 | 24.8k | int ret = ProcessInitialHeader( p_dec, &oggpacket ); |
415 | | |
416 | 24.8k | if (ret != VLC_SUCCESS) |
417 | 24.6k | { |
418 | 24.6k | msg_Err( p_dec, "initial Opus header is corrupted" ); |
419 | 24.6k | opus_header_clean( &p_sys->header ); |
420 | 24.6k | opus_header_init( &p_sys->header ); |
421 | 24.6k | } |
422 | | |
423 | 24.8k | free( p_alloc ); |
424 | | |
425 | 24.8k | return ret; |
426 | 24.8k | } |
427 | | |
428 | | /***************************************************************************** |
429 | | * ProcessInitialHeader: processes the initial Opus header packet. |
430 | | *****************************************************************************/ |
431 | | static int ProcessInitialHeader( decoder_t *p_dec, ogg_packet *p_oggpacket ) |
432 | 24.8k | { |
433 | 24.8k | decoder_sys_t *p_sys = p_dec->p_sys; |
434 | 24.8k | OpusHeader *p_header = &p_sys->header; |
435 | | |
436 | 24.8k | if( !opus_header_parse((unsigned char *)p_oggpacket->packet,p_oggpacket->bytes,p_header) ) |
437 | 3.31k | { |
438 | 3.31k | msg_Err( p_dec, "cannot read Opus header" ); |
439 | 3.31k | return VLC_EGENERIC; |
440 | 3.31k | } |
441 | | |
442 | 21.5k | msg_Dbg( p_dec, "Opus audio with %d channels, %d samples preskip, %d samplerate", |
443 | 21.5k | p_header->channels, p_header->preskip, p_header->input_sample_rate ); |
444 | | |
445 | 21.5k | if((p_header->channels>2 && p_header->channel_mapping==0) || |
446 | 21.5k | (p_header->channels>8 && p_header->channel_mapping==1) || |
447 | 21.5k | (p_header->channels>18 && p_header->channel_mapping==2) || |
448 | 21.5k | (p_header->channels>18 && p_header->channel_mapping==3)) |
449 | 0 | { |
450 | 0 | msg_Err( p_dec, "Unsupported channel mapping" ); |
451 | 0 | return VLC_EGENERIC; |
452 | 0 | } |
453 | 21.5k | if (p_header->channel_mapping >= 2) |
454 | 21.2k | { |
455 | 21.2k | int i_order = floor(sqrt(p_header->channels)); |
456 | 21.2k | int i_nondiegetic = p_header->channels - i_order * i_order; |
457 | 21.2k | msg_Dbg( p_dec, "Opus Ambisonic audio order=%d channels=%d+%d", |
458 | 21.2k | i_order, p_header->channels - i_nondiegetic, i_nondiegetic); |
459 | 21.2k | if (i_nondiegetic != 0 && i_nondiegetic != 2) |
460 | 17.2k | { |
461 | 17.2k | msg_Err( p_dec, "Unsupported ambisonic channel mapping" ); |
462 | 17.2k | return VLC_EGENERIC; |
463 | 17.2k | } |
464 | 21.2k | } |
465 | | |
466 | | /* Setup the format */ |
467 | 4.25k | p_dec->fmt_out.audio.i_channels = p_header->channels; |
468 | 4.25k | p_dec->fmt_out.audio.i_rate = 48000; |
469 | | |
470 | 4.25k | if (p_header->channel_mapping <= 1) |
471 | 232 | { |
472 | 232 | p_dec->fmt_out.audio.i_physical_channels = |
473 | 232 | pi_channels_maps[p_header->channels]; |
474 | 232 | } |
475 | 4.02k | else //p_header->channel_mapping >= 2 |
476 | 4.02k | { |
477 | 4.02k | p_dec->fmt_out.audio.channel_type = AUDIO_CHANNEL_TYPE_AMBISONICS; |
478 | 4.02k | } |
479 | | |
480 | | /* Opus decoder init */ |
481 | 4.25k | if( DecoderCreate( p_sys ) != VLC_SUCCESS ) |
482 | 4.02k | { |
483 | 4.02k | msg_Err( p_dec, "decoder initialization failed" ); |
484 | 4.02k | return VLC_EGENERIC; |
485 | 4.02k | } |
486 | | |
487 | 232 | #ifdef OPUS_SET_GAIN |
488 | 232 | if( SetDecoderGain( p_sys, p_header->gain ) != VLC_SUCCESS ) |
489 | 0 | { |
490 | 0 | msg_Err( p_dec, "OPUS_SET_GAIN failed" ); |
491 | 0 | DecoderDestroy( p_sys ); |
492 | 0 | return VLC_EGENERIC; |
493 | 0 | } |
494 | 232 | #endif |
495 | | |
496 | 232 | date_Init( &p_sys->end_date, 48000, 1 ); |
497 | | |
498 | 232 | return VLC_SUCCESS; |
499 | 232 | } |
500 | | |
501 | | /***************************************************************************** |
502 | | * Flush: |
503 | | *****************************************************************************/ |
504 | | static void Flush( decoder_t *p_dec ) |
505 | 33 | { |
506 | 33 | decoder_sys_t *p_sys = p_dec->p_sys; |
507 | | |
508 | 33 | date_Set( &p_sys->end_date, VLC_TICK_INVALID ); |
509 | 33 | } |
510 | | |
511 | | /***************************************************************************** |
512 | | * ProcessPacket: processes a Opus packet. |
513 | | *****************************************************************************/ |
514 | | static block_t *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket, |
515 | | block_t *p_block ) |
516 | 654k | { |
517 | 654k | decoder_sys_t *p_sys = p_dec->p_sys; |
518 | | |
519 | 654k | if( p_block->i_flags & (BLOCK_FLAG_CORRUPTED|BLOCK_FLAG_DISCONTINUITY) ) |
520 | 33 | { |
521 | 33 | Flush( p_dec ); |
522 | 33 | if( p_block->i_flags & BLOCK_FLAG_CORRUPTED ) |
523 | 0 | { |
524 | 0 | block_Release( p_block ); |
525 | 0 | return NULL; |
526 | 0 | } |
527 | 33 | } |
528 | | |
529 | | /* Date management */ |
530 | 654k | if( p_block->i_pts != VLC_TICK_INVALID && |
531 | 654k | p_block->i_pts != date_Get( &p_sys->end_date ) ) |
532 | 653k | { |
533 | 653k | date_Set( &p_sys->end_date, p_block->i_pts ); |
534 | 653k | } |
535 | | |
536 | 654k | if( date_Get( &p_sys->end_date ) == VLC_TICK_INVALID ) |
537 | 0 | { |
538 | | /* We've just started the stream, wait for the first PTS. */ |
539 | 0 | block_Release( p_block ); |
540 | 0 | return NULL; |
541 | 0 | } |
542 | | |
543 | | /* trimming info */ |
544 | 654k | vlc_tick_t i_max_duration = (p_block->i_flags & BLOCK_FLAG_END_OF_SEQUENCE) ? |
545 | 654k | p_block->i_length : 0; |
546 | | |
547 | 654k | block_t *p_aout_buffer = DecodePacket( p_dec, p_oggpacket, |
548 | 654k | p_block->i_nb_samples, |
549 | 654k | i_max_duration ); |
550 | | |
551 | 654k | block_Release( p_block ); |
552 | 654k | return p_aout_buffer; |
553 | 654k | } |
554 | | |
555 | | /***************************************************************************** |
556 | | * DecodePacket: decodes a Opus packet. |
557 | | *****************************************************************************/ |
558 | | static block_t *DecodePacket( decoder_t *p_dec, ogg_packet *p_oggpacket, |
559 | | int i_nb_samples, vlc_tick_t i_duration ) |
560 | 654k | { |
561 | 654k | decoder_sys_t *p_sys = p_dec->p_sys; |
562 | | |
563 | 654k | if( !p_oggpacket->bytes ) |
564 | 823 | return NULL; |
565 | | |
566 | 654k | int spp; |
567 | 654k | spp=opus_packet_get_nb_frames(p_oggpacket->packet,p_oggpacket->bytes); |
568 | 654k | if(spp>0)spp*=opus_packet_get_samples_per_frame(p_oggpacket->packet,48000); |
569 | 654k | if(spp<120||spp>120*48)return NULL; |
570 | | |
571 | | /* Since the information isn't always available at the demux level |
572 | | * use the packet's sample number */ |
573 | 539k | if(!i_nb_samples) |
574 | 510k | i_nb_samples = spp; |
575 | | |
576 | 539k | if( decoder_UpdateAudioFormat( p_dec ) ) |
577 | 539k | return NULL; |
578 | 0 | block_t *p_aout_buffer=decoder_NewAudioBuffer( p_dec, spp ); |
579 | 0 | if ( !p_aout_buffer ) |
580 | 0 | { |
581 | 0 | msg_Err(p_dec, "Oops: No new buffer was returned!"); |
582 | 0 | return NULL; |
583 | 0 | } |
584 | | |
585 | 0 | spp = DecoderDecodeFloat( p_sys, p_oggpacket, spp, p_aout_buffer ); |
586 | |
|
587 | 0 | int i_end_trim = 0; |
588 | 0 | if( i_duration > 0 && spp > 0 && |
589 | 0 | i_duration < vlc_tick_from_samples(i_nb_samples, 48000) ) |
590 | 0 | { |
591 | 0 | i_end_trim = spp - VLC_CLIP(samples_from_vlc_tick(i_duration, 48000), 0, spp); |
592 | 0 | } |
593 | |
|
594 | 0 | if( spp < 0 || i_nb_samples <= 0 || i_end_trim >= i_nb_samples) |
595 | 0 | { |
596 | 0 | block_Release(p_aout_buffer); |
597 | 0 | if( spp < 0 ) |
598 | 0 | msg_Err( p_dec, "Error: corrupted stream?" ); |
599 | 0 | return NULL; |
600 | 0 | } |
601 | | |
602 | 0 | p_aout_buffer->i_buffer = (i_nb_samples - i_end_trim) * |
603 | 0 | p_sys->header.channels * sizeof(float); |
604 | |
|
605 | 0 | if( spp > i_nb_samples ) |
606 | 0 | { |
607 | 0 | memmove(p_aout_buffer->p_buffer, |
608 | 0 | p_aout_buffer->p_buffer |
609 | 0 | + (spp - i_nb_samples)*p_sys->header.channels*sizeof(float), |
610 | 0 | p_aout_buffer->i_buffer); |
611 | 0 | } |
612 | 0 | i_nb_samples -= i_end_trim; |
613 | |
|
614 | | #ifndef OPUS_SET_GAIN |
615 | | if(p_sys->header.gain!=0) |
616 | | { |
617 | | float gain = pow(10., p_sys->header.gain/5120.); |
618 | | float *buf =(float *)p_aout_buffer->p_buffer; |
619 | | for( int i = 0; i < i_nb_samples*p_sys->header.channels; i++) |
620 | | buf[i] *= gain; |
621 | | } |
622 | | #endif |
623 | 0 | p_aout_buffer->i_nb_samples = i_nb_samples; |
624 | 0 | p_aout_buffer->i_pts = date_Get( &p_sys->end_date ); |
625 | 0 | p_aout_buffer->i_length = date_Increment( &p_sys->end_date, i_nb_samples ) |
626 | 0 | - p_aout_buffer->i_pts; |
627 | 0 | return p_aout_buffer; |
628 | 0 | } |
629 | | |
630 | | /***************************************************************************** |
631 | | * CloseDecoder: Opus decoder destruction |
632 | | *****************************************************************************/ |
633 | | static void CloseDecoder( vlc_object_t *p_this ) |
634 | 459 | { |
635 | 459 | decoder_t * p_dec = (decoder_t *)p_this; |
636 | 459 | decoder_sys_t *p_sys = p_dec->p_sys; |
637 | | |
638 | 459 | DecoderDestroy( p_sys ); |
639 | | |
640 | 459 | opus_header_clean( &p_sys->header ); |
641 | 459 | free( p_sys ); |
642 | 459 | } |
643 | | |
644 | | #ifdef ENABLE_SOUT |
645 | | |
646 | | /* only ever encode 20 ms at a time, going longer doesn't yield much compression |
647 | | gain, shorter does have a compression loss, and doesn't matter so much in |
648 | | Ogg, unless you really need low latency, which would also require muxing one |
649 | | packet per page. */ |
650 | | static const unsigned OPUS_FRAME_SIZE = 960; /* 48000 * 20 / 1000 */ |
651 | | |
652 | | typedef struct |
653 | | { |
654 | | OpusMSEncoder *enc; |
655 | | float *buffer; |
656 | | unsigned i_nb_samples; |
657 | | int i_samples_delay; |
658 | | block_t *padding; |
659 | | int nb_streams; |
660 | | } encoder_sys_t; |
661 | | |
662 | | static unsigned fill_buffer(encoder_t *enc, unsigned src_start, block_t *src, |
663 | | unsigned samples) |
664 | 0 | { |
665 | 0 | encoder_sys_t *p_sys = enc->p_sys; |
666 | 0 | const unsigned channels = enc->fmt_out.audio.i_channels; |
667 | 0 | const float *src_buf = ((const float *) src->p_buffer) + src_start; |
668 | 0 | float *dest_buf = p_sys->buffer + (p_sys->i_nb_samples * channels); |
669 | 0 | const unsigned len = samples * channels; |
670 | |
|
671 | 0 | memcpy(dest_buf, src_buf, len * sizeof(float)); |
672 | |
|
673 | 0 | p_sys->i_nb_samples += samples; |
674 | 0 | src_start += len; |
675 | |
|
676 | 0 | src->i_nb_samples -= samples; |
677 | 0 | return src_start; |
678 | 0 | } |
679 | | |
680 | | static block_t *Encode(encoder_t *enc, block_t *buf) |
681 | 0 | { |
682 | 0 | encoder_sys_t *sys = enc->p_sys; |
683 | |
|
684 | 0 | if (!buf) |
685 | 0 | return NULL; |
686 | | |
687 | 0 | vlc_tick_t i_pts = buf->i_pts - |
688 | 0 | vlc_tick_from_samples( sys->i_samples_delay, |
689 | 0 | enc->fmt_in.audio.i_rate ); |
690 | |
|
691 | 0 | sys->i_samples_delay += buf->i_nb_samples; |
692 | |
|
693 | 0 | block_t *result = NULL; |
694 | 0 | unsigned src_start = 0; |
695 | 0 | unsigned padding_start = 0; |
696 | | /* The maximum Opus frame size is 1275 bytes + TOC sequence length. */ |
697 | 0 | const unsigned OPUS_MAX_ENCODED_BYTES = ((1275 + 3) * sys->nb_streams) - 2; |
698 | |
|
699 | 0 | while (sys->i_nb_samples + buf->i_nb_samples >= OPUS_FRAME_SIZE) |
700 | 0 | { |
701 | 0 | block_t *out_block = block_Alloc(OPUS_MAX_ENCODED_BYTES); |
702 | 0 | if (unlikely(out_block == NULL)) |
703 | 0 | { |
704 | 0 | block_ChainRelease(result); |
705 | 0 | return NULL; |
706 | 0 | } |
707 | | |
708 | | /* add padding to beginning */ |
709 | 0 | if (sys->padding) |
710 | 0 | { |
711 | 0 | const size_t leftover_space = OPUS_FRAME_SIZE - sys->i_nb_samples; |
712 | 0 | padding_start = fill_buffer(enc, padding_start, sys->padding, |
713 | 0 | __MIN(sys->padding->i_nb_samples, leftover_space)); |
714 | 0 | if (sys->padding->i_nb_samples <= 0) |
715 | 0 | { |
716 | 0 | block_Release(sys->padding); |
717 | 0 | sys->padding = NULL; |
718 | 0 | } |
719 | 0 | } |
720 | | |
721 | | /* padding may have been freed either before or inside previous |
722 | | * if-statement */ |
723 | 0 | if (!sys->padding) |
724 | 0 | { |
725 | 0 | const size_t leftover_space = OPUS_FRAME_SIZE - sys->i_nb_samples; |
726 | 0 | src_start = fill_buffer(enc, src_start, buf, |
727 | 0 | __MIN(buf->i_nb_samples, leftover_space)); |
728 | 0 | } |
729 | |
|
730 | 0 | opus_int32 bytes_encoded = opus_multistream_encode_float(sys->enc, sys->buffer, |
731 | 0 | OPUS_FRAME_SIZE, out_block->p_buffer, out_block->i_buffer); |
732 | |
|
733 | 0 | if (bytes_encoded < 0) |
734 | 0 | { |
735 | 0 | block_Release(out_block); |
736 | 0 | } |
737 | 0 | else |
738 | 0 | { |
739 | 0 | out_block->i_length = vlc_tick_from_samples( OPUS_FRAME_SIZE, |
740 | 0 | enc->fmt_in.audio.i_rate ); |
741 | |
|
742 | 0 | out_block->i_dts = out_block->i_pts = i_pts; |
743 | |
|
744 | 0 | sys->i_samples_delay -= OPUS_FRAME_SIZE; |
745 | |
|
746 | 0 | i_pts += out_block->i_length; |
747 | |
|
748 | 0 | sys->i_nb_samples = 0; |
749 | |
|
750 | 0 | out_block->i_buffer = bytes_encoded; |
751 | 0 | block_ChainAppend(&result, out_block); |
752 | 0 | } |
753 | 0 | } |
754 | | |
755 | | /* put leftover samples at beginning of buffer */ |
756 | 0 | if (buf->i_nb_samples > 0) |
757 | 0 | fill_buffer(enc, src_start, buf, buf->i_nb_samples); |
758 | |
|
759 | 0 | return result; |
760 | 0 | } |
761 | | |
762 | | static int OpenEncoder(vlc_object_t *p_this) |
763 | 0 | { |
764 | 0 | encoder_t *enc = (encoder_t *)p_this; |
765 | |
|
766 | 0 | if (enc->fmt_out.i_codec != VLC_CODEC_OPUS) |
767 | 0 | return VLC_EGENERIC; |
768 | | |
769 | 0 | encoder_sys_t *sys = malloc(sizeof(*sys)); |
770 | 0 | if (!sys) |
771 | 0 | return VLC_ENOMEM; |
772 | | |
773 | 0 | int status = VLC_SUCCESS; |
774 | 0 | sys->buffer = NULL; |
775 | 0 | sys->enc = NULL; |
776 | |
|
777 | 0 | enc->fmt_in.i_codec = VLC_CODEC_FL32; |
778 | 0 | enc->fmt_in.audio.i_rate = /* Only 48kHz */ |
779 | 0 | enc->fmt_out.audio.i_rate = 48000; |
780 | 0 | enc->fmt_out.audio.i_channels = enc->fmt_in.audio.i_channels; |
781 | |
|
782 | 0 | OpusHeader header; |
783 | 0 | opus_header_init(&header); |
784 | |
|
785 | 0 | opus_prepare_header(enc->fmt_out.audio.i_channels, |
786 | 0 | enc->fmt_out.audio.i_rate, &header); |
787 | | |
788 | | /* needed for max encoded size calculation */ |
789 | 0 | sys->nb_streams = header.nb_streams; |
790 | |
|
791 | 0 | int err; |
792 | 0 | sys->enc = |
793 | 0 | opus_multistream_surround_encoder_create(enc->fmt_in.audio.i_rate, |
794 | 0 | enc->fmt_in.audio.i_channels, header.channel_mapping, |
795 | 0 | &header.nb_streams, &header.nb_coupled, header.stream_map, |
796 | 0 | OPUS_APPLICATION_AUDIO, &err); |
797 | |
|
798 | 0 | if (err != OPUS_OK) |
799 | 0 | { |
800 | 0 | msg_Err(enc, "Could not create encoder: error %d", err); |
801 | 0 | sys->enc = NULL; |
802 | 0 | status = VLC_EGENERIC; |
803 | 0 | goto error; |
804 | 0 | } |
805 | | |
806 | | /* TODO: vbr, fec */ |
807 | | |
808 | 0 | if( enc->fmt_out.i_bitrate ) |
809 | 0 | opus_multistream_encoder_ctl(sys->enc, OPUS_SET_BITRATE( enc->fmt_out.i_bitrate )); |
810 | | |
811 | | /* Buffer for incoming audio, since opus only accepts frame sizes that are |
812 | | multiples of 2.5ms */ |
813 | 0 | sys->buffer = vlc_alloc(header.channels, sizeof(float) * OPUS_FRAME_SIZE); |
814 | 0 | if (!sys->buffer) { |
815 | 0 | status = VLC_ENOMEM; |
816 | 0 | goto error; |
817 | 0 | } |
818 | | |
819 | 0 | sys->i_nb_samples = 0; |
820 | |
|
821 | 0 | sys->i_samples_delay = 0; |
822 | 0 | int ret = opus_multistream_encoder_ctl(sys->enc, |
823 | 0 | OPUS_GET_LOOKAHEAD(&sys->i_samples_delay)); |
824 | 0 | if (ret != OPUS_OK) |
825 | 0 | msg_Err(enc, "Unable to get number of lookahead samples: %s\n", |
826 | 0 | opus_strerror(ret)); |
827 | |
|
828 | 0 | header.preskip = sys->i_samples_delay; |
829 | | |
830 | | /* Now that we have preskip, we can write the header to extradata */ |
831 | 0 | if (opus_write_header((uint8_t **) &enc->fmt_out.p_extra, |
832 | 0 | &enc->fmt_out.i_extra, &header, opus_get_version_string())) |
833 | 0 | { |
834 | 0 | status = VLC_ENOMEM; |
835 | 0 | goto error; |
836 | 0 | } |
837 | | |
838 | 0 | if (sys->i_samples_delay > 0) |
839 | 0 | { |
840 | 0 | const unsigned padding_samples = sys->i_samples_delay * |
841 | 0 | enc->fmt_out.audio.i_channels; |
842 | 0 | sys->padding = block_Alloc(padding_samples * sizeof(float)); |
843 | 0 | if (!sys->padding) { |
844 | 0 | status = VLC_ENOMEM; |
845 | 0 | goto error; |
846 | 0 | } |
847 | 0 | sys->padding->i_nb_samples = sys->i_samples_delay; |
848 | 0 | float *pad_ptr = (float *) sys->padding->p_buffer; |
849 | 0 | memset(pad_ptr, 0, padding_samples * sizeof(float)); |
850 | 0 | } |
851 | 0 | else |
852 | 0 | { |
853 | 0 | sys->padding = NULL; |
854 | 0 | } |
855 | | |
856 | 0 | opus_header_clean(&header); |
857 | |
|
858 | 0 | if (status != VLC_SUCCESS) |
859 | 0 | { |
860 | 0 | free(sys->buffer); |
861 | 0 | opus_multistream_encoder_destroy(sys->enc); |
862 | 0 | free(sys); |
863 | 0 | return status; |
864 | 0 | } |
865 | | |
866 | 0 | static const struct vlc_encoder_operations ops = |
867 | 0 | { |
868 | 0 | .close = CloseEncoder, |
869 | 0 | .encode_audio = Encode, |
870 | 0 | }; |
871 | 0 | enc->ops = &ops; |
872 | 0 | enc->p_sys = sys; |
873 | |
|
874 | 0 | return VLC_SUCCESS; |
875 | | |
876 | 0 | error: |
877 | 0 | opus_header_clean(&header); |
878 | 0 | if (sys->enc) |
879 | 0 | opus_multistream_encoder_destroy(sys->enc); |
880 | 0 | free(sys->buffer); |
881 | 0 | free(sys); |
882 | 0 | return status; |
883 | 0 | } |
884 | | |
885 | | static void CloseEncoder(encoder_t *enc) |
886 | 0 | { |
887 | 0 | encoder_sys_t *sys = enc->p_sys; |
888 | |
|
889 | 0 | opus_multistream_encoder_destroy(sys->enc); |
890 | 0 | if (sys->padding) |
891 | 0 | block_Release(sys->padding); |
892 | 0 | free(sys->buffer); |
893 | 0 | free(sys); |
894 | 0 | } |
895 | | #endif /* ENABLE_SOUT */ |