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 int32 time = (int32)((float)lastFrame * TimeDuration() 740 / (1000000 * _FrameDuration())); 741 label.SetToFormat(B_TRANSLATE("Do you want to resume %s at %dm%ds?"), 742 item->Name().String(), time / 60, time % 60); 743 BAlert *alert = new BAlert(B_TRANSLATE("Resume?"), label, 744 B_TRANSLATE("Resume"), B_TRANSLATE("Reset")); 745 resume = alert->Go() == 0; 746 } 747 748 if (resume) 749 SetFramePosition(lastFrame); 750 } 751 752 if (lastVolume >= 0) 753 SetVolume(lastVolume); 754 755 Play(); 756} 757 758 759void 760Controller::SetVolume(float value) 761{ 762// printf("Controller::SetVolume %.4f\n", value); 763 BAutolock _(this); 764 765 value = max_c(0.0, min_c(2.0, value)); 766 767 if (fVolume != value) { 768 if (fMuted) 769 ToggleMute(); 770 771 fVolume = value; 772 fAudioSupplier->SetVolume(fVolume); 773 774 _NotifyVolumeChanged(fVolume); 775 } 776} 777 778 779void 780Controller::VolumeUp() 781{ 782 // TODO: linear <-> exponential 783 SetVolume(Volume() + 0.05); 784} 785 786 787void 788Controller::VolumeDown() 789{ 790 // TODO: linear <-> exponential 791 SetVolume(Volume() - 0.05); 792} 793 794 795void 796Controller::ToggleMute() 797{ 798 BAutolock _(this); 799 800 fMuted = !fMuted; 801 802 if (fMuted) 803 fAudioSupplier->SetVolume(0.0); 804 else 805 fAudioSupplier->SetVolume(fVolume); 806 807 _NotifyMutedChanged(fMuted); 808} 809 810 811float 812Controller::Volume() 813{ 814 BAutolock _(this); 815 816 return fVolume; 817} 818 819 820int64 821Controller::SetPosition(float value) 822{ 823 BAutolock _(this); 824 825 return SetFramePosition(_FrameDuration() * value); 826} 827 828 829int64 830Controller::SetFramePosition(int64 value) 831{ 832 BAutolock _(this); 833 834 fPendingSeekRequests++; 835 fRequestedSeekFrame = max_c(0, min_c(_FrameDuration(), value)); 836 fSeekFrame = fRequestedSeekFrame; 837 838 int64 currentFrame = CurrentFrame(); 839 840 // Snap to a video keyframe, since that will be the fastest 841 // to display and seeking will feel more snappy. Note that we 842 // don't store this change in fSeekFrame, since we still want 843 // to report the originally requested seek frame in TimePosition() 844 // until we could reach that frame. 845 if (Duration() > 240 && fVideoTrackSupplier != NULL 846 && abs(value - currentFrame) > 5) { 847 fVideoTrackSupplier->FindKeyFrameForFrame(&fSeekFrame); 848 } 849 850//printf("SetFramePosition(%lld) -> %lld (current: %lld, duration: %lld) " 851//"(video: %p)\n", value, fSeekFrame, currentFrame, _FrameDuration(), 852//fVideoTrackSupplier); 853 if (fSeekFrame != currentFrame) { 854 int64 seekFrame = fSeekFrame; 855 SetCurrentFrame(fSeekFrame); 856 // May trigger the notification and reset fSeekFrame, 857 // if next current frame == seek frame. 858 return seekFrame; 859 } else 860 NotifySeekHandled(fRequestedSeekFrame); 861 return currentFrame; 862} 863 864 865int64 866Controller::SetTimePosition(bigtime_t value) 867{ 868 BAutolock _(this); 869 870 return SetPosition((float)value / TimeDuration()); 871} 872 873 874// #pragma mark - 875 876 877bool 878Controller::HasFile() 879{ 880 // you need to hold the data lock 881 return fItem != NULL && fItem->HasTrackSupplier(); 882} 883 884 885status_t 886Controller::GetFileFormatInfo(media_file_format* fileFormat) 887{ 888 // you need to hold the data lock 889 if (fItem == NULL || !fItem->HasTrackSupplier()) 890 return B_NO_INIT; 891 return fItem->GetTrackSupplier()->GetFileFormatInfo(fileFormat); 892} 893 894 895status_t 896Controller::GetCopyright(BString* copyright) 897{ 898 // you need to hold the data lock 899 if (fItem == NULL || !fItem->HasTrackSupplier()) 900 return B_NO_INIT; 901 return fItem->GetTrackSupplier()->GetCopyright(copyright); 902} 903 904 905status_t 906Controller::GetLocation(BString* location) 907{ 908 // you need to hold the data lock 909 if (!fItem.IsSet()) 910 return B_NO_INIT; 911 *location = fItem->LocationURI(); 912 return B_OK; 913} 914 915 916status_t 917Controller::GetName(BString* name) 918{ 919 // you need to hold the data lock 920 if (!fItem.IsSet()) 921 return B_NO_INIT; 922 *name = fItem->Name(); 923 return B_OK; 924} 925 926 927status_t 928Controller::GetEncodedVideoFormat(media_format* format) 929{ 930 // you need to hold the data lock 931 if (fVideoTrackSupplier) 932 return fVideoTrackSupplier->GetEncodedFormat(format); 933 return B_NO_INIT; 934} 935 936 937status_t 938Controller::GetVideoCodecInfo(media_codec_info* info) 939{ 940 // you need to hold the data lock 941 if (fVideoTrackSupplier) 942 return fVideoTrackSupplier->GetCodecInfo(info); 943 return B_NO_INIT; 944} 945 946 947status_t 948Controller::GetEncodedAudioFormat(media_format* format) 949{ 950 // you need to hold the data lock 951 if (fAudioTrackSupplier) 952 return fAudioTrackSupplier->GetEncodedFormat(format); 953 return B_NO_INIT; 954} 955 956 957status_t 958Controller::GetAudioCodecInfo(media_codec_info* info) 959{ 960 // you need to hold the data lock 961 if (fAudioTrackSupplier) 962 return fAudioTrackSupplier->GetCodecInfo(info); 963 return B_NO_INIT; 964} 965 966 967status_t 968Controller::GetMetaData(BMessage* metaData) 969{ 970 // you need to hold the data lock 971 if (fItem == NULL || !fItem->HasTrackSupplier()) 972 return B_NO_INIT; 973 return fItem->GetTrackSupplier()->GetMetaData(metaData); 974} 975 976 977status_t 978Controller::GetVideoMetaData(int32 index, BMessage* metaData) 979{ 980 // you need to hold the data lock 981 if (fItem == NULL || !fItem->HasTrackSupplier()) 982 return B_NO_INIT; 983 return fItem->GetTrackSupplier()->GetVideoMetaData(index, metaData); 984} 985 986 987status_t 988Controller::GetAudioMetaData(int32 index, BMessage* metaData) 989{ 990 // you need to hold the data lock 991 if (fItem == NULL || !fItem->HasTrackSupplier()) 992 return B_NO_INIT; 993 return fItem->GetTrackSupplier()->GetAudioMetaData(index, metaData); 994} 995 996 997// #pragma mark - 998 999 1000void 1001Controller::SetVideoView(VideoView *view) 1002{ 1003 BAutolock _(this); 1004 1005 fVideoView = view; 1006} 1007 1008 1009bool 1010Controller::IsOverlayActive() 1011{ 1012 if (fVideoView) 1013 return fVideoView->IsOverlayActive(); 1014 1015 return false; 1016} 1017 1018 1019// #pragma mark - 1020 1021 1022bool 1023Controller::AddListener(Listener* listener) 1024{ 1025 BAutolock _(this); 1026 1027 if (listener && !fListeners.HasItem(listener)) 1028 return fListeners.AddItem(listener); 1029 return false; 1030} 1031 1032 1033void 1034Controller::RemoveListener(Listener* listener) 1035{ 1036 BAutolock _(this); 1037 1038 fListeners.RemoveItem(listener); 1039} 1040 1041 1042// #pragma mark - Private 1043 1044 1045void 1046Controller::_AdoptGlobalSettings() 1047{ 1048 mpSettings settings; 1049 Settings::Default()->Get(settings); 1050 1051 fAutoplaySetting = settings.autostart; 1052 // not yet used: 1053 fLoopMovies = settings.loopMovie; 1054 fLoopSounds = settings.loopSound; 1055 fBackgroundMovieVolumeMode = settings.backgroundMovieVolumeMode; 1056 fResume = settings.resume; 1057} 1058 1059 1060uint32 1061Controller::_PlaybackState(int32 playingMode) const 1062{ 1063 uint32 state = 0; 1064 switch (playingMode) { 1065 case MODE_PLAYING_PAUSED_FORWARD: 1066 case MODE_PLAYING_PAUSED_BACKWARD: 1067 state = PLAYBACK_STATE_PAUSED; 1068 break; 1069 case MODE_PLAYING_FORWARD: 1070 case MODE_PLAYING_BACKWARD: 1071 state = PLAYBACK_STATE_PLAYING; 1072 break; 1073 1074 default: 1075 state = PLAYBACK_STATE_STOPPED; 1076 break; 1077 } 1078 return state; 1079} 1080 1081 1082bigtime_t 1083Controller::_TimePosition() const 1084{ 1085 if (fDuration == 0) 1086 return 0; 1087 1088 // Check if we are still waiting to reach the seekframe, 1089 // pass the last pending seek frame back to the caller, so 1090 // that the view of the current frame/time from the outside 1091 // does not depend on the internal latency to reach requested 1092 // frames asynchronously. 1093 int64 frame; 1094 if (fPendingSeekRequests > 0) 1095 frame = fRequestedSeekFrame; 1096 else 1097 frame = fCurrentFrame; 1098 1099 return frame * fDuration / _FrameDuration(); 1100} 1101 1102 1103int64 1104Controller::_FrameDuration() const 1105{ 1106 // This should really be total frames (video frames at that) 1107 // TODO: It is not so nice that the MediaPlayer still measures 1108 // in video frames if only playing audio. Here for example, it will 1109 // return a duration of 0 if the audio clip happens to be shorter than 1110 // one video frame at 25 fps. 1111 return (int64)((double)fDuration * fVideoFrameRate / 1000000.0); 1112} 1113 1114 1115// #pragma mark - Notifications 1116 1117 1118void 1119Controller::_NotifyFileChanged(PlaylistItem* item, status_t result) const 1120{ 1121 BList listeners(fListeners); 1122 int32 count = listeners.CountItems(); 1123 for (int32 i = 0; i < count; i++) { 1124 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1125 listener->FileChanged(item, result); 1126 } 1127} 1128 1129 1130void 1131Controller::_NotifyFileFinished() const 1132{ 1133 BList listeners(fListeners); 1134 int32 count = listeners.CountItems(); 1135 for (int32 i = 0; i < count; i++) { 1136 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1137 listener->FileFinished(); 1138 } 1139} 1140 1141 1142void 1143Controller::_NotifyVideoTrackChanged(int32 index) const 1144{ 1145 BList listeners(fListeners); 1146 int32 count = listeners.CountItems(); 1147 for (int32 i = 0; i < count; i++) { 1148 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1149 listener->VideoTrackChanged(index); 1150 } 1151} 1152 1153 1154void 1155Controller::_NotifyAudioTrackChanged(int32 index) const 1156{ 1157 BList listeners(fListeners); 1158 int32 count = listeners.CountItems(); 1159 for (int32 i = 0; i < count; i++) { 1160 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1161 listener->AudioTrackChanged(index); 1162 } 1163} 1164 1165 1166void 1167Controller::_NotifySubTitleTrackChanged(int32 index) const 1168{ 1169 BList listeners(fListeners); 1170 int32 count = listeners.CountItems(); 1171 for (int32 i = 0; i < count; i++) { 1172 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1173 listener->SubTitleTrackChanged(index); 1174 } 1175} 1176 1177 1178void 1179Controller::_NotifyVideoStatsChanged() const 1180{ 1181 BList listeners(fListeners); 1182 int32 count = listeners.CountItems(); 1183 for (int32 i = 0; i < count; i++) { 1184 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1185 listener->VideoStatsChanged(); 1186 } 1187} 1188 1189 1190void 1191Controller::_NotifyAudioStatsChanged() const 1192{ 1193 BList listeners(fListeners); 1194 int32 count = listeners.CountItems(); 1195 for (int32 i = 0; i < count; i++) { 1196 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1197 listener->AudioStatsChanged(); 1198 } 1199} 1200 1201 1202void 1203Controller::_NotifyPlaybackStateChanged(uint32 state) const 1204{ 1205 BList listeners(fListeners); 1206 int32 count = listeners.CountItems(); 1207 for (int32 i = 0; i < count; i++) { 1208 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1209 listener->PlaybackStateChanged(state); 1210 } 1211} 1212 1213 1214void 1215Controller::_NotifyPositionChanged(float position) const 1216{ 1217 BList listeners(fListeners); 1218 int32 count = listeners.CountItems(); 1219 for (int32 i = 0; i < count; i++) { 1220 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1221 listener->PositionChanged(position); 1222 } 1223} 1224 1225 1226void 1227Controller::_NotifySeekHandled(int64 seekFrame) const 1228{ 1229 BList listeners(fListeners); 1230 int32 count = listeners.CountItems(); 1231 for (int32 i = 0; i < count; i++) { 1232 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1233 listener->SeekHandled(seekFrame); 1234 } 1235} 1236 1237 1238void 1239Controller::_NotifyVolumeChanged(float volume) const 1240{ 1241 BList listeners(fListeners); 1242 int32 count = listeners.CountItems(); 1243 for (int32 i = 0; i < count; i++) { 1244 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1245 listener->VolumeChanged(volume); 1246 } 1247} 1248 1249 1250void 1251Controller::_NotifyMutedChanged(bool muted) const 1252{ 1253 BList listeners(fListeners); 1254 int32 count = listeners.CountItems(); 1255 for (int32 i = 0; i < count; i++) { 1256 Listener* listener = (Listener*)listeners.ItemAtFast(i); 1257 listener->MutedChanged(muted); 1258 } 1259} 1260 1261 1262void 1263Controller::NotifyPlayModeChanged(int32 mode) const 1264{ 1265 uint32 state = _PlaybackState(mode); 1266 if (fVideoView) 1267 fVideoView->SetPlaying(state == PLAYBACK_STATE_PLAYING); 1268 _NotifyPlaybackStateChanged(state); 1269} 1270 1271 1272void 1273Controller::NotifyLoopModeChanged(int32 mode) const 1274{ 1275} 1276 1277 1278void 1279Controller::NotifyLoopingEnabledChanged(bool enabled) const 1280{ 1281} 1282 1283 1284void 1285Controller::NotifyVideoBoundsChanged(BRect bounds) const 1286{ 1287} 1288 1289 1290void 1291Controller::NotifyFPSChanged(float fps) const 1292{ 1293} 1294 1295 1296void 1297Controller::NotifyCurrentFrameChanged(int64 frame) const 1298{ 1299 fCurrentFrame = frame; 1300 bigtime_t timePosition = _TimePosition(); 1301 _NotifyPositionChanged((float)timePosition / fDuration); 1302 1303 if (fSubTitles != NULL) { 1304 const SubTitle* subTitle = fSubTitles->SubTitleAt(timePosition); 1305 if (subTitle != NULL) 1306 fVideoView->SetSubTitle(subTitle->text.String()); 1307 else 1308 fVideoView->SetSubTitle(NULL); 1309 } 1310} 1311 1312 1313void 1314Controller::NotifySpeedChanged(float speed) const 1315{ 1316} 1317 1318 1319void 1320Controller::NotifyFrameDropped() const 1321{ 1322// printf("Controller::NotifyFrameDropped()\n"); 1323} 1324 1325 1326void 1327Controller::NotifyStopFrameReached() const 1328{ 1329 // Currently, this means we reached the end of the current 1330 // file and should play the next file 1331 _NotifyFileFinished(); 1332} 1333 1334 1335void 1336Controller::NotifySeekHandled(int64 seekedFrame) const 1337{ 1338 if (fPendingSeekRequests == 0) 1339 return; 1340 1341 fPendingSeekRequests--; 1342 if (fPendingSeekRequests == 0) { 1343 fSeekFrame = -1; 1344 fRequestedSeekFrame = -1; 1345 } 1346 1347 _NotifySeekHandled(seekedFrame); 1348} 1349 1350