btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / apps / mediaplayer / Controller.cpp
blob76d839a6c6b0a822d57b52680dfe6461e74a7a0f
1 /*
2 * Controller.cpp - Media Player for the Haiku Operating System
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)
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.
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.
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.
24 #include "Controller.h"
26 #include <new>
27 #include <stdio.h>
28 #include <string.h>
30 #include <Autolock.h>
31 #include <Bitmap.h>
32 #include <Debug.h>
33 #include <Path.h>
34 #include <Window.h> // for debugging only
36 #include "AutoDeleter.h"
37 #include "ControllerView.h"
38 #include "MainApp.h"
39 #include "PlaybackState.h"
40 #include "Settings.h"
41 #include "VideoView.h"
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"
53 using std::nothrow;
56 class TrackSupplierReleaser {
57 public:
58 TrackSupplierReleaser(PlaylistItemRef& owner)
60 fOwner(owner),
61 fRelease(true)
64 virtual ~TrackSupplierReleaser()
66 if (fRelease)
67 fOwner.Get()->ReleaseTrackSupplier();
70 void Detach()
72 fRelease = false;
75 private:
76 PlaylistItemRef& fOwner;
77 bool fRelease;
81 void
82 HandleError(const char *text, status_t err)
84 if (err != B_OK) {
85 printf("%s. error 0x%08x (%s)\n",text, (int)err, strerror(err));
86 fflush(NULL);
87 exit(1);
92 // #pragma mark - Controller::Listener
95 Controller::Listener::Listener() {}
96 Controller::Listener::~Listener() {}
97 void Controller::Listener::FileFinished() {}
98 void Controller::Listener::FileChanged(PlaylistItem* item, status_t result) {}
99 void Controller::Listener::VideoTrackChanged(int32) {}
100 void Controller::Listener::AudioTrackChanged(int32) {}
101 void Controller::Listener::SubTitleTrackChanged(int32) {}
102 void Controller::Listener::VideoStatsChanged() {}
103 void Controller::Listener::AudioStatsChanged() {}
104 void Controller::Listener::PlaybackStateChanged(uint32) {}
105 void Controller::Listener::PositionChanged(float) {}
106 void Controller::Listener::SeekHandled(int64 seekFrame) {}
107 void Controller::Listener::VolumeChanged(float) {}
108 void Controller::Listener::MutedChanged(bool) {}
111 // #pragma mark - Controller
114 enum {
115 MSG_SET_TO = 'stto'
119 Controller::Controller()
121 NodeManager(),
122 fVideoView(NULL),
123 fVolume(1.0),
124 fActiveVolume(1.0),
125 fMuted(false),
127 fItem(NULL),
129 fVideoSupplier(new ProxyVideoSupplier()),
130 fAudioSupplier(new ProxyAudioSupplier(this)),
131 fVideoTrackSupplier(NULL),
132 fAudioTrackSupplier(NULL),
133 fSubTitles(NULL),
134 fSubTitlesIndex(-1),
136 fCurrentFrame(0),
137 fDuration(0),
138 fVideoFrameRate(25.0),
140 fPendingSeekRequests(0),
141 fSeekFrame(-1),
142 fRequestedSeekFrame(-1),
144 fGlobalSettingsListener(this),
146 fListeners(4)
148 Settings::Default()->AddListener(&fGlobalSettingsListener);
149 _AdoptGlobalSettings();
151 fAutoplay = fAutoplaySetting;
155 Controller::~Controller()
157 Settings::Default()->RemoveListener(&fGlobalSettingsListener);
158 SetTo(NULL);
162 // #pragma mark - NodeManager interface
165 void
166 Controller::MessageReceived(BMessage* message)
168 switch (message->what) {
169 case MSG_OBJECT_CHANGED:
170 // received from fGlobalSettingsListener
171 // TODO: find out which object, if we ever watch more than
172 // the global settings instance...
173 _AdoptGlobalSettings();
174 break;
176 case MSG_SET_TO:
178 PlaylistItem* item;
179 if (message->FindPointer("item", (void**)&item) == B_OK) {
180 PlaylistItemRef itemRef(item, true);
181 // The reference was passed with the message.
182 SetTo(itemRef);
183 } else
184 _NotifyFileChanged(NULL, B_BAD_VALUE);
186 break;
189 default:
190 NodeManager::MessageReceived(message);
195 int64
196 Controller::Duration()
198 return _FrameDuration();
202 VideoTarget*
203 Controller::CreateVideoTarget()
205 return fVideoView;
209 VideoSupplier*
210 Controller::CreateVideoSupplier()
212 return fVideoSupplier;
216 AudioSupplier*
217 Controller::CreateAudioSupplier()
219 return fAudioSupplier;
223 // #pragma mark -
226 status_t
227 Controller::SetToAsync(const PlaylistItemRef& item)
229 PlaylistItemRef additionalReference(item);
231 BMessage message(MSG_SET_TO);
232 status_t ret = message.AddPointer("item", item.Get());
233 if (ret != B_OK)
234 return ret;
236 ret = PostMessage(&message);
237 if (ret != B_OK)
238 return ret;
240 // The additional reference is now passed along with the message...
241 additionalReference.Detach();
243 return B_OK;
247 status_t
248 Controller::SetTo(const PlaylistItemRef& item)
250 BAutolock _(this);
252 if (fItem == item) {
253 if (InitCheck() == B_OK) {
254 if (fAutoplay) {
255 SetPosition(0.0);
256 StartPlaying(true);
259 return B_OK;
262 fAudioSupplier->SetSupplier(NULL, fVideoFrameRate);
263 fVideoSupplier->SetSupplier(NULL);
265 if (fItem != NULL)
266 TrackSupplierReleaser oldSupplierReleaser(fItem);
268 fItem = item;
270 // Do not delete the supplier chain until after we called
271 // NodeManager::Init() to setup a new media node chain
272 ObjectDeleter<VideoTrackSupplier> videoSupplierDeleter(
273 fVideoTrackSupplier);
274 ObjectDeleter<AudioTrackSupplier> audioSupplierDeleter(
275 fAudioTrackSupplier);
277 fVideoTrackSupplier = NULL;
278 fAudioTrackSupplier = NULL;
279 fSubTitles = NULL;
280 fSubTitlesIndex = -1;
282 fCurrentFrame = 0;
283 fDuration = 0;
284 fVideoFrameRate = 25.0;
286 fPendingSeekRequests = 0;
287 fSeekFrame = -1;
288 fRequestedSeekFrame = -1;
290 if (fItem.Get() == NULL)
291 return B_BAD_VALUE;
293 TrackSupplier* trackSupplier = fItem->GetTrackSupplier();
294 if (trackSupplier == NULL) {
295 _NotifyFileChanged(item.Get(), B_NO_MEMORY);
296 return B_NO_MEMORY;
298 TrackSupplierReleaser trackSupplierReleaser(fItem);
300 status_t err = trackSupplier->InitCheck();
301 if (err != B_OK) {
302 printf("Controller::SetTo: InitCheck failed\n");
303 _NotifyFileChanged(item.Get(), err);
304 return err;
307 if (trackSupplier->CountAudioTracks() == 0
308 && trackSupplier->CountVideoTracks() == 0) {
309 _NotifyFileChanged(item.Get(), B_MEDIA_NO_HANDLER);
310 return B_MEDIA_NO_HANDLER;
313 SelectAudioTrack(0);
314 SelectVideoTrack(0);
316 if (fAudioTrackSupplier == NULL && fVideoTrackSupplier == NULL) {
317 printf("Controller::SetTo: no audio or video tracks found or "
318 "no decoders\n");
319 _NotifyFileChanged(item.Get(), B_MEDIA_NO_HANDLER);
320 return B_MEDIA_NO_HANDLER;
323 trackSupplierReleaser.Detach();
325 // prevent blocking the creation of new overlay buffers
326 if (fVideoView)
327 fVideoView->DisableOverlay();
329 // get video properties (if there is video at all)
330 bool useOverlays = fVideoView ? fVideoView->UseOverlays() : true;
332 int width;
333 int height;
334 GetSize(&width, &height);
335 color_space preferredVideoFormat = B_NO_COLOR_SPACE;
336 if (fVideoTrackSupplier != NULL) {
337 const media_format& format = fVideoTrackSupplier->Format();
338 preferredVideoFormat = format.u.raw_video.display.format;
341 uint32 enabledNodes;
342 if (!fVideoTrackSupplier)
343 enabledNodes = AUDIO_ONLY;
344 else if (!fAudioTrackSupplier)
345 enabledNodes = VIDEO_ONLY;
346 else
347 enabledNodes = AUDIO_AND_VIDEO;
349 float audioFrameRate = 44100.0f;
350 uint32 audioChannels = 2;
351 if (fAudioTrackSupplier != NULL) {
352 const media_format& audioTrackFormat = fAudioTrackSupplier->Format();
353 audioFrameRate = audioTrackFormat.u.raw_audio.frame_rate;
354 audioChannels = audioTrackFormat.u.raw_audio.channel_count;
357 if (InitCheck() != B_OK) {
358 Init(BRect(0, 0, width - 1, height - 1), fVideoFrameRate,
359 preferredVideoFormat, audioFrameRate, audioChannels, LOOPING_ALL,
360 false, 1.0, enabledNodes, useOverlays);
361 } else {
362 FormatChanged(BRect(0, 0, width - 1, height - 1), fVideoFrameRate,
363 preferredVideoFormat, audioFrameRate, audioChannels, enabledNodes,
364 useOverlays);
367 _NotifyFileChanged(item.Get(), B_OK);
369 if (fAutoplay)
370 StartPlaying(true);
372 return B_OK;
376 void
377 Controller::PlayerActivated(bool active)
379 if (LockWithTimeout(5000) != B_OK)
380 return;
382 if (active && gMainApp->PlayerCount() > 1) {
383 if (fActiveVolume != fVolume)
384 SetVolume(fActiveVolume);
385 } else {
386 fActiveVolume = fVolume;
387 if (gMainApp->PlayerCount() > 1)
388 switch (fBackgroundMovieVolumeMode) {
389 case mpSettings::BG_MOVIES_MUTED:
390 SetVolume(0.0);
391 break;
392 case mpSettings::BG_MOVIES_HALF_VLUME:
393 SetVolume(fVolume * 0.25);
394 break;
395 case mpSettings::BG_MOVIES_FULL_VOLUME:
396 default:
397 break;
401 Unlock();
405 void
406 Controller::GetSize(int *width, int *height, int* _widthAspect,
407 int* _heightAspect)
409 BAutolock _(this);
411 if (fVideoTrackSupplier) {
412 media_format format = fVideoTrackSupplier->Format();
413 *height = format.u.raw_video.display.line_count;
414 *width = format.u.raw_video.display.line_width;
415 int widthAspect = 0;
416 int heightAspect = 0;
417 // Ignore format aspect when both values are 1. If they have been
418 // intentionally at 1:1 then no harm is done for quadratic videos,
419 // only if the video is indeed encoded anamorphotic, but supposed
420 // to be displayed quadratic... extremely unlikely.
421 if (format.u.raw_video.pixel_width_aspect
422 != format.u.raw_video.pixel_height_aspect
423 && format.u.raw_video.pixel_width_aspect != 1) {
424 widthAspect = format.u.raw_video.pixel_width_aspect;
425 heightAspect = format.u.raw_video.pixel_height_aspect;
427 if (_widthAspect != NULL)
428 *_widthAspect = widthAspect;
429 if (_heightAspect != NULL)
430 *_heightAspect = heightAspect;
431 } else {
432 *height = 0;
433 *width = 0;
434 if (_widthAspect != NULL)
435 *_widthAspect = 1;
436 if (_heightAspect != NULL)
437 *_heightAspect = 1;
443 Controller::AudioTrackCount()
445 BAutolock _(this);
447 if (fItem != NULL && fItem->HasTrackSupplier())
448 return fItem->GetTrackSupplier()->CountAudioTracks();
449 return 0;
454 Controller::VideoTrackCount()
456 BAutolock _(this);
458 if (fItem != NULL && fItem->HasTrackSupplier())
459 return fItem->GetTrackSupplier()->CountVideoTracks();
460 return 0;
465 Controller::SubTitleTrackCount()
467 BAutolock _(this);
469 if (fItem != NULL && fItem->HasTrackSupplier())
470 return fItem->GetTrackSupplier()->CountSubTitleTracks();
471 return 0;
475 status_t
476 Controller::SelectAudioTrack(int n)
478 BAutolock _(this);
479 if (fItem == NULL || !fItem->HasTrackSupplier())
480 return B_NO_INIT;
482 ObjectDeleter<AudioTrackSupplier> deleter(fAudioTrackSupplier);
483 fAudioTrackSupplier
484 = fItem->GetTrackSupplier()->CreateAudioTrackForIndex(n);
485 if (fAudioTrackSupplier == NULL)
486 return B_BAD_INDEX;
488 bigtime_t a = fAudioTrackSupplier->Duration();
489 bigtime_t v = fVideoTrackSupplier != NULL
490 ? fVideoTrackSupplier->Duration() : 0;
491 fDuration = max_c(a, v);
492 DurationChanged();
493 // TODO: notify duration changed!
495 fAudioSupplier->SetSupplier(fAudioTrackSupplier, fVideoFrameRate);
497 _NotifyAudioTrackChanged(n);
498 return B_OK;
503 Controller::CurrentAudioTrack()
505 BAutolock _(this);
507 if (fAudioTrackSupplier == NULL)
508 return -1;
510 return fAudioTrackSupplier->TrackIndex();
515 Controller::AudioTrackChannelCount()
517 media_format format;
518 if (GetEncodedAudioFormat(&format) == B_OK)
519 return format.u.encoded_audio.output.channel_count;
521 return 2;
525 status_t
526 Controller::SelectVideoTrack(int n)
528 BAutolock _(this);
530 if (fItem == NULL || !fItem->HasTrackSupplier())
531 return B_NO_INIT;
533 ObjectDeleter<VideoTrackSupplier> deleter(fVideoTrackSupplier);
534 fVideoTrackSupplier
535 = fItem->GetTrackSupplier()->CreateVideoTrackForIndex(n);
536 if (fVideoTrackSupplier == NULL)
537 return B_BAD_INDEX;
539 bigtime_t a = fAudioTrackSupplier ? fAudioTrackSupplier->Duration() : 0;
540 bigtime_t v = fVideoTrackSupplier->Duration();
541 fDuration = max_c(a, v);
542 fVideoFrameRate = fVideoTrackSupplier->Format().u.raw_video.field_rate;
543 if (fVideoFrameRate <= 0.0) {
544 printf("Controller::SelectVideoTrack(%d) - invalid video frame rate: %.1f\n",
545 n, fVideoFrameRate);
546 fVideoFrameRate = 25.0;
549 DurationChanged();
550 // TODO: notify duration changed!
552 fVideoSupplier->SetSupplier(fVideoTrackSupplier);
554 _NotifyVideoTrackChanged(n);
555 return B_OK;
560 Controller::CurrentVideoTrack()
562 BAutolock _(this);
564 if (fVideoTrackSupplier == NULL)
565 return -1;
567 return fVideoTrackSupplier->TrackIndex();
571 status_t
572 Controller::SelectSubTitleTrack(int n)
574 BAutolock _(this);
576 if (fItem == NULL || !fItem->HasTrackSupplier())
577 return B_NO_INIT;
579 fSubTitlesIndex = n;
580 fSubTitles =
581 fItem->GetTrackSupplier()->SubTitleTrackForIndex(n);
583 const SubTitle* subTitle = NULL;
584 if (fSubTitles != NULL)
585 subTitle = fSubTitles->SubTitleAt(_TimePosition());
586 if (subTitle != NULL)
587 fVideoView->SetSubTitle(subTitle->text.String());
588 else
589 fVideoView->SetSubTitle(NULL);
591 _NotifySubTitleTrackChanged(n);
592 return B_OK;
597 Controller::CurrentSubTitleTrack()
599 BAutolock _(this);
601 if (fSubTitles == NULL)
602 return -1;
604 return fSubTitlesIndex;
608 const char*
609 Controller::SubTitleTrackName(int n)
611 BAutolock _(this);
613 if (fItem == NULL || !fItem->HasTrackSupplier())
614 return NULL;
616 const SubTitles* subTitles
617 = fItem->GetTrackSupplier()->SubTitleTrackForIndex(n);
618 if (subTitles == NULL)
619 return NULL;
621 return subTitles->Name();
625 // #pragma mark -
628 void
629 Controller::Stop()
631 //printf("Controller::Stop\n");
633 BAutolock _(this);
635 StopPlaying();
636 SetPosition(0.0);
638 fAutoplay = fAutoplaySetting;
642 void
643 Controller::Play()
645 //printf("Controller::Play\n");
647 BAutolock _(this);
649 StartPlaying();
650 fAutoplay = true;
654 void
655 Controller::Pause()
657 // printf("Controller::Pause\n");
659 BAutolock _(this);
661 PausePlaying();
663 fAutoplay = fAutoplaySetting;
667 void
668 Controller::TogglePlaying()
670 // printf("Controller::TogglePlaying\n");
672 BAutolock _(this);
674 if (InitCheck() == B_OK) {
675 NodeManager::TogglePlaying();
677 fAutoplay = IsPlaying() || fAutoplaySetting;
682 uint32
683 Controller::PlaybackState()
685 BAutolock _(this);
687 return _PlaybackState(PlaybackManager::PlayMode());
691 bigtime_t
692 Controller::TimeDuration()
694 BAutolock _(this);
696 return fDuration;
700 bigtime_t
701 Controller::TimePosition()
703 BAutolock _(this);
705 return _TimePosition();
709 void
710 Controller::SetVolume(float value)
712 // printf("Controller::SetVolume %.4f\n", value);
713 BAutolock _(this);
715 value = max_c(0.0, min_c(2.0, value));
717 if (fVolume != value) {
718 if (fMuted)
719 ToggleMute();
721 fVolume = value;
722 fAudioSupplier->SetVolume(fVolume);
724 _NotifyVolumeChanged(fVolume);
728 void
729 Controller::VolumeUp()
731 // TODO: linear <-> exponential
732 SetVolume(Volume() + 0.05);
735 void
736 Controller::VolumeDown()
738 // TODO: linear <-> exponential
739 SetVolume(Volume() - 0.05);
742 void
743 Controller::ToggleMute()
745 BAutolock _(this);
747 fMuted = !fMuted;
749 if (fMuted)
750 fAudioSupplier->SetVolume(0.0);
751 else
752 fAudioSupplier->SetVolume(fVolume);
754 _NotifyMutedChanged(fMuted);
758 float
759 Controller::Volume()
761 BAutolock _(this);
763 return fVolume;
767 int64
768 Controller::SetPosition(float value)
770 BAutolock _(this);
772 return SetFramePosition(_FrameDuration() * value);
776 int64
777 Controller::SetFramePosition(int64 value)
779 BAutolock _(this);
781 fPendingSeekRequests++;
782 fRequestedSeekFrame = max_c(0, min_c(_FrameDuration(), value));
783 fSeekFrame = fRequestedSeekFrame;
785 int64 currentFrame = CurrentFrame();
787 // Snap to a video keyframe, since that will be the fastest
788 // to display and seeking will feel more snappy. Note that we
789 // don't store this change in fSeekFrame, since we still want
790 // to report the originally requested seek frame in TimePosition()
791 // until we could reach that frame.
792 if (Duration() > 240 && fVideoTrackSupplier != NULL
793 && abs(value - currentFrame) > 5) {
794 fVideoTrackSupplier->FindKeyFrameForFrame(&fSeekFrame);
797 //printf("SetFramePosition(%lld) -> %lld (current: %lld, duration: %lld) "
798 //"(video: %p)\n", value, fSeekFrame, currentFrame, _FrameDuration(),
799 //fVideoTrackSupplier);
800 if (fSeekFrame != currentFrame) {
801 int64 seekFrame = fSeekFrame;
802 SetCurrentFrame(fSeekFrame);
803 // May trigger the notification and reset fSeekFrame,
804 // if next current frame == seek frame.
805 return seekFrame;
806 } else
807 NotifySeekHandled(fRequestedSeekFrame);
808 return currentFrame;
812 int64
813 Controller::SetTimePosition(bigtime_t value)
815 BAutolock _(this);
817 return SetPosition((float)value / TimeDuration());
821 // #pragma mark -
824 bool
825 Controller::HasFile()
827 // you need to hold the data lock
828 return fItem != NULL && fItem->HasTrackSupplier();
832 status_t
833 Controller::GetFileFormatInfo(media_file_format* fileFormat)
835 // you need to hold the data lock
836 if (fItem == NULL || !fItem->HasTrackSupplier())
837 return B_NO_INIT;
838 return fItem->GetTrackSupplier()->GetFileFormatInfo(fileFormat);
842 status_t
843 Controller::GetCopyright(BString* copyright)
845 // you need to hold the data lock
846 if (fItem == NULL || !fItem->HasTrackSupplier())
847 return B_NO_INIT;
848 return fItem->GetTrackSupplier()->GetCopyright(copyright);
852 status_t
853 Controller::GetLocation(BString* location)
855 // you need to hold the data lock
856 if (fItem.Get() == NULL)
857 return B_NO_INIT;
858 *location = fItem->LocationURI();
859 return B_OK;
863 status_t
864 Controller::GetName(BString* name)
866 // you need to hold the data lock
867 if (fItem.Get() == NULL)
868 return B_NO_INIT;
869 *name = fItem->Name();
870 return B_OK;
874 status_t
875 Controller::GetEncodedVideoFormat(media_format* format)
877 // you need to hold the data lock
878 if (fVideoTrackSupplier)
879 return fVideoTrackSupplier->GetEncodedFormat(format);
880 return B_NO_INIT;
884 status_t
885 Controller::GetVideoCodecInfo(media_codec_info* info)
887 // you need to hold the data lock
888 if (fVideoTrackSupplier)
889 return fVideoTrackSupplier->GetCodecInfo(info);
890 return B_NO_INIT;
894 status_t
895 Controller::GetEncodedAudioFormat(media_format* format)
897 // you need to hold the data lock
898 if (fAudioTrackSupplier)
899 return fAudioTrackSupplier->GetEncodedFormat(format);
900 return B_NO_INIT;
904 status_t
905 Controller::GetAudioCodecInfo(media_codec_info* info)
907 // you need to hold the data lock
908 if (fAudioTrackSupplier)
909 return fAudioTrackSupplier->GetCodecInfo(info);
910 return B_NO_INIT;
914 status_t
915 Controller::GetMetaData(BMessage* metaData)
917 // you need to hold the data lock
918 if (fItem == NULL || !fItem->HasTrackSupplier())
919 return B_NO_INIT;
920 return fItem->GetTrackSupplier()->GetMetaData(metaData);
924 status_t
925 Controller::GetVideoMetaData(int32 index, BMessage* metaData)
927 // you need to hold the data lock
928 if (fItem == NULL || !fItem->HasTrackSupplier())
929 return B_NO_INIT;
930 return fItem->GetTrackSupplier()->GetVideoMetaData(index, metaData);
934 status_t
935 Controller::GetAudioMetaData(int32 index, BMessage* metaData)
937 // you need to hold the data lock
938 if (fItem == NULL || !fItem->HasTrackSupplier())
939 return B_NO_INIT;
940 return fItem->GetTrackSupplier()->GetAudioMetaData(index, metaData);
944 // #pragma mark -
947 void
948 Controller::SetVideoView(VideoView *view)
950 BAutolock _(this);
952 fVideoView = view;
956 bool
957 Controller::IsOverlayActive()
959 if (fVideoView)
960 return fVideoView->IsOverlayActive();
962 return false;
966 // #pragma mark -
969 bool
970 Controller::AddListener(Listener* listener)
972 BAutolock _(this);
974 if (listener && !fListeners.HasItem(listener))
975 return fListeners.AddItem(listener);
976 return false;
980 void
981 Controller::RemoveListener(Listener* listener)
983 BAutolock _(this);
985 fListeners.RemoveItem(listener);
989 // #pragma mark - Private
992 void
993 Controller::_AdoptGlobalSettings()
995 mpSettings settings;
996 Settings::Default()->Get(settings);
998 fAutoplaySetting = settings.autostart;
999 // not yet used:
1000 fLoopMovies = settings.loopMovie;
1001 fLoopSounds = settings.loopSound;
1002 fBackgroundMovieVolumeMode = settings.backgroundMovieVolumeMode;
1006 uint32
1007 Controller::_PlaybackState(int32 playingMode) const
1009 uint32 state = 0;
1010 switch (playingMode) {
1011 case MODE_PLAYING_PAUSED_FORWARD:
1012 case MODE_PLAYING_PAUSED_BACKWARD:
1013 state = PLAYBACK_STATE_PAUSED;
1014 break;
1015 case MODE_PLAYING_FORWARD:
1016 case MODE_PLAYING_BACKWARD:
1017 state = PLAYBACK_STATE_PLAYING;
1018 break;
1020 default:
1021 state = PLAYBACK_STATE_STOPPED;
1022 break;
1024 return state;
1028 bigtime_t
1029 Controller::_TimePosition() const
1031 if (fDuration == 0)
1032 return 0;
1034 // Check if we are still waiting to reach the seekframe,
1035 // pass the last pending seek frame back to the caller, so
1036 // that the view of the current frame/time from the outside
1037 // does not depend on the internal latency to reach requested
1038 // frames asynchronously.
1039 int64 frame;
1040 if (fPendingSeekRequests > 0)
1041 frame = fRequestedSeekFrame;
1042 else
1043 frame = fCurrentFrame;
1045 return frame * fDuration / _FrameDuration();
1049 int64
1050 Controller::_FrameDuration() const
1052 // This should really be total frames (video frames at that)
1053 // TODO: It is not so nice that the MediaPlayer still measures
1054 // in video frames if only playing audio. Here for example, it will
1055 // return a duration of 0 if the audio clip happens to be shorter than
1056 // one video frame at 25 fps.
1057 return (int64)((double)fDuration * fVideoFrameRate / 1000000.0);
1061 // #pragma mark - Notifications
1064 void
1065 Controller::_NotifyFileChanged(PlaylistItem* item, status_t result) const
1067 BList listeners(fListeners);
1068 int32 count = listeners.CountItems();
1069 for (int32 i = 0; i < count; i++) {
1070 Listener* listener = (Listener*)listeners.ItemAtFast(i);
1071 listener->FileChanged(item, result);
1076 void
1077 Controller::_NotifyFileFinished() const
1079 BList listeners(fListeners);
1080 int32 count = listeners.CountItems();
1081 for (int32 i = 0; i < count; i++) {
1082 Listener* listener = (Listener*)listeners.ItemAtFast(i);
1083 listener->FileFinished();
1088 void
1089 Controller::_NotifyVideoTrackChanged(int32 index) const
1091 BList listeners(fListeners);
1092 int32 count = listeners.CountItems();
1093 for (int32 i = 0; i < count; i++) {
1094 Listener* listener = (Listener*)listeners.ItemAtFast(i);
1095 listener->VideoTrackChanged(index);
1100 void
1101 Controller::_NotifyAudioTrackChanged(int32 index) const
1103 BList listeners(fListeners);
1104 int32 count = listeners.CountItems();
1105 for (int32 i = 0; i < count; i++) {
1106 Listener* listener = (Listener*)listeners.ItemAtFast(i);
1107 listener->AudioTrackChanged(index);
1112 void
1113 Controller::_NotifySubTitleTrackChanged(int32 index) const
1115 BList listeners(fListeners);
1116 int32 count = listeners.CountItems();
1117 for (int32 i = 0; i < count; i++) {
1118 Listener* listener = (Listener*)listeners.ItemAtFast(i);
1119 listener->SubTitleTrackChanged(index);
1124 void
1125 Controller::_NotifyVideoStatsChanged() const
1127 BList listeners(fListeners);
1128 int32 count = listeners.CountItems();
1129 for (int32 i = 0; i < count; i++) {
1130 Listener* listener = (Listener*)listeners.ItemAtFast(i);
1131 listener->VideoStatsChanged();
1136 void
1137 Controller::_NotifyAudioStatsChanged() const
1139 BList listeners(fListeners);
1140 int32 count = listeners.CountItems();
1141 for (int32 i = 0; i < count; i++) {
1142 Listener* listener = (Listener*)listeners.ItemAtFast(i);
1143 listener->AudioStatsChanged();
1148 void
1149 Controller::_NotifyPlaybackStateChanged(uint32 state) const
1151 BList listeners(fListeners);
1152 int32 count = listeners.CountItems();
1153 for (int32 i = 0; i < count; i++) {
1154 Listener* listener = (Listener*)listeners.ItemAtFast(i);
1155 listener->PlaybackStateChanged(state);
1160 void
1161 Controller::_NotifyPositionChanged(float position) const
1163 BList listeners(fListeners);
1164 int32 count = listeners.CountItems();
1165 for (int32 i = 0; i < count; i++) {
1166 Listener* listener = (Listener*)listeners.ItemAtFast(i);
1167 listener->PositionChanged(position);
1172 void
1173 Controller::_NotifySeekHandled(int64 seekFrame) const
1175 BList listeners(fListeners);
1176 int32 count = listeners.CountItems();
1177 for (int32 i = 0; i < count; i++) {
1178 Listener* listener = (Listener*)listeners.ItemAtFast(i);
1179 listener->SeekHandled(seekFrame);
1184 void
1185 Controller::_NotifyVolumeChanged(float volume) const
1187 BList listeners(fListeners);
1188 int32 count = listeners.CountItems();
1189 for (int32 i = 0; i < count; i++) {
1190 Listener* listener = (Listener*)listeners.ItemAtFast(i);
1191 listener->VolumeChanged(volume);
1196 void
1197 Controller::_NotifyMutedChanged(bool muted) const
1199 BList listeners(fListeners);
1200 int32 count = listeners.CountItems();
1201 for (int32 i = 0; i < count; i++) {
1202 Listener* listener = (Listener*)listeners.ItemAtFast(i);
1203 listener->MutedChanged(muted);
1208 void
1209 Controller::NotifyPlayModeChanged(int32 mode) const
1211 uint32 state = _PlaybackState(mode);
1212 if (fVideoView)
1213 fVideoView->SetPlaying(state == PLAYBACK_STATE_PLAYING);
1214 _NotifyPlaybackStateChanged(state);
1218 void
1219 Controller::NotifyLoopModeChanged(int32 mode) const
1224 void
1225 Controller::NotifyLoopingEnabledChanged(bool enabled) const
1230 void
1231 Controller::NotifyVideoBoundsChanged(BRect bounds) const
1236 void
1237 Controller::NotifyFPSChanged(float fps) const
1242 void
1243 Controller::NotifyCurrentFrameChanged(int64 frame) const
1245 fCurrentFrame = frame;
1246 bigtime_t timePosition = _TimePosition();
1247 _NotifyPositionChanged((float)timePosition / fDuration);
1249 if (fSubTitles != NULL) {
1250 const SubTitle* subTitle = fSubTitles->SubTitleAt(timePosition);
1251 if (subTitle != NULL)
1252 fVideoView->SetSubTitle(subTitle->text.String());
1253 else
1254 fVideoView->SetSubTitle(NULL);
1259 void
1260 Controller::NotifySpeedChanged(float speed) const
1265 void
1266 Controller::NotifyFrameDropped() const
1268 // printf("Controller::NotifyFrameDropped()\n");
1272 void
1273 Controller::NotifyStopFrameReached() const
1275 // Currently, this means we reached the end of the current
1276 // file and should play the next file
1277 _NotifyFileFinished();
1281 void
1282 Controller::NotifySeekHandled(int64 seekedFrame) const
1284 if (fPendingSeekRequests == 0)
1285 return;
1287 fPendingSeekRequests--;
1288 if (fPendingSeekRequests == 0) {
1289 fSeekFrame = -1;
1290 fRequestedSeekFrame = -1;
1293 _NotifySeekHandled(seekedFrame);