1 /* 2 * Controller.cpp - Media Player for the Haiku Operating System 3 * 4 * Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de> 5 * Copyright (C) 2007 Stephan Aßmus <superstippi@gmx.de> 6 * Copyright (C) 2007 Fredrik Modéen <fredrik@modeen.se> 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License 10 * version 2 as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 */ 22 #include "Controller.h" 23 24 #include <new> 25 #include <stdio.h> 26 #include <string.h> 27 28 #include <Autolock.h> 29 #include <Bitmap.h> 30 #include <Debug.h> 31 #include <MediaFile.h> 32 #include <MediaTrack.h> 33 #include <Path.h> 34 #include <Window.h> // for debugging only 35 36 #include "ControllerView.h" 37 #include "PlaybackState.h" 38 #include "SoundOutput.h" 39 #include "VideoView.h" 40 41 // suppliers 42 #include "AudioSupplier.h" 43 #include "MediaTrackAudioSupplier.h" 44 #include "MediaTrackVideoSupplier.h" 45 #include "VideoSupplier.h" 46 47 using std::nothrow; 48 49 50 #define AUDIO_PLAY_PRIORITY 110 51 #define VIDEO_PLAY_PRIORITY 20 52 #define AUDIO_DECODE_PRIORITY 13 53 #define VIDEO_DECODE_PRIORITY 13 54 55 void 56 HandleError(const char *text, status_t err) 57 { 58 if (err != B_OK) { 59 printf("%s. error 0x%08x (%s)\n",text, (int)err, strerror(err)); 60 fflush(NULL); 61 exit(1); 62 } 63 } 64 65 66 // #pragma mark - 67 68 69 Controller::Listener::Listener() {} 70 Controller::Listener::~Listener() {} 71 void Controller::Listener::FileFinished() {} 72 void Controller::Listener::FileChanged() {} 73 void Controller::Listener::VideoTrackChanged(int32) {} 74 void Controller::Listener::AudioTrackChanged(int32) {} 75 void Controller::Listener::VideoStatsChanged() {} 76 void Controller::Listener::AudioStatsChanged() {} 77 void Controller::Listener::PlaybackStateChanged(uint32) {} 78 void Controller::Listener::PositionChanged(float) {} 79 void Controller::Listener::VolumeChanged(float) {} 80 void Controller::Listener::MutedChanged(bool) {} 81 82 83 // #pragma mark - 84 85 86 Controller::Controller() 87 : fVideoView(NULL) 88 , fPaused(false) 89 , fStopped(true) 90 , fVolume(1.0) 91 , fMuted(false) 92 93 , fRef() 94 , fMediaFile(0) 95 , fDataLock("controller data lock") 96 97 , fVideoSupplier(NULL) 98 , fAudioSupplier(NULL) 99 100 , fVideoSupplierLock("video supplier lock") 101 , fAudioSupplierLock("audio supplier lock") 102 103 , fAudioTrackList(new BList) 104 , fVideoTrackList(new BList) 105 , fAudioDecodeSem(-1) 106 , fVideoDecodeSem(-1) 107 , fAudioPlaySem(-1) 108 , fVideoPlaySem(-1) 109 , fAudioDecodeThread(-1) 110 , fVideoDecodeThread(-1) 111 , fAudioPlayThread(-1) 112 , fVideoPlayThread(-1) 113 , fSoundOutput(NULL) 114 , fSeekAudio(false) 115 , fSeekVideo(false) 116 , fSeekPosition(0) 117 , fPosition(0) 118 , fDuration(0) 119 , fAudioBufferCount(MAX_AUDIO_BUFFERS) 120 , fAudioBufferReadIndex(0) 121 , fAudioBufferWriteIndex(0) 122 , fVideoBufferCount(MAX_VIDEO_BUFFERS) 123 , fVideoBufferReadIndex(0) 124 , fVideoBufferWriteIndex(0) 125 , fTimeSourceLock("time source lock") 126 , fTimeSourceSysTime(0) 127 , fTimeSourcePerfTime(0) 128 , fAutoplay(true) 129 , fPauseAtEndOfStream(false) 130 , fSeekToStartAfterPause(false) 131 , fCurrentBitmap(NULL) 132 , fBitmapLock("bitmap lock") 133 , fListeners(4) 134 { 135 for (int i = 0; i < MAX_AUDIO_BUFFERS; i++) { 136 fAudioBuffer[i].bitmap = NULL; 137 fAudioBuffer[i].buffer = NULL; 138 fAudioBuffer[i].sizeMax = 0; 139 fAudioBuffer[i].formatChanged = false; 140 fAudioBuffer[i].endOfStream = false; 141 } 142 for (int i = 0; i < MAX_VIDEO_BUFFERS; i++) { 143 fVideoBuffer[i].bitmap = NULL; 144 fVideoBuffer[i].buffer = NULL; 145 fVideoBuffer[i].sizeMax = 0; 146 fVideoBuffer[i].formatChanged = false; 147 fVideoBuffer[i].endOfStream = false; 148 } 149 150 fStopped = fAutoplay ? false : true; 151 152 _StartThreads(); 153 } 154 155 156 Controller::~Controller() 157 { 158 _StopThreads(); 159 160 if (fMediaFile) 161 fMediaFile->ReleaseAllTracks(); 162 delete fMediaFile; 163 delete fAudioTrackList; 164 delete fVideoTrackList; 165 166 delete fSoundOutput; 167 } 168 169 170 // #pragma mark - 171 172 173 bool 174 Controller::Lock() 175 { 176 return fDataLock.Lock(); 177 } 178 179 180 status_t 181 Controller::LockWithTimeout(bigtime_t timeout) 182 { 183 return fDataLock.LockWithTimeout(timeout); 184 } 185 186 187 void 188 Controller::Unlock() 189 { 190 return fDataLock.Unlock(); 191 } 192 193 194 // #pragma mark - 195 196 197 status_t 198 Controller::SetTo(const entry_ref &ref) 199 { 200 BAutolock dl(fDataLock); 201 BAutolock al(fVideoSupplierLock); 202 BAutolock vl(fAudioSupplierLock); 203 204 if (fRef == ref) 205 return B_OK; 206 207 fRef = ref; 208 209 fAudioTrackList->MakeEmpty(); 210 fVideoTrackList->MakeEmpty(); 211 if (fMediaFile) 212 fMediaFile->ReleaseAllTracks(); 213 delete fMediaFile; 214 fMediaFile = NULL; 215 delete fVideoSupplier; 216 fVideoSupplier = NULL; 217 delete fAudioSupplier; 218 fAudioSupplier = NULL; 219 220 fSeekAudio = true; 221 fSeekVideo = true; 222 fSeekPosition = 0; 223 fPaused = false; 224 fStopped = fAutoplay ? false : true; 225 fPauseAtEndOfStream = false; 226 fSeekToStartAfterPause = false; 227 fTimeSourceSysTime = system_time(); 228 fTimeSourcePerfTime = 0; 229 fDuration = 0; 230 231 _UpdatePosition(0); 232 233 status_t err; 234 235 BMediaFile *mf = new BMediaFile(&ref); 236 err = mf->InitCheck(); 237 if (err != B_OK) { 238 printf("Controller::SetTo: initcheck failed\n"); 239 delete mf; 240 _NotifyFileChanged(); 241 return err; 242 } 243 244 int trackcount = mf->CountTracks(); 245 if (trackcount <= 0) { 246 printf("Controller::SetTo: trackcount %d\n", trackcount); 247 delete mf; 248 _NotifyFileChanged(); 249 return B_MEDIA_NO_HANDLER; 250 } 251 252 for (int i = 0; i < trackcount; i++) { 253 BMediaTrack *t = mf->TrackAt(i); 254 media_format f; 255 err = t->EncodedFormat(&f); 256 if (err != B_OK) { 257 printf("Controller::SetTo: EncodedFormat failed for track index %d, error 0x%08lx (%s)\n", 258 i, err, strerror(err)); 259 mf->ReleaseTrack(t); 260 continue; 261 } 262 if (f.IsAudio()) { 263 fAudioTrackList->AddItem(t); 264 } else if (f.IsVideo()) { 265 fVideoTrackList->AddItem(t); 266 } else { 267 printf("Controller::SetTo: track index %d has unknown type\n", i); 268 mf->ReleaseTrack(t); 269 } 270 } 271 272 if (AudioTrackCount() == 0 && VideoTrackCount() == 0) { 273 printf("Controller::SetTo: no audio or video tracks found\n"); 274 delete mf; 275 _NotifyFileChanged(); 276 return B_MEDIA_NO_HANDLER; 277 } 278 279 printf("Controller::SetTo: %d audio track, %d video track\n", AudioTrackCount(), VideoTrackCount()); 280 281 fMediaFile = mf; 282 283 SelectAudioTrack(0); 284 SelectVideoTrack(0); 285 286 _NotifyFileChanged(); 287 _NotifyPlaybackStateChanged(); 288 289 return B_OK; 290 } 291 292 293 void 294 Controller::GetSize(int *width, int *height) 295 { 296 BAutolock _(fVideoSupplierLock); 297 298 if (fVideoSupplier) { 299 media_format format = fVideoSupplier->Format(); 300 // TODO: take aspect ratio into account! 301 *height = format.u.raw_video.display.line_count; 302 *width = format.u.raw_video.display.line_width; 303 } else { 304 *height = 480; 305 *width = 640; 306 } 307 } 308 309 310 int 311 Controller::AudioTrackCount() 312 { 313 BAutolock _(fDataLock); 314 315 return fAudioTrackList->CountItems(); 316 } 317 318 319 int 320 Controller::VideoTrackCount() 321 { 322 BAutolock _(fDataLock); 323 324 return fVideoTrackList->CountItems(); 325 } 326 327 328 status_t 329 Controller::SelectAudioTrack(int n) 330 { 331 BAutolock _(fAudioSupplierLock); 332 333 BMediaTrack* track = (BMediaTrack *)fAudioTrackList->ItemAt(n); 334 if (!track) 335 return B_ERROR; 336 337 delete fAudioSupplier; 338 fAudioSupplier = new MediaTrackAudioSupplier(track); 339 340 bigtime_t a = fAudioSupplier->Duration(); 341 bigtime_t v = fVideoSupplier ? fVideoSupplier->Duration() : 0;; 342 fDuration = max_c(a, v); 343 344 _NotifyAudioTrackChanged(n); 345 return B_OK; 346 } 347 348 349 status_t 350 Controller::SelectVideoTrack(int n) 351 { 352 BAutolock _(fVideoSupplierLock); 353 354 BMediaTrack* track = (BMediaTrack *)fVideoTrackList->ItemAt(n); 355 if (!track) 356 return B_ERROR; 357 358 delete fVideoSupplier; 359 fVideoSupplier = new MediaTrackVideoSupplier(track, 360 IsOverlayActive() ? B_YCbCr422 : B_RGB32); 361 362 bigtime_t a = fAudioSupplier ? fAudioSupplier->Duration() : 0; 363 bigtime_t v = fVideoSupplier->Duration(); 364 fDuration = max_c(a, v); 365 366 _NotifyVideoTrackChanged(n); 367 return B_OK; 368 } 369 370 371 // #pragma mark - 372 373 374 void 375 Controller::Stop() 376 { 377 printf("Controller::Stop\n"); 378 379 BAutolock _(fDataLock); 380 381 if (fStopped) 382 return; 383 384 fPaused = false; 385 fStopped = true; 386 387 fSeekAudio = true; 388 fSeekVideo = true; 389 fSeekPosition = 0; 390 391 _NotifyPlaybackStateChanged(); 392 _UpdatePosition(0, false, true); 393 } 394 395 396 void 397 Controller::Play() 398 { 399 printf("Controller::Play\n"); 400 401 BAutolock _(fDataLock); 402 403 if (!fPaused && !fStopped) 404 return; 405 406 fStopped = false; 407 fPaused = false; 408 409 if (fSeekToStartAfterPause) { 410 printf("seeking to start after pause\n"); 411 SetPosition(0); 412 fSeekToStartAfterPause = false; 413 } 414 415 _NotifyPlaybackStateChanged(); 416 } 417 418 419 void 420 Controller::Pause() 421 { 422 printf("Controller::Pause\n"); 423 424 BAutolock _(fDataLock); 425 426 if (fStopped || fPaused) 427 return; 428 429 fPaused = true; 430 431 _NotifyPlaybackStateChanged(); 432 } 433 434 435 void 436 Controller::TogglePlaying() 437 { 438 BAutolock _(fDataLock); 439 440 if (IsPaused() || IsStopped()) 441 Play(); 442 else 443 Pause(); 444 } 445 446 447 bool 448 Controller::IsPaused() const 449 { 450 BAutolock _(fDataLock); 451 452 return fPaused; 453 } 454 455 456 bool 457 Controller::IsStopped() const 458 { 459 BAutolock _(fDataLock); 460 461 return fStopped; 462 } 463 464 465 uint32 466 Controller::PlaybackState() const 467 { 468 BAutolock _(fDataLock); 469 470 if (fStopped) 471 return PLAYBACK_STATE_STOPPED; 472 if (fPaused) 473 return PLAYBACK_STATE_PAUSED; 474 return PLAYBACK_STATE_PLAYING; 475 } 476 477 478 bigtime_t 479 Controller::Duration() 480 { 481 BAutolock _(fDataLock); 482 483 return fDuration; 484 } 485 486 487 bigtime_t 488 Controller::Position() 489 { 490 BAutolock _(fDataLock); 491 492 return fPosition; 493 } 494 495 496 void 497 Controller::SetVolume(float value) 498 { 499 printf("Controller::SetVolume %.4f\n", value); 500 if (!Lock()) 501 return; 502 503 value = max_c(0.0, min_c(2.0, value)); 504 505 if (fVolume != value) { 506 if (fMuted) 507 ToggleMute(); 508 509 fVolume = value; 510 if (fSoundOutput) 511 fSoundOutput->SetVolume(fVolume); 512 513 _NotifyVolumeChanged(fVolume); 514 } 515 516 Unlock(); 517 } 518 519 void 520 Controller::VolumeUp() 521 { 522 // TODO: linear <-> exponential 523 SetVolume(Volume() + 0.05); 524 } 525 526 void 527 Controller::VolumeDown() 528 { 529 // TODO: linear <-> exponential 530 SetVolume(Volume() - 0.05); 531 } 532 533 void 534 Controller::ToggleMute() 535 { 536 if (!Lock()) 537 return; 538 539 fMuted = !fMuted; 540 541 if (fSoundOutput) { 542 if (fMuted) 543 fSoundOutput->SetVolume(0.0); 544 else 545 fSoundOutput->SetVolume(fVolume); 546 } 547 548 _NotifyMutedChanged(fMuted); 549 550 Unlock(); 551 } 552 553 554 float 555 Controller::Volume() const 556 { 557 BAutolock _(fDataLock); 558 559 return fVolume; 560 } 561 562 563 void 564 Controller::SetPosition(float value) 565 { 566 printf("Controller::SetPosition %.4f\n", value); 567 568 BAutolock _(fDataLock); 569 570 fSeekPosition = bigtime_t(value * Duration()); 571 fSeekAudio = true; 572 fSeekVideo = true; 573 574 fSeekToStartAfterPause = false; 575 576 // release_sem(fAudioWaitSem); 577 // release_sem(fVideoWaitSem); 578 } 579 580 581 // #pragma mark - 582 583 584 bool 585 Controller::HasFile() 586 { 587 // you need to hold the data lock 588 return fMediaFile != NULL; 589 } 590 591 592 status_t 593 Controller::GetFileFormatInfo(media_file_format* fileFormat) 594 { 595 // you need to hold the data lock 596 if (!fMediaFile) 597 return B_NO_INIT; 598 return fMediaFile->GetFileFormatInfo(fileFormat); 599 } 600 601 602 status_t 603 Controller::GetCopyright(BString* copyright) 604 { 605 // you need to hold the data lock 606 if (!fMediaFile) 607 return B_NO_INIT; 608 *copyright = fMediaFile->Copyright(); 609 return B_OK; 610 } 611 612 613 status_t 614 Controller::GetLocation(BString* location) 615 { 616 // you need to hold the data lock 617 if (!fMediaFile) 618 return B_NO_INIT; 619 BPath path(&fRef); 620 status_t ret = path.InitCheck(); 621 if (ret < B_OK) 622 return ret; 623 *location = ""; 624 *location << "file://" << path.Path(); 625 return B_OK; 626 } 627 628 629 status_t 630 Controller::GetName(BString* name) 631 { 632 // you need to hold the data lock 633 if (!fMediaFile) 634 return B_NO_INIT; 635 *name = fRef.name; 636 return B_OK; 637 } 638 639 640 status_t 641 Controller::GetEncodedVideoFormat(media_format* format) 642 { 643 // you need to hold the data lock 644 if (fVideoSupplier) 645 return fVideoSupplier->GetEncodedFormat(format); 646 return B_NO_INIT; 647 } 648 649 650 status_t 651 Controller::GetVideoCodecInfo(media_codec_info* info) 652 { 653 // you need to hold the data lock 654 if (fVideoSupplier) 655 return fVideoSupplier->GetCodecInfo(info); 656 return B_NO_INIT; 657 } 658 659 660 status_t 661 Controller::GetEncodedAudioFormat(media_format* format) 662 { 663 // you need to hold the data lock 664 if (fAudioSupplier) 665 return fAudioSupplier->GetEncodedFormat(format); 666 return B_NO_INIT; 667 } 668 669 670 status_t 671 Controller::GetAudioCodecInfo(media_codec_info* info) 672 { 673 // you need to hold the data lock 674 if (fAudioSupplier) 675 return fAudioSupplier->GetCodecInfo(info); 676 return B_NO_INIT; 677 } 678 679 680 // #pragma mark - 681 682 683 void 684 Controller::SetVideoView(VideoView *view) 685 { 686 BAutolock _(fDataLock); 687 688 fVideoView = view; 689 fVideoView->SetController(this); 690 } 691 692 693 bool 694 Controller::IsOverlayActive() 695 { 696 // return true; 697 return false; 698 } 699 700 701 bool 702 Controller::LockBitmap() 703 { 704 return fBitmapLock.Lock(); 705 } 706 707 708 void 709 Controller::UnlockBitmap() 710 { 711 fBitmapLock.Unlock(); 712 } 713 714 715 BBitmap * 716 Controller::Bitmap() 717 { 718 return fCurrentBitmap; 719 } 720 721 722 // #pragma mark - 723 724 725 bool 726 Controller::AddListener(Listener* listener) 727 { 728 BAutolock _(fDataLock); 729 730 if (listener && !fListeners.HasItem(listener)) 731 return fListeners.AddItem(listener); 732 return false; 733 } 734 735 736 void 737 Controller::RemoveListener(Listener* listener) 738 { 739 BAutolock _(fDataLock); 740 741 fListeners.RemoveItem(listener); 742 } 743 744 745 // #pragma mark - 746 747 748 void 749 Controller::_AudioDecodeThread() 750 { 751 AudioSupplier* lastSupplier = NULL; 752 size_t bufferSize = 0; 753 size_t frameSize = 0; 754 bool decodeError = false; 755 756 printf("audio decode start\n"); 757 758 while (acquire_sem(fAudioDecodeSem) == B_OK) { 759 //printf("audio decoding..\n"); 760 buffer_info *buffer = &fAudioBuffer[fAudioBufferWriteIndex]; 761 fAudioBufferWriteIndex = (fAudioBufferWriteIndex + 1) % fAudioBufferCount; 762 763 if (!fAudioSupplierLock.Lock()) 764 return; 765 766 buffer->formatChanged = lastSupplier != fAudioSupplier; 767 lastSupplier = fAudioSupplier; 768 769 if (!lastSupplier) { 770 // no audio supplier 771 buffer->sizeUsed = 0; 772 buffer->startTime = 0; 773 774 fAudioSupplierLock.Unlock(); 775 snooze(10000); 776 release_sem(fAudioPlaySem); 777 continue; 778 } 779 780 if (buffer->formatChanged) { 781 printf("audio format changed\n"); 782 buffer->mediaFormat = lastSupplier->Format(); 783 bufferSize = buffer->mediaFormat.u.raw_audio.buffer_size; 784 frameSize = (buffer->mediaFormat.u.raw_audio.format & 0xf) 785 * buffer->mediaFormat.u.raw_audio.channel_count; 786 } 787 788 if (buffer->sizeMax < bufferSize) { 789 delete[] buffer->buffer; 790 buffer->buffer = new char [bufferSize]; 791 buffer->sizeMax = bufferSize; 792 } 793 794 if (fSeekAudio) { 795 bigtime_t pos = fSeekPosition; 796 lastSupplier->SeekToTime(&pos); 797 fSeekAudio = false; 798 decodeError = false; 799 } 800 801 int64 frames; 802 if (!decodeError) { 803 buffer->endOfStream = false; 804 status_t ret = lastSupplier->ReadFrames(buffer->buffer, 805 &frames, &buffer->startTime); 806 decodeError = B_OK != ret; 807 if (ret != B_OK) 808 printf("audio decode error: %s\n", strerror(ret)); 809 if (ret == B_LAST_BUFFER_ERROR) { 810 _EndOfStreamReached(); 811 buffer->endOfStream = true; 812 } 813 } 814 if (!decodeError) { 815 buffer->sizeUsed = frames * frameSize; 816 } else { 817 buffer->sizeUsed = 0; 818 buffer->startTime = 0; 819 820 fAudioSupplierLock.Unlock(); 821 snooze(10000); 822 release_sem(fAudioPlaySem); 823 continue; 824 } 825 826 fAudioSupplierLock.Unlock(); 827 828 release_sem(fAudioPlaySem); 829 } 830 } 831 832 833 void 834 Controller::_AudioPlayThread() 835 { 836 bigtime_t bufferDuration = 0; 837 bigtime_t audioLatency = 0; 838 status_t status; 839 840 printf("audio play start\n"); 841 842 while (acquire_sem(fAudioPlaySem) == B_OK) { 843 //printf("audio playing..\n"); 844 buffer_info *buffer = &fAudioBuffer[fAudioBufferReadIndex]; 845 fAudioBufferReadIndex = (fAudioBufferReadIndex + 1) % fAudioBufferCount; 846 wait: 847 if (fPaused || fStopped) { 848 //printf("waiting..\n"); 849 status = acquire_sem_etc(fVideoWaitSem, 1, B_RELATIVE_TIMEOUT, 50000); 850 if (status != B_OK && status != B_TIMED_OUT) 851 break; 852 goto wait; 853 } 854 855 if (!fDataLock.Lock()) 856 return; 857 858 if (buffer->sizeUsed == 0) { 859 bool pause = fPauseAtEndOfStream && buffer->endOfStream; 860 fDataLock.Unlock(); 861 release_sem(fAudioDecodeSem); 862 if (pause) { 863 fPauseAtEndOfStream = false; 864 fSeekToStartAfterPause = true; 865 Pause(); 866 } else 867 snooze(25000); 868 continue; 869 } 870 871 if (!fSoundOutput || buffer->formatChanged) { 872 if (!fSoundOutput 873 || !(fSoundOutput->Format() == buffer->mediaFormat.u.raw_audio)) { 874 delete fSoundOutput; 875 fSoundOutput = new (nothrow) SoundOutput(fRef.name, 876 buffer->mediaFormat.u.raw_audio); 877 fSoundOutput->SetVolume(fVolume); 878 bufferDuration = bigtime_t(1000000.0 879 * (buffer->mediaFormat.u.raw_audio.buffer_size 880 / (buffer->mediaFormat.u.raw_audio.channel_count 881 * (buffer->mediaFormat.u.raw_audio.format & 0xf))) 882 / buffer->mediaFormat.u.raw_audio.frame_rate); 883 printf("audio format changed, new buffer duration %Ld\n", bufferDuration); 884 } 885 } 886 887 // TODO: fix performance time update (in case no audio) 888 if (fTimeSourceLock.Lock()) { 889 audioLatency = fSoundOutput->Latency(); 890 fTimeSourceSysTime = system_time() + audioLatency - bufferDuration; 891 fTimeSourcePerfTime = buffer->startTime; 892 fTimeSourceLock.Unlock(); 893 } 894 // printf("timesource: sys: %Ld perf: %Ld\n", fTimeSourceSysTime, 895 // fTimeSourcePerfTime); 896 897 if (fSoundOutput) { 898 fSoundOutput->Play(buffer->buffer, buffer->sizeUsed); 899 _UpdatePosition(buffer->startTime); 900 } 901 902 903 fDataLock.Unlock(); 904 905 release_sem(fAudioDecodeSem); 906 } 907 } 908 909 910 // #pragma mark - 911 912 913 void 914 Controller::_VideoDecodeThread() 915 { 916 VideoSupplier* lastSupplier = NULL; 917 size_t bufferSize = 0; 918 size_t bytePerRow = 0; 919 int lineWidth = 0; 920 int lineCount = 0; 921 bool decodeError = false; 922 status_t status; 923 924 printf("video decode start\n"); 925 926 while (acquire_sem(fVideoDecodeSem) == B_OK) { 927 buffer_info *buffer = &fVideoBuffer[fVideoBufferWriteIndex]; 928 fVideoBufferWriteIndex = (fVideoBufferWriteIndex + 1) % fVideoBufferCount; 929 930 if (!fVideoSupplierLock.Lock()) 931 return; 932 933 buffer->formatChanged = lastSupplier != fVideoSupplier; 934 lastSupplier = fVideoSupplier; 935 936 if (!lastSupplier) { 937 // no video supplier 938 buffer->sizeUsed = 0; 939 buffer->startTime = 0; 940 941 fVideoSupplierLock.Unlock(); 942 snooze(10000); 943 release_sem(fVideoDecodeSem); 944 continue; 945 } 946 947 948 if (buffer->formatChanged) { 949 //printf("Video track changed\n"); 950 buffer->mediaFormat = lastSupplier->Format(); 951 952 bytePerRow = buffer->mediaFormat.u.raw_video.display.bytes_per_row; 953 lineWidth = buffer->mediaFormat.u.raw_video.display.line_width; 954 lineCount = buffer->mediaFormat.u.raw_video.display.line_count; 955 bufferSize = lineCount * bytePerRow; 956 } 957 958 if (buffer->sizeMax != bufferSize) { 959 LockBitmap(); 960 961 BRect r(0, 0, lineWidth - 1, lineCount - 1); 962 if (buffer->bitmap == fCurrentBitmap) 963 fCurrentBitmap = NULL; 964 delete buffer->bitmap; 965 printf("allocating bitmap #%ld %d %d %ld\n", 966 fVideoBufferWriteIndex, lineWidth, lineCount, bytePerRow); 967 if (buffer->mediaFormat.u.raw_video.display.format == B_YCbCr422) { 968 buffer->bitmap = new BBitmap(r, B_BITMAP_WILL_OVERLAY 969 | (fVideoBufferWriteIndex == 0) ? 970 B_BITMAP_RESERVE_OVERLAY_CHANNEL : 0, 971 B_YCbCr422, bytePerRow); 972 } else { 973 buffer->bitmap = new BBitmap(r, 0, B_RGB32, bytePerRow); 974 } 975 status = buffer->bitmap->InitCheck(); 976 if (status != B_OK) { 977 printf("bitmap init status %08lx %s\n", status, strerror(status)); 978 return; 979 } 980 buffer->buffer = (char *)buffer->bitmap->Bits(); 981 buffer->sizeMax = bufferSize; 982 983 UnlockBitmap(); 984 } 985 986 if (fSeekVideo) { 987 bigtime_t pos = fSeekPosition; 988 lastSupplier->SeekToTime(&pos); 989 fSeekVideo = false; 990 decodeError = false; 991 } 992 993 if (!decodeError) { 994 // printf("reading video frame...\n"); 995 status_t ret = lastSupplier->ReadFrame(buffer->buffer, 996 &buffer->startTime); 997 decodeError = B_OK != ret; 998 if (ret == B_LAST_BUFFER_ERROR) { 999 buffer->endOfStream = true; 1000 _EndOfStreamReached(true); 1001 } 1002 } 1003 if (!decodeError) { 1004 buffer->sizeUsed = buffer->sizeMax; 1005 } else { 1006 buffer->sizeUsed = 0; 1007 buffer->startTime = 0; 1008 1009 fVideoSupplierLock.Unlock(); 1010 snooze(10000); 1011 release_sem(fVideoPlaySem); 1012 continue; 1013 } 1014 1015 fVideoSupplierLock.Unlock(); 1016 1017 release_sem(fVideoPlaySem); 1018 } 1019 } 1020 1021 1022 void 1023 Controller::_VideoPlayThread() 1024 { 1025 status_t status; 1026 printf("video decode start\n"); 1027 1028 while (acquire_sem(fVideoPlaySem) == B_OK) { 1029 1030 buffer_info *buffer = &fVideoBuffer[fVideoBufferReadIndex]; 1031 fVideoBufferReadIndex = (fVideoBufferReadIndex + 1) % fVideoBufferCount; 1032 wait: 1033 if (fPaused || fStopped) { 1034 //printf("waiting..\n"); 1035 status = acquire_sem_etc(fVideoWaitSem, 1, B_RELATIVE_TIMEOUT, 50000); 1036 if (status != B_OK && status != B_TIMED_OUT) 1037 break; 1038 goto wait; 1039 } 1040 1041 bigtime_t waituntil; 1042 bigtime_t waitdelta; 1043 bigtime_t now; 1044 if (fTimeSourceLock.Lock()) { 1045 now = system_time(); 1046 waituntil = fTimeSourceSysTime - fTimeSourcePerfTime + buffer->startTime - 1000; 1047 waitdelta = waituntil - now; 1048 fTimeSourceLock.Unlock(); 1049 } else { 1050 // puhh... 1051 } 1052 1053 #if 0 1054 char test[100]; 1055 sprintf(test, "sys %.6f perf %.6f, vid %.6f, now %.6f, waituntil %.6f, waitdelta %.6f", 1056 fTimeSourceSysTime / 1E6, fTimeSourcePerfTime / 1E6, 1057 buffer->startTime / 1E6, now / 1E6, 1058 waituntil / 1E6, waitdelta / 1E6); 1059 if (fVideoView->LockLooperWithTimeout(5000) == B_OK) { 1060 fVideoView->Window()->SetTitle(test); 1061 fVideoView->UnlockLooper(); 1062 } 1063 #endif 1064 1065 if (fAudioSupplierLock.Lock()) { 1066 if (!fAudioSupplier) { 1067 fTimeSourceSysTime = system_time(); 1068 fTimeSourcePerfTime = buffer->startTime; 1069 } 1070 fAudioSupplierLock.Unlock(); 1071 } else { 1072 // puhh... 1073 } 1074 1075 1076 #if 1 1077 if (waitdelta < -150000) { 1078 printf("video: frame %.6f too late, dropped\n", waitdelta / -1E6); 1079 release_sem(fVideoDecodeSem); 1080 continue; 1081 } 1082 #endif 1083 1084 status = acquire_sem_etc(fVideoWaitSem, 1, B_ABSOLUTE_TIMEOUT, waituntil); 1085 if (status == B_OK) { // interrupted by seeking 1086 printf("video: video wait interruped\n"); 1087 continue; 1088 } 1089 if (status != B_TIMED_OUT) 1090 break; 1091 1092 if (!fDataLock.Lock()) 1093 return; 1094 1095 if (fVideoView) { 1096 if (buffer->sizeUsed == buffer->sizeMax) { 1097 LockBitmap(); 1098 fCurrentBitmap = buffer->bitmap; 1099 fVideoView->DrawFrame(); 1100 UnlockBitmap(); 1101 1102 _UpdatePosition(buffer->startTime, true); 1103 } else { 1104 bool pause = fPauseAtEndOfStream && buffer->endOfStream; 1105 fDataLock.Unlock(); 1106 1107 release_sem(fVideoDecodeSem); 1108 1109 if (pause) { 1110 fPauseAtEndOfStream = false; 1111 fSeekToStartAfterPause = true; 1112 Pause(); 1113 } 1114 //else 1115 // snooze(25000); 1116 continue; 1117 } 1118 } else 1119 debugger("fVideoView == NULL"); 1120 1121 fDataLock.Unlock(); 1122 1123 // snooze(60000); 1124 release_sem(fVideoDecodeSem); 1125 } 1126 1127 // status_t status = acquire_sem_etc(fVideoWaitSem, 1, B_ABSOLUTE_TIMEOUT, buffer->startTime); 1128 // if (status != B_TIMED_OUT) 1129 // return; 1130 } 1131 1132 1133 // #pragma mark - 1134 1135 1136 void 1137 Controller::_StartThreads() 1138 { 1139 if (fAudioDecodeSem > 0) 1140 return; 1141 1142 fAudioBufferReadIndex = 0; 1143 fAudioBufferWriteIndex = 0; 1144 fVideoBufferReadIndex = 0; 1145 fVideoBufferWriteIndex = 0; 1146 fAudioDecodeSem = create_sem(fAudioBufferCount, "audio decode sem"); 1147 fVideoDecodeSem = create_sem(fVideoBufferCount - 2, "video decode sem"); 1148 fAudioPlaySem = create_sem(0, "audio play sem"); 1149 fVideoPlaySem = create_sem(0, "video play sem"); 1150 fAudioWaitSem = create_sem(0, "audio wait sem"); 1151 fVideoWaitSem = create_sem(0, "video wait sem"); 1152 fAudioDecodeThread = spawn_thread(_AudioDecodeThreadEntry, "audio decode", AUDIO_DECODE_PRIORITY, this); 1153 fVideoDecodeThread = spawn_thread(_VideoDecodeThreadEntry, "video decode", VIDEO_DECODE_PRIORITY, this); 1154 fAudioPlayThread = spawn_thread(_AudioPlayThreadEntry, "audio play", AUDIO_PLAY_PRIORITY, this); 1155 fVideoPlayThread = spawn_thread(_VideoPlayThreadEntry, "video play", VIDEO_PLAY_PRIORITY, this); 1156 resume_thread(fAudioDecodeThread); 1157 resume_thread(fVideoDecodeThread); 1158 resume_thread(fAudioPlayThread); 1159 resume_thread(fVideoPlayThread); 1160 } 1161 1162 1163 void 1164 Controller::_StopThreads() 1165 { 1166 if (fAudioDecodeSem < 0) 1167 return; 1168 1169 delete_sem(fAudioDecodeSem); 1170 delete_sem(fVideoDecodeSem); 1171 delete_sem(fAudioPlaySem); 1172 delete_sem(fVideoPlaySem); 1173 delete_sem(fAudioWaitSem); 1174 delete_sem(fVideoWaitSem); 1175 1176 status_t dummy; 1177 wait_for_thread(fAudioDecodeThread, &dummy); 1178 wait_for_thread(fVideoDecodeThread, &dummy); 1179 wait_for_thread(fAudioPlayThread, &dummy); 1180 wait_for_thread(fVideoPlayThread, &dummy); 1181 fAudioDecodeThread = -1; 1182 fVideoDecodeThread = -1; 1183 fAudioPlayThread = -1; 1184 fVideoPlayThread = -1; 1185 fAudioWaitSem = -1; 1186 fVideoWaitSem = -1; 1187 fAudioDecodeSem = -1; 1188 fVideoDecodeSem = -1; 1189 fAudioPlaySem = -1; 1190 fVideoPlaySem = -1; 1191 } 1192 1193 1194 // #pragma mark - 1195 1196 1197 void 1198 Controller::_EndOfStreamReached(bool isVideo) 1199 { 1200 // you need to hold the fDataLock 1201 1202 // prefer end of audio stream over end of video stream 1203 if (isVideo && fAudioSupplier) 1204 return; 1205 1206 // NOTE: executed in audio/video decode thread 1207 if (!fStopped) { 1208 fPauseAtEndOfStream = true; 1209 _NotifyFileFinished(); 1210 } 1211 } 1212 1213 1214 void 1215 Controller::_UpdatePosition(bigtime_t position, bool isVideoPosition, bool force) 1216 { 1217 // you need to hold the fDataLock 1218 1219 if (!force && fStopped) 1220 return; 1221 1222 // prefer audio position over video position 1223 if (isVideoPosition && fAudioSupplier) 1224 return; 1225 1226 // BAutolock _(fTimeSourceLock); 1227 // fTimeSourcePerfTime = position; 1228 1229 fPosition = position; 1230 float scale = fDuration > 0 ? (float)fPosition / fDuration : 0.0; 1231 _NotifyPositionChanged(scale); 1232 } 1233 1234 1235 // #pragma mark - 1236 1237 1238 int32 1239 Controller::_AudioDecodeThreadEntry(void *self) 1240 { 1241 static_cast<Controller *>(self)->_AudioDecodeThread(); 1242 return 0; 1243 } 1244 1245 1246 int32 1247 Controller::_VideoDecodeThreadEntry(void *self) 1248 { 1249 static_cast<Controller *>(self)->_VideoDecodeThread(); 1250 return 0; 1251 } 1252 1253 1254 int32 1255 Controller::_AudioPlayThreadEntry(void *self) 1256 { 1257 static_cast<Controller *>(self)->_AudioPlayThread(); 1258 return 0; 1259 } 1260 1261 1262 int32 1263 Controller::_VideoPlayThreadEntry(void *self) 1264 { 1265 static_cast<Controller *>(self)->_VideoPlayThread(); 1266 return 0; 1267 } 1268 1269 1270 // #pragma mark - 1271 1272 1273 void 1274 Controller::_NotifyFileChanged() 1275 { 1276 BList listeners(fListeners); 1277 int32 count = listeners.CountItems(); 1278 for (int32 i = 0; i < count; i++) { 1279 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1280 listener->FileChanged(); 1281 } 1282 } 1283 1284 1285 void 1286 Controller::_NotifyFileFinished() 1287 { 1288 BList listeners(fListeners); 1289 int32 count = listeners.CountItems(); 1290 for (int32 i = 0; i < count; i++) { 1291 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1292 listener->FileFinished(); 1293 } 1294 } 1295 1296 1297 void 1298 Controller::_NotifyVideoTrackChanged(int32 index) 1299 { 1300 BList listeners(fListeners); 1301 int32 count = listeners.CountItems(); 1302 for (int32 i = 0; i < count; i++) { 1303 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1304 listener->VideoTrackChanged(index); 1305 } 1306 } 1307 1308 1309 void 1310 Controller::_NotifyAudioTrackChanged(int32 index) 1311 { 1312 BList listeners(fListeners); 1313 int32 count = listeners.CountItems(); 1314 for (int32 i = 0; i < count; i++) { 1315 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1316 listener->AudioTrackChanged(index); 1317 } 1318 } 1319 1320 1321 void 1322 Controller::_NotifyVideoStatsChanged() 1323 { 1324 BList listeners(fListeners); 1325 int32 count = listeners.CountItems(); 1326 for (int32 i = 0; i < count; i++) { 1327 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1328 listener->VideoStatsChanged(); 1329 } 1330 } 1331 1332 1333 void 1334 Controller::_NotifyAudioStatsChanged() 1335 { 1336 BList listeners(fListeners); 1337 int32 count = listeners.CountItems(); 1338 for (int32 i = 0; i < count; i++) { 1339 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1340 listener->AudioStatsChanged(); 1341 } 1342 } 1343 1344 1345 void 1346 Controller::_NotifyPlaybackStateChanged() 1347 { 1348 uint32 state = PlaybackState(); 1349 BList listeners(fListeners); 1350 int32 count = listeners.CountItems(); 1351 for (int32 i = 0; i < count; i++) { 1352 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1353 listener->PlaybackStateChanged(state); 1354 } 1355 } 1356 1357 1358 void 1359 Controller::_NotifyPositionChanged(float position) 1360 { 1361 BList listeners(fListeners); 1362 int32 count = listeners.CountItems(); 1363 for (int32 i = 0; i < count; i++) { 1364 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1365 listener->PositionChanged(position); 1366 } 1367 } 1368 1369 1370 void 1371 Controller::_NotifyVolumeChanged(float volume) 1372 { 1373 BList listeners(fListeners); 1374 int32 count = listeners.CountItems(); 1375 for (int32 i = 0; i < count; i++) { 1376 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1377 listener->VolumeChanged(volume); 1378 } 1379 } 1380 1381 1382 void 1383 Controller::_NotifyMutedChanged(bool muted) 1384 { 1385 BList listeners(fListeners); 1386 int32 count = listeners.CountItems(); 1387 for (int32 i = 0; i < count; i++) { 1388 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1389 listener->MutedChanged(muted); 1390 } 1391 } 1392