1 /* OpenCP Module Player
2  * copyright (c) '94-'10 Niklas Beisert <nbeisert@physik.tu-muenchen.de>
3  *
4  * OGGPlay - Player for Ogg Vorbis files
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  * revision history: (please note changes here)
21  *  -nb040911   Stian Skjelstad <stian@nixia.no>
22  *    -first release
23  *  -ss040916   Stian Skjelstad <stian@nixia.no>
24  *    -fixed problem regarding random-sound in the first buffer-run
25  *  -ss040916   Stian Skjelstad <stian@nixia.no>
26  *    -fixed the signess problem around PANPROC
27  */
28 
29 #include "config.h"
30 #include <string.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <vorbis/codec.h>
35 #include <vorbis/vorbisfile.h>
36 #include "types.h"
37 #include "cpiface/gif.h"
38 #include "cpiface/jpeg.h"
39 #include "cpiface/png.h"
40 #include "dev/deviplay.h"
41 #include "dev/player.h"
42 #include "dev/plrasm.h"
43 #include "dev/ringbuffer.h"
44 #include "filesel/filesystem.h"
45 #include "oggplay.h"
46 #include "stuff/imsrtns.h"
47 #include "stuff/timer.h"
48 #include "stuff/poll.h"
49 
50 static int current_section;
51 
52 static int stereo; /* 32 bit booleans are fast */
53 static int bit16;
54 static int signedout;
55 static uint32_t samprate;
56 static uint8_t reversestereo;
57 
58 /* static unsigned long amplify; TODO */
59 static unsigned long voll,volr;
60 static int pan;
61 static int srnd;
62 
63 static int16_t *buf16=NULL;
64 static uint32_t bufpos;
65 static uint32_t buflen;
66 static void *plrbuf;
67 
68 /*static uint32_t amplify;*/
69 
70 static OggVorbis_File ov;
71 static int oggstereo;
72 static int oggrate;
73 static ogg_int64_t oggpos; /* absolute sample position in the source stream */
74 static ogg_int64_t ogglen; /* absolute length in samples positions of the source stream */
75 static int oggneedseek;
76 
77 static int16_t *oggbuf=NULL;
78 static struct ringbuffer_t *oggbufpos = 0;
79 static uint_fast32_t oggbuffpos;
80 static uint_fast32_t oggbufrate;
81 static volatile int active;
82 static int looped;
83 static int donotloop;
84 
85 static int inpause;
86 
87 static volatile int clipbusy=0;
88 
89 static struct ocpfilehandle_t *oggfile;
90 
91 #define PANPROC \
92 do { \
93 	float _rs = rs, _ls = ls; \
94 	if(pan==-64) \
95 	{ \
96 		float t=_ls; \
97 		_ls = _rs; \
98 		_rs = t; \
99 	} else if(pan==64) \
100 	{ \
101 	} else if(pan==0) \
102 		_rs=_ls=(_rs+_ls) / 2.0; \
103 	else if(pan<0) \
104 	{ \
105 		_ls = _ls / (-pan/-64.0+2.0) + _rs*(64.0+pan)/128.0; \
106 		_rs = _rs / (-pan/-64.0+2.0) + _ls*(64.0+pan)/128.0; \
107 	} else if(pan<64) \
108 	{ \
109 		_ls = _ls / (pan/-64.0+2.0) + _rs*(64.0-pan)/128.0; \
110 		_rs = _rs / (pan/-64.0+2.0) + _ls*(64.0-pan)/128.0; \
111 	} \
112 	rs = _rs * volr / 256.0; \
113 	ls = _ls * voll / 256.0; \
114 	if (srnd) \
115 	{ \
116 		ls ^= 0xffff; \
117 	} \
118 } while(0)
119 
120 static void oggIdler(void)
121 {
122 	if (!active)
123 		return;
124 
125 	while (1)
126 	{
127 		size_t read;
128 		long result = 0;
129 		int pos1, pos2;
130 		int length1, length2;
131 
132 		if (oggneedseek)
133 		{
134 			oggneedseek=0;
135 #ifdef HAVE_OV_PCM_SEEK_LAP
136 			ov_pcm_seek_lap(&ov, oggpos);
137 #else
138 			ov_pcm_seek(&ov, oggpos);
139 #endif
140 
141 		}
142 		if (ov_pcm_tell(&ov)!=oggpos)
143 		{
144 			fprintf (stderr, "[playogg]: warning, frame position is broken in file (got=%" PRId64 ", expected= %" PRId64 ")\n", ov_pcm_tell(&ov), oggpos);
145 		}
146 
147 		ringbuffer_get_head_samples (oggbufpos, &pos1, &length1, &pos2, &length2);
148 
149 		if (!length1)
150 		{
151 			return;
152 		}
153 		read = length1;
154 
155 		/* check if we are going to read until EOF, and if so, do we allow loop or not */
156 		if (oggpos+read>=ogglen)
157 		{
158 			read=(ogglen-oggpos);
159 		}
160 
161 		if (read)
162 		{
163 #ifndef WORDS_BIGENDIAN
164 			result=ov_read(&ov, (char *)(oggbuf+(pos1<<1)), read<<(1+oggstereo), 0, 2, 1, &current_section);
165 #else
166 			result=ov_read(&ov, (char *)(oggbuf+(pos1<<1)), read<<(1+oggstereo), 1, 2, 1, &current_section);
167 #endif
168 
169 			if (result<=0) /* broken data... we can survive */
170 			{
171 				plrClearBuf (oggbuf+(pos1<<1), read<<1, 0); /* always clear stereo */
172 				fprintf (stderr, "[playogg] ov_read failed: %ld\n", result);
173 				result=read;
174 			} else {
175 				result>>=(1+oggstereo);
176 				if (!oggstereo)
177 				{
178 					plrMono16ToStereo16 (oggbuf+(pos1<<1), result);
179 				}
180 			}
181 			ringbuffer_head_add_samples (oggbufpos, result);
182 		} else {
183 			break;
184 		}
185 
186 		if ((oggpos+result) >= ogglen)
187 		{
188 			if (donotloop)
189 			{
190 				looped |= 1;
191 				oggpos = ogglen;
192 				break;
193 			} else {
194 				looped &= ~1;
195 				oggpos = 0;
196 				oggneedseek = 1;
197 			}
198 		} else {
199 			oggpos += result;
200 		}
201 	}
202 }
203 
204 void __attribute__ ((visibility ("internal"))) oggIdle(void)
205 {
206 	uint32_t bufdelta;
207 	uint32_t pass2;
208 
209 	if (clipbusy++)
210 	{
211 		clipbusy--;
212 		return;
213 	}
214 
215 
216 	{
217 		uint32_t bufplayed;
218 
219 		bufplayed=plrGetBufPos()>>(stereo+bit16);
220 
221 		bufdelta=(buflen+bufplayed-bufpos)%buflen;
222 	}
223 
224 	if (!bufdelta)
225 	{
226 		clipbusy--;
227 		if (plrIdle)
228 			plrIdle();
229 		return;
230 	}
231 	oggIdler();
232 
233 	if (inpause)
234 	{ /* If we are in pause, we fill buffer with the correct type of zeroes */
235 		if ((bufpos+bufdelta)>buflen)
236 			pass2=bufpos+bufdelta-buflen;
237 		else
238 			pass2=0;
239 		if (bit16)
240 		{
241 			plrClearBuf((uint16_t *)plrbuf+(bufpos<<stereo), (bufdelta-pass2)<<stereo, signedout);
242 			if (pass2)
243 				plrClearBuf((uint16_t *)plrbuf, pass2<<stereo, signedout);
244 		} else {
245 			plrClearBuf(buf16, bufdelta<<stereo, signedout);
246 			plr16to8((uint8_t *)plrbuf+(bufpos<<stereo), (uint16_t *)buf16, (bufdelta-pass2)<<stereo);
247 			if (pass2)
248 				plr16to8((uint8_t *)plrbuf, (uint16_t *)buf16+((bufdelta-pass2)<<stereo), pass2<<stereo);
249 		}
250 		bufpos+=bufdelta;
251 		if (bufpos>=buflen)
252 			bufpos-=buflen;
253 	} else {
254 		int pos1, length1, pos2, length2;
255 		int i;
256 		int buf16_filled = 0;
257 
258 		/* how much data is available.. we are using a ringbuffer, so we might receive two fragments */
259 		ringbuffer_get_tail_samples (oggbufpos, &pos1, &length1, &pos2, &length2);
260 
261 		/* are the speed 1:1, if so filling up buf16 is very easy */
262 		if (oggbufrate==0x10000)
263 		{
264 			int16_t *t = buf16;
265 
266 			if (bufdelta>(length1+length2))
267 			{
268 				bufdelta=(length1+length2);
269 				looped |= 2;
270 			} else {
271 				looped &= ~2;
272 			}
273 
274 			for (buf16_filled=0; buf16_filled<bufdelta; buf16_filled++)
275 			{
276 				int16_t rs, ls;
277 
278 				if (!length1)
279 				{
280 					pos1 = pos2;
281 					length1 = length2;
282 					pos2 = 0;
283 					length2 = 0;
284 				}
285 
286 				if (!length1)
287 				{
288 					fprintf (stderr, "playogg: ERROR, length1 == 0, in oggIdle\n");
289 					_exit(1);
290 				}
291 
292 				rs = oggbuf[pos1<<1];
293 				ls = oggbuf[(pos1<<1) + 1];
294 
295 				PANPROC;
296 
297 				*(t++) = rs;
298 				*(t++) = ls;
299 
300 				pos1++;
301 				length1--;
302 			}
303 
304 			ringbuffer_tail_consume_samples (oggbufpos, buf16_filled); /* add this rate buf16_filled == tail_used */
305 		} else {
306 			/* We are going to perform cubic interpolation of rate conversion... this bit is tricky */
307 			unsigned int accumulated_progress = 0;
308 
309 			looped &= ~2;
310 
311 			for (buf16_filled=0; buf16_filled<bufdelta; buf16_filled++)
312 			{
313 				uint32_t wpm1, wp0, wp1, wp2;
314 				int32_t rc0, rc1, rc2, rc3, rvm1,rv1,rv2;
315 				int32_t lc0, lc1, lc2, lc3, lvm1,lv1,lv2;
316 				unsigned int progress;
317 				int16_t rs, ls;
318 
319 				/* will the interpolation overflow? */
320 				if ((length1+length2) <= 3)
321 				{
322 					looped |= 2;
323 					break;
324 				}
325 				/* will we overflow the wavebuf if we advance? */
326 				if ((length1+length2) < ((oggbufrate+oggbuffpos)>>16))
327 				{
328 					looped |= 2;
329 					break;
330 				}
331 
332 				switch (length1) /* if we are close to the wrap between buffer segment 1 and 2, len1 will grow down to a small number */
333 				{
334 					case 1:
335 						wpm1 = pos1;
336 						wp0  = pos2;
337 						wp1  = pos2+1;
338 						wp2  = pos2+2;
339 						break;
340 					case 2:
341 						wpm1 = pos1;
342 						wp0  = pos1+1;
343 						wp1  = pos2;
344 						wp2  = pos2+1;
345 						break;
346 					case 3:
347 						wpm1 = pos1;
348 						wp0  = pos1+1;
349 						wp1  = pos1+2;
350 						wp2  = pos2;
351 						break;
352 					default:
353 						wpm1 = pos1;
354 						wp0  = pos1+1;
355 						wp1  = pos1+2;
356 						wp2  = pos1+3;
357 						break;
358 				}
359 
360 
361 				rvm1 = (uint16_t)oggbuf[(wpm1<<1)+0]^0x8000; /* we temporary need data to be unsigned - hence the ^0x8000 */
362 				lvm1 = (uint16_t)oggbuf[(wpm1<<1)+1]^0x8000;
363 				 rc0 = (uint16_t)oggbuf[(wp0<<1)+0]^0x8000;
364 				 lc0 = (uint16_t)oggbuf[(wp0<<1)+1]^0x8000;
365 				 rv1 = (uint16_t)oggbuf[(wp1<<1)+0]^0x8000;
366 				 lv1 = (uint16_t)oggbuf[(wp1<<1)+1]^0x8000;
367 				 rv2 = (uint16_t)oggbuf[(wp2<<1)+0]^0x8000;
368 				 lv2 = (uint16_t)oggbuf[(wp2<<1)+1]^0x8000;
369 
370 				rc1 = rv1-rvm1;
371 				rc2 = 2*rvm1-2*rc0+rv1-rv2;
372 				rc3 = rc0-rvm1-rv1+rv2;
373 				rc3 =  imulshr16(rc3,oggbuffpos);
374 				rc3 += rc2;
375 				rc3 =  imulshr16(rc3,oggbuffpos);
376 				rc3 += rc1;
377 				rc3 =  imulshr16(rc3,oggbuffpos);
378 				rc3 += rc0;
379 				if (rc3<0)
380 					rc3=0;
381 				if (rc3>65535)
382 					rc3=65535;
383 
384 				lc1 = lv1-lvm1;
385 				lc2 = 2*lvm1-2*lc0+lv1-lv2;
386 				lc3 = lc0-lvm1-lv1+lv2;
387 				lc3 =  imulshr16(lc3,oggbuffpos);
388 				lc3 += lc2;
389 				lc3 =  imulshr16(lc3,oggbuffpos);
390 				lc3 += lc1;
391 				lc3 =  imulshr16(lc3,oggbuffpos);
392 				lc3 += lc0;
393 				if (lc3<0)
394 					lc3=0;
395 				if (lc3>65535)
396 					lc3=65535;
397 
398 				rs = rc3 ^ 0x8000;
399 				ls = lc3 ^ 0x8000;
400 
401 				PANPROC;
402 
403 				buf16[(buf16_filled<<1)+0] = rs;
404 				buf16[(buf16_filled<<1)+1] = ls;
405 
406 				oggbuffpos+=oggbufrate;
407 				progress = oggbuffpos>>16;
408 				oggbuffpos &= 0xffff;
409 
410 				accumulated_progress += progress;
411 
412 				/* did we wrap? if so, progress up to the wrapping point */
413 				if (progress >= length1)
414 				{
415 					progress -= length1;
416 					pos1 = pos2;
417 					length1 = length2;
418 					pos2 = 0;
419 					length2 = 0;
420 				}
421 				if (progress)
422 				{
423 					pos1 += progress;
424 					length1 -= progress;
425 				}
426 			}
427 			ringbuffer_tail_consume_samples (oggbufpos, accumulated_progress);
428 		}
429 
430 		bufdelta=buf16_filled;
431 
432 		if ((bufpos+bufdelta)>buflen)
433 			pass2=bufpos+bufdelta-buflen;
434 		else
435 			pass2=0;
436 		bufdelta-=pass2;
437 
438 		if (bit16)
439 		{
440 			if (stereo)
441 			{
442 				int16_t *p=(int16_t *)plrbuf+2*bufpos;
443 				int16_t *b=buf16;
444 				if (signedout)
445 				{
446 					for (i=0; i<bufdelta; i++)
447 					{
448 						p[0]=b[0];
449 						p[1]=b[1];
450 						p+=2;
451 						b+=2;
452 					}
453 					p=(int16_t *)plrbuf;
454 					for (i=0; i<pass2; i++)
455 					{
456 						p[0]=b[0];
457 						p[1]=b[1];
458 						p+=2;
459 						b+=2;
460 					}
461 				} else {
462 					for (i=0; i<bufdelta; i++)
463 					{
464 						p[0]=b[0]^0x8000;
465 						p[1]=b[1]^0x8000;
466 						p+=2;
467 						b+=2;
468 					}
469 					p=(int16_t *)plrbuf;
470 					for (i=0; i<pass2; i++)
471 					{
472 						p[0]=b[0]^0x8000;
473 						p[1]=b[1]^0x8000;
474 						p+=2;
475 						b+=2;
476 					}
477 				}
478 			} else {
479 				int16_t *p=(int16_t *)plrbuf+bufpos;
480 				int16_t *b=buf16;
481 				if (signedout)
482 				{
483 					for (i=0; i<bufdelta; i++)
484 					{
485 						p[0]=b[0];
486 						p++;
487 						b++;
488 					}
489 					p=(int16_t *)plrbuf;
490 					for (i=0; i<pass2; i++)
491 					{
492 						p[0]=b[0];
493 						p++;
494 						b++;
495 					}
496 				} else {
497 					for (i=0; i<bufdelta; i++)
498 					{
499 						p[0]=b[0]^0x8000;
500 						p++;
501 						b++;
502 					}
503 					p=(int16_t *)plrbuf;
504 					for (i=0; i<pass2; i++)
505 					{
506 						p[0]=b[0]^0x8000;
507 						p++;
508 						b++;
509 					}
510 				}
511 			}
512 		} else {
513 			if (stereo)
514 			{
515 				uint8_t *p=(uint8_t *)plrbuf+2*bufpos;
516 				uint8_t *b=(uint8_t *)buf16;
517 				if (signedout)
518 				{
519 					for (i=0; i<bufdelta; i++)
520 					{
521 						p[0]=b[1];
522 						p[1]=b[3];
523 						p+=2;
524 						b+=4;
525 					}
526 					p=(uint8_t *)plrbuf;
527 					for (i=0; i<pass2; i++)
528 					{
529 						p[0]=b[1];
530 						p[1]=b[3];
531 						p+=2;
532 						b+=4;
533 					}
534 				} else {
535 					for (i=0; i<bufdelta; i++)
536 					{
537 						p[0]=b[1]^0x80;
538 						p[1]=b[3]^0x80;
539 						p+=2;
540 						b+=4;
541 					}
542 					p=(uint8_t *)plrbuf;
543 					for (i=0; i<pass2; i++)
544 					{
545 						p[0]=b[1]^0x80;
546 						p[1]=b[3]^0x80;
547 						p+=2;
548 						b+=4;
549 					}
550 				}
551 			} else {
552 				uint8_t *p=(uint8_t *)plrbuf+bufpos;
553 				int16_t *b=buf16;
554 				if (signedout)
555 				{
556 					for (i=0; i<bufdelta; i++)
557 					{
558 						p[0]=(b[0]+b[1])>>9;
559 						p++;
560 						b+=2;
561 					}
562 					p=(uint8_t *)plrbuf;
563 					for (i=0; i<pass2; i++)
564 					{
565 						p[0]=(b[0]+b[1])>>9;
566 						p++;
567 						b+=2;
568 					}
569 				} else {
570 					for (i=0; i<bufdelta; i++)
571 					{
572 						p[0]=((b[0]+b[1])>>9)^0x80;
573 						p++;
574 						b+=2;
575 					}
576 					p=(uint8_t *)plrbuf;
577 					for (i=0; i<pass2; i++)
578 					{
579 						p[0]=((b[0]+b[1])>>9)^0x80;
580 						p++;
581 						b+=2;
582 					}
583 				}
584 			}
585 		}
586 		bufpos+=buf16_filled;
587 		if (bufpos>=buflen)
588 			bufpos-=buflen;
589 	}
590 
591 	plrAdvanceTo(bufpos<<(stereo+bit16));
592 
593 	if (plrIdle)
594 		plrIdle();
595 
596 	clipbusy--;
597 }
598 
599 void __attribute__ ((visibility ("internal"))) oggSetAmplify(uint32_t amp)
600 {
601 /*
602 	amplify=amp;
603 	float v[9];
604 	float ampf=(float)vols[9]*(amplify/65536.0)/65536.0;
605 	int i;
606 	for (i=0; i<9; i++)
607 		v[i]=ampf*vols[i];
608 	rawogg.ioctl(ampegdecoder::ioctlsetstereo, v, 4*9);
609 	*/
610 }
611 
612 
613 static size_t read_func (void *ptr, size_t size, size_t nmemb, void *token)
614 {
615 	uint64_t retval;
616 	retval = oggfile->read (oggfile, ptr, size * nmemb);
617 	return retval / size;
618 }
619 
620 static int seek_func (void *token, ogg_int64_t offset, int whence)
621 {
622 	switch (whence)
623 	{
624 		case SEEK_SET:
625 			if (oggfile->seek_set (oggfile, offset) < 0)
626 			{
627 				return -1;
628 			}
629 			break;
630 		case SEEK_END:
631 			if (oggfile->seek_end (oggfile, offset) < 0)
632 			{
633 				return -1;
634 			}
635 			break;
636 		case SEEK_CUR:
637 			if (oggfile->seek_cur (oggfile, offset) < 0)
638 			{
639 				return -1;
640 			}
641 			break;
642 		default:
643 			return -1;
644 	}
645 	return oggfile->getpos (oggfile);
646 }
647 
648 static int close_func(void *token)
649 {
650 	return 0;
651 }
652 
653 static long tell_func (void *token)
654 {
655 	return oggfile->getpos (oggfile);
656 }
657 
658 
659 struct ogg_comment_t __attribute__ ((visibility ("internal"))) **ogg_comments;
660 int                  __attribute__ ((visibility ("internal")))   ogg_comments_count;
661 struct ogg_picture_t __attribute__ ((visibility ("internal")))  *ogg_pictures;
662 int                  __attribute__ ((visibility ("internal")))   ogg_pictures_count;
663 
664 static void add_comment2(const char *title, const char *value)
665 {
666 	int n = 0;
667 	for (n = 0; n < ogg_comments_count; n++)
668 	{
669 		int res = strcmp (ogg_comments[n]->title, title);
670 		if (res == 0)
671 		{
672 			// append to at this point
673 			ogg_comments[n] = realloc (ogg_comments[n], sizeof (ogg_comments[n]) + sizeof (ogg_comments[n]->value[0]) * (ogg_comments[n]->value_count + 1));
674 			ogg_comments[n]->value[ogg_comments[n]->value_count++] = strdup(value);
675 			return;
676 		}
677 		if (res < 0)
678 		{
679 			continue;
680 		} else {
681 			// insert it at this point
682 			break;
683 		}
684 	}
685 
686 	ogg_comments = realloc (ogg_comments, sizeof (ogg_comments[0]) * (ogg_comments_count+1));
687 	memmove (ogg_comments + n + 1, ogg_comments + n, (ogg_comments_count - n) * sizeof (ogg_comments[0]));
688 	ogg_comments[n] = malloc (sizeof (*ogg_comments[n]) + sizeof (ogg_comments[n]->value[0]));
689 	ogg_comments[n]->title = strdup (title);
690 	ogg_comments[n]->value_count = 1;
691 	ogg_comments[n]->value[0] = strdup (value);
692 	ogg_comments_count++;
693 }
694 
695 static void add_picture(const uint16_t actual_width,
696 		        const uint16_t actual_height,
697 			uint8_t *data_bgra,
698 			const char *description,
699 			const uint32_t description_length,
700 			const uint32_t picture_type)
701 {
702 	ogg_pictures = realloc (ogg_pictures, sizeof (ogg_pictures[0]) * (ogg_pictures_count + 1));
703 	ogg_pictures[ogg_pictures_count].picture_type = picture_type;
704 	ogg_pictures[ogg_pictures_count].description = malloc (description_length + 1);
705 	memcpy (ogg_pictures[ogg_pictures_count].description, description, description_length);
706 	ogg_pictures[ogg_pictures_count].description[description_length] = 0;
707 	ogg_pictures[ogg_pictures_count].width = actual_width;
708 	ogg_pictures[ogg_pictures_count].height = actual_height;
709 	ogg_pictures[ogg_pictures_count].data_bgra = data_bgra;
710 	ogg_pictures[ogg_pictures_count].scaled_width = 0;
711 	ogg_pictures[ogg_pictures_count].scaled_height = 0;
712 	ogg_pictures[ogg_pictures_count].scaled_data_bgra = 0;
713 
714 	ogg_pictures_count++;
715 }
716 
717 #ifdef __GNUC__
718 #pragma GCC diagnostic push
719 #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
720 #endif
721 static void add_picture_binary(const uint8_t *src, unsigned int srclen)
722 {
723 	uint32_t picture_type;
724 	uint32_t mime_length;
725 	const uint8_t *mime;
726 	uint32_t description_length;
727 	const uint8_t *description;
728 	uint32_t width;
729 	uint32_t height;
730 	uint32_t bpp;
731 	uint32_t colors; // if GIF color palette
732 	uint32_t data_length;
733 	const uint8_t *data;
734 
735 	if (srclen < 4)
736 	{
737 		return;
738 	}
739 	picture_type = (src[0]<<24) | (src[1]<<16) | (src[2]<<8) | src[3];
740 	src += 4; srclen -= 4;
741 
742 	if (srclen < 4)
743 	{
744 		return;
745 	}
746 	mime_length = (src[0]<<24) | (src[1]<<16) | (src[2]<<8) | src[3];
747 	src += 4; srclen -= 4;
748 
749 	if (srclen < mime_length)
750 	{
751 		return;
752 	}
753 	mime = src;
754 	src += mime_length; srclen -= mime_length;
755 
756 	if (srclen < 4)
757 	{
758 		return;
759 	}
760 	description_length = (src[0]<<24) | (src[1]<<16) | (src[2]<<8) | src[3];
761 	src += 4; srclen -= 4;
762 
763 	if (srclen < description_length)
764 	{
765 		return;
766 	}
767 	description = src;
768 	src += description_length; srclen -= description_length;
769 
770 	if (srclen < 4)
771 	{
772 		return;
773 	}
774 	width = (src[0]<<24) | (src[1]<<16) | (src[2]<<8) | src[3];
775 	src += 4; srclen -= 4;
776 
777 	if (srclen < 4)
778 	{
779 		return;
780 	}
781 	height = (src[0]<<24) | (src[1]<<16) | (src[2]<<8) | src[3];
782 	src += 4; srclen -= 4;
783 
784 	if (srclen < 4)
785 	{
786 		return;
787 	}
788 	bpp = (src[0]<<24) | (src[1]<<16) | (src[2]<<8) | src[3];
789 	src += 4; srclen -= 4;
790 
791 	if (srclen < 4)
792 	{
793 		return;
794 	}
795 	colors = (src[0]<<24) | (src[1]<<16) | (src[2]<<8) | src[3];
796 	src += 4; srclen -= 4;
797 
798 	if (srclen < 4)
799 	{
800 		return;
801 	}
802 	data_length = (src[0]<<24) | (src[1]<<16) | (src[2]<<8) | src[3];
803 	src += 4; srclen -= 4;
804 
805 	if (srclen < data_length)
806 	{
807 		return;
808 	}
809 	data = src;
810 	src += data_length; srclen -= data_length;
811 
812 #if 0
813 	if ((mime_length == 3) && (!strncasecmp (mime, "-->", 3)))
814 	{
815 		// TODO - URL
816 	}
817 #endif
818 #ifdef HAVE_LZW
819 	if ((mime_length == 9) && (!strncasecmp ((const char *)mime, "image/gif", 9)))
820 	{
821 		uint16_t actual_height, actual_width;
822 		uint8_t *data_bgra;
823 		if (!GIF87_try_open_bgra (&actual_width, &actual_height, &data_bgra, data, data_length))
824 		{
825 			add_picture (actual_width, actual_height, data_bgra, (const char *)description, description_length, picture_type);
826 		}
827 		return;
828 	}
829 #endif
830 
831 	if ((mime_length == 9) && (!strncasecmp ((const char *)mime, "image/png", 9)))
832 	{
833 		uint16_t actual_height, actual_width;
834 		uint8_t *data_bgra;
835 		if (!try_open_png (&actual_width, &actual_height, &data_bgra, (uint8_t *)data, data_length))
836 		{
837 			add_picture (actual_width, actual_height, data_bgra, (const char *)description, description_length, picture_type);
838 		}
839 		return;
840 	}
841 
842 	if (((mime_length == 9) && (!strncasecmp ((const char *)mime, "image/jpg", 9))) || ((mime_length == 10) && (!strncasecmp ((const char *)mime, "image/jpeg", 10))))
843 	{
844 		uint16_t actual_height, actual_width;
845 		uint8_t *data_bgra;
846 		if (!try_open_jpeg (&actual_width, &actual_height, &data_bgra, data, data_length))
847 		{
848 			add_picture (actual_width, actual_height, data_bgra, (const char *)description, description_length, picture_type);
849 		}
850 		return;
851 	}
852 }
853 #ifdef __GNUC__
854 #pragma GCC diagnostic pop
855 #endif
856 
857 static uint8_t base64_index (const char src)
858 {
859 	if ((src >= 'A') && (src <= 'Z')) return src - 'A';
860 	if ((src >= 'a') && (src <= 'z')) return src - 'a' + 26;
861 	if ((src >= '0') && (src <= '9')) return src - '0' + 52;
862 	if (src == '+') return 62;
863 	if (src == '/') return 63;
864 	if (src == '=') return 64;
865 	return 65;
866 }
867 
868 static void add_picture_base64(const char *src)
869 {
870 	int srclen = strlen (src);
871 	uint8_t *dst;
872 	int dstlen = 0;
873 
874 	if (srclen < 2)
875 	{
876 		return;
877 	}
878 
879 	dst = malloc (srclen * 3 / 4); // this is a good estimate, but it might overshoot due to padding
880 
881 	while (srclen >= 2)
882 	{
883 		uint8_t tmp1, tmp2, tmp3, tmp4;
884 
885 		tmp1 = base64_index (*src);
886 		src++; srclen--;
887 		if (tmp1 >= 64)
888 		{
889 			break;
890 		}
891 
892 		tmp2 = base64_index (*src);
893 		src++; srclen--;
894 		if (tmp2 >= 64)
895 		{/* this is invalid encoding */
896 			break;
897 		}
898 
899 		*dst = (tmp1<<2) | (tmp2>>4); //6 + 2
900 		dst++; dstlen++;
901 
902 		if (!srclen)
903 		{
904 			break;
905 		}
906 		tmp3 = base64_index (*src);
907 		src++; srclen--;
908 		if (tmp3 >= 64)
909 		{
910 			break;
911 		}
912 
913 		*dst = (tmp2<<4) | (tmp3>>2); //4 + 4
914 		dst++; dstlen++;
915 
916 		if (!srclen)
917 		{
918 			break;
919 		}
920 		tmp4 = base64_index (*src);
921 		src++; srclen--;
922 		if (tmp4 >= 64)
923 		{
924 			break;
925 		}
926 
927 		*dst = (tmp3<<6) | tmp4; // 2 + 6
928 		dst++; dstlen++;
929 	}
930 
931 	dst -= dstlen;
932 
933 	add_picture_binary(dst, dstlen);
934 
935 	free (dst);
936 }
937 
938 static void add_comment(const char *src)
939 {
940 	char *equal, *tmp, *tmp2;
941 	if (!strncasecmp (src, "METADATA_BLOCK_PICTURE=", 23))
942 	{
943 		add_picture_base64(src + 23);
944 		return;
945 	}
946 	equal = strchr (src, '=');
947 
948 	if (!equal)
949 	{
950 		return;
951 	}
952 	if (equal == src)
953 	{
954 		return;
955 	}
956 
957 	tmp = malloc (equal - src + 1);
958 	strncpy (tmp, src, equal - src);
959 	tmp[equal-src] = 0;
960 
961 	if ((tmp[0] >= 'a') && (tmp[0] <= 'z')) tmp[0] -= 0x20;
962 
963 	for (tmp2 = tmp + 1; *tmp2; tmp2++)
964 	{
965 		if ((tmp2[0] >= 'A') && (tmp2[0] <= 'Z')) tmp2[0] += 0x20;
966 	}
967 
968 	add_comment2(tmp, src + (equal - src) + 1);
969 
970 	free (tmp);
971 }
972 
973 static ov_callbacks callbacks =
974 {
975 	read_func,
976 	seek_func,
977 	close_func,
978 	tell_func
979 };
980 int __attribute__ ((visibility ("internal"))) oggOpenPlayer(struct ocpfilehandle_t *oggf)
981 {
982 	struct vorbis_info *vi;
983 
984 	if (!plrPlay)
985 		return 0;
986 
987 	oggf->seek_set (oggf, 0);
988 	if (oggfile)
989 	{
990 		oggfile->unref (oggfile);
991 		oggfile = 0;
992 	}
993 	oggfile = oggf;
994 	oggfile->ref (oggfile);
995 	if (ov_open_callbacks(0 /* token*/, &ov, NULL, 0, callbacks))
996 	{
997 		return -1; /* we don't bother to do more exact */
998 	}
999 
1000 	vi=ov_info(&ov,-1);
1001 	oggstereo=(vi->channels>=2);
1002 	oggrate=vi->rate;
1003 
1004 	plrSetOptions(oggrate, (PLR_SIGNEDOUT|PLR_16BIT)|PLR_STEREO);
1005 	stereo=!!(plrOpt&PLR_STEREO);
1006 	bit16=!!(plrOpt&PLR_16BIT);
1007 	signedout=!!(plrOpt&PLR_SIGNEDOUT);
1008 	reversestereo=!!(plrOpt&PLR_REVERSESTEREO);
1009 	samprate=plrRate;
1010 
1011 	oggbufrate=imuldiv(65536, oggrate, samprate);
1012 
1013 	ogglen=ov_pcm_total(&ov, -1);
1014 	if (!ogglen)
1015 		return 0;
1016 
1017 	oggbuf=malloc(1024 * 128);
1018 	if (!oggbuf)
1019 		return 0;
1020 	oggbufpos = ringbuffer_new_samples (RINGBUFFER_FLAGS_STEREO | RINGBUFFER_FLAGS_16BIT | RINGBUFFER_FLAGS_SIGNED, 1024*32);
1021 	if (!oggbufpos)
1022 	{
1023 		free(oggbuf);
1024 		oggbuf = 0;
1025 		return 0;
1026 	}
1027 	oggbuffpos=0;
1028 	current_section=0;
1029 	oggneedseek=0;
1030 
1031 	{
1032 		int i;
1033 
1034 		vorbis_comment *vf = 0;
1035 		vf = ov_comment (&ov, -1);
1036 		if (vf)
1037 		{
1038 			for (i=0; i < vf->comments; i++)
1039 			{
1040 				add_comment(vf->user_comments[i]);
1041 			}
1042 		}
1043 	}
1044 
1045 	if (!plrOpenPlayer(&plrbuf, &buflen, plrBufSize * plrRate / 1000, oggf))
1046 	{
1047 		ringbuffer_free (oggbufpos);
1048 		oggbufpos = 0;
1049 
1050 		free(oggbuf);
1051 		oggbuf = 0;
1052 		return 0;
1053 	}
1054 
1055 	inpause=0;
1056 	looped=0;
1057 	oggSetVolume(64, 0, 64, 0);
1058 /*
1059 	oggSetAmplify(amplify);   TODO */
1060 
1061 	buf16=malloc(sizeof(uint16_t)*buflen*2);
1062 	if (!buf16)
1063 	{
1064 		plrClosePlayer();
1065 
1066 		ringbuffer_free (oggbufpos);
1067 		oggbufpos = 0;
1068 
1069 		free(oggbuf);
1070 		oggbuf = 0;
1071 		return 0;
1072 	}
1073 	bufpos=0;
1074 
1075 	if (!pollInit(oggIdle))
1076 	{
1077 		plrClosePlayer();
1078 
1079 		free (buf16);
1080 		buf16 = 0;
1081 
1082 		ringbuffer_free (oggbufpos);
1083 		oggbufpos = 0;
1084 
1085 		free(oggbuf);
1086 		oggbuf = 0;
1087 
1088 		return 0;
1089 	}
1090 	active=1;
1091 
1092 	return 1;
1093 }
1094 
1095 void __attribute__ ((visibility ("internal"))) oggClosePlayer(void)
1096 {
1097 	int i, j;
1098 	active=0;
1099 
1100 	pollClose();
1101 
1102 	plrClosePlayer();
1103 
1104 	ringbuffer_free (oggbufpos);
1105 	oggbufpos = 0;
1106 
1107 	free(oggbuf);
1108 	oggbuf=NULL;
1109 
1110 	free(buf16);
1111 	buf16=NULL;
1112 
1113 	ov_clear(&ov);
1114 
1115 	for (i=0; i < ogg_comments_count; i++)
1116 	{
1117 		for (j=0; j < ogg_comments[i]->value_count; j++)
1118 		{
1119 			free (ogg_comments[i]->value[j]);
1120 		}
1121 		free (ogg_comments[i]->title);
1122 		free (ogg_comments[i]);
1123 	}
1124 	free (ogg_comments);
1125 	ogg_comments = 0;
1126 	ogg_comments_count = 0;
1127 
1128 	for (i=0; i < ogg_pictures_count; i++)
1129 	{
1130 		free (ogg_pictures[i].data_bgra);
1131 		free (ogg_pictures[i].scaled_data_bgra);
1132 		free (ogg_pictures[i].description);
1133 	}
1134 	free (ogg_pictures);
1135 	ogg_pictures = 0;
1136 	ogg_pictures_count = 0;
1137 
1138 	if (oggfile)
1139 	{
1140 		oggfile->unref (oggfile);
1141 		oggfile = 0;
1142 	}
1143 }
1144 
1145 char __attribute__ ((visibility ("internal"))) oggLooped(void)
1146 {
1147 	return looped == 3;
1148 }
1149 
1150 void __attribute__ ((visibility ("internal"))) oggSetLoop(uint8_t s)
1151 {
1152 	donotloop=!s;
1153 }
1154 
1155 void __attribute__ ((visibility ("internal"))) oggPause(uint8_t p)
1156 {
1157 	inpause=p;
1158 }
1159 
1160 void __attribute__ ((visibility ("internal"))) oggSetSpeed(uint16_t sp)
1161 {
1162 	if (sp<32)
1163 		sp=32;
1164 	oggbufrate=imuldiv(256*sp, oggrate, samprate);
1165 }
1166 
1167 void __attribute__ ((visibility ("internal"))) oggSetVolume(uint8_t vol_, int8_t bal_, int8_t pan_, uint8_t opt)
1168 {
1169 	pan=pan_;
1170 	if (reversestereo)
1171 	{
1172 		pan = -pan;
1173 	}
1174 	volr=voll=vol_*4;
1175 	if (bal_<0)
1176 		voll=(voll*(64+bal_))>>6;
1177 	else
1178 		volr=(volr*(64-bal_))>>6;
1179 	srnd=opt;
1180 }
1181 
1182 ogg_int64_t __attribute__ ((visibility ("internal"))) oggGetPos(void)
1183 {
1184 #warning TODO, deduct devp buffer!
1185 	return (oggpos+ogglen-ringbuffer_get_tail_available_samples(oggbufpos))%ogglen;
1186 }
1187 
1188 void __attribute__ ((visibility ("internal"))) oggGetInfo(struct ogginfo *i)
1189 {
1190 	static int lastsafe=0;
1191 	i->pos=oggGetPos();
1192 	i->len=ogglen;
1193 	i->rate=oggrate;
1194 	i->stereo=oggstereo;
1195 	i->bit16=1;
1196 	if ((i->bitrate=ov_bitrate_instant(&ov))<0)
1197 		i->bitrate=lastsafe;
1198 	else
1199 		lastsafe=i->bitrate;
1200 	i->bitrate/=1000;
1201 }
1202 
1203 void __attribute__ ((visibility ("internal"))) oggSetPos(ogg_int64_t pos)
1204 {
1205 	pos=(pos+ogglen)%ogglen;
1206 
1207 	oggneedseek=1;
1208 	oggpos=pos;
1209 	ringbuffer_reset(oggbufpos);
1210 }
1211 
1212