repository_infos: Enable automatic updates on the main Haiku repostiory.
[haiku.git] / src / apps / mediaplayer / Controller.cpp
blob2efda09162e0fd1e97f094fb5c6a30417fdb8d58
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>
6 * Copyright (C) 2007-2009 Fredrik Modéen <[FirstName]@[LastName].se>
8 * Released under the terms of the MIT license.
9 */
12 #include "Controller.h"
14 #include <new>
15 #include <stdio.h>
16 #include <string.h>
18 #include <Autolock.h>
19 #include <Bitmap.h>
20 #include <Debug.h>
21 #include <Path.h>
22 #include <Window.h> // for debugging only
24 #include "AutoDeleter.h"
25 #include "ControllerView.h"
26 #include "MainApp.h"
27 #include "PlaybackState.h"
28 #include "Settings.h"
29 #include "VideoView.h"
31 // suppliers
32 #include "AudioTrackSupplier.h"
33 #include "MediaTrackAudioSupplier.h"
34 #include "MediaTrackVideoSupplier.h"
35 #include "ProxyAudioSupplier.h"
36 #include "ProxyVideoSupplier.h"
37 #include "SubTitles.h"
38 #include "TrackSupplier.h"
39 #include "VideoTrackSupplier.h"
41 using std::nothrow;
44 class TrackSupplierReleaser {
45 public:
46 TrackSupplierReleaser(PlaylistItemRef& owner)
48 fOwner(owner),
49 fRelease(true)
52 virtual ~TrackSupplierReleaser()
54 if (fRelease)
55 fOwner.Get()->ReleaseTrackSupplier();
58 void Detach()
60 fRelease = false;
63 private:
64 PlaylistItemRef& fOwner;
65 bool fRelease;
69 void
70 HandleError(const char *text, status_t err)
72 if (err != B_OK) {
73 printf("%s. error 0x%08x (%s)\n",text, (int)err, strerror(err));
74 fflush(NULL);
75 exit(1);
80 // #pragma mark - Controller::Listener
83 Controller::Listener::Listener() {}
84 Controller::Listener::~Listener() {}
85 void Controller::Listener::FileFinished() {}
86 void Controller::Listener::FileChanged(PlaylistItem* item, status_t result) {}
87 void Controller::Listener::VideoTrackChanged(int32) {}
88 void Controller::Listener::AudioTrackChanged(int32) {}
89 void Controller::Listener::SubTitleTrackChanged(int32) {}
90 void Controller::Listener::VideoStatsChanged() {}
91 void Controller::Listener::AudioStatsChanged() {}
92 void Controller::Listener::PlaybackStateChanged(uint32) {}
93 void Controller::Listener::PositionChanged(float) {}
94 void Controller::Listener::SeekHandled(int64 seekFrame) {}
95 void Controller::Listener::VolumeChanged(float) {}
96 void Controller::Listener::MutedChanged(bool) {}
99 // #pragma mark - Controller
102 enum {
103 MSG_SET_TO = 'stto'
107 Controller::Controller()
109 NodeManager(),
110 fVideoView(NULL),
111 fVolume(1.0),
112 fActiveVolume(1.0),
113 fMuted(false),
115 fItem(NULL),
117 fVideoSupplier(new ProxyVideoSupplier()),
118 fAudioSupplier(new ProxyAudioSupplier(this)),
119 fVideoTrackSupplier(NULL),
120 fAudioTrackSupplier(NULL),
121 fSubTitles(NULL),
122 fSubTitlesIndex(-1),
124 fCurrentFrame(0),
125 fDuration(0),
126 fVideoFrameRate(25.0),
128 fPendingSeekRequests(0),
129 fSeekFrame(-1),
130 fRequestedSeekFrame(-1),
132 fGlobalSettingsListener(this),
134 fListeners(4)
136 Settings::Default()->AddListener(&fGlobalSettingsListener);
137 _AdoptGlobalSettings();
139 fAutoplay = fAutoplaySetting;
143 Controller::~Controller()
145 Settings::Default()->RemoveListener(&fGlobalSettingsListener);
146 SetTo(NULL);
150 // #pragma mark - NodeManager interface
153 void
154 Controller::MessageReceived(BMessage* message)
156 switch (message->what) {
157 case MSG_OBJECT_CHANGED:
158 // received from fGlobalSettingsListener
159 // TODO: find out which object, if we ever watch more than
160 // the global settings instance...
161 _AdoptGlobalSettings();
162 break;
164 case MSG_SET_TO:
166 PlaylistItem* item;
167 if (message->FindPointer("item", (void**)&item) == B_OK) {
168 PlaylistItemRef itemRef(item, true);
169 // The reference was passed with the message.
170 SetTo(itemRef);
171 } else
172 _NotifyFileChanged(NULL, B_BAD_VALUE);
174 break;
177 default:
178 NodeManager::MessageReceived(message);
183 int64
184 Controller::Duration()
186 return _FrameDuration();
190 VideoTarget*
191 Controller::CreateVideoTarget()
193 return fVideoView;
197 VideoSupplier*
198 Controller::CreateVideoSupplier()
200 return fVideoSupplier;
204 AudioSupplier*
205 Controller::CreateAudioSupplier()
207 return fAudioSupplier;
211 // #pragma mark -
214 status_t
215 Controller::SetToAsync(const PlaylistItemRef& item)
217 PlaylistItemRef additionalReference(item);
219 BMessage message(MSG_SET_TO);
220 status_t ret = message.AddPointer("item", item.Get());
221 if (ret != B_OK)
222 return ret;
224 ret = PostMessage(&message);
225 if (ret != B_OK)
226 return ret;
228 // The additional reference is now passed along with the message...
229 additionalReference.Detach();
231 return B_OK;
235 status_t
236 Controller::SetTo(const PlaylistItemRef& item)
238 BAutolock _(this);
240 if (fItem == item) {
241 if (InitCheck() == B_OK) {
242 if (fAutoplay) {
243 SetPosition(0.0);
244 StartPlaying(true);
247 return B_OK;
250 fAudioSupplier->SetSupplier(NULL, fVideoFrameRate);
251 fVideoSupplier->SetSupplier(NULL);
253 if (fItem != NULL)
254 TrackSupplierReleaser oldSupplierReleaser(fItem);
256 fItem = item;
258 // Do not delete the supplier chain until after we called
259 // NodeManager::Init() to setup a new media node chain
260 ObjectDeleter<VideoTrackSupplier> videoSupplierDeleter(
261 fVideoTrackSupplier);
262 ObjectDeleter<AudioTrackSupplier> audioSupplierDeleter(
263 fAudioTrackSupplier);
265 fVideoTrackSupplier = NULL;
266 fAudioTrackSupplier = NULL;
267 fSubTitles = NULL;
268 fSubTitlesIndex = -1;
270 fCurrentFrame = 0;
271 fDuration = 0;
272 fVideoFrameRate = 25.0;
274 fPendingSeekRequests = 0;
275 fSeekFrame = -1;
276 fRequestedSeekFrame = -1;
278 if (fItem.Get() == NULL)
279 return B_BAD_VALUE;
281 TrackSupplier* trackSupplier = fItem->GetTrackSupplier();
282 if (trackSupplier == NULL) {
283 _NotifyFileChanged(item.Get(), B_NO_MEMORY);
284 return B_NO_MEMORY;
286 TrackSupplierReleaser trackSupplierReleaser(fItem);
288 status_t err = trackSupplier->InitCheck();
289 if (err != B_OK) {
290 printf("Controller::SetTo: InitCheck failed\n");
291 _NotifyFileChanged(item.Get(), err);
292 return err;
295 if (trackSupplier->CountAudioTracks() == 0
296 && trackSupplier->CountVideoTracks() == 0) {
297 _NotifyFileChanged(item.Get(), B_MEDIA_NO_HANDLER);
298 return B_MEDIA_NO_HANDLER;
301 SelectAudioTrack(0);
302 SelectVideoTrack(0);
304 if (fAudioTrackSupplier == NULL && fVideoTrackSupplier == NULL) {
305 printf("Controller::SetTo: no audio or video tracks found or "
306 "no decoders\n");
307 _NotifyFileChanged(item.Get(), B_MEDIA_NO_HANDLER);
308 return B_MEDIA_NO_HANDLER;
311 trackSupplierReleaser.Detach();
313 // prevent blocking the creation of new overlay buffers
314 if (fVideoView)
315 fVideoView->DisableOverlay();
317 // get video properties (if there is video at all)
318 bool useOverlays = fVideoView ? fVideoView->UseOverlays() : true;
320 int width;
321 int height;
322 GetSize(&width, &height);
323 color_space preferredVideoFormat = B_NO_COLOR_SPACE;
324 if (fVideoTrackSupplier != NULL) {
325 const media_format& format = fVideoTrackSupplier->Format();
326 preferredVideoFormat = format.u.raw_video.display.format;
329 uint32 enabledNodes;
330 if (!fVideoTrackSupplier)
331 enabledNodes = AUDIO_ONLY;
332 else if (!fAudioTrackSupplier)
333 enabledNodes = VIDEO_ONLY;
334 else
335 enabledNodes = AUDIO_AND_VIDEO;
337 float audioFrameRate = 44100.0f;
338 uint32 audioChannels = 2;
339 if (fAudioTrackSupplier != NULL) {
340 const media_format& audioTrackFormat = fAudioTrackSupplier->Format();
341 audioFrameRate = audioTrackFormat.u.raw_audio.frame_rate;
342 audioChannels = audioTrackFormat.u.raw_audio.channel_count;
345 if (InitCheck() != B_OK) {
346 Init(BRect(0, 0, width - 1, height - 1), fVideoFrameRate,
347 preferredVideoFormat, audioFrameRate, audioChannels, LOOPING_ALL,
348 false, 1.0, enabledNodes, useOverlays);
349 } else {
350 FormatChanged(BRect(0, 0, width - 1, height - 1), fVideoFrameRate,
351 preferredVideoFormat, audioFrameRate, audioChannels, enabledNodes,
352 useOverlays);
355 _NotifyFileChanged(item.Get(), B_OK);
357 if (fAutoplay)
358 StartPlaying(true);
360 return B_OK;
364 void
365 Controller::PlayerActivated(bool active)
367 if (LockWithTimeout(5000) != B_OK)
368 return;
370 if (active && gMainApp->PlayerCount() > 1) {
371 if (fActiveVolume != fVolume)
372 SetVolume(fActiveVolume);
373 } else {
374 fActiveVolume = fVolume;
375 if (gMainApp->PlayerCount() > 1)
376 switch (fBackgroundMovieVolumeMode) {
377 case mpSettings::BG_MOVIES_MUTED:
378 SetVolume(0.0);
379 break;
380 case mpSettings::BG_MOVIES_HALF_VLUME:
381 SetVolume(fVolume * 0.25);
382 break;
383 case mpSettings::BG_MOVIES_FULL_VOLUME:
384 default:
385 break;
389 Unlock();
393 void
394 Controller::GetSize(int *width, int *height, int* _widthAspect,
395 int* _heightAspect)
397 BAutolock _(this);
399 if (fVideoTrackSupplier) {
400 media_format format = fVideoTrackSupplier->Format();
401 *height = format.u.raw_video.display.line_count;
402 *width = format.u.raw_video.display.line_width;
403 int widthAspect = 0;
404 int heightAspect = 0;
405 // Ignore format aspect when both values are 1. If they have been
406 // intentionally at 1:1 then no harm is done for quadratic videos,
407 // only if the video is indeed encoded anamorphotic, but supposed
408 // to be displayed quadratic... extremely unlikely.
409 if (format.u.raw_video.pixel_width_aspect
410 != format.u.raw_video.pixel_height_aspect
411 && format.u.raw_video.pixel_width_aspect != 1) {
412 widthAspect = format.u.raw_video.pixel_width_aspect;
413 heightAspect = format.u.raw_video.pixel_height_aspect;
415 if (_widthAspect != NULL)
416 *_widthAspect = widthAspect;
417 if (_heightAspect != NULL)
418 *_heightAspect = heightAspect;
419 } else {
420 *height = 0;
421 *width = 0;
422 if (_widthAspect != NULL)
423 *_widthAspect = 1;
424 if (_heightAspect != NULL)
425 *_heightAspect = 1;
431 Controller::AudioTrackCount()
433 BAutolock _(this);
435 if (fItem != NULL && fItem->HasTrackSupplier())
436 return fItem->GetTrackSupplier()->CountAudioTracks();
437 return 0;
442 Controller::VideoTrackCount()
444 BAutolock _(this);
446 if (fItem != NULL && fItem->HasTrackSupplier())
447 return fItem->GetTrackSupplier()->CountVideoTracks();
448 return 0;
453 Controller::SubTitleTrackCount()
455 BAutolock _(this);
457 if (fItem != NULL && fItem->HasTrackSupplier())
458 return fItem->GetTrackSupplier()->CountSubTitleTracks();
459 return 0;
463 status_t
464 Controller::SelectAudioTrack(int n)
466 BAutolock _(this);
467 if (fItem == NULL || !fItem->HasTrackSupplier())
468 return B_NO_INIT;
470 ObjectDeleter<AudioTrackSupplier> deleter(fAudioTrackSupplier);
471 fAudioTrackSupplier
472 = fItem->GetTrackSupplier()->CreateAudioTrackForIndex(n);
473 if (fAudioTrackSupplier == NULL)
474 return B_BAD_INDEX;
476 bigtime_t a = fAudioTrackSupplier->Duration();
477 bigtime_t v = fVideoTrackSupplier != NULL
478 ? fVideoTrackSupplier->Duration() : 0;
479 fDuration = max_c(a, v);
480 DurationChanged();
481 // TODO: notify duration changed!
483 fAudioSupplier->SetSupplier(fAudioTrackSupplier, fVideoFrameRate);
485 _NotifyAudioTrackChanged(n);
486 return B_OK;
491 Controller::CurrentAudioTrack()
493 BAutolock _(this);
495 if (fAudioTrackSupplier == NULL)
496 return -1;
498 return fAudioTrackSupplier->TrackIndex();
503 Controller::AudioTrackChannelCount()
505 media_format format;
506 if (GetEncodedAudioFormat(&format) == B_OK)
507 return format.u.encoded_audio.output.channel_count;
509 return 2;
513 status_t
514 Controller::SelectVideoTrack(int n)
516 BAutolock _(this);
518 if (fItem == NULL || !fItem->HasTrackSupplier())
519 return B_NO_INIT;
521 ObjectDeleter<VideoTrackSupplier> deleter(fVideoTrackSupplier);
522 fVideoTrackSupplier
523 = fItem->GetTrackSupplier()->CreateVideoTrackForIndex(n);
524 if (fVideoTrackSupplier == NULL)
525 return B_BAD_INDEX;
527 bigtime_t a = fAudioTrackSupplier ? fAudioTrackSupplier->Duration() : 0;
528 bigtime_t v = fVideoTrackSupplier->Duration();
529 fDuration = max_c(a, v);
530 fVideoFrameRate = fVideoTrackSupplier->Format().u.raw_video.field_rate;
531 if (fVideoFrameRate <= 0.0) {
532 printf("Controller::SelectVideoTrack(%d) - invalid video frame rate: %.1f\n",
533 n, fVideoFrameRate);
534 fVideoFrameRate = 25.0;
537 DurationChanged();
538 // TODO: notify duration changed!
540 fVideoSupplier->SetSupplier(fVideoTrackSupplier);
542 _NotifyVideoTrackChanged(n);
543 return B_OK;
548 Controller::CurrentVideoTrack()
550 BAutolock _(this);
552 if (fVideoTrackSupplier == NULL)
553 return -1;
555 return fVideoTrackSupplier->TrackIndex();
559 status_t
560 Controller::SelectSubTitleTrack(int n)
562 BAutolock _(this);
564 if (fItem == NULL || !fItem->HasTrackSupplier())
565 return B_NO_INIT;
567 fSubTitlesIndex = n;
568 fSubTitles =
569 fItem->GetTrackSupplier()->SubTitleTrackForIndex(n);
571 const SubTitle* subTitle = NULL;
572 if (fSubTitles != NULL)
573 subTitle = fSubTitles->SubTitleAt(_TimePosition());
574 if (subTitle != NULL)
575 fVideoView->SetSubTitle(subTitle->text.String());
576 else
577 fVideoView->SetSubTitle(NULL);
579 _NotifySubTitleTrackChanged(n);
580 return B_OK;
585 Controller::CurrentSubTitleTrack()
587 BAutolock _(this);
589 if (fSubTitles == NULL)
590 return -1;
592 return fSubTitlesIndex;
596 const char*
597 Controller::SubTitleTrackName(int n)
599 BAutolock _(this);
601 if (fItem == NULL || !fItem->HasTrackSupplier())
602 return NULL;
604 const SubTitles* subTitles
605 = fItem->GetTrackSupplier()->SubTitleTrackForIndex(n);
606 if (subTitles == NULL)
607 return NULL;
609 return subTitles->Name();
613 // #pragma mark -
616 void
617 Controller::Stop()
619 //printf("Controller::Stop\n");
621 BAutolock _(this);
623 StopPlaying();
624 SetPosition(0.0);
626 fAutoplay = fAutoplaySetting;
630 void
631 Controller::Play()
633 //printf("Controller::Play\n");
635 BAutolock _(this);
637 StartPlaying();
638 fAutoplay = true;
642 void
643 Controller::Pause()
645 // printf("Controller::Pause\n");
647 BAutolock _(this);
649 PausePlaying();
651 fAutoplay = fAutoplaySetting;
655 void
656 Controller::TogglePlaying()
658 // printf("Controller::TogglePlaying\n");
660 BAutolock _(this);
662 if (InitCheck() == B_OK) {
663 NodeManager::TogglePlaying();
665 fAutoplay = IsPlaying() || fAutoplaySetting;
670 uint32
671 Controller::PlaybackState()
673 BAutolock _(this);
675 return _PlaybackState(PlaybackManager::PlayMode());
679 bigtime_t
680 Controller::TimeDuration()
682 BAutolock _(this);
684 return fDuration;
688 bigtime_t
689 Controller::TimePosition()
691 BAutolock _(this);
693 return _TimePosition();
697 void
698 Controller::SetVolume(float value)
700 // printf("Controller::SetVolume %.4f\n", value);
701 BAutolock _(this);
703 value = max_c(0.0, min_c(2.0, value));
705 if (fVolume != value) {
706 if (fMuted)
707 ToggleMute();
709 fVolume = value;
710 fAudioSupplier->SetVolume(fVolume);
712 _NotifyVolumeChanged(fVolume);
716 void
717 Controller::VolumeUp()
719 // TODO: linear <-> exponential
720 SetVolume(Volume() + 0.05);
723 void
724 Controller::VolumeDown()
726 // TODO: linear <-> exponential
727 SetVolume(Volume() - 0.05);
730 void
731 Controller::ToggleMute()
733 BAutolock _(this);
735 fMuted = !fMuted;
737 if (fMuted)
738 fAudioSupplier->SetVolume(0.0);
739 else
740 fAudioSupplier->SetVolume(fVolume);
742 _NotifyMutedChanged(fMuted);
746 float
747 Controller::Volume()
749 BAutolock _(this);
751 return fVolume;
755 int64
756 Controller::SetPosition(float value)
758 BAutolock _(this);
760 return SetFramePosition(_FrameDuration() * value);
764 int64
765 Controller::SetFramePosition(int64 value)
767 BAutolock _(this);
769 fPendingSeekRequests++;
770 fRequestedSeekFrame = max_c(0, min_c(_FrameDuration(), value));
771 fSeekFrame = fRequestedSeekFrame;
773 int64 currentFrame = CurrentFrame();
775 // Snap to a video keyframe, since that will be the fastest
776 // to display and seeking will feel more snappy. Note that we
777 // don't store this change in fSeekFrame, since we still want
778 // to report the originally requested seek frame in TimePosition()
779 // until we could reach that frame.
780 if (Duration() > 240 && fVideoTrackSupplier != NULL
781 && abs(value - currentFrame) > 5) {
782 fVideoTrackSupplier->FindKeyFrameForFrame(&fSeekFrame);
785 //printf("SetFramePosition(%lld) -> %lld (current: %lld, duration: %lld) "
786 //"(video: %p)\n", value, fSeekFrame, currentFrame, _FrameDuration(),
787 //fVideoTrackSupplier);
788 if (fSeekFrame != currentFrame) {
789 int64 seekFrame = fSeekFrame;
790 SetCurrentFrame(fSeekFrame);
791 // May trigger the notification and reset fSeekFrame,
792 // if next current frame == seek frame.
793 return seekFrame;
794 } else
795 NotifySeekHandled(fRequestedSeekFrame);
796 return currentFrame;
800 int64
801 Controller::SetTimePosition(bigtime_t value)
803 BAutolock _(this);
805 return SetPosition((float)value / TimeDuration());
809 // #pragma mark -
812 bool
813 Controller::HasFile()
815 // you need to hold the data lock
816 return fItem != NULL && fItem->HasTrackSupplier();
820 status_t
821 Controller::GetFileFormatInfo(media_file_format* fileFormat)
823 // you need to hold the data lock
824 if (fItem == NULL || !fItem->HasTrackSupplier())
825 return B_NO_INIT;
826 return fItem->GetTrackSupplier()->GetFileFormatInfo(fileFormat);
830 status_t
831 Controller::GetCopyright(BString* copyright)
833 // you need to hold the data lock
834 if (fItem == NULL || !fItem->HasTrackSupplier())
835 return B_NO_INIT;
836 return fItem->GetTrackSupplier()->GetCopyright(copyright);
840 status_t
841 Controller::GetLocation(BString* location)
843 // you need to hold the data lock
844 if (fItem.Get() == NULL)
845 return B_NO_INIT;
846 *location = fItem->LocationURI();
847 return B_OK;
851 status_t
852 Controller::GetName(BString* name)
854 // you need to hold the data lock
855 if (fItem.Get() == NULL)
856 return B_NO_INIT;
857 *name = fItem->Name();
858 return B_OK;
862 status_t
863 Controller::GetEncodedVideoFormat(media_format* format)
865 // you need to hold the data lock
866 if (fVideoTrackSupplier)
867 return fVideoTrackSupplier->GetEncodedFormat(format);
868 return B_NO_INIT;
872 status_t
873 Controller::GetVideoCodecInfo(media_codec_info* info)
875 // you need to hold the data lock
876 if (fVideoTrackSupplier)
877 return fVideoTrackSupplier->GetCodecInfo(info);
878 return B_NO_INIT;
882 status_t
883 Controller::GetEncodedAudioFormat(media_format* format)
885 // you need to hold the data lock
886 if (fAudioTrackSupplier)
887 return fAudioTrackSupplier->GetEncodedFormat(format);
888 return B_NO_INIT;
892 status_t
893 Controller::GetAudioCodecInfo(media_codec_info* info)
895 // you need to hold the data lock
896 if (fAudioTrackSupplier)
897 return fAudioTrackSupplier->GetCodecInfo(info);
898 return B_NO_INIT;
902 status_t
903 Controller::GetMetaData(BMessage* metaData)
905 // you need to hold the data lock
906 if (fItem == NULL || !fItem->HasTrackSupplier())
907 return B_NO_INIT;
908 return fItem->GetTrackSupplier()->GetMetaData(metaData);
912 status_t
913 Controller::GetVideoMetaData(int32 index, BMessage* metaData)
915 // you need to hold the data lock
916 if (fItem == NULL || !fItem->HasTrackSupplier())
917 return B_NO_INIT;
918 return fItem->GetTrackSupplier()->GetVideoMetaData(index, metaData);
922 status_t
923 Controller::GetAudioMetaData(int32 index, BMessage* metaData)
925 // you need to hold the data lock
926 if (fItem == NULL || !fItem->HasTrackSupplier())
927 return B_NO_INIT;
928 return fItem->GetTrackSupplier()->GetAudioMetaData(index, metaData);
932 // #pragma mark -
935 void
936 Controller::SetVideoView(VideoView *view)
938 BAutolock _(this);
940 fVideoView = view;
944 bool
945 Controller::IsOverlayActive()
947 if (fVideoView)
948 return fVideoView->IsOverlayActive();
950 return false;
954 // #pragma mark -
957 bool
958 Controller::AddListener(Listener* listener)
960 BAutolock _(this);
962 if (listener && !fListeners.HasItem(listener))
963 return fListeners.AddItem(listener);
964 return false;
968 void
969 Controller::RemoveListener(Listener* listener)
971 BAutolock _(this);
973 fListeners.RemoveItem(listener);
977 // #pragma mark - Private
980 void
981 Controller::_AdoptGlobalSettings()
983 mpSettings settings;
984 Settings::Default()->Get(settings);
986 fAutoplaySetting = settings.autostart;
987 // not yet used:
988 fLoopMovies = settings.loopMovie;
989 fLoopSounds = settings.loopSound;
990 fBackgroundMovieVolumeMode = settings.backgroundMovieVolumeMode;
994 uint32
995 Controller::_PlaybackState(int32 playingMode) const
997 uint32 state = 0;
998 switch (playingMode) {
999 case MODE_PLAYING_PAUSED_FORWARD:
1000 case MODE_PLAYING_PAUSED_BACKWARD:
1001 state = PLAYBACK_STATE_PAUSED;
1002 break;
1003 case MODE_PLAYING_FORWARD:
1004 case MODE_PLAYING_BACKWARD:
1005 state = PLAYBACK_STATE_PLAYING;
1006 break;
1008 default:
1009 state = PLAYBACK_STATE_STOPPED;
1010 break;
1012 return state;
1016 bigtime_t
1017 Controller::_TimePosition() const
1019 if (fDuration == 0)
1020 return 0;
1022 // Check if we are still waiting to reach the seekframe,
1023 // pass the last pending seek frame back to the caller, so
1024 // that the view of the current frame/time from the outside
1025 // does not depend on the internal latency to reach requested
1026 // frames asynchronously.
1027 int64 frame;
1028 if (fPendingSeekRequests > 0)
1029 frame = fRequestedSeekFrame;
1030 else
1031 frame = fCurrentFrame;
1033 return frame * fDuration / _FrameDuration();
1037 int64
1038 Controller::_FrameDuration() const
1040 // This should really be total frames (video frames at that)
1041 // TODO: It is not so nice that the MediaPlayer still measures
1042 // in video frames if only playing audio. Here for example, it will
1043 // return a duration of 0 if the audio clip happens to be shorter than
1044 // one video frame at 25 fps.
1045 return (int64)((double)fDuration * fVideoFrameRate / 1000000.0);
1049 // #pragma mark - Notifications
1052 void
1053 Controller::_NotifyFileChanged(PlaylistItem* item, status_t result) const
1055 BList listeners(fListeners);
1056 int32 count = listeners.CountItems();
1057 for (int32 i = 0; i < count; i++) {
1058 Listener* listener = (Listener*)listeners.ItemAtFast(i);
1059 listener->FileChanged(item, result);
1064 void
1065 Controller::_NotifyFileFinished() 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->FileFinished();
1076 void
1077 Controller::_NotifyVideoTrackChanged(int32 index) 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->VideoTrackChanged(index);
1088 void
1089 Controller::_NotifyAudioTrackChanged(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->AudioTrackChanged(index);
1100 void
1101 Controller::_NotifySubTitleTrackChanged(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->SubTitleTrackChanged(index);
1112 void
1113 Controller::_NotifyVideoStatsChanged() 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->VideoStatsChanged();
1124 void
1125 Controller::_NotifyAudioStatsChanged() 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->AudioStatsChanged();
1136 void
1137 Controller::_NotifyPlaybackStateChanged(uint32 state) 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->PlaybackStateChanged(state);
1148 void
1149 Controller::_NotifyPositionChanged(float position) 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->PositionChanged(position);
1160 void
1161 Controller::_NotifySeekHandled(int64 seekFrame) 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->SeekHandled(seekFrame);
1172 void
1173 Controller::_NotifyVolumeChanged(float volume) 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->VolumeChanged(volume);
1184 void
1185 Controller::_NotifyMutedChanged(bool muted) 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->MutedChanged(muted);
1196 void
1197 Controller::NotifyPlayModeChanged(int32 mode) const
1199 uint32 state = _PlaybackState(mode);
1200 if (fVideoView)
1201 fVideoView->SetPlaying(state == PLAYBACK_STATE_PLAYING);
1202 _NotifyPlaybackStateChanged(state);
1206 void
1207 Controller::NotifyLoopModeChanged(int32 mode) const
1212 void
1213 Controller::NotifyLoopingEnabledChanged(bool enabled) const
1218 void
1219 Controller::NotifyVideoBoundsChanged(BRect bounds) const
1224 void
1225 Controller::NotifyFPSChanged(float fps) const
1230 void
1231 Controller::NotifyCurrentFrameChanged(int64 frame) const
1233 fCurrentFrame = frame;
1234 bigtime_t timePosition = _TimePosition();
1235 _NotifyPositionChanged((float)timePosition / fDuration);
1237 if (fSubTitles != NULL) {
1238 const SubTitle* subTitle = fSubTitles->SubTitleAt(timePosition);
1239 if (subTitle != NULL)
1240 fVideoView->SetSubTitle(subTitle->text.String());
1241 else
1242 fVideoView->SetSubTitle(NULL);
1247 void
1248 Controller::NotifySpeedChanged(float speed) const
1253 void
1254 Controller::NotifyFrameDropped() const
1256 // printf("Controller::NotifyFrameDropped()\n");
1260 void
1261 Controller::NotifyStopFrameReached() const
1263 // Currently, this means we reached the end of the current
1264 // file and should play the next file
1265 _NotifyFileFinished();
1269 void
1270 Controller::NotifySeekHandled(int64 seekedFrame) const
1272 if (fPendingSeekRequests == 0)
1273 return;
1275 fPendingSeekRequests--;
1276 if (fPendingSeekRequests == 0) {
1277 fSeekFrame = -1;
1278 fRequestedSeekFrame = -1;
1281 _NotifySeekHandled(seekedFrame);