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