1 /*
2 * Copyright (C) 2015-2020 Alibaba Group Holding Limited
3 *
4 */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <stdint.h>
9 #include <string.h>
10 #include <signal.h>
11
12 #include "uvoice_types.h"
13 #include "uvoice_player.h"
14
15 #include "uvoice_os.h"
16 #include "uvoice_common.h"
17 #include "uvoice_play.h"
18
19 #include "opensource/libogg/include/ogg/ogg.h"
20 #include "opensource/libvorbis/include/vorbis/codec.h"
21
22
23 #define OGG_DECODE_INPUT_SIZE 4096
24
25 #define OGG_DECODE_OUTPUT_SAMPLES_MAX 1024
26
27 enum {
28 OGG_FLOW_FIND_IDENTIFY_HEADER = 0,
29 OGG_FLOW_FIND_COMMENT_AND_CODEBOOK,
30 OGG_FLOW_DECODE_PACKET,
31 };
32
33 typedef struct {
34 uint8_t *input_buffer;
35 int flow;
36 ogg_sync_state state;
37 ogg_page page;
38 ogg_packet packet;
39 ogg_stream_state stream;
40 vorbis_info vb_info;
41 vorbis_comment vb_comment;
42 vorbis_dsp_state vb_dsp_state;
43 vorbis_block vb_block;
44 } ogg_decoder_t;
45
46
ogg_decoder_reset(void * priv)47 static int ogg_decoder_reset(void *priv)
48 {
49 media_decoder_t *mdecoder = (media_decoder_t *)priv;
50 ogg_decoder_t *ogg;
51
52 if (!mdecoder) {
53 M_LOGE("mdecoder null !\n");
54 return -1;
55 }
56
57 ogg = mdecoder->decoder;
58 if (!ogg) {
59 M_LOGE("ogg decoder null !\n");
60 return -1;
61 }
62
63 ogg_sync_clear(&ogg->state);
64 ogg_sync_reset(&ogg->state);
65 ogg->flow = OGG_FLOW_FIND_IDENTIFY_HEADER;
66
67 M_LOGD("ogg reset\n");
68 return 0;
69 }
70
ogg_decoder_process(void * priv,const uint8_t * buffer,int nbytes)71 static int ogg_decoder_process(void *priv, const uint8_t *buffer, int nbytes)
72 {
73 media_decoder_t *mdecoder = (media_decoder_t *)priv;
74 ogg_decoder_t *ogg;
75 char *ogg_buffer;
76 int serial;
77 int out_len;
78 static int index = 0;
79 static bool stream_end = false;
80 int ret;
81
82 if (!mdecoder) {
83 M_LOGE("mdecoder null !\n");
84 return -1;
85 }
86
87 ogg = mdecoder->decoder;
88 if (!ogg) {
89 M_LOGE("ogg null !\n");
90 return -1;
91 }
92
93 ogg_buffer = ogg_sync_buffer(&ogg->state, nbytes);
94 if (!ogg_buffer) {
95 M_LOGE("sync buffer failed !\n");
96 return -1;
97 }
98
99 memcpy(ogg_buffer, buffer, nbytes);
100
101 ret = ogg_sync_wrote(&ogg->state, nbytes);
102 if (ret) {
103 M_LOGE("ogg sync buffer failed %d!\n", ret);
104 return -1;
105 }
106
107 if (ogg->flow == OGG_FLOW_FIND_COMMENT_AND_CODEBOOK) {
108 //M_LOGD("find comment and codebook headers index %d\n", index);
109 goto __find_comment_and_codebook;
110 } else if (ogg->flow == OGG_FLOW_DECODE_PACKET) {
111 //M_LOGD("find and decode packet\n");
112 goto __find_and_decode_packet;
113 }
114
115 ret = ogg_sync_pageout(&ogg->state, &ogg->page);
116 if (ret != 1) {
117 if (nbytes != mdecoder->input_size) {
118 M_LOGW("tail buffer %d discard\n", nbytes);
119 goto __exit;
120 }
121 M_LOGE("input not ogg stream !\n");
122 return -1;
123 }
124
125 serial = ogg_page_serialno(&ogg->page);
126
127 if (ogg_page_bos(&ogg->page)) {
128 //M_LOGD("init ogg stream with serial %d\n", serial);
129 ret = ogg_stream_init(&ogg->stream, serial);
130 if (ret) {
131 M_LOGE("ogg stream init failed %d!\n", ret);
132 return -1;
133 }
134 } else {
135 M_LOGE("not ogg stream bos !\n");
136 return -1;
137 }
138
139 vorbis_info_init(&ogg->vb_info);
140 vorbis_comment_init(&ogg->vb_comment);
141
142 ret = ogg_stream_pagein(&ogg->stream, &ogg->page);
143 if (ret < 0) {
144 M_LOGE("read first page failed %d!\n", ret);
145 goto __exit_err;
146 }
147
148 ret = ogg_stream_packetout(&ogg->stream, &ogg->packet);
149 if (ret != 1){
150 M_LOGE("read initial header packet failed %d!\n", ret);
151 goto __exit_err;
152 }
153
154 ret = vorbis_synthesis_headerin(&ogg->vb_info,
155 &ogg->vb_comment, &ogg->packet);
156 if (ret < 0) {
157 M_LOGE("ogg stream not contain vorbis %d!\n", ret);
158 goto __exit_err;
159 }
160
161 index = 0;
162 ogg->flow = OGG_FLOW_FIND_COMMENT_AND_CODEBOOK;
163
164 __find_comment_and_codebook:
165 while (index < 2) {
166 while (index < 2) {
167 ret = ogg_sync_pageout(&ogg->state, &ogg->page);
168 if (ret == 0) {
169 //M_LOGD("need more input\n");
170 break;
171 }
172 if (ret == 1) {
173 ogg_stream_pagein(&ogg->stream, &ogg->page);
174 while (index < 2) {
175 ret = ogg_stream_packetout(&ogg->stream, &ogg->packet);
176 if (ret == 0)
177 break;
178 if (ret < 0) {
179 M_LOGE("second header corrupt %d!\n", ret);
180 goto __exit_err;
181 }
182
183 ret = vorbis_synthesis_headerin(&ogg->vb_info,
184 &ogg->vb_comment, &ogg->packet);
185 if (ret < 0) {
186 M_LOGE("secondary header corrupt %d!\n", ret);
187 goto __exit_err;
188 }
189 index++;
190 }
191 }
192 }
193 //M_LOGD("need more input, fill %d returned %d storage %d\n",
194 // ogg->state.fill, ogg->state.returned, ogg->state.storage);
195 goto __exit;
196 }
197
198 //M_LOGD("rate %d channels %d\n",
199 // ogg->vb_info.rate, ogg->vb_info.channels);
200
201 if (!mdecoder->running) {
202 media_pcminfo_t pcm_info;
203 memset(&pcm_info, 0, sizeof(pcm_info));
204 pcm_info.rate = ogg->vb_info.rate;
205 pcm_info.frames = 1024;
206 if (mdecoder->stere_enable)
207 pcm_info.channels = ogg->vb_info.channels;
208 else
209 pcm_info.channels = 1;
210
211 mdecoder->buffer_out_size = OGG_DECODE_OUTPUT_SAMPLES_MAX * pcm_info.channels * 2;
212 M_LOGD("alloc out buffer %u\n", mdecoder->buffer_out_size);
213 mdecoder->buffer_out = snd_zalloc(mdecoder->buffer_out_size, AFM_EXTN);
214 if (!mdecoder->buffer_out) {
215 M_LOGE("alloc mdecoder failed !\n");
216 goto __exit_err;
217 }
218
219 pcm_info.bits = 16;
220 mdecoder->message(mdecoder->priv,
221 PLAYER_MSG_PCM_INFO, &pcm_info);
222 mdecoder->running = 1;
223 }
224
225 ogg->flow = OGG_FLOW_DECODE_PACKET;
226 ret = vorbis_synthesis_init(&ogg->vb_dsp_state, &ogg->vb_info);
227 if (ret != 0) {
228 M_LOGW("vorbis synthesis init failed %d!\n", ret);
229 goto __exit2;
230 }
231
232 vorbis_block_init(&ogg->vb_dsp_state, &ogg->vb_block);
233
234 stream_end = false;
235 //M_LOGD("decode packet, returned %d fill %d\n",
236 // ogg->state.fill, ogg->state.returned);
237
238 __find_and_decode_packet:
239 /* The rest is just a straight decode loop until end of stream */
240 while (!stream_end) {
241 while (!stream_end) {
242 ret = ogg_sync_pageout(&ogg->state, &ogg->page);
243 if (ret == 0) {
244 //M_LOGD("require more input\n");
245 break;
246 }
247 if (ret < 0) { /* missing or corrupt data at this page position */
248 M_LOGW("corrupt or missing data in bitstream, continue\n");
249 } else {
250 ogg_stream_pagein(&ogg->stream, &ogg->page);
251 /* can safely ignore errors at this point */
252 while (1) {
253 ret = ogg_stream_packetout(&ogg->stream, &ogg->packet);
254 if (ret == 0) {
255 //M_LOGD("require more data\n");
256 break;
257 }
258 if (ret < 0) {
259 /* missing or corrupt data at this page position */
260 /* no reason to complain; already complained above */
261 M_LOGW("corrupt or missing data in bitstream, continue\n");
262 } else {
263 /* we have a packet. Decode it */
264 float **pcm;
265 int samples;
266
267 if (vorbis_synthesis(&ogg->vb_block, &ogg->packet) == 0)
268 vorbis_synthesis_blockin(&ogg->vb_dsp_state, &ogg->vb_block);
269 /* pcm is a multichannel float vector. In stereo, for
270 * example, pcm[0] is left, and pcm[1] is right. samples is
271 * the size of each channel. Convert the float values
272 * (-1.<=range<=1.) to whatever PCM format and write it out
273 */
274
275 while ((samples = vorbis_synthesis_pcmout(&ogg->vb_dsp_state,
276 &pcm)) > 0) {
277 int i, j;
278 int clip = 0;
279 int bout = samples <= OGG_DECODE_OUTPUT_SAMPLES_MAX ?
280 samples : OGG_DECODE_OUTPUT_SAMPLES_MAX;
281 int channels = mdecoder->stere_enable ? ogg->vb_info.channels : 1;
282 ogg_int16_t *convbuffer = (ogg_int16_t *)mdecoder->buffer_out;
283
284 /* convert floats to 16 bit signed ints (host order) and
285 * interleave
286 */
287 for (i = 0; i < channels; i++) {
288 ogg_int16_t *ptr = convbuffer + i;
289 float *mono = pcm[i];
290 for (j = 0; j < bout; j++) {
291 #if 1
292 int val = floor(mono[j] * 32767.f + .5f);
293 #else /* optional dither */
294 int val=mono[j]*32767.f+drand48()-0.5f;
295 #endif
296 /* might as well guard against clipping */
297 if (val > 32767) {
298 val = 32767;
299 clip = 1;
300 }
301 if (val < -32768){
302 val = -32768;
303 clip = 1;
304 }
305 *ptr = val;
306 ptr += channels;
307 }
308 }
309
310 if (clip)
311 M_LOGW("clipping in frame %ld\n",
312 (long)(ogg->vb_dsp_state.sequence));
313
314 out_len = bout * channels * 2;
315
316 //M_LOGD("bout %d out_len %d channels %d\n",
317 // bout, out_len, ogg->vb_info.channels);
318 if (out_len > mdecoder->buffer_out_size) {
319 M_LOGE("output size %d overrange !\n", out_len);
320 goto __exit_err;
321 }
322
323 if (mdecoder->output(mdecoder->priv, mdecoder->buffer_out, out_len)) {
324 M_LOGE("output failed !\n");
325 goto __exit_err;
326 }
327
328 /* tell libvorbis how many samples we actually consumed */
329 vorbis_synthesis_read(&ogg->vb_dsp_state, bout);
330 }
331 }
332 }
333
334 if (ogg_page_eos(&ogg->page)) {
335 M_LOGD("stream end\n");
336 stream_end = true;
337 }
338 }
339 }
340
341 if (!stream_end) {
342 if (nbytes != mdecoder->input_size) {
343 M_LOGD("tail buffer %d\n", nbytes);
344 stream_end = true;
345 continue;
346 }
347 //M_LOGD("require more input, fill %d returned %d storage %d\n",
348 // ogg->state.fill, ogg->state.returned, ogg->state.storage);
349
350 goto __exit;
351 }
352 }
353
354 ogg->flow = OGG_FLOW_FIND_IDENTIFY_HEADER;
355
356 vorbis_block_clear(&ogg->vb_block);
357 vorbis_dsp_clear(&ogg->vb_dsp_state);
358
359 __exit2:
360 ogg_stream_clear(&ogg->stream);
361 vorbis_comment_clear(&ogg->vb_comment);
362 vorbis_info_clear(&ogg->vb_info);
363
364 __exit:
365 return 0;
366
367 __exit_err:
368 ogg_stream_clear(&ogg->state);
369 vorbis_comment_clear(&ogg->vb_comment);
370 vorbis_info_clear(&ogg->vb_info);
371 return -1;
372 }
373
ogg_decoder_action(void * priv,player_action_t action,void * arg)374 static int ogg_decoder_action(void *priv, player_action_t action, void *arg)
375 {
376 return 0;
377 }
378
ogg_decoder_create(media_decoder_t * mdecoder)379 int ogg_decoder_create(media_decoder_t *mdecoder)
380 {
381 ogg_decoder_t *ogg;
382
383 if (!mdecoder) {
384 M_LOGE("mdecoder null !\n");
385 return -1;
386 }
387
388 ogg = snd_zalloc(sizeof(ogg_decoder_t), AFM_MAIN);
389 if (!ogg) {
390 M_LOGE("alloc ogg decoder failed !\n");
391 return -1;
392 }
393
394 ogg_sync_init(&ogg->state);
395
396 ogg->flow = OGG_FLOW_FIND_IDENTIFY_HEADER;
397 mdecoder->input_size = OGG_DECODE_INPUT_SIZE;
398
399 mdecoder->decode = ogg_decoder_process;
400 mdecoder->action = ogg_decoder_action;
401 mdecoder->reset = ogg_decoder_reset;
402 mdecoder->decoder = ogg;
403
404 M_LOGD("ogg create\n");
405 return 0;
406 }
407
ogg_decoder_release(media_decoder_t * mdecoder)408 int ogg_decoder_release(media_decoder_t *mdecoder)
409 {
410 ogg_decoder_t *ogg;
411
412 if (!mdecoder) {
413 M_LOGE("mdecoder null !\n");
414 return -1;
415 }
416
417 if (mdecoder->buffer_out) {
418 snd_free(mdecoder->buffer_out);
419 mdecoder->buffer_out = NULL;
420 mdecoder->buffer_out_size = 0;
421 }
422
423 ogg = mdecoder->decoder;
424 if (!ogg) {
425 M_LOGE("ogg null !\n");
426 return -1;
427 }
428
429 ogg_sync_clear(&ogg->state);
430
431 snd_free(ogg);
432 M_LOGD("ogg release\n");
433 return 0;
434 }
435
436