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, ¤t_section); 165 #else 166 result=ov_read(&ov, (char *)(oggbuf+(pos1<<1)), read<<(1+oggstereo), 1, 2, 1, ¤t_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