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.Get() == NULL) 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.Get() == NULL) 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 int32 time = (int32)((float)lastFrame * TimeDuration() 740 / (1000000 * _FrameDuration())); 741 label.SetToFormat(B_TRANSLATE("Do you want to resume %s at %dm%ds?"), 742 item->Name().String(), time / 60, time % 60); 743 BAlert *alert = new BAlert(B_TRANSLATE("Resume?"), label, 744 B_TRANSLATE("Resume"), B_TRANSLATE("Reset")); 745 resume = alert->Go() == 0; 746 } 747 748 if (resume) 749 SetFramePosition(lastFrame); 750 } 751 752 if (lastVolume >= 0) 753 SetVolume(lastVolume); 754 755 Play(); 756 } 757 758 759 void 760 Controller::SetVolume(float value) 761 { 762 // printf("Controller::SetVolume %.4f\n", value); 763 BAutolock _(this); 764 765 value = max_c(0.0, min_c(2.0, value)); 766 767 if (fVolume != value) { 768 if (fMuted) 769 ToggleMute(); 770 771 fVolume = value; 772 fAudioSupplier->SetVolume(fVolume); 773 774 _NotifyVolumeChanged(fVolume); 775 } 776 } 777 778 779 void 780 Controller::VolumeUp() 781 { 782 // TODO: linear <-> exponential 783 SetVolume(Volume() + 0.05); 784 } 785 786 787 void 788 Controller::VolumeDown() 789 { 790 // TODO: linear <-> exponential 791 SetVolume(Volume() - 0.05); 792 } 793 794 795 void 796 Controller::ToggleMute() 797 { 798 BAutolock _(this); 799 800 fMuted = !fMuted; 801 802 if (fMuted) 803 fAudioSupplier->SetVolume(0.0); 804 else 805 fAudioSupplier->SetVolume(fVolume); 806 807 _NotifyMutedChanged(fMuted); 808 } 809 810 811 float 812 Controller::Volume() 813 { 814 BAutolock _(this); 815 816 return fVolume; 817 } 818 819 820 int64 821 Controller::SetPosition(float value) 822 { 823 BAutolock _(this); 824 825 return SetFramePosition(_FrameDuration() * value); 826 } 827 828 829 int64 830 Controller::SetFramePosition(int64 value) 831 { 832 BAutolock _(this); 833 834 fPendingSeekRequests++; 835 fRequestedSeekFrame = max_c(0, min_c(_FrameDuration(), value)); 836 fSeekFrame = fRequestedSeekFrame; 837 838 int64 currentFrame = CurrentFrame(); 839 840 // Snap to a video keyframe, since that will be the fastest 841 // to display and seeking will feel more snappy. Note that we 842 // don't store this change in fSeekFrame, since we still want 843 // to report the originally requested seek frame in TimePosition() 844 // until we could reach that frame. 845 if (Duration() > 240 && fVideoTrackSupplier != NULL 846 && abs(value - currentFrame) > 5) { 847 fVideoTrackSupplier->FindKeyFrameForFrame(&fSeekFrame); 848 } 849 850 //printf("SetFramePosition(%lld) -> %lld (current: %lld, duration: %lld) " 851 //"(video: %p)\n", value, fSeekFrame, currentFrame, _FrameDuration(), 852 //fVideoTrackSupplier); 853 if (fSeekFrame != currentFrame) { 854 int64 seekFrame = fSeekFrame; 855 SetCurrentFrame(fSeekFrame); 856 // May trigger the notification and reset fSeekFrame, 857 // if next current frame == seek frame. 858 return seekFrame; 859 } else 860 NotifySeekHandled(fRequestedSeekFrame); 861 return currentFrame; 862 } 863 864 865 int64 866 Controller::SetTimePosition(bigtime_t value) 867 { 868 BAutolock _(this); 869 870 return SetPosition((float)value / TimeDuration()); 871 } 872 873 874 // #pragma mark - 875 876 877 bool 878 Controller::HasFile() 879 { 880 // you need to hold the data lock 881 return fItem != NULL && fItem->HasTrackSupplier(); 882 } 883 884 885 status_t 886 Controller::GetFileFormatInfo(media_file_format* fileFormat) 887 { 888 // you need to hold the data lock 889 if (fItem == NULL || !fItem->HasTrackSupplier()) 890 return B_NO_INIT; 891 return fItem->GetTrackSupplier()->GetFileFormatInfo(fileFormat); 892 } 893 894 895 status_t 896 Controller::GetCopyright(BString* copyright) 897 { 898 // you need to hold the data lock 899 if (fItem == NULL || !fItem->HasTrackSupplier()) 900 return B_NO_INIT; 901 return fItem->GetTrackSupplier()->GetCopyright(copyright); 902 } 903 904 905 status_t 906 Controller::GetLocation(BString* location) 907 { 908 // you need to hold the data lock 909 if (fItem.Get() == NULL) 910 return B_NO_INIT; 911 *location = fItem->LocationURI(); 912 return B_OK; 913 } 914 915 916 status_t 917 Controller::GetName(BString* name) 918 { 919 // you need to hold the data lock 920 if (fItem.Get() == NULL) 921 return B_NO_INIT; 922 *name = fItem->Name(); 923 return B_OK; 924 } 925 926 927 status_t 928 Controller::GetEncodedVideoFormat(media_format* format) 929 { 930 // you need to hold the data lock 931 if (fVideoTrackSupplier) 932 return fVideoTrackSupplier->GetEncodedFormat(format); 933 return B_NO_INIT; 934 } 935 936 937 status_t 938 Controller::GetVideoCodecInfo(media_codec_info* info) 939 { 940 // you need to hold the data lock 941 if (fVideoTrackSupplier) 942 return fVideoTrackSupplier->GetCodecInfo(info); 943 return B_NO_INIT; 944 } 945 946 947 status_t 948 Controller::GetEncodedAudioFormat(media_format* format) 949 { 950 // you need to hold the data lock 951 if (fAudioTrackSupplier) 952 return fAudioTrackSupplier->GetEncodedFormat(format); 953 return B_NO_INIT; 954 } 955 956 957 status_t 958 Controller::GetAudioCodecInfo(media_codec_info* info) 959 { 960 // you need to hold the data lock 961 if (fAudioTrackSupplier) 962 return fAudioTrackSupplier->GetCodecInfo(info); 963 return B_NO_INIT; 964 } 965 966 967 status_t 968 Controller::GetMetaData(BMessage* metaData) 969 { 970 // you need to hold the data lock 971 if (fItem == NULL || !fItem->HasTrackSupplier()) 972 return B_NO_INIT; 973 return fItem->GetTrackSupplier()->GetMetaData(metaData); 974 } 975 976 977 status_t 978 Controller::GetVideoMetaData(int32 index, BMessage* metaData) 979 { 980 // you need to hold the data lock 981 if (fItem == NULL || !fItem->HasTrackSupplier()) 982 return B_NO_INIT; 983 return fItem->GetTrackSupplier()->GetVideoMetaData(index, metaData); 984 } 985 986 987 status_t 988 Controller::GetAudioMetaData(int32 index, BMessage* metaData) 989 { 990 // you need to hold the data lock 991 if (fItem == NULL || !fItem->HasTrackSupplier()) 992 return B_NO_INIT; 993 return fItem->GetTrackSupplier()->GetAudioMetaData(index, metaData); 994 } 995 996 997 // #pragma mark - 998 999 1000 void 1001 Controller::SetVideoView(VideoView *view) 1002 { 1003 BAutolock _(this); 1004 1005 fVideoView = view; 1006 } 1007 1008 1009 bool 1010 Controller::IsOverlayActive() 1011 { 1012 if (fVideoView) 1013 return fVideoView->IsOverlayActive(); 1014 1015 return false; 1016 } 1017 1018 1019 // #pragma mark - 1020 1021 1022 bool 1023 Controller::AddListener(Listener* listener) 1024 { 1025 BAutolock _(this); 1026 1027 if (listener && !fListeners.HasItem(listener)) 1028 return fListeners.AddItem(listener); 1029 return false; 1030 } 1031 1032 1033 void 1034 Controller::RemoveListener(Listener* listener) 1035 { 1036 BAutolock _(this); 1037 1038 fListeners.RemoveItem(listener); 1039 } 1040 1041 1042 // #pragma mark - Private 1043 1044 1045 void 1046 Controller::_AdoptGlobalSettings() 1047 { 1048 mpSettings settings; 1049 Settings::Default()->Get(settings); 1050 1051 fAutoplaySetting = settings.autostart; 1052 // not yet used: 1053 fLoopMovies = settings.loopMovie; 1054 fLoopSounds = settings.loopSound; 1055 fBackgroundMovieVolumeMode = settings.backgroundMovieVolumeMode; 1056 fResume = settings.resume; 1057 } 1058 1059 1060 uint32 1061 Controller::_PlaybackState(int32 playingMode) const 1062 { 1063 uint32 state = 0; 1064 switch (playingMode) { 1065 case MODE_PLAYING_PAUSED_FORWARD: 1066 case MODE_PLAYING_PAUSED_BACKWARD: 1067 state = PLAYBACK_STATE_PAUSED; 1068 break; 1069 case MODE_PLAYING_FORWARD: 1070 case MODE_PLAYING_BACKWARD: 1071 state = PLAYBACK_STATE_PLAYING; 1072 break; 1073 1074 default: 1075 state = PLAYBACK_STATE_STOPPED; 1076 break; 1077 } 1078 return state; 1079 } 1080 1081 1082 bigtime_t 1083 Controller::_TimePosition() const 1084 { 1085 if (fDuration == 0) 1086 return 0; 1087 1088 // Check if we are still waiting to reach the seekframe, 1089 // pass the last pending seek frame back to the caller, so 1090 // that the view of the current frame/time from the outside 1091 // does not depend on the internal latency to reach requested 1092 // frames asynchronously. 1093 int64 frame; 1094 if (fPendingSeekRequests > 0) 1095 frame = fRequestedSeekFrame; 1096 else 1097 frame = fCurrentFrame; 1098 1099 return frame * fDuration / _FrameDuration(); 1100 } 1101 1102 1103 int64 1104 Controller::_FrameDuration() const 1105 { 1106 // This should really be total frames (video frames at that) 1107 // TODO: It is not so nice that the MediaPlayer still measures 1108 // in video frames if only playing audio. Here for example, it will 1109 // return a duration of 0 if the audio clip happens to be shorter than 1110 // one video frame at 25 fps. 1111 return (int64)((double)fDuration * fVideoFrameRate / 1000000.0); 1112 } 1113 1114 1115 // #pragma mark - Notifications 1116 1117 1118 void 1119 Controller::_NotifyFileChanged(PlaylistItem* item, status_t result) const 1120 { 1121 BList listeners(fListeners); 1122 int32 count = listeners.CountItems(); 1123 for (int32 i = 0; i < count; i++) { 1124 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1125 listener->FileChanged(item, result); 1126 } 1127 } 1128 1129 1130 void 1131 Controller::_NotifyFileFinished() const 1132 { 1133 BList listeners(fListeners); 1134 int32 count = listeners.CountItems(); 1135 for (int32 i = 0; i < count; i++) { 1136 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1137 listener->FileFinished(); 1138 } 1139 } 1140 1141 1142 void 1143 Controller::_NotifyVideoTrackChanged(int32 index) const 1144 { 1145 BList listeners(fListeners); 1146 int32 count = listeners.CountItems(); 1147 for (int32 i = 0; i < count; i++) { 1148 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1149 listener->VideoTrackChanged(index); 1150 } 1151 } 1152 1153 1154 void 1155 Controller::_NotifyAudioTrackChanged(int32 index) const 1156 { 1157 BList listeners(fListeners); 1158 int32 count = listeners.CountItems(); 1159 for (int32 i = 0; i < count; i++) { 1160 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1161 listener->AudioTrackChanged(index); 1162 } 1163 } 1164 1165 1166 void 1167 Controller::_NotifySubTitleTrackChanged(int32 index) const 1168 { 1169 BList listeners(fListeners); 1170 int32 count = listeners.CountItems(); 1171 for (int32 i = 0; i < count; i++) { 1172 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1173 listener->SubTitleTrackChanged(index); 1174 } 1175 } 1176 1177 1178 void 1179 Controller::_NotifyVideoStatsChanged() const 1180 { 1181 BList listeners(fListeners); 1182 int32 count = listeners.CountItems(); 1183 for (int32 i = 0; i < count; i++) { 1184 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1185 listener->VideoStatsChanged(); 1186 } 1187 } 1188 1189 1190 void 1191 Controller::_NotifyAudioStatsChanged() const 1192 { 1193 BList listeners(fListeners); 1194 int32 count = listeners.CountItems(); 1195 for (int32 i = 0; i < count; i++) { 1196 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1197 listener->AudioStatsChanged(); 1198 } 1199 } 1200 1201 1202 void 1203 Controller::_NotifyPlaybackStateChanged(uint32 state) const 1204 { 1205 BList listeners(fListeners); 1206 int32 count = listeners.CountItems(); 1207 for (int32 i = 0; i < count; i++) { 1208 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1209 listener->PlaybackStateChanged(state); 1210 } 1211 } 1212 1213 1214 void 1215 Controller::_NotifyPositionChanged(float position) const 1216 { 1217 BList listeners(fListeners); 1218 int32 count = listeners.CountItems(); 1219 for (int32 i = 0; i < count; i++) { 1220 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1221 listener->PositionChanged(position); 1222 } 1223 } 1224 1225 1226 void 1227 Controller::_NotifySeekHandled(int64 seekFrame) const 1228 { 1229 BList listeners(fListeners); 1230 int32 count = listeners.CountItems(); 1231 for (int32 i = 0; i < count; i++) { 1232 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1233 listener->SeekHandled(seekFrame); 1234 } 1235 } 1236 1237 1238 void 1239 Controller::_NotifyVolumeChanged(float volume) const 1240 { 1241 BList listeners(fListeners); 1242 int32 count = listeners.CountItems(); 1243 for (int32 i = 0; i < count; i++) { 1244 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1245 listener->VolumeChanged(volume); 1246 } 1247 } 1248 1249 1250 void 1251 Controller::_NotifyMutedChanged(bool muted) const 1252 { 1253 BList listeners(fListeners); 1254 int32 count = listeners.CountItems(); 1255 for (int32 i = 0; i < count; i++) { 1256 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1257 listener->MutedChanged(muted); 1258 } 1259 } 1260 1261 1262 void 1263 Controller::NotifyPlayModeChanged(int32 mode) const 1264 { 1265 uint32 state = _PlaybackState(mode); 1266 if (fVideoView) 1267 fVideoView->SetPlaying(state == PLAYBACK_STATE_PLAYING); 1268 _NotifyPlaybackStateChanged(state); 1269 } 1270 1271 1272 void 1273 Controller::NotifyLoopModeChanged(int32 mode) const 1274 { 1275 } 1276 1277 1278 void 1279 Controller::NotifyLoopingEnabledChanged(bool enabled) const 1280 { 1281 } 1282 1283 1284 void 1285 Controller::NotifyVideoBoundsChanged(BRect bounds) const 1286 { 1287 } 1288 1289 1290 void 1291 Controller::NotifyFPSChanged(float fps) const 1292 { 1293 } 1294 1295 1296 void 1297 Controller::NotifyCurrentFrameChanged(int64 frame) const 1298 { 1299 fCurrentFrame = frame; 1300 bigtime_t timePosition = _TimePosition(); 1301 _NotifyPositionChanged((float)timePosition / fDuration); 1302 1303 if (fSubTitles != NULL) { 1304 const SubTitle* subTitle = fSubTitles->SubTitleAt(timePosition); 1305 if (subTitle != NULL) 1306 fVideoView->SetSubTitle(subTitle->text.String()); 1307 else 1308 fVideoView->SetSubTitle(NULL); 1309 } 1310 } 1311 1312 1313 void 1314 Controller::NotifySpeedChanged(float speed) const 1315 { 1316 } 1317 1318 1319 void 1320 Controller::NotifyFrameDropped() const 1321 { 1322 // printf("Controller::NotifyFrameDropped()\n"); 1323 } 1324 1325 1326 void 1327 Controller::NotifyStopFrameReached() const 1328 { 1329 // Currently, this means we reached the end of the current 1330 // file and should play the next file 1331 _NotifyFileFinished(); 1332 } 1333 1334 1335 void 1336 Controller::NotifySeekHandled(int64 seekedFrame) const 1337 { 1338 if (fPendingSeekRequests == 0) 1339 return; 1340 1341 fPendingSeekRequests--; 1342 if (fPendingSeekRequests == 0) { 1343 fSeekFrame = -1; 1344 fRequestedSeekFrame = -1; 1345 } 1346 1347 _NotifySeekHandled(seekedFrame); 1348 } 1349 1350