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