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