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 ? fSoundOutput->Latency() : 0; 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 if (fSoundOutput->InitCheck() >= B_OK) 899 fSoundOutput->Play(buffer->buffer, buffer->sizeUsed); 900 _UpdatePosition(buffer->startTime); 901 } 902 903 904 fDataLock.Unlock(); 905 906 release_sem(fAudioDecodeSem); 907 } 908 } 909 910 911 // #pragma mark - 912 913 914 void 915 Controller::_VideoDecodeThread() 916 { 917 VideoSupplier* lastSupplier = NULL; 918 size_t bufferSize = 0; 919 size_t bytePerRow = 0; 920 int lineWidth = 0; 921 int lineCount = 0; 922 bool decodeError = false; 923 status_t status; 924 925 printf("video decode start\n"); 926 927 while (acquire_sem(fVideoDecodeSem) == B_OK) { 928 buffer_info *buffer = &fVideoBuffer[fVideoBufferWriteIndex]; 929 fVideoBufferWriteIndex = (fVideoBufferWriteIndex + 1) % fVideoBufferCount; 930 931 if (!fVideoSupplierLock.Lock()) 932 return; 933 934 buffer->formatChanged = lastSupplier != fVideoSupplier; 935 lastSupplier = fVideoSupplier; 936 937 if (!lastSupplier) { 938 // no video supplier 939 buffer->sizeUsed = 0; 940 buffer->startTime = 0; 941 942 fVideoSupplierLock.Unlock(); 943 snooze(10000); 944 release_sem(fVideoDecodeSem); 945 continue; 946 } 947 948 949 if (buffer->formatChanged) { 950 //printf("Video track changed\n"); 951 buffer->mediaFormat = lastSupplier->Format(); 952 953 bytePerRow = buffer->mediaFormat.u.raw_video.display.bytes_per_row; 954 lineWidth = buffer->mediaFormat.u.raw_video.display.line_width; 955 lineCount = buffer->mediaFormat.u.raw_video.display.line_count; 956 bufferSize = lineCount * bytePerRow; 957 } 958 959 if (buffer->sizeMax != bufferSize) { 960 LockBitmap(); 961 962 BRect r(0, 0, lineWidth - 1, lineCount - 1); 963 if (buffer->bitmap == fCurrentBitmap) 964 fCurrentBitmap = NULL; 965 delete buffer->bitmap; 966 printf("allocating bitmap #%ld %d %d %ld\n", 967 fVideoBufferWriteIndex, lineWidth, lineCount, bytePerRow); 968 if (buffer->mediaFormat.u.raw_video.display.format == B_YCbCr422) { 969 buffer->bitmap = new BBitmap(r, B_BITMAP_WILL_OVERLAY 970 | (fVideoBufferWriteIndex == 0) ? 971 B_BITMAP_RESERVE_OVERLAY_CHANNEL : 0, 972 B_YCbCr422, bytePerRow); 973 } else { 974 buffer->bitmap = new BBitmap(r, 0, B_RGB32, bytePerRow); 975 } 976 status = buffer->bitmap->InitCheck(); 977 if (status != B_OK) { 978 printf("bitmap init status %08lx %s\n", status, strerror(status)); 979 return; 980 } 981 buffer->buffer = (char *)buffer->bitmap->Bits(); 982 buffer->sizeMax = bufferSize; 983 984 UnlockBitmap(); 985 } 986 987 if (fSeekVideo) { 988 bigtime_t pos = fSeekPosition; 989 lastSupplier->SeekToTime(&pos); 990 fSeekVideo = false; 991 decodeError = false; 992 } 993 994 if (!decodeError) { 995 // printf("reading video frame...\n"); 996 status_t ret = lastSupplier->ReadFrame(buffer->buffer, 997 &buffer->startTime); 998 decodeError = B_OK != ret; 999 if (ret == B_LAST_BUFFER_ERROR) { 1000 buffer->endOfStream = true; 1001 _EndOfStreamReached(true); 1002 } 1003 } 1004 if (!decodeError) { 1005 buffer->sizeUsed = buffer->sizeMax; 1006 } else { 1007 buffer->sizeUsed = 0; 1008 buffer->startTime = 0; 1009 1010 fVideoSupplierLock.Unlock(); 1011 snooze(10000); 1012 release_sem(fVideoPlaySem); 1013 continue; 1014 } 1015 1016 fVideoSupplierLock.Unlock(); 1017 1018 release_sem(fVideoPlaySem); 1019 } 1020 } 1021 1022 1023 void 1024 Controller::_VideoPlayThread() 1025 { 1026 status_t status; 1027 printf("video decode start\n"); 1028 1029 while (acquire_sem(fVideoPlaySem) == B_OK) { 1030 1031 buffer_info *buffer = &fVideoBuffer[fVideoBufferReadIndex]; 1032 fVideoBufferReadIndex = (fVideoBufferReadIndex + 1) % fVideoBufferCount; 1033 wait: 1034 if (fPaused || fStopped) { 1035 //printf("waiting..\n"); 1036 status = acquire_sem_etc(fVideoWaitSem, 1, B_RELATIVE_TIMEOUT, 50000); 1037 if (status != B_OK && status != B_TIMED_OUT) 1038 break; 1039 goto wait; 1040 } 1041 1042 bigtime_t waituntil; 1043 bigtime_t waitdelta; 1044 bigtime_t now; 1045 if (fTimeSourceLock.Lock()) { 1046 now = system_time(); 1047 waituntil = fTimeSourceSysTime - fTimeSourcePerfTime + buffer->startTime - 1000; 1048 waitdelta = waituntil - now; 1049 fTimeSourceLock.Unlock(); 1050 } else { 1051 // puhh... 1052 return; 1053 } 1054 1055 #if 0 1056 char test[100]; 1057 sprintf(test, "sys %.6f perf %.6f, vid %.6f, now %.6f, waituntil %.6f, waitdelta %.6f", 1058 fTimeSourceSysTime / 1E6, fTimeSourcePerfTime / 1E6, 1059 buffer->startTime / 1E6, now / 1E6, 1060 waituntil / 1E6, waitdelta / 1E6); 1061 if (fVideoView->LockLooperWithTimeout(5000) == B_OK) { 1062 fVideoView->Window()->SetTitle(test); 1063 fVideoView->UnlockLooper(); 1064 } 1065 #endif 1066 1067 if (fAudioSupplierLock.Lock()) { 1068 if (!fAudioSupplier) { 1069 fTimeSourceSysTime = system_time(); 1070 fTimeSourcePerfTime = buffer->startTime; 1071 } 1072 fAudioSupplierLock.Unlock(); 1073 } else { 1074 // puhh... 1075 } 1076 1077 1078 #if 1 1079 if (waitdelta < -150000) { 1080 printf("video: frame %.6f too late, dropped\n", waitdelta / -1E6); 1081 release_sem(fVideoDecodeSem); 1082 continue; 1083 } 1084 #endif 1085 1086 status = acquire_sem_etc(fVideoWaitSem, 1, B_ABSOLUTE_TIMEOUT, waituntil); 1087 if (status == B_OK) { // interrupted by seeking 1088 printf("video: video wait interruped\n"); 1089 continue; 1090 } 1091 if (status != B_TIMED_OUT) 1092 break; 1093 1094 if (!fDataLock.Lock()) 1095 return; 1096 1097 if (fVideoView) { 1098 if (buffer->sizeUsed == buffer->sizeMax) { 1099 LockBitmap(); 1100 fCurrentBitmap = buffer->bitmap; 1101 fVideoView->DrawFrame(); 1102 UnlockBitmap(); 1103 1104 _UpdatePosition(buffer->startTime, true); 1105 } else { 1106 bool pause = fPauseAtEndOfStream && buffer->endOfStream; 1107 fDataLock.Unlock(); 1108 1109 release_sem(fVideoDecodeSem); 1110 1111 if (pause) { 1112 fPauseAtEndOfStream = false; 1113 fSeekToStartAfterPause = true; 1114 Pause(); 1115 } 1116 //else 1117 // snooze(25000); 1118 continue; 1119 } 1120 } else 1121 debugger("fVideoView == NULL"); 1122 1123 fDataLock.Unlock(); 1124 1125 // snooze(60000); 1126 release_sem(fVideoDecodeSem); 1127 } 1128 1129 // status_t status = acquire_sem_etc(fVideoWaitSem, 1, B_ABSOLUTE_TIMEOUT, buffer->startTime); 1130 // if (status != B_TIMED_OUT) 1131 // return; 1132 } 1133 1134 1135 // #pragma mark - 1136 1137 1138 void 1139 Controller::_StartThreads() 1140 { 1141 if (fAudioDecodeSem > 0) 1142 return; 1143 1144 fAudioBufferReadIndex = 0; 1145 fAudioBufferWriteIndex = 0; 1146 fVideoBufferReadIndex = 0; 1147 fVideoBufferWriteIndex = 0; 1148 fAudioDecodeSem = create_sem(fAudioBufferCount, "audio decode sem"); 1149 fVideoDecodeSem = create_sem(fVideoBufferCount - 2, "video decode sem"); 1150 fAudioPlaySem = create_sem(0, "audio play sem"); 1151 fVideoPlaySem = create_sem(0, "video play sem"); 1152 fAudioWaitSem = create_sem(0, "audio wait sem"); 1153 fVideoWaitSem = create_sem(0, "video wait sem"); 1154 fAudioDecodeThread = spawn_thread(_AudioDecodeThreadEntry, "audio decode", AUDIO_DECODE_PRIORITY, this); 1155 fVideoDecodeThread = spawn_thread(_VideoDecodeThreadEntry, "video decode", VIDEO_DECODE_PRIORITY, this); 1156 fAudioPlayThread = spawn_thread(_AudioPlayThreadEntry, "audio play", AUDIO_PLAY_PRIORITY, this); 1157 fVideoPlayThread = spawn_thread(_VideoPlayThreadEntry, "video play", VIDEO_PLAY_PRIORITY, this); 1158 resume_thread(fAudioDecodeThread); 1159 resume_thread(fVideoDecodeThread); 1160 resume_thread(fAudioPlayThread); 1161 resume_thread(fVideoPlayThread); 1162 } 1163 1164 1165 void 1166 Controller::_StopThreads() 1167 { 1168 if (fAudioDecodeSem < 0) 1169 return; 1170 1171 delete_sem(fAudioDecodeSem); 1172 delete_sem(fVideoDecodeSem); 1173 delete_sem(fAudioPlaySem); 1174 delete_sem(fVideoPlaySem); 1175 delete_sem(fAudioWaitSem); 1176 delete_sem(fVideoWaitSem); 1177 1178 status_t dummy; 1179 wait_for_thread(fAudioDecodeThread, &dummy); 1180 wait_for_thread(fVideoDecodeThread, &dummy); 1181 wait_for_thread(fAudioPlayThread, &dummy); 1182 wait_for_thread(fVideoPlayThread, &dummy); 1183 fAudioDecodeThread = -1; 1184 fVideoDecodeThread = -1; 1185 fAudioPlayThread = -1; 1186 fVideoPlayThread = -1; 1187 fAudioWaitSem = -1; 1188 fVideoWaitSem = -1; 1189 fAudioDecodeSem = -1; 1190 fVideoDecodeSem = -1; 1191 fAudioPlaySem = -1; 1192 fVideoPlaySem = -1; 1193 } 1194 1195 1196 // #pragma mark - 1197 1198 1199 void 1200 Controller::_EndOfStreamReached(bool isVideo) 1201 { 1202 // you need to hold the fDataLock 1203 1204 // prefer end of audio stream over end of video stream 1205 if (isVideo && fAudioSupplier) 1206 return; 1207 1208 // NOTE: executed in audio/video decode thread 1209 if (!fStopped) { 1210 fPauseAtEndOfStream = true; 1211 _NotifyFileFinished(); 1212 } 1213 } 1214 1215 1216 void 1217 Controller::_UpdatePosition(bigtime_t position, bool isVideoPosition, bool force) 1218 { 1219 // you need to hold the fDataLock 1220 1221 if (!force && fStopped) 1222 return; 1223 1224 // prefer audio position over video position 1225 if (isVideoPosition && (fAudioSupplier && fSoundOutput 1226 && fSoundOutput->InitCheck() >= B_OK)) 1227 return; 1228 1229 // BAutolock _(fTimeSourceLock); 1230 // fTimeSourcePerfTime = position; 1231 1232 fPosition = position; 1233 float scale = fDuration > 0 ? (float)fPosition / fDuration : 0.0; 1234 _NotifyPositionChanged(scale); 1235 } 1236 1237 1238 // #pragma mark - 1239 1240 1241 int32 1242 Controller::_AudioDecodeThreadEntry(void *self) 1243 { 1244 static_cast<Controller *>(self)->_AudioDecodeThread(); 1245 return 0; 1246 } 1247 1248 1249 int32 1250 Controller::_VideoDecodeThreadEntry(void *self) 1251 { 1252 static_cast<Controller *>(self)->_VideoDecodeThread(); 1253 return 0; 1254 } 1255 1256 1257 int32 1258 Controller::_AudioPlayThreadEntry(void *self) 1259 { 1260 static_cast<Controller *>(self)->_AudioPlayThread(); 1261 return 0; 1262 } 1263 1264 1265 int32 1266 Controller::_VideoPlayThreadEntry(void *self) 1267 { 1268 static_cast<Controller *>(self)->_VideoPlayThread(); 1269 return 0; 1270 } 1271 1272 1273 // #pragma mark - 1274 1275 1276 void 1277 Controller::_NotifyFileChanged() 1278 { 1279 BList listeners(fListeners); 1280 int32 count = listeners.CountItems(); 1281 for (int32 i = 0; i < count; i++) { 1282 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1283 listener->FileChanged(); 1284 } 1285 } 1286 1287 1288 void 1289 Controller::_NotifyFileFinished() 1290 { 1291 BList listeners(fListeners); 1292 int32 count = listeners.CountItems(); 1293 for (int32 i = 0; i < count; i++) { 1294 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1295 listener->FileFinished(); 1296 } 1297 } 1298 1299 1300 void 1301 Controller::_NotifyVideoTrackChanged(int32 index) 1302 { 1303 BList listeners(fListeners); 1304 int32 count = listeners.CountItems(); 1305 for (int32 i = 0; i < count; i++) { 1306 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1307 listener->VideoTrackChanged(index); 1308 } 1309 } 1310 1311 1312 void 1313 Controller::_NotifyAudioTrackChanged(int32 index) 1314 { 1315 BList listeners(fListeners); 1316 int32 count = listeners.CountItems(); 1317 for (int32 i = 0; i < count; i++) { 1318 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1319 listener->AudioTrackChanged(index); 1320 } 1321 } 1322 1323 1324 void 1325 Controller::_NotifyVideoStatsChanged() 1326 { 1327 BList listeners(fListeners); 1328 int32 count = listeners.CountItems(); 1329 for (int32 i = 0; i < count; i++) { 1330 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1331 listener->VideoStatsChanged(); 1332 } 1333 } 1334 1335 1336 void 1337 Controller::_NotifyAudioStatsChanged() 1338 { 1339 BList listeners(fListeners); 1340 int32 count = listeners.CountItems(); 1341 for (int32 i = 0; i < count; i++) { 1342 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1343 listener->AudioStatsChanged(); 1344 } 1345 } 1346 1347 1348 void 1349 Controller::_NotifyPlaybackStateChanged() 1350 { 1351 uint32 state = PlaybackState(); 1352 BList listeners(fListeners); 1353 int32 count = listeners.CountItems(); 1354 for (int32 i = 0; i < count; i++) { 1355 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1356 listener->PlaybackStateChanged(state); 1357 } 1358 } 1359 1360 1361 void 1362 Controller::_NotifyPositionChanged(float position) 1363 { 1364 BList listeners(fListeners); 1365 int32 count = listeners.CountItems(); 1366 for (int32 i = 0; i < count; i++) { 1367 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1368 listener->PositionChanged(position); 1369 } 1370 } 1371 1372 1373 void 1374 Controller::_NotifyVolumeChanged(float volume) 1375 { 1376 BList listeners(fListeners); 1377 int32 count = listeners.CountItems(); 1378 for (int32 i = 0; i < count; i++) { 1379 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1380 listener->VolumeChanged(volume); 1381 } 1382 } 1383 1384 1385 void 1386 Controller::_NotifyMutedChanged(bool muted) 1387 { 1388 BList listeners(fListeners); 1389 int32 count = listeners.CountItems(); 1390 for (int32 i = 0; i < count; i++) { 1391 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1392 listener->MutedChanged(muted); 1393 } 1394 } 1395