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