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 53using std::nothrow; 54 55 56void 57HandleError(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 70Controller::Listener::Listener() {} 71Controller::Listener::~Listener() {} 72void Controller::Listener::FileFinished() {} 73void Controller::Listener::FileChanged(PlaylistItem* item, status_t result) {} 74void Controller::Listener::VideoTrackChanged(int32) {} 75void Controller::Listener::AudioTrackChanged(int32) {} 76void Controller::Listener::SubTitleTrackChanged(int32) {} 77void Controller::Listener::VideoStatsChanged() {} 78void Controller::Listener::AudioStatsChanged() {} 79void Controller::Listener::PlaybackStateChanged(uint32) {} 80void Controller::Listener::PositionChanged(float) {} 81void Controller::Listener::SeekHandled(int64 seekFrame) {} 82void Controller::Listener::VolumeChanged(float) {} 83void Controller::Listener::MutedChanged(bool) {} 84 85 86// #pragma mark - Controller 87 88 89enum { 90 MSG_SET_TO = 'stto' 91}; 92 93 94Controller::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 131Controller::~Controller() 132{ 133 Settings::Default()->RemoveListener(&fGlobalSettingsListener); 134 SetTo(NULL); 135} 136 137 138// #pragma mark - NodeManager interface 139 140 141void 142Controller::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 171int64 172Controller::Duration() 173{ 174 return _FrameDuration(); 175} 176 177 178VideoTarget* 179Controller::CreateVideoTarget() 180{ 181 return fVideoView; 182} 183 184 185VideoSupplier* 186Controller::CreateVideoSupplier() 187{ 188 return fVideoSupplier; 189} 190 191 192AudioSupplier* 193Controller::CreateAudioSupplier() 194{ 195 return fAudioSupplier; 196} 197 198 199// #pragma mark - 200 201 202status_t 203Controller::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 223status_t 224Controller::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 354void 355Controller::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 383void 384Controller::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 420int 421Controller::AudioTrackCount() 422{ 423 BAutolock _(this); 424 425 if (fTrackSupplier != NULL) 426 return fTrackSupplier->CountAudioTracks(); 427 return 0; 428} 429 430 431int 432Controller::VideoTrackCount() 433{ 434 BAutolock _(this); 435 436 if (fTrackSupplier != NULL) 437 return fTrackSupplier->CountVideoTracks(); 438 return 0; 439} 440 441 442int 443Controller::SubTitleTrackCount() 444{ 445 BAutolock _(this); 446 447 if (fTrackSupplier != NULL) 448 return fTrackSupplier->CountSubTitleTracks(); 449 return 0; 450} 451 452 453status_t 454Controller::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 479int 480Controller::CurrentAudioTrack() 481{ 482 BAutolock _(this); 483 484 if (fAudioTrackSupplier == NULL) 485 return -1; 486 487 return fAudioTrackSupplier->TrackIndex(); 488} 489 490 491int 492Controller::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 502status_t 503Controller::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 535int 536Controller::CurrentVideoTrack() 537{ 538 BAutolock _(this); 539 540 if (fVideoTrackSupplier == NULL) 541 return -1; 542 543 return fVideoTrackSupplier->TrackIndex(); 544} 545 546 547status_t 548Controller::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 571int 572Controller::CurrentSubTitleTrack() 573{ 574 BAutolock _(this); 575 576 if (fSubTitles == NULL) 577 return -1; 578 579 return fSubTitlesIndex; 580} 581 582 583const char* 584Controller::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 602void 603Controller::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 616void 617Controller::Play() 618{ 619 //printf("Controller::Play\n"); 620 621 BAutolock _(this); 622 623 StartPlaying(); 624 fAutoplay = true; 625} 626 627 628void 629Controller::Pause() 630{ 631// printf("Controller::Pause\n"); 632 633 BAutolock _(this); 634 635 PausePlaying(); 636 637 fAutoplay = fAutoplaySetting; 638} 639 640 641void 642Controller::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 656uint32 657Controller::PlaybackState() 658{ 659 BAutolock _(this); 660 661 return _PlaybackState(PlaybackManager::PlayMode()); 662} 663 664 665bigtime_t 666Controller::TimeDuration() 667{ 668 BAutolock _(this); 669 670 return fDuration; 671} 672 673 674bigtime_t 675Controller::TimePosition() 676{ 677 BAutolock _(this); 678 679 return _TimePosition(); 680} 681 682 683void 684Controller::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 702void 703Controller::VolumeUp() 704{ 705 // TODO: linear <-> exponential 706 SetVolume(Volume() + 0.05); 707} 708 709void 710Controller::VolumeDown() 711{ 712 // TODO: linear <-> exponential 713 SetVolume(Volume() - 0.05); 714} 715 716void 717Controller::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 732float 733Controller::Volume() 734{ 735 BAutolock _(this); 736 737 return fVolume; 738} 739 740 741int64 742Controller::SetPosition(float value) 743{ 744 BAutolock _(this); 745 746 return SetFramePosition(_FrameDuration() * value); 747} 748 749 750int64 751Controller::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 786int64 787Controller::SetTimePosition(bigtime_t value) 788{ 789 BAutolock _(this); 790 791 return SetPosition((float)value / TimeDuration()); 792} 793 794 795// #pragma mark - 796 797 798bool 799Controller::HasFile() 800{ 801 // you need to hold the data lock 802 return fTrackSupplier != NULL; 803} 804 805 806status_t 807Controller::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 816status_t 817Controller::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 826status_t 827Controller::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 837status_t 838Controller::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 848status_t 849Controller::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 858status_t 859Controller::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 868status_t 869Controller::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 878status_t 879Controller::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 888status_t 889Controller::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 898status_t 899Controller::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 908status_t 909Controller::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 921void 922Controller::SetVideoView(VideoView *view) 923{ 924 BAutolock _(this); 925 926 fVideoView = view; 927} 928 929 930bool 931Controller::IsOverlayActive() 932{ 933 if (fVideoView) 934 return fVideoView->IsOverlayActive(); 935 936 return false; 937} 938 939 940// #pragma mark - 941 942 943bool 944Controller::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 954void 955Controller::RemoveListener(Listener* listener) 956{ 957 BAutolock _(this); 958 959 fListeners.RemoveItem(listener); 960} 961 962 963// #pragma mark - Private 964 965 966void 967Controller::_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 980uint32 981Controller::_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 1002bigtime_t 1003Controller::_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 1023int64 1024Controller::_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 1038void 1039Controller::_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 1050void 1051Controller::_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 1062void 1063Controller::_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 1074void 1075Controller::_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 1086void 1087Controller::_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 1098void 1099Controller::_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 1110void 1111Controller::_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 1122void 1123Controller::_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 1134void 1135Controller::_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 1146void 1147Controller::_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 1158void 1159Controller::_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 1170void 1171Controller::_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 1182void 1183Controller::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 1192void 1193Controller::NotifyLoopModeChanged(int32 mode) const 1194{ 1195} 1196 1197 1198void 1199Controller::NotifyLoopingEnabledChanged(bool enabled) const 1200{ 1201} 1202 1203 1204void 1205Controller::NotifyVideoBoundsChanged(BRect bounds) const 1206{ 1207} 1208 1209 1210void 1211Controller::NotifyFPSChanged(float fps) const 1212{ 1213} 1214 1215 1216void 1217Controller::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 1233void 1234Controller::NotifySpeedChanged(float speed) const 1235{ 1236} 1237 1238 1239void 1240Controller::NotifyFrameDropped() const 1241{ 1242// printf("Controller::NotifyFrameDropped()\n"); 1243} 1244 1245 1246void 1247Controller::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 1255void 1256Controller::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