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-2008 Stephan Aßmus <superstippi@gmx.de> (MIT Ok) 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 "AutoDeleter.h" 37 #include "ControllerView.h" 38 #include "PlaybackState.h" 39 #include "VideoView.h" 40 41 // suppliers 42 #include "AudioTrackSupplier.h" 43 #include "MediaTrackAudioSupplier.h" 44 #include "MediaTrackVideoSupplier.h" 45 #include "ProxyAudioSupplier.h" 46 #include "ProxyVideoSupplier.h" 47 #include "VideoTrackSupplier.h" 48 49 using std::nothrow; 50 51 52 void 53 HandleError(const char *text, status_t err) 54 { 55 if (err != B_OK) { 56 printf("%s. error 0x%08x (%s)\n",text, (int)err, strerror(err)); 57 fflush(NULL); 58 exit(1); 59 } 60 } 61 62 63 // #pragma mark - Controller::Listener 64 65 66 Controller::Listener::Listener() {} 67 Controller::Listener::~Listener() {} 68 void Controller::Listener::FileFinished() {} 69 void Controller::Listener::FileChanged() {} 70 void Controller::Listener::VideoTrackChanged(int32) {} 71 void Controller::Listener::AudioTrackChanged(int32) {} 72 void Controller::Listener::VideoStatsChanged() {} 73 void Controller::Listener::AudioStatsChanged() {} 74 void Controller::Listener::PlaybackStateChanged(uint32) {} 75 void Controller::Listener::PositionChanged(float) {} 76 void Controller::Listener::VolumeChanged(float) {} 77 void Controller::Listener::MutedChanged(bool) {} 78 79 80 // #pragma mark - Controller 81 82 83 Controller::Controller() 84 : NodeManager() 85 , fVideoView(NULL) 86 , fVolume(1.0) 87 , fMuted(false) 88 89 , fRef() 90 , fMediaFile(NULL) 91 92 , fVideoSupplier(new ProxyVideoSupplier()) 93 , fAudioSupplier(new ProxyAudioSupplier(this)) 94 , fVideoTrackSupplier(NULL) 95 , fAudioTrackSupplier(NULL) 96 97 , fAudioTrackList(4) 98 , fVideoTrackList(2) 99 100 , fPosition(0) 101 , fDuration(0) 102 , fVideoFrameRate(25.0) 103 104 , fAutoplay(true) 105 , fPauseAtEndOfStream(false) 106 , fSeekToStartAfterPause(false) 107 108 , fListeners(4) 109 { 110 fStopped = fAutoplay ? false : true; 111 } 112 113 114 Controller::~Controller() 115 { 116 if (fMediaFile) 117 fMediaFile->ReleaseAllTracks(); 118 delete fMediaFile; 119 } 120 121 122 // #pragma mark - NodeManager interface 123 124 125 int64 126 Controller::Duration() 127 { 128 // TODO: It is not so nice that the MediaPlayer still measures 129 // in video frames if only playing audio. Here for example, it will 130 // return a duration of 0 if the audio clip happens to be shorter than 131 // one video frame at 25 fps. 132 return (int64)((double)fDuration * fVideoFrameRate / 1000000.0); 133 } 134 135 136 VideoTarget* 137 Controller::CreateVideoTarget() 138 { 139 return fVideoView; 140 } 141 142 143 VideoSupplier* 144 Controller::CreateVideoSupplier() 145 { 146 return fVideoSupplier; 147 } 148 149 150 AudioSupplier* 151 Controller::CreateAudioSupplier() 152 { 153 return fAudioSupplier; 154 } 155 156 157 // #pragma mark - 158 159 160 status_t 161 Controller::SetTo(const entry_ref &ref) 162 { 163 BAutolock _(this); 164 165 if (fRef == ref) { 166 if (InitCheck() == B_OK) { 167 SetCurrentFrame(0); 168 StartPlaying(); 169 } 170 return B_OK; 171 } 172 173 fRef = ref; 174 175 fAudioSupplier->SetSupplier(NULL, fVideoFrameRate); 176 fVideoSupplier->SetSupplier(NULL); 177 178 fAudioTrackList.MakeEmpty(); 179 fVideoTrackList.MakeEmpty(); 180 181 ObjectDeleter<BMediaFile> oldMediaFileDeleter(fMediaFile); 182 // BMediaFile destructor will call ReleaseAllTracks() 183 fMediaFile = NULL; 184 185 // Do not delete the supplier chain until after we called 186 // NodeManager::Init() to setup a new media node chain 187 ObjectDeleter<VideoTrackSupplier> videoSupplierDeleter( 188 fVideoTrackSupplier); 189 ObjectDeleter<AudioTrackSupplier> audioSupplierDeleter( 190 fAudioTrackSupplier); 191 192 fVideoTrackSupplier = NULL; 193 fAudioTrackSupplier = NULL; 194 195 fPauseAtEndOfStream = false; 196 fSeekToStartAfterPause = false; 197 fDuration = 0; 198 fVideoFrameRate = 25.0; 199 200 status_t err; 201 202 BMediaFile* mf = new BMediaFile(&ref); 203 ObjectDeleter<BMediaFile> mediaFileDeleter(mf); 204 205 err = mf->InitCheck(); 206 if (err != B_OK) { 207 printf("Controller::SetTo: initcheck failed\n"); 208 _NotifyFileChanged(); 209 return err; 210 } 211 212 int trackcount = mf->CountTracks(); 213 if (trackcount <= 0) { 214 printf("Controller::SetTo: trackcount %d\n", trackcount); 215 _NotifyFileChanged(); 216 return B_MEDIA_NO_HANDLER; 217 } 218 219 for (int i = 0; i < trackcount; i++) { 220 BMediaTrack* t = mf->TrackAt(i); 221 media_format f; 222 err = t->EncodedFormat(&f); 223 if (err != B_OK || t->Duration() <= 0) { 224 printf("Controller::SetTo: EncodedFormat failed for track index %d, error 0x%08lx (%s)\n", 225 i, err, strerror(err)); 226 mf->ReleaseTrack(t); 227 continue; 228 } 229 if (f.IsAudio()) { 230 if (!fAudioTrackList.AddItem(t)) 231 return B_NO_MEMORY; 232 } else if (f.IsVideo()) { 233 if (!fVideoTrackList.AddItem(t)) 234 return B_NO_MEMORY; 235 } else { 236 printf("Controller::SetTo: track index %d has unknown type\n", i); 237 mf->ReleaseTrack(t); 238 } 239 } 240 241 printf("Controller::SetTo: %d audio track, %d video track\n", 242 AudioTrackCount(), VideoTrackCount()); 243 244 fMediaFile = mf; 245 mediaFileDeleter.Detach(); 246 247 SelectAudioTrack(0); 248 SelectVideoTrack(0); 249 250 if (fAudioTrackSupplier == NULL && fVideoTrackSupplier == NULL) { 251 printf("Controller::SetTo: no audio or video tracks found or " 252 "no decoders\n"); 253 _NotifyFileChanged(); 254 delete fMediaFile; 255 fMediaFile = NULL; 256 return B_MEDIA_NO_HANDLER; 257 } 258 259 // prevent blocking the creation of new overlay buffers 260 fVideoView->DisableOverlay(); 261 262 // get video properties (if there is video at all) 263 int width; 264 int height; 265 GetSize(&width, &height); 266 color_space preferredVideoFormat = B_NO_COLOR_SPACE; 267 if (fVideoTrackSupplier) { 268 const media_format& format = fVideoTrackSupplier->Format(); 269 preferredVideoFormat = format.u.raw_video.display.format; 270 } 271 272 if (InitCheck() != B_OK) { 273 Init(BRect(0, 0, width - 1, height - 1), fVideoFrameRate, 274 preferredVideoFormat, LOOPING_ALL, false); 275 } else { 276 FormatChanged(BRect(0, 0, width - 1, height - 1), fVideoFrameRate, 277 preferredVideoFormat); 278 } 279 280 _NotifyFileChanged(); 281 282 SetCurrentFrame(0); 283 if (fAutoplay) 284 StartPlaying(true); 285 286 return B_OK; 287 } 288 289 290 void 291 Controller::GetSize(int *width, int *height) 292 { 293 BAutolock _(this); 294 295 if (fVideoTrackSupplier) { 296 media_format format = fVideoTrackSupplier->Format(); 297 // TODO: take aspect ratio into account! 298 *height = format.u.raw_video.display.line_count; 299 *width = format.u.raw_video.display.line_width; 300 } else { 301 *height = 0; 302 *width = 0; 303 } 304 } 305 306 307 int 308 Controller::AudioTrackCount() 309 { 310 BAutolock _(this); 311 312 return fAudioTrackList.CountItems(); 313 } 314 315 316 int 317 Controller::VideoTrackCount() 318 { 319 BAutolock _(this); 320 321 return fVideoTrackList.CountItems(); 322 } 323 324 325 status_t 326 Controller::SelectAudioTrack(int n) 327 { 328 BAutolock _(this); 329 330 BMediaTrack* track = (BMediaTrack *)fAudioTrackList.ItemAt(n); 331 if (!track) 332 return B_ERROR; 333 334 ObjectDeleter<AudioTrackSupplier> deleter(fAudioTrackSupplier); 335 fAudioTrackSupplier = new MediaTrackAudioSupplier(track, n); 336 337 bigtime_t a = fAudioTrackSupplier->Duration(); 338 bigtime_t v = fVideoTrackSupplier ? fVideoTrackSupplier->Duration() : 0;; 339 fDuration = max_c(a, v); 340 DurationChanged(); 341 // TODO: notify duration changed! 342 343 fAudioSupplier->SetSupplier(fAudioTrackSupplier, fVideoFrameRate); 344 345 _NotifyAudioTrackChanged(n); 346 return B_OK; 347 } 348 349 350 int 351 Controller::CurrentAudioTrack() 352 { 353 BAutolock _(this); 354 355 if (fAudioTrackSupplier == NULL) 356 return -1; 357 358 return fAudioTrackSupplier->TrackIndex(); 359 } 360 361 362 status_t 363 Controller::SelectVideoTrack(int n) 364 { 365 BAutolock _(this); 366 367 BMediaTrack* track = (BMediaTrack *)fVideoTrackList.ItemAt(n); 368 if (!track) 369 return B_ERROR; 370 371 status_t initStatus; 372 ObjectDeleter<VideoTrackSupplier> deleter(fVideoTrackSupplier); 373 fVideoTrackSupplier = new MediaTrackVideoSupplier(track, n, initStatus); 374 if (initStatus < B_OK) { 375 delete fVideoTrackSupplier; 376 fVideoTrackSupplier = NULL; 377 return initStatus; 378 } 379 380 bigtime_t a = fAudioTrackSupplier ? fAudioTrackSupplier->Duration() : 0; 381 bigtime_t v = fVideoTrackSupplier->Duration(); 382 fDuration = max_c(a, v); 383 fVideoFrameRate = fVideoTrackSupplier->Format().u.raw_video.field_rate; 384 if (fVideoFrameRate <= 0.0) { 385 printf("Controller::SelectVideoTrack(%d) - invalid video frame rate: %.1f\n", n, 386 fVideoFrameRate); 387 fVideoFrameRate = 25.0; 388 } 389 390 DurationChanged(); 391 // TODO: notify duration changed! 392 393 fVideoSupplier->SetSupplier(fVideoTrackSupplier); 394 395 _NotifyVideoTrackChanged(n); 396 return B_OK; 397 } 398 399 400 int 401 Controller::CurrentVideoTrack() 402 { 403 BAutolock _(this); 404 405 if (fVideoTrackSupplier == NULL) 406 return -1; 407 408 return fVideoTrackSupplier->TrackIndex(); 409 } 410 411 412 // #pragma mark - 413 414 415 void 416 Controller::Stop() 417 { 418 printf("Controller::Stop\n"); 419 420 BAutolock _(this); 421 422 StopPlaying(); 423 SetCurrentFrame(0); 424 } 425 426 427 void 428 Controller::Play() 429 { 430 printf("Controller::Play\n"); 431 432 BAutolock _(this); 433 434 if (fSeekToStartAfterPause) { 435 printf("seeking to start after pause\n"); 436 SetPosition(0); 437 fSeekToStartAfterPause = false; 438 } 439 440 StartPlaying(); 441 } 442 443 444 void 445 Controller::Pause() 446 { 447 printf("Controller::Pause\n"); 448 449 BAutolock _(this); 450 451 PausePlaying(); 452 } 453 454 455 void 456 Controller::TogglePlaying() 457 { 458 printf("Controller::TogglePlaying\n"); 459 460 BAutolock _(this); 461 462 NodeManager::TogglePlaying(); 463 } 464 465 466 uint32 467 Controller::PlaybackState() 468 { 469 BAutolock _(this); 470 471 return _PlaybackState(PlaybackManager::PlayMode()); 472 } 473 474 475 bigtime_t 476 Controller::TimeDuration() 477 { 478 BAutolock _(this); 479 480 return fDuration; 481 } 482 483 484 bigtime_t 485 Controller::TimePosition() 486 { 487 BAutolock _(this); 488 489 return fPosition; 490 } 491 492 493 void 494 Controller::SetVolume(float value) 495 { 496 printf("Controller::SetVolume %.4f\n", value); 497 if (!Lock()) 498 return; 499 500 value = max_c(0.0, min_c(2.0, value)); 501 502 if (fVolume != value) { 503 if (fMuted) 504 ToggleMute(); 505 506 fVolume = value; 507 fAudioSupplier->SetVolume(fVolume); 508 509 _NotifyVolumeChanged(fVolume); 510 } 511 512 Unlock(); 513 } 514 515 void 516 Controller::VolumeUp() 517 { 518 // TODO: linear <-> exponential 519 SetVolume(Volume() + 0.05); 520 } 521 522 void 523 Controller::VolumeDown() 524 { 525 // TODO: linear <-> exponential 526 SetVolume(Volume() - 0.05); 527 } 528 529 void 530 Controller::ToggleMute() 531 { 532 if (!Lock()) 533 return; 534 535 fMuted = !fMuted; 536 537 if (fMuted) 538 fAudioSupplier->SetVolume(0.0); 539 else 540 fAudioSupplier->SetVolume(fVolume); 541 542 _NotifyMutedChanged(fMuted); 543 544 Unlock(); 545 } 546 547 548 float 549 Controller::Volume() 550 { 551 BAutolock _(this); 552 553 return fVolume; 554 } 555 556 557 void 558 Controller::SetPosition(float value) 559 { 560 BAutolock _(this); 561 562 SetCurrentFrame(Duration() * value); 563 564 fSeekToStartAfterPause = false; 565 } 566 567 568 // #pragma mark - 569 570 571 bool 572 Controller::HasFile() 573 { 574 // you need to hold the data lock 575 return fMediaFile != NULL; 576 } 577 578 579 status_t 580 Controller::GetFileFormatInfo(media_file_format* fileFormat) 581 { 582 // you need to hold the data lock 583 if (!fMediaFile) 584 return B_NO_INIT; 585 return fMediaFile->GetFileFormatInfo(fileFormat); 586 } 587 588 589 status_t 590 Controller::GetCopyright(BString* copyright) 591 { 592 // you need to hold the data lock 593 if (!fMediaFile) 594 return B_NO_INIT; 595 *copyright = fMediaFile->Copyright(); 596 return B_OK; 597 } 598 599 600 status_t 601 Controller::GetLocation(BString* location) 602 { 603 // you need to hold the data lock 604 if (!fMediaFile) 605 return B_NO_INIT; 606 BPath path(&fRef); 607 status_t ret = path.InitCheck(); 608 if (ret < B_OK) 609 return ret; 610 *location = ""; 611 *location << "file://" << path.Path(); 612 return B_OK; 613 } 614 615 616 status_t 617 Controller::GetName(BString* name) 618 { 619 // you need to hold the data lock 620 if (!fMediaFile) 621 return B_NO_INIT; 622 *name = fRef.name; 623 return B_OK; 624 } 625 626 627 status_t 628 Controller::GetEncodedVideoFormat(media_format* format) 629 { 630 // you need to hold the data lock 631 if (fVideoTrackSupplier) 632 return fVideoTrackSupplier->GetEncodedFormat(format); 633 return B_NO_INIT; 634 } 635 636 637 status_t 638 Controller::GetVideoCodecInfo(media_codec_info* info) 639 { 640 // you need to hold the data lock 641 if (fVideoTrackSupplier) 642 return fVideoTrackSupplier->GetCodecInfo(info); 643 return B_NO_INIT; 644 } 645 646 647 status_t 648 Controller::GetEncodedAudioFormat(media_format* format) 649 { 650 // you need to hold the data lock 651 if (fAudioTrackSupplier) 652 return fAudioTrackSupplier->GetEncodedFormat(format); 653 return B_NO_INIT; 654 } 655 656 657 status_t 658 Controller::GetAudioCodecInfo(media_codec_info* info) 659 { 660 // you need to hold the data lock 661 if (fAudioTrackSupplier) 662 return fAudioTrackSupplier->GetCodecInfo(info); 663 return B_NO_INIT; 664 } 665 666 667 // #pragma mark - 668 669 670 void 671 Controller::SetVideoView(VideoView *view) 672 { 673 BAutolock _(this); 674 675 fVideoView = view; 676 } 677 678 679 bool 680 Controller::IsOverlayActive() 681 { 682 if (fVideoView) 683 return fVideoView->IsOverlayActive(); 684 685 return false; 686 } 687 688 689 // #pragma mark - 690 691 692 bool 693 Controller::AddListener(Listener* listener) 694 { 695 BAutolock _(this); 696 697 if (listener && !fListeners.HasItem(listener)) 698 return fListeners.AddItem(listener); 699 return false; 700 } 701 702 703 void 704 Controller::RemoveListener(Listener* listener) 705 { 706 BAutolock _(this); 707 708 fListeners.RemoveItem(listener); 709 } 710 711 712 // #pragma mark - Private 713 714 715 uint32 716 Controller::_PlaybackState(int32 playingMode) const 717 { 718 uint32 state = 0; 719 switch (playingMode) { 720 case MODE_PLAYING_PAUSED_FORWARD: 721 case MODE_PLAYING_PAUSED_BACKWARD: 722 state = PLAYBACK_STATE_PAUSED; 723 break; 724 case MODE_PLAYING_FORWARD: 725 case MODE_PLAYING_BACKWARD: 726 state = PLAYBACK_STATE_PLAYING; 727 break; 728 729 default: 730 state = PLAYBACK_STATE_STOPPED; 731 break; 732 } 733 return state; 734 } 735 736 737 // #pragma mark - Notifications 738 739 740 void 741 Controller::_NotifyFileChanged() const 742 { 743 BList listeners(fListeners); 744 int32 count = listeners.CountItems(); 745 for (int32 i = 0; i < count; i++) { 746 Listener* listener = (Listener*)listeners.ItemAtFast(i); 747 listener->FileChanged(); 748 } 749 } 750 751 752 void 753 Controller::_NotifyFileFinished() const 754 { 755 BList listeners(fListeners); 756 int32 count = listeners.CountItems(); 757 for (int32 i = 0; i < count; i++) { 758 Listener* listener = (Listener*)listeners.ItemAtFast(i); 759 listener->FileFinished(); 760 } 761 } 762 763 764 void 765 Controller::_NotifyVideoTrackChanged(int32 index) const 766 { 767 BList listeners(fListeners); 768 int32 count = listeners.CountItems(); 769 for (int32 i = 0; i < count; i++) { 770 Listener* listener = (Listener*)listeners.ItemAtFast(i); 771 listener->VideoTrackChanged(index); 772 } 773 } 774 775 776 void 777 Controller::_NotifyAudioTrackChanged(int32 index) const 778 { 779 BList listeners(fListeners); 780 int32 count = listeners.CountItems(); 781 for (int32 i = 0; i < count; i++) { 782 Listener* listener = (Listener*)listeners.ItemAtFast(i); 783 listener->AudioTrackChanged(index); 784 } 785 } 786 787 788 void 789 Controller::_NotifyVideoStatsChanged() const 790 { 791 BList listeners(fListeners); 792 int32 count = listeners.CountItems(); 793 for (int32 i = 0; i < count; i++) { 794 Listener* listener = (Listener*)listeners.ItemAtFast(i); 795 listener->VideoStatsChanged(); 796 } 797 } 798 799 800 void 801 Controller::_NotifyAudioStatsChanged() const 802 { 803 BList listeners(fListeners); 804 int32 count = listeners.CountItems(); 805 for (int32 i = 0; i < count; i++) { 806 Listener* listener = (Listener*)listeners.ItemAtFast(i); 807 listener->AudioStatsChanged(); 808 } 809 } 810 811 812 void 813 Controller::_NotifyPlaybackStateChanged(uint32 state) const 814 { 815 BList listeners(fListeners); 816 int32 count = listeners.CountItems(); 817 for (int32 i = 0; i < count; i++) { 818 Listener* listener = (Listener*)listeners.ItemAtFast(i); 819 listener->PlaybackStateChanged(state); 820 } 821 } 822 823 824 void 825 Controller::_NotifyPositionChanged(float position) const 826 { 827 BList listeners(fListeners); 828 int32 count = listeners.CountItems(); 829 for (int32 i = 0; i < count; i++) { 830 Listener* listener = (Listener*)listeners.ItemAtFast(i); 831 listener->PositionChanged(position); 832 } 833 } 834 835 836 void 837 Controller::_NotifyVolumeChanged(float volume) const 838 { 839 BList listeners(fListeners); 840 int32 count = listeners.CountItems(); 841 for (int32 i = 0; i < count; i++) { 842 Listener* listener = (Listener*)listeners.ItemAtFast(i); 843 listener->VolumeChanged(volume); 844 } 845 } 846 847 848 void 849 Controller::_NotifyMutedChanged(bool muted) const 850 { 851 BList listeners(fListeners); 852 int32 count = listeners.CountItems(); 853 for (int32 i = 0; i < count; i++) { 854 Listener* listener = (Listener*)listeners.ItemAtFast(i); 855 listener->MutedChanged(muted); 856 } 857 } 858 859 860 void 861 Controller::NotifyPlayModeChanged(int32 mode) const 862 { 863 _NotifyPlaybackStateChanged(_PlaybackState(mode)); 864 } 865 866 867 void 868 Controller::NotifyLoopModeChanged(int32 mode) const 869 { 870 } 871 872 873 void 874 Controller::NotifyLoopingEnabledChanged(bool enabled) const 875 { 876 } 877 878 879 void 880 Controller::NotifyVideoBoundsChanged(BRect bounds) const 881 { 882 } 883 884 885 void 886 Controller::NotifyFPSChanged(float fps) const 887 { 888 } 889 890 891 void 892 Controller::NotifyCurrentFrameChanged(int32 frame) const 893 { 894 float position = 0.0; 895 double duration = (double)fDuration * fVideoFrameRate / 1000000.0; 896 if (duration > 0) 897 position = (float)frame / duration; 898 fPosition = (bigtime_t)(position * fDuration + 0.5); 899 _NotifyPositionChanged(position); 900 } 901 902 903 void 904 Controller::NotifySpeedChanged(float speed) const 905 { 906 } 907 908 909 void 910 Controller::NotifyFrameDropped() const 911 { 912 // printf("Controller::NotifyFrameDropped()\n"); 913 } 914 915 916 void 917 Controller::NotifyStopFrameReached() const 918 { 919 // Currently, this means we reached the end of the current 920 // file and should play the next file 921 _NotifyFileFinished(); 922 } 923 924