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