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