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