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> 6 * Copyright (C) 2007-2009 Fredrik Modéen <[FirstName]@[LastName].se> 7 * 8 * Released under the terms of the MIT license. 9 */ 10 11 12 #include "Controller.h" 13 14 #include <new> 15 #include <stdio.h> 16 #include <string.h> 17 18 #include <Autolock.h> 19 #include <Bitmap.h> 20 #include <Catalog.h> 21 #include <Debug.h> 22 #include <Path.h> 23 #include <Window.h> // for debugging only 24 25 #include "AutoDeleter.h" 26 #include "ControllerView.h" 27 #include "MainApp.h" 28 #include "PlaybackState.h" 29 #include "Settings.h" 30 #include "VideoView.h" 31 32 // suppliers 33 #include "AudioTrackSupplier.h" 34 #include "MediaTrackAudioSupplier.h" 35 #include "MediaTrackVideoSupplier.h" 36 #include "ProxyAudioSupplier.h" 37 #include "ProxyVideoSupplier.h" 38 #include "SubTitles.h" 39 #include "TrackSupplier.h" 40 #include "VideoTrackSupplier.h" 41 42 43 #undef B_TRANSLATION_CONTEXT 44 #define B_TRANSLATION_CONTEXT "MediaPlayer-Controller" 45 #define MIN_WIDTH 250 46 47 using std::nothrow; 48 49 50 class TrackSupplierReleaser { 51 public: 52 TrackSupplierReleaser(PlaylistItemRef& owner) 53 : 54 fOwner(owner), 55 fRelease(true) 56 {} 57 58 virtual ~TrackSupplierReleaser() 59 { 60 if (fRelease) 61 fOwner.Get()->ReleaseTrackSupplier(); 62 } 63 64 void Detach() 65 { 66 fRelease = false; 67 } 68 69 private: 70 PlaylistItemRef& fOwner; 71 bool fRelease; 72 }; 73 74 75 void 76 HandleError(const char *text, status_t err) 77 { 78 if (err != B_OK) { 79 printf("%s. error 0x%08x (%s)\n",text, (int)err, strerror(err)); 80 fflush(NULL); 81 exit(1); 82 } 83 } 84 85 86 // #pragma mark - Controller::Listener 87 88 89 Controller::Listener::Listener() {} 90 Controller::Listener::~Listener() {} 91 void Controller::Listener::FileFinished() {} 92 void Controller::Listener::FileChanged(PlaylistItem* item, status_t result) {} 93 void Controller::Listener::VideoTrackChanged(int32) {} 94 void Controller::Listener::AudioTrackChanged(int32) {} 95 void Controller::Listener::SubTitleTrackChanged(int32) {} 96 void Controller::Listener::VideoStatsChanged() {} 97 void Controller::Listener::AudioStatsChanged() {} 98 void Controller::Listener::PlaybackStateChanged(uint32) {} 99 void Controller::Listener::PositionChanged(float) {} 100 void Controller::Listener::SeekHandled(int64 seekFrame) {} 101 void Controller::Listener::VolumeChanged(float) {} 102 void Controller::Listener::MutedChanged(bool) {} 103 104 105 // #pragma mark - Controller 106 107 108 enum { 109 MSG_SET_TO = 'stto' 110 }; 111 112 113 Controller::Controller() 114 : 115 NodeManager(), 116 fVideoView(NULL), 117 fVolume(1.0), 118 fActiveVolume(1.0), 119 fMuted(false), 120 121 fItem(NULL), 122 123 fVideoSupplier(new ProxyVideoSupplier()), 124 fAudioSupplier(new ProxyAudioSupplier(this)), 125 fVideoTrackSupplier(NULL), 126 fAudioTrackSupplier(NULL), 127 fSubTitles(NULL), 128 fSubTitlesIndex(-1), 129 130 fCurrentFrame(0), 131 fDuration(0), 132 fVideoFrameRate(25.0), 133 134 fPendingSeekRequests(0), 135 fSeekFrame(-1), 136 fRequestedSeekFrame(-1), 137 138 fGlobalSettingsListener(this), 139 140 fListeners(4) 141 { 142 Settings::Default()->AddListener(&fGlobalSettingsListener); 143 _AdoptGlobalSettings(); 144 145 fAutoplay = fAutoplaySetting; 146 } 147 148 149 Controller::~Controller() 150 { 151 Settings::Default()->RemoveListener(&fGlobalSettingsListener); 152 SetTo(NULL); 153 } 154 155 156 // #pragma mark - NodeManager interface 157 158 159 void 160 Controller::MessageReceived(BMessage* message) 161 { 162 switch (message->what) { 163 case MSG_OBJECT_CHANGED: 164 // received from fGlobalSettingsListener 165 // TODO: find out which object, if we ever watch more than 166 // the global settings instance... 167 _AdoptGlobalSettings(); 168 break; 169 170 case MSG_SET_TO: 171 { 172 PlaylistItem* item; 173 if (message->FindPointer("item", (void**)&item) == B_OK) { 174 PlaylistItemRef itemRef(item, true); 175 // The reference was passed with the message. 176 SetTo(itemRef); 177 } else 178 _NotifyFileChanged(NULL, B_BAD_VALUE); 179 180 break; 181 } 182 183 default: 184 NodeManager::MessageReceived(message); 185 } 186 } 187 188 189 int64 190 Controller::Duration() 191 { 192 return _FrameDuration(); 193 } 194 195 196 VideoTarget* 197 Controller::CreateVideoTarget() 198 { 199 return fVideoView; 200 } 201 202 203 VideoSupplier* 204 Controller::CreateVideoSupplier() 205 { 206 return fVideoSupplier; 207 } 208 209 210 AudioSupplier* 211 Controller::CreateAudioSupplier() 212 { 213 return fAudioSupplier; 214 } 215 216 217 // #pragma mark - 218 219 220 status_t 221 Controller::SetToAsync(const PlaylistItemRef& item) 222 { 223 PlaylistItemRef additionalReference(item); 224 225 BMessage message(MSG_SET_TO); 226 status_t ret = message.AddPointer("item", item.Get()); 227 if (ret != B_OK) 228 return ret; 229 230 ret = PostMessage(&message); 231 if (ret != B_OK) 232 return ret; 233 234 // The additional reference is now passed along with the message... 235 additionalReference.Detach(); 236 237 return B_OK; 238 } 239 240 241 status_t 242 Controller::SetTo(const PlaylistItemRef& item) 243 { 244 BAutolock _(this); 245 246 if (fItem == item) { 247 if (InitCheck() == B_OK) { 248 if (fAutoplay) { 249 SetPosition(0.0); 250 StartPlaying(true); 251 } 252 } 253 return B_OK; 254 } 255 256 fAudioSupplier->SetSupplier(NULL, fVideoFrameRate); 257 fVideoSupplier->SetSupplier(NULL); 258 259 if (fItem != NULL) 260 TrackSupplierReleaser oldSupplierReleaser(fItem); 261 262 fItem = item; 263 264 // Do not delete the supplier chain until after we called 265 // NodeManager::Init() to setup a new media node chain 266 ObjectDeleter<VideoTrackSupplier> videoSupplierDeleter( 267 fVideoTrackSupplier); 268 ObjectDeleter<AudioTrackSupplier> audioSupplierDeleter( 269 fAudioTrackSupplier); 270 271 fVideoTrackSupplier = NULL; 272 fAudioTrackSupplier = NULL; 273 fSubTitles = NULL; 274 fSubTitlesIndex = -1; 275 276 fCurrentFrame = 0; 277 fDuration = 0; 278 fVideoFrameRate = 25.0; 279 280 fPendingSeekRequests = 0; 281 fSeekFrame = -1; 282 fRequestedSeekFrame = -1; 283 284 if (!fItem.IsSet()) 285 return B_BAD_VALUE; 286 287 TrackSupplier* trackSupplier = fItem->GetTrackSupplier(); 288 if (trackSupplier == NULL) { 289 _NotifyFileChanged(item.Get(), B_NO_MEMORY); 290 return B_NO_MEMORY; 291 } 292 TrackSupplierReleaser trackSupplierReleaser(fItem); 293 294 status_t err = trackSupplier->InitCheck(); 295 if (err != B_OK) { 296 printf("Controller::SetTo: InitCheck failed\n"); 297 _NotifyFileChanged(item.Get(), err); 298 return err; 299 } 300 301 if (trackSupplier->CountAudioTracks() == 0 302 && trackSupplier->CountVideoTracks() == 0) { 303 _NotifyFileChanged(item.Get(), B_MEDIA_NO_HANDLER); 304 return B_MEDIA_NO_HANDLER; 305 } 306 307 SelectAudioTrack(0); 308 SelectVideoTrack(0); 309 310 if (fAudioTrackSupplier == NULL && fVideoTrackSupplier == NULL) { 311 printf("Controller::SetTo: no audio or video tracks found or " 312 "no decoders\n"); 313 _NotifyFileChanged(item.Get(), B_MEDIA_NO_HANDLER); 314 return B_MEDIA_NO_HANDLER; 315 } 316 317 trackSupplierReleaser.Detach(); 318 319 // prevent blocking the creation of new overlay buffers 320 if (fVideoView) 321 fVideoView->DisableOverlay(); 322 323 // get video properties (if there is video at all) 324 bool useOverlays = fVideoView ? fVideoView->UseOverlays() : true; 325 326 int width; 327 int height; 328 GetSize(&width, &height); 329 color_space preferredVideoFormat = B_NO_COLOR_SPACE; 330 if (fVideoTrackSupplier != NULL) { 331 const media_format& format = fVideoTrackSupplier->Format(); 332 preferredVideoFormat = format.u.raw_video.display.format; 333 } 334 335 uint32 enabledNodes; 336 if (!fVideoTrackSupplier) 337 enabledNodes = AUDIO_ONLY; 338 else if (!fAudioTrackSupplier) 339 enabledNodes = VIDEO_ONLY; 340 else 341 enabledNodes = AUDIO_AND_VIDEO; 342 343 float audioFrameRate = 44100.0f; 344 uint32 audioChannels = 2; 345 if (fAudioTrackSupplier != NULL) { 346 const media_format& audioTrackFormat = fAudioTrackSupplier->Format(); 347 audioFrameRate = audioTrackFormat.u.raw_audio.frame_rate; 348 audioChannels = audioTrackFormat.u.raw_audio.channel_count; 349 } 350 351 if (InitCheck() != B_OK) { 352 Init(BRect(0, 0, width - 1, height - 1), fVideoFrameRate, 353 preferredVideoFormat, audioFrameRate, audioChannels, LOOPING_ALL, 354 false, 1.0, enabledNodes, useOverlays); 355 } else { 356 FormatChanged(BRect(0, 0, width - 1, height - 1), fVideoFrameRate, 357 preferredVideoFormat, audioFrameRate, audioChannels, enabledNodes, 358 useOverlays); 359 } 360 361 _NotifyFileChanged(item.Get(), B_OK); 362 363 if (fAutoplay) 364 StartPlaying(true); 365 366 return B_OK; 367 } 368 369 370 void 371 Controller::PlayerActivated(bool active) 372 { 373 if (LockWithTimeout(5000) != B_OK) 374 return; 375 376 if (active && gMainApp->PlayerCount() > 1) { 377 if (fActiveVolume != fVolume) 378 SetVolume(fActiveVolume); 379 } else { 380 fActiveVolume = fVolume; 381 if (gMainApp->PlayerCount() > 1) 382 switch (fBackgroundMovieVolumeMode) { 383 case mpSettings::BG_MOVIES_MUTED: 384 SetVolume(0.0); 385 break; 386 case mpSettings::BG_MOVIES_HALF_VLUME: 387 SetVolume(fVolume * 0.25); 388 break; 389 case mpSettings::BG_MOVIES_FULL_VOLUME: 390 default: 391 break; 392 } 393 } 394 395 Unlock(); 396 } 397 398 399 void 400 Controller::GetSize(int *width, int *height, int* _widthAspect, 401 int* _heightAspect) 402 { 403 BAutolock _(this); 404 405 if (fVideoTrackSupplier) { 406 media_format format = fVideoTrackSupplier->Format(); 407 *height = format.u.raw_video.display.line_count; 408 *width = format.u.raw_video.display.line_width; 409 int widthAspect = 0; 410 int heightAspect = 0; 411 // Ignore format aspect when both values are 1. If they have been 412 // intentionally at 1:1 then no harm is done for quadratic videos, 413 // only if the video is indeed encoded anamorphotic, but supposed 414 // to be displayed quadratic... extremely unlikely. 415 if (format.u.raw_video.pixel_width_aspect 416 != format.u.raw_video.pixel_height_aspect 417 && format.u.raw_video.pixel_width_aspect != 1) { 418 widthAspect = format.u.raw_video.pixel_width_aspect; 419 heightAspect = format.u.raw_video.pixel_height_aspect; 420 } 421 if (_widthAspect != NULL) 422 *_widthAspect = widthAspect; 423 if (_heightAspect != NULL) 424 *_heightAspect = heightAspect; 425 } else { 426 *height = 0; 427 *width = 0; 428 if (_widthAspect != NULL) 429 *_widthAspect = 1; 430 if (_heightAspect != NULL) 431 *_heightAspect = 1; 432 } 433 } 434 435 436 int 437 Controller::AudioTrackCount() 438 { 439 BAutolock _(this); 440 441 if (fItem != NULL && fItem->HasTrackSupplier()) 442 return fItem->GetTrackSupplier()->CountAudioTracks(); 443 return 0; 444 } 445 446 447 int 448 Controller::VideoTrackCount() 449 { 450 BAutolock _(this); 451 452 if (fItem != NULL && fItem->HasTrackSupplier()) 453 return fItem->GetTrackSupplier()->CountVideoTracks(); 454 return 0; 455 } 456 457 458 int 459 Controller::SubTitleTrackCount() 460 { 461 BAutolock _(this); 462 463 if (fItem != NULL && fItem->HasTrackSupplier()) 464 return fItem->GetTrackSupplier()->CountSubTitleTracks(); 465 return 0; 466 } 467 468 469 status_t 470 Controller::SelectAudioTrack(int n) 471 { 472 BAutolock _(this); 473 if (fItem == NULL || !fItem->HasTrackSupplier()) 474 return B_NO_INIT; 475 476 ObjectDeleter<AudioTrackSupplier> deleter(fAudioTrackSupplier); 477 fAudioTrackSupplier 478 = fItem->GetTrackSupplier()->CreateAudioTrackForIndex(n); 479 if (fAudioTrackSupplier == NULL) 480 return B_BAD_INDEX; 481 482 bigtime_t a = fAudioTrackSupplier->Duration(); 483 bigtime_t v = fVideoTrackSupplier != NULL 484 ? fVideoTrackSupplier->Duration() : 0; 485 fDuration = max_c(a, v); 486 DurationChanged(); 487 // TODO: notify duration changed! 488 489 fAudioSupplier->SetSupplier(fAudioTrackSupplier, fVideoFrameRate); 490 491 _NotifyAudioTrackChanged(n); 492 return B_OK; 493 } 494 495 496 int 497 Controller::CurrentAudioTrack() 498 { 499 BAutolock _(this); 500 501 if (fAudioTrackSupplier == NULL) 502 return -1; 503 504 return fAudioTrackSupplier->TrackIndex(); 505 } 506 507 508 int 509 Controller::AudioTrackChannelCount() 510 { 511 media_format format; 512 if (GetEncodedAudioFormat(&format) == B_OK) 513 return format.u.encoded_audio.output.channel_count; 514 515 return 2; 516 } 517 518 519 status_t 520 Controller::SelectVideoTrack(int n) 521 { 522 BAutolock _(this); 523 524 if (fItem == NULL || !fItem->HasTrackSupplier()) 525 return B_NO_INIT; 526 527 ObjectDeleter<VideoTrackSupplier> deleter(fVideoTrackSupplier); 528 fVideoTrackSupplier 529 = fItem->GetTrackSupplier()->CreateVideoTrackForIndex(n); 530 if (fVideoTrackSupplier == NULL) 531 return B_BAD_INDEX; 532 533 bigtime_t a = fAudioTrackSupplier ? fAudioTrackSupplier->Duration() : 0; 534 bigtime_t v = fVideoTrackSupplier->Duration(); 535 fDuration = max_c(a, v); 536 fVideoFrameRate = fVideoTrackSupplier->Format().u.raw_video.field_rate; 537 if (fVideoFrameRate <= 0.0) { 538 printf("Controller::SelectVideoTrack(%d) - invalid video frame rate: %.1f\n", 539 n, fVideoFrameRate); 540 fVideoFrameRate = 25.0; 541 } 542 543 DurationChanged(); 544 // TODO: notify duration changed! 545 546 fVideoSupplier->SetSupplier(fVideoTrackSupplier); 547 548 _NotifyVideoTrackChanged(n); 549 return B_OK; 550 } 551 552 553 int 554 Controller::CurrentVideoTrack() 555 { 556 BAutolock _(this); 557 558 if (fVideoTrackSupplier == NULL) 559 return -1; 560 561 return fVideoTrackSupplier->TrackIndex(); 562 } 563 564 565 status_t 566 Controller::SelectSubTitleTrack(int n) 567 { 568 BAutolock _(this); 569 570 if (fItem == NULL || !fItem->HasTrackSupplier()) 571 return B_NO_INIT; 572 573 fSubTitlesIndex = n; 574 fSubTitles = 575 fItem->GetTrackSupplier()->SubTitleTrackForIndex(n); 576 577 const SubTitle* subTitle = NULL; 578 if (fSubTitles != NULL) 579 subTitle = fSubTitles->SubTitleAt(_TimePosition()); 580 if (subTitle != NULL) 581 fVideoView->SetSubTitle(subTitle->text.String()); 582 else 583 fVideoView->SetSubTitle(NULL); 584 585 _NotifySubTitleTrackChanged(n); 586 return B_OK; 587 } 588 589 590 int 591 Controller::CurrentSubTitleTrack() 592 { 593 BAutolock _(this); 594 595 if (fSubTitles == NULL) 596 return -1; 597 598 return fSubTitlesIndex; 599 } 600 601 602 const char* 603 Controller::SubTitleTrackName(int n) 604 { 605 BAutolock _(this); 606 607 if (fItem == NULL || !fItem->HasTrackSupplier()) 608 return NULL; 609 610 const SubTitles* subTitles 611 = fItem->GetTrackSupplier()->SubTitleTrackForIndex(n); 612 if (subTitles == NULL) 613 return NULL; 614 615 return subTitles->Name(); 616 } 617 618 619 // #pragma mark - 620 621 622 void 623 Controller::Stop() 624 { 625 //printf("Controller::Stop\n"); 626 627 BAutolock _(this); 628 629 StopPlaying(); 630 SetPosition(0.0); 631 632 fAutoplay = fAutoplaySetting; 633 } 634 635 636 void 637 Controller::Play() 638 { 639 //printf("Controller::Play\n"); 640 641 BAutolock _(this); 642 643 StartPlaying(); 644 fAutoplay = true; 645 } 646 647 648 void 649 Controller::Pause() 650 { 651 // printf("Controller::Pause\n"); 652 653 BAutolock _(this); 654 655 PausePlaying(); 656 657 fAutoplay = fAutoplaySetting; 658 } 659 660 661 void 662 Controller::TogglePlaying() 663 { 664 // printf("Controller::TogglePlaying\n"); 665 666 BAutolock _(this); 667 668 if (InitCheck() == B_OK) { 669 NodeManager::TogglePlaying(); 670 671 fAutoplay = IsPlaying() || fAutoplaySetting; 672 } 673 } 674 675 676 uint32 677 Controller::PlaybackState() 678 { 679 BAutolock _(this); 680 681 return _PlaybackState(PlaybackManager::PlayMode()); 682 } 683 684 685 bigtime_t 686 Controller::TimeDuration() 687 { 688 BAutolock _(this); 689 690 return fDuration; 691 } 692 693 694 bigtime_t 695 Controller::TimePosition() 696 { 697 BAutolock _(this); 698 699 return _TimePosition(); 700 } 701 702 703 status_t 704 Controller::SaveState(bool reset) 705 { 706 if (!fItem.IsSet()) 707 return B_OK; 708 if (reset) 709 fCurrentFrame = 0; 710 status_t status = fItem.Get()->SetLastVolume(fVolume); 711 if (status == B_OK) 712 status = fItem.Get()->SetLastFrame(fCurrentFrame); 713 else 714 fItem.Get()->SetLastFrame(fCurrentFrame); 715 return status; 716 } 717 718 719 void 720 Controller::RestoreState() 721 { 722 PlaylistItem *item =fItem.Get(); 723 if (item == NULL) 724 return; 725 726 int lastFrame = item->LastFrame(); 727 float lastVolume = item->LastVolume(); 728 729 // Don't Pause()/Play() if we have nothing to do. 730 if (lastFrame <= 0 && lastVolume < 0) 731 return; 732 733 Pause(); 734 735 if (lastFrame > 0) { 736 bool resume = fResume == mpSettings::RESUME_ALWAYS; 737 if (fResume == mpSettings::RESUME_ASK) { 738 BString label; 739 int time = (int)((float)lastFrame * TimeDuration() / (1000000 * _FrameDuration())); 740 label.SetToFormat(B_TRANSLATE("Do you want to resume %s at %dm%ds?"), 741 item->Name().String(), time / 60, time % 60); 742 BAlert *alert = new BAlert(B_TRANSLATE("Resume?"), label, 743 B_TRANSLATE("Resume"), B_TRANSLATE("Reset")); 744 resume = alert->Go() == 0; 745 } 746 747 if (resume) 748 SetFramePosition(lastFrame); 749 } 750 751 if (lastVolume >= 0) 752 SetVolume(lastVolume); 753 754 Play(); 755 } 756 757 758 void 759 Controller::SetVolume(float value) 760 { 761 // printf("Controller::SetVolume %.4f\n", value); 762 BAutolock _(this); 763 764 value = max_c(0.0, min_c(2.0, value)); 765 766 if (fVolume != value) { 767 if (fMuted) 768 ToggleMute(); 769 770 fVolume = value; 771 fAudioSupplier->SetVolume(fVolume); 772 773 _NotifyVolumeChanged(fVolume); 774 } 775 } 776 777 778 void 779 Controller::VolumeUp() 780 { 781 // TODO: linear <-> exponential 782 SetVolume(Volume() + 0.05); 783 } 784 785 786 void 787 Controller::VolumeDown() 788 { 789 // TODO: linear <-> exponential 790 SetVolume(Volume() - 0.05); 791 } 792 793 794 void 795 Controller::ToggleMute() 796 { 797 BAutolock _(this); 798 799 fMuted = !fMuted; 800 801 if (fMuted) 802 fAudioSupplier->SetVolume(0.0); 803 else 804 fAudioSupplier->SetVolume(fVolume); 805 806 _NotifyMutedChanged(fMuted); 807 } 808 809 810 float 811 Controller::Volume() 812 { 813 BAutolock _(this); 814 815 return fVolume; 816 } 817 818 819 int64 820 Controller::SetPosition(float value) 821 { 822 BAutolock _(this); 823 824 return SetFramePosition(_FrameDuration() * value); 825 } 826 827 828 int64 829 Controller::SetFramePosition(int64 value) 830 { 831 BAutolock _(this); 832 833 fPendingSeekRequests++; 834 fRequestedSeekFrame = max_c(0, min_c(_FrameDuration(), value)); 835 fSeekFrame = fRequestedSeekFrame; 836 837 int64 currentFrame = CurrentFrame(); 838 839 // Snap to a video keyframe, since that will be the fastest 840 // to display and seeking will feel more snappy. Note that we 841 // don't store this change in fSeekFrame, since we still want 842 // to report the originally requested seek frame in TimePosition() 843 // until we could reach that frame. 844 if (Duration() > 240 && fVideoTrackSupplier != NULL 845 && abs(value - currentFrame) > 5) { 846 fVideoTrackSupplier->FindKeyFrameForFrame(&fSeekFrame); 847 } 848 849 //printf("SetFramePosition(%lld) -> %lld (current: %lld, duration: %lld) " 850 //"(video: %p)\n", value, fSeekFrame, currentFrame, _FrameDuration(), 851 //fVideoTrackSupplier); 852 if (fSeekFrame != currentFrame) { 853 int64 seekFrame = fSeekFrame; 854 SetCurrentFrame(fSeekFrame); 855 // May trigger the notification and reset fSeekFrame, 856 // if next current frame == seek frame. 857 return seekFrame; 858 } else 859 NotifySeekHandled(fRequestedSeekFrame); 860 return currentFrame; 861 } 862 863 864 int64 865 Controller::SetTimePosition(bigtime_t value) 866 { 867 BAutolock _(this); 868 869 return SetPosition((float)value / TimeDuration()); 870 } 871 872 873 // #pragma mark - 874 875 876 bool 877 Controller::HasFile() 878 { 879 // you need to hold the data lock 880 return fItem != NULL && fItem->HasTrackSupplier(); 881 } 882 883 884 status_t 885 Controller::GetFileFormatInfo(media_file_format* fileFormat) 886 { 887 // you need to hold the data lock 888 if (fItem == NULL || !fItem->HasTrackSupplier()) 889 return B_NO_INIT; 890 return fItem->GetTrackSupplier()->GetFileFormatInfo(fileFormat); 891 } 892 893 894 status_t 895 Controller::GetCopyright(BString* copyright) 896 { 897 // you need to hold the data lock 898 if (fItem == NULL || !fItem->HasTrackSupplier()) 899 return B_NO_INIT; 900 return fItem->GetTrackSupplier()->GetCopyright(copyright); 901 } 902 903 904 status_t 905 Controller::GetLocation(BString* location) 906 { 907 // you need to hold the data lock 908 if (!fItem.IsSet()) 909 return B_NO_INIT; 910 *location = fItem->LocationURI(); 911 return B_OK; 912 } 913 914 915 status_t 916 Controller::GetName(BString* name) 917 { 918 // you need to hold the data lock 919 if (!fItem.IsSet()) 920 return B_NO_INIT; 921 *name = fItem->Name(); 922 return B_OK; 923 } 924 925 926 status_t 927 Controller::GetEncodedVideoFormat(media_format* format) 928 { 929 // you need to hold the data lock 930 if (fVideoTrackSupplier) 931 return fVideoTrackSupplier->GetEncodedFormat(format); 932 return B_NO_INIT; 933 } 934 935 936 status_t 937 Controller::GetVideoCodecInfo(media_codec_info* info) 938 { 939 // you need to hold the data lock 940 if (fVideoTrackSupplier) 941 return fVideoTrackSupplier->GetCodecInfo(info); 942 return B_NO_INIT; 943 } 944 945 946 status_t 947 Controller::GetEncodedAudioFormat(media_format* format) 948 { 949 // you need to hold the data lock 950 if (fAudioTrackSupplier) 951 return fAudioTrackSupplier->GetEncodedFormat(format); 952 return B_NO_INIT; 953 } 954 955 956 status_t 957 Controller::GetAudioCodecInfo(media_codec_info* info) 958 { 959 // you need to hold the data lock 960 if (fAudioTrackSupplier) 961 return fAudioTrackSupplier->GetCodecInfo(info); 962 return B_NO_INIT; 963 } 964 965 966 status_t 967 Controller::GetMetaData(BMessage* metaData) 968 { 969 // you need to hold the data lock 970 if (fItem == NULL || !fItem->HasTrackSupplier()) 971 return B_NO_INIT; 972 return fItem->GetTrackSupplier()->GetMetaData(metaData); 973 } 974 975 976 status_t 977 Controller::GetVideoMetaData(int32 index, BMessage* metaData) 978 { 979 // you need to hold the data lock 980 if (fItem == NULL || !fItem->HasTrackSupplier()) 981 return B_NO_INIT; 982 return fItem->GetTrackSupplier()->GetVideoMetaData(index, metaData); 983 } 984 985 986 status_t 987 Controller::GetAudioMetaData(int32 index, BMessage* metaData) 988 { 989 // you need to hold the data lock 990 if (fItem == NULL || !fItem->HasTrackSupplier()) 991 return B_NO_INIT; 992 return fItem->GetTrackSupplier()->GetAudioMetaData(index, metaData); 993 } 994 995 996 // #pragma mark - 997 998 999 void 1000 Controller::SetVideoView(VideoView *view) 1001 { 1002 BAutolock _(this); 1003 1004 fVideoView = view; 1005 } 1006 1007 1008 bool 1009 Controller::IsOverlayActive() 1010 { 1011 if (fVideoView) 1012 return fVideoView->IsOverlayActive(); 1013 1014 return false; 1015 } 1016 1017 1018 // #pragma mark - 1019 1020 1021 bool 1022 Controller::AddListener(Listener* listener) 1023 { 1024 BAutolock _(this); 1025 1026 if (listener && !fListeners.HasItem(listener)) 1027 return fListeners.AddItem(listener); 1028 return false; 1029 } 1030 1031 1032 void 1033 Controller::RemoveListener(Listener* listener) 1034 { 1035 BAutolock _(this); 1036 1037 fListeners.RemoveItem(listener); 1038 } 1039 1040 1041 // #pragma mark - Private 1042 1043 1044 void 1045 Controller::_AdoptGlobalSettings() 1046 { 1047 mpSettings settings; 1048 Settings::Default()->Get(settings); 1049 1050 fAutoplaySetting = settings.autostart; 1051 // not yet used: 1052 fLoopMovies = settings.loopMovie; 1053 fLoopSounds = settings.loopSound; 1054 fBackgroundMovieVolumeMode = settings.backgroundMovieVolumeMode; 1055 fResume = settings.resume; 1056 } 1057 1058 1059 uint32 1060 Controller::_PlaybackState(int32 playingMode) const 1061 { 1062 uint32 state = 0; 1063 switch (playingMode) { 1064 case MODE_PLAYING_PAUSED_FORWARD: 1065 case MODE_PLAYING_PAUSED_BACKWARD: 1066 state = PLAYBACK_STATE_PAUSED; 1067 break; 1068 case MODE_PLAYING_FORWARD: 1069 case MODE_PLAYING_BACKWARD: 1070 state = PLAYBACK_STATE_PLAYING; 1071 break; 1072 1073 default: 1074 state = PLAYBACK_STATE_STOPPED; 1075 break; 1076 } 1077 return state; 1078 } 1079 1080 1081 bigtime_t 1082 Controller::_TimePosition() const 1083 { 1084 if (fDuration == 0) 1085 return 0; 1086 1087 // Check if we are still waiting to reach the seekframe, 1088 // pass the last pending seek frame back to the caller, so 1089 // that the view of the current frame/time from the outside 1090 // does not depend on the internal latency to reach requested 1091 // frames asynchronously. 1092 int64 frame; 1093 if (fPendingSeekRequests > 0) 1094 frame = fRequestedSeekFrame; 1095 else 1096 frame = fCurrentFrame; 1097 1098 return frame * fDuration / _FrameDuration(); 1099 } 1100 1101 1102 int64 1103 Controller::_FrameDuration() const 1104 { 1105 // This should really be total frames (video frames at that) 1106 // TODO: It is not so nice that the MediaPlayer still measures 1107 // in video frames if only playing audio. Here for example, it will 1108 // return a duration of 0 if the audio clip happens to be shorter than 1109 // one video frame at 25 fps. 1110 return (int64)((double)fDuration * fVideoFrameRate / 1000000.0); 1111 } 1112 1113 1114 // #pragma mark - Notifications 1115 1116 1117 void 1118 Controller::_NotifyFileChanged(PlaylistItem* item, status_t result) const 1119 { 1120 BList listeners(fListeners); 1121 int32 count = listeners.CountItems(); 1122 for (int32 i = 0; i < count; i++) { 1123 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1124 listener->FileChanged(item, result); 1125 } 1126 } 1127 1128 1129 void 1130 Controller::_NotifyFileFinished() const 1131 { 1132 BList listeners(fListeners); 1133 int32 count = listeners.CountItems(); 1134 for (int32 i = 0; i < count; i++) { 1135 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1136 listener->FileFinished(); 1137 } 1138 } 1139 1140 1141 void 1142 Controller::_NotifyVideoTrackChanged(int32 index) const 1143 { 1144 BList listeners(fListeners); 1145 int32 count = listeners.CountItems(); 1146 for (int32 i = 0; i < count; i++) { 1147 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1148 listener->VideoTrackChanged(index); 1149 } 1150 } 1151 1152 1153 void 1154 Controller::_NotifyAudioTrackChanged(int32 index) const 1155 { 1156 BList listeners(fListeners); 1157 int32 count = listeners.CountItems(); 1158 for (int32 i = 0; i < count; i++) { 1159 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1160 listener->AudioTrackChanged(index); 1161 } 1162 } 1163 1164 1165 void 1166 Controller::_NotifySubTitleTrackChanged(int32 index) const 1167 { 1168 BList listeners(fListeners); 1169 int32 count = listeners.CountItems(); 1170 for (int32 i = 0; i < count; i++) { 1171 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1172 listener->SubTitleTrackChanged(index); 1173 } 1174 } 1175 1176 1177 void 1178 Controller::_NotifyVideoStatsChanged() const 1179 { 1180 BList listeners(fListeners); 1181 int32 count = listeners.CountItems(); 1182 for (int32 i = 0; i < count; i++) { 1183 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1184 listener->VideoStatsChanged(); 1185 } 1186 } 1187 1188 1189 void 1190 Controller::_NotifyAudioStatsChanged() const 1191 { 1192 BList listeners(fListeners); 1193 int32 count = listeners.CountItems(); 1194 for (int32 i = 0; i < count; i++) { 1195 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1196 listener->AudioStatsChanged(); 1197 } 1198 } 1199 1200 1201 void 1202 Controller::_NotifyPlaybackStateChanged(uint32 state) const 1203 { 1204 BList listeners(fListeners); 1205 int32 count = listeners.CountItems(); 1206 for (int32 i = 0; i < count; i++) { 1207 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1208 listener->PlaybackStateChanged(state); 1209 } 1210 } 1211 1212 1213 void 1214 Controller::_NotifyPositionChanged(float position) const 1215 { 1216 BList listeners(fListeners); 1217 int32 count = listeners.CountItems(); 1218 for (int32 i = 0; i < count; i++) { 1219 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1220 listener->PositionChanged(position); 1221 } 1222 } 1223 1224 1225 void 1226 Controller::_NotifySeekHandled(int64 seekFrame) const 1227 { 1228 BList listeners(fListeners); 1229 int32 count = listeners.CountItems(); 1230 for (int32 i = 0; i < count; i++) { 1231 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1232 listener->SeekHandled(seekFrame); 1233 } 1234 } 1235 1236 1237 void 1238 Controller::_NotifyVolumeChanged(float volume) const 1239 { 1240 BList listeners(fListeners); 1241 int32 count = listeners.CountItems(); 1242 for (int32 i = 0; i < count; i++) { 1243 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1244 listener->VolumeChanged(volume); 1245 } 1246 } 1247 1248 1249 void 1250 Controller::_NotifyMutedChanged(bool muted) const 1251 { 1252 BList listeners(fListeners); 1253 int32 count = listeners.CountItems(); 1254 for (int32 i = 0; i < count; i++) { 1255 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1256 listener->MutedChanged(muted); 1257 } 1258 } 1259 1260 1261 void 1262 Controller::NotifyPlayModeChanged(int32 mode) const 1263 { 1264 uint32 state = _PlaybackState(mode); 1265 if (fVideoView) 1266 fVideoView->SetPlaying(state == PLAYBACK_STATE_PLAYING); 1267 _NotifyPlaybackStateChanged(state); 1268 } 1269 1270 1271 void 1272 Controller::NotifyLoopModeChanged(int32 mode) const 1273 { 1274 } 1275 1276 1277 void 1278 Controller::NotifyLoopingEnabledChanged(bool enabled) const 1279 { 1280 } 1281 1282 1283 void 1284 Controller::NotifyVideoBoundsChanged(BRect bounds) const 1285 { 1286 } 1287 1288 1289 void 1290 Controller::NotifyFPSChanged(float fps) const 1291 { 1292 } 1293 1294 1295 void 1296 Controller::NotifyCurrentFrameChanged(int64 frame) const 1297 { 1298 fCurrentFrame = frame; 1299 bigtime_t timePosition = _TimePosition(); 1300 _NotifyPositionChanged((float)timePosition / fDuration); 1301 1302 if (fSubTitles != NULL) { 1303 const SubTitle* subTitle = fSubTitles->SubTitleAt(timePosition); 1304 if (subTitle != NULL) 1305 fVideoView->SetSubTitle(subTitle->text.String()); 1306 else 1307 fVideoView->SetSubTitle(NULL); 1308 } 1309 } 1310 1311 1312 void 1313 Controller::NotifySpeedChanged(float speed) const 1314 { 1315 } 1316 1317 1318 void 1319 Controller::NotifyFrameDropped() const 1320 { 1321 // printf("Controller::NotifyFrameDropped()\n"); 1322 } 1323 1324 1325 void 1326 Controller::NotifyStopFrameReached() const 1327 { 1328 // Currently, this means we reached the end of the current 1329 // file and should play the next file 1330 _NotifyFileFinished(); 1331 } 1332 1333 1334 void 1335 Controller::NotifySeekHandled(int64 seekedFrame) const 1336 { 1337 if (fPendingSeekRequests == 0) 1338 return; 1339 1340 fPendingSeekRequests--; 1341 if (fPendingSeekRequests == 0) { 1342 fSeekFrame = -1; 1343 fRequestedSeekFrame = -1; 1344 } 1345 1346 _NotifySeekHandled(seekedFrame); 1347 } 1348 1349