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