xref: /haiku/src/apps/mediaplayer/Controller.cpp (revision 3995592cdf304335132305e27c40cbb0b1ac46e3)
1 /*
2  * Controller.cpp - Media Player for the Haiku Operating System
3  *
4  * Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de>
5  * Copyright (C) 2007-2008 Stephan Aßmus <superstippi@gmx.de>
6  * Copyright (C) 2007-2009 Fredrik Modéen <[FirstName]@[LastName].se>
7  *
8  * Released under the terms of the MIT license.
9  */
10 
11 
12 #include "Controller.h"
13 
14 #include <new>
15 #include <stdio.h>
16 #include <string.h>
17 
18 #include <Autolock.h>
19 #include <Bitmap.h>
20 #include <Debug.h>
21 #include <Path.h>
22 #include <Window.h> // for debugging only
23 
24 #include "AutoDeleter.h"
25 #include "ControllerView.h"
26 #include "MainApp.h"
27 #include "PlaybackState.h"
28 #include "Settings.h"
29 #include "VideoView.h"
30 
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"
40 
41 using std::nothrow;
42 
43 
44 class TrackSupplierReleaser {
45 public:
46 	TrackSupplierReleaser(PlaylistItemRef& owner)
47 		:
48 		fOwner(owner),
49 		fRelease(true)
50 		{}
51 
52 	virtual ~TrackSupplierReleaser()
53 	{
54 		if (fRelease)
55 			fOwner.Get()->ReleaseTrackSupplier();
56 	}
57 
58 	void Detach()
59 	{
60 		fRelease = false;
61 	}
62 
63 private:
64 	PlaylistItemRef&	fOwner;
65 	bool				fRelease;
66 };
67 
68 
69 void
70 HandleError(const char *text, status_t err)
71 {
72 	if (err != B_OK) {
73 		printf("%s. error 0x%08x (%s)\n",text, (int)err, strerror(err));
74 		fflush(NULL);
75 		exit(1);
76 	}
77 }
78 
79 
80 // #pragma mark - Controller::Listener
81 
82 
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) {}
97 
98 
99 // #pragma mark - Controller
100 
101 
102 enum {
103 	MSG_SET_TO = 'stto'
104 };
105 
106 
107 Controller::Controller()
108 	:
109 	NodeManager(),
110 	fVideoView(NULL),
111 	fVolume(1.0),
112 	fActiveVolume(1.0),
113 	fMuted(false),
114 
115 	fItem(NULL),
116 
117 	fVideoSupplier(new ProxyVideoSupplier()),
118 	fAudioSupplier(new ProxyAudioSupplier(this)),
119 	fVideoTrackSupplier(NULL),
120 	fAudioTrackSupplier(NULL),
121 	fSubTitles(NULL),
122 	fSubTitlesIndex(-1),
123 
124 	fCurrentFrame(0),
125 	fDuration(0),
126 	fVideoFrameRate(25.0),
127 
128 	fPendingSeekRequests(0),
129 	fSeekFrame(-1),
130 	fRequestedSeekFrame(-1),
131 
132 	fGlobalSettingsListener(this),
133 
134 	fListeners(4)
135 {
136 	Settings::Default()->AddListener(&fGlobalSettingsListener);
137 	_AdoptGlobalSettings();
138 
139 	fAutoplay = fAutoplaySetting;
140 }
141 
142 
143 Controller::~Controller()
144 {
145 	Settings::Default()->RemoveListener(&fGlobalSettingsListener);
146 	SetTo(NULL);
147 }
148 
149 
150 // #pragma mark - NodeManager interface
151 
152 
153 void
154 Controller::MessageReceived(BMessage* message)
155 {
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;
163 
164 		case MSG_SET_TO:
165 		{
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);
173 
174 			break;
175 		}
176 
177 		default:
178 			NodeManager::MessageReceived(message);
179 	}
180 }
181 
182 
183 int64
184 Controller::Duration()
185 {
186 	return _FrameDuration();
187 }
188 
189 
190 VideoTarget*
191 Controller::CreateVideoTarget()
192 {
193 	return fVideoView;
194 }
195 
196 
197 VideoSupplier*
198 Controller::CreateVideoSupplier()
199 {
200 	return fVideoSupplier;
201 }
202 
203 
204 AudioSupplier*
205 Controller::CreateAudioSupplier()
206 {
207 	return fAudioSupplier;
208 }
209 
210 
211 // #pragma mark -
212 
213 
214 status_t
215 Controller::SetToAsync(const PlaylistItemRef& item)
216 {
217 	PlaylistItemRef additionalReference(item);
218 
219 	BMessage message(MSG_SET_TO);
220 	status_t ret = message.AddPointer("item", item.Get());
221 	if (ret != B_OK)
222 		return ret;
223 
224 	ret = PostMessage(&message);
225 	if (ret != B_OK)
226 		return ret;
227 
228 	// The additional reference is now passed along with the message...
229 	additionalReference.Detach();
230 
231 	return B_OK;
232 }
233 
234 
235 status_t
236 Controller::SetTo(const PlaylistItemRef& item)
237 {
238 	BAutolock _(this);
239 
240 	if (fItem == item) {
241 		if (InitCheck() == B_OK) {
242 			if (fAutoplay) {
243 				SetPosition(0.0);
244 				StartPlaying(true);
245 			}
246 		}
247 		return B_OK;
248 	}
249 
250 	fAudioSupplier->SetSupplier(NULL, fVideoFrameRate);
251 	fVideoSupplier->SetSupplier(NULL);
252 
253 	if (fItem != NULL)
254 		TrackSupplierReleaser oldSupplierReleaser(fItem);
255 
256 	fItem = item;
257 
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);
264 
265 	fVideoTrackSupplier = NULL;
266 	fAudioTrackSupplier = NULL;
267 	fSubTitles = NULL;
268 	fSubTitlesIndex = -1;
269 
270 	fCurrentFrame = 0;
271 	fDuration = 0;
272 	fVideoFrameRate = 25.0;
273 
274 	fPendingSeekRequests = 0;
275 	fSeekFrame = -1;
276 	fRequestedSeekFrame = -1;
277 
278 	if (fItem.Get() == NULL)
279 		return B_BAD_VALUE;
280 
281 	TrackSupplier* trackSupplier = fItem->GetTrackSupplier();
282 	if (trackSupplier == NULL) {
283 		_NotifyFileChanged(item.Get(), B_NO_MEMORY);
284 		return B_NO_MEMORY;
285 	}
286 	TrackSupplierReleaser trackSupplierReleaser(fItem);
287 
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;
293 	}
294 
295 	if (trackSupplier->CountAudioTracks() == 0
296 		&& trackSupplier->CountVideoTracks() == 0) {
297 		_NotifyFileChanged(item.Get(), B_MEDIA_NO_HANDLER);
298 		return B_MEDIA_NO_HANDLER;
299 	}
300 
301 	SelectAudioTrack(0);
302 	SelectVideoTrack(0);
303 
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;
309 	}
310 
311 	trackSupplierReleaser.Detach();
312 
313 	// prevent blocking the creation of new overlay buffers
314 	if (fVideoView)
315 		fVideoView->DisableOverlay();
316 
317 	// get video properties (if there is video at all)
318 	bool useOverlays = fVideoView ? fVideoView->UseOverlays() : true;
319 
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;
327 	}
328 
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;
336 
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;
343 	}
344 
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);
353 	}
354 
355 	_NotifyFileChanged(item.Get(), B_OK);
356 
357 	if (fAutoplay)
358 		StartPlaying(true);
359 
360 	return B_OK;
361 }
362 
363 
364 void
365 Controller::PlayerActivated(bool active)
366 {
367 	if (LockWithTimeout(5000) != B_OK)
368 		return;
369 
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;
386 			}
387 	}
388 
389 	Unlock();
390 }
391 
392 
393 void
394 Controller::GetSize(int *width, int *height, int* _widthAspect,
395 	int* _heightAspect)
396 {
397 	BAutolock _(this);
398 
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;
414 		}
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;
426 	}
427 }
428 
429 
430 int
431 Controller::AudioTrackCount()
432 {
433 	BAutolock _(this);
434 
435 	if (fItem != NULL && fItem->HasTrackSupplier())
436 		return fItem->GetTrackSupplier()->CountAudioTracks();
437 	return 0;
438 }
439 
440 
441 int
442 Controller::VideoTrackCount()
443 {
444 	BAutolock _(this);
445 
446 	if (fItem != NULL && fItem->HasTrackSupplier())
447 		return fItem->GetTrackSupplier()->CountVideoTracks();
448 	return 0;
449 }
450 
451 
452 int
453 Controller::SubTitleTrackCount()
454 {
455 	BAutolock _(this);
456 
457 	if (fItem != NULL && fItem->HasTrackSupplier())
458 		return fItem->GetTrackSupplier()->CountSubTitleTracks();
459 	return 0;
460 }
461 
462 
463 status_t
464 Controller::SelectAudioTrack(int n)
465 {
466 	BAutolock _(this);
467 	if (fItem == NULL || !fItem->HasTrackSupplier())
468 		return B_NO_INIT;
469 
470 	ObjectDeleter<AudioTrackSupplier> deleter(fAudioTrackSupplier);
471 	fAudioTrackSupplier
472 		= fItem->GetTrackSupplier()->CreateAudioTrackForIndex(n);
473 	if (fAudioTrackSupplier == NULL)
474 		return B_BAD_INDEX;
475 
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!
482 
483 	fAudioSupplier->SetSupplier(fAudioTrackSupplier, fVideoFrameRate);
484 
485 	_NotifyAudioTrackChanged(n);
486 	return B_OK;
487 }
488 
489 
490 int
491 Controller::CurrentAudioTrack()
492 {
493 	BAutolock _(this);
494 
495 	if (fAudioTrackSupplier == NULL)
496 		return -1;
497 
498 	return fAudioTrackSupplier->TrackIndex();
499 }
500 
501 
502 int
503 Controller::AudioTrackChannelCount()
504 {
505 	media_format format;
506 	if (GetEncodedAudioFormat(&format) == B_OK)
507 		return format.u.encoded_audio.output.channel_count;
508 
509 	return 2;
510 }
511 
512 
513 status_t
514 Controller::SelectVideoTrack(int n)
515 {
516 	BAutolock _(this);
517 
518 	if (fItem == NULL || !fItem->HasTrackSupplier())
519 		return B_NO_INIT;
520 
521 	ObjectDeleter<VideoTrackSupplier> deleter(fVideoTrackSupplier);
522 	fVideoTrackSupplier
523 		= fItem->GetTrackSupplier()->CreateVideoTrackForIndex(n);
524 	if (fVideoTrackSupplier == NULL)
525 		return B_BAD_INDEX;
526 
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;
535 	}
536 
537 	DurationChanged();
538 	// TODO: notify duration changed!
539 
540 	fVideoSupplier->SetSupplier(fVideoTrackSupplier);
541 
542 	_NotifyVideoTrackChanged(n);
543 	return B_OK;
544 }
545 
546 
547 int
548 Controller::CurrentVideoTrack()
549 {
550 	BAutolock _(this);
551 
552 	if (fVideoTrackSupplier == NULL)
553 		return -1;
554 
555 	return fVideoTrackSupplier->TrackIndex();
556 }
557 
558 
559 status_t
560 Controller::SelectSubTitleTrack(int n)
561 {
562 	BAutolock _(this);
563 
564 	if (fItem == NULL || !fItem->HasTrackSupplier())
565 		return B_NO_INIT;
566 
567 	fSubTitlesIndex = n;
568 	fSubTitles =
569 		fItem->GetTrackSupplier()->SubTitleTrackForIndex(n);
570 
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);
578 
579 	_NotifySubTitleTrackChanged(n);
580 	return B_OK;
581 }
582 
583 
584 int
585 Controller::CurrentSubTitleTrack()
586 {
587 	BAutolock _(this);
588 
589 	if (fSubTitles == NULL)
590 		return -1;
591 
592 	return fSubTitlesIndex;
593 }
594 
595 
596 const char*
597 Controller::SubTitleTrackName(int n)
598 {
599 	BAutolock _(this);
600 
601 	if (fItem == NULL || !fItem->HasTrackSupplier())
602 		return NULL;
603 
604 	const SubTitles* subTitles
605 		= fItem->GetTrackSupplier()->SubTitleTrackForIndex(n);
606 	if (subTitles == NULL)
607 		return NULL;
608 
609 	return subTitles->Name();
610 }
611 
612 
613 // #pragma mark -
614 
615 
616 void
617 Controller::Stop()
618 {
619 	//printf("Controller::Stop\n");
620 
621 	BAutolock _(this);
622 
623 	StopPlaying();
624 	SetPosition(0.0);
625 
626 	fAutoplay = fAutoplaySetting;
627 }
628 
629 
630 void
631 Controller::Play()
632 {
633 	//printf("Controller::Play\n");
634 
635 	BAutolock _(this);
636 
637 	StartPlaying();
638 	fAutoplay = true;
639 }
640 
641 
642 void
643 Controller::Pause()
644 {
645 //	printf("Controller::Pause\n");
646 
647 	BAutolock _(this);
648 
649 	PausePlaying();
650 
651 	fAutoplay = fAutoplaySetting;
652 }
653 
654 
655 void
656 Controller::TogglePlaying()
657 {
658 //	printf("Controller::TogglePlaying\n");
659 
660 	BAutolock _(this);
661 
662 	if (InitCheck() == B_OK) {
663 		NodeManager::TogglePlaying();
664 
665 		fAutoplay = IsPlaying() || fAutoplaySetting;
666 	}
667 }
668 
669 
670 uint32
671 Controller::PlaybackState()
672 {
673 	BAutolock _(this);
674 
675 	return _PlaybackState(PlaybackManager::PlayMode());
676 }
677 
678 
679 bigtime_t
680 Controller::TimeDuration()
681 {
682 	BAutolock _(this);
683 
684 	return fDuration;
685 }
686 
687 
688 bigtime_t
689 Controller::TimePosition()
690 {
691 	BAutolock _(this);
692 
693 	return _TimePosition();
694 }
695 
696 
697 void
698 Controller::SetVolume(float value)
699 {
700 //	printf("Controller::SetVolume %.4f\n", value);
701 	BAutolock _(this);
702 
703 	value = max_c(0.0, min_c(2.0, value));
704 
705 	if (fVolume != value) {
706 		if (fMuted)
707 			ToggleMute();
708 
709 		fVolume = value;
710 		fAudioSupplier->SetVolume(fVolume);
711 
712 		_NotifyVolumeChanged(fVolume);
713 	}
714 }
715 
716 void
717 Controller::VolumeUp()
718 {
719 	// TODO: linear <-> exponential
720 	SetVolume(Volume() + 0.05);
721 }
722 
723 void
724 Controller::VolumeDown()
725 {
726 	// TODO: linear <-> exponential
727 	SetVolume(Volume() - 0.05);
728 }
729 
730 void
731 Controller::ToggleMute()
732 {
733 	BAutolock _(this);
734 
735 	fMuted = !fMuted;
736 
737 	if (fMuted)
738 		fAudioSupplier->SetVolume(0.0);
739 	else
740 		fAudioSupplier->SetVolume(fVolume);
741 
742 	_NotifyMutedChanged(fMuted);
743 }
744 
745 
746 float
747 Controller::Volume()
748 {
749 	BAutolock _(this);
750 
751 	return fVolume;
752 }
753 
754 
755 int64
756 Controller::SetPosition(float value)
757 {
758 	BAutolock _(this);
759 
760 	return SetFramePosition(_FrameDuration() * value);
761 }
762 
763 
764 int64
765 Controller::SetFramePosition(int64 value)
766 {
767 	BAutolock _(this);
768 
769 	fPendingSeekRequests++;
770 	fRequestedSeekFrame = max_c(0, min_c(_FrameDuration(), value));
771 	fSeekFrame = fRequestedSeekFrame;
772 
773 	int64 currentFrame = CurrentFrame();
774 
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);
783 	}
784 
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;
797 }
798 
799 
800 int64
801 Controller::SetTimePosition(bigtime_t value)
802 {
803 	BAutolock _(this);
804 
805 	return SetPosition((float)value / TimeDuration());
806 }
807 
808 
809 // #pragma mark -
810 
811 
812 bool
813 Controller::HasFile()
814 {
815 	// you need to hold the data lock
816 	return fItem != NULL && fItem->HasTrackSupplier();
817 }
818 
819 
820 status_t
821 Controller::GetFileFormatInfo(media_file_format* fileFormat)
822 {
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);
827 }
828 
829 
830 status_t
831 Controller::GetCopyright(BString* copyright)
832 {
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);
837 }
838 
839 
840 status_t
841 Controller::GetLocation(BString* location)
842 {
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;
848 }
849 
850 
851 status_t
852 Controller::GetName(BString* name)
853 {
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;
859 }
860 
861 
862 status_t
863 Controller::GetEncodedVideoFormat(media_format* format)
864 {
865 	// you need to hold the data lock
866 	if (fVideoTrackSupplier)
867 		return fVideoTrackSupplier->GetEncodedFormat(format);
868 	return B_NO_INIT;
869 }
870 
871 
872 status_t
873 Controller::GetVideoCodecInfo(media_codec_info* info)
874 {
875 	// you need to hold the data lock
876 	if (fVideoTrackSupplier)
877 		return fVideoTrackSupplier->GetCodecInfo(info);
878 	return B_NO_INIT;
879 }
880 
881 
882 status_t
883 Controller::GetEncodedAudioFormat(media_format* format)
884 {
885 	// you need to hold the data lock
886 	if (fAudioTrackSupplier)
887 		return fAudioTrackSupplier->GetEncodedFormat(format);
888 	return B_NO_INIT;
889 }
890 
891 
892 status_t
893 Controller::GetAudioCodecInfo(media_codec_info* info)
894 {
895 	// you need to hold the data lock
896 	if (fAudioTrackSupplier)
897 		return fAudioTrackSupplier->GetCodecInfo(info);
898 	return B_NO_INIT;
899 }
900 
901 
902 status_t
903 Controller::GetMetaData(BMessage* metaData)
904 {
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);
909 }
910 
911 
912 status_t
913 Controller::GetVideoMetaData(int32 index, BMessage* metaData)
914 {
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);
919 }
920 
921 
922 status_t
923 Controller::GetAudioMetaData(int32 index, BMessage* metaData)
924 {
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);
929 }
930 
931 
932 // #pragma mark -
933 
934 
935 void
936 Controller::SetVideoView(VideoView *view)
937 {
938 	BAutolock _(this);
939 
940 	fVideoView = view;
941 }
942 
943 
944 bool
945 Controller::IsOverlayActive()
946 {
947 	if (fVideoView)
948 		return fVideoView->IsOverlayActive();
949 
950 	return false;
951 }
952 
953 
954 // #pragma mark -
955 
956 
957 bool
958 Controller::AddListener(Listener* listener)
959 {
960 	BAutolock _(this);
961 
962 	if (listener && !fListeners.HasItem(listener))
963 		return fListeners.AddItem(listener);
964 	return false;
965 }
966 
967 
968 void
969 Controller::RemoveListener(Listener* listener)
970 {
971 	BAutolock _(this);
972 
973 	fListeners.RemoveItem(listener);
974 }
975 
976 
977 // #pragma mark - Private
978 
979 
980 void
981 Controller::_AdoptGlobalSettings()
982 {
983 	mpSettings settings;
984 	Settings::Default()->Get(settings);
985 
986 	fAutoplaySetting = settings.autostart;
987 	// not yet used:
988 	fLoopMovies = settings.loopMovie;
989 	fLoopSounds = settings.loopSound;
990 	fBackgroundMovieVolumeMode = settings.backgroundMovieVolumeMode;
991 }
992 
993 
994 uint32
995 Controller::_PlaybackState(int32 playingMode) const
996 {
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;
1007 
1008 		default:
1009 			state = PLAYBACK_STATE_STOPPED;
1010 			break;
1011 	}
1012 	return state;
1013 }
1014 
1015 
1016 bigtime_t
1017 Controller::_TimePosition() const
1018 {
1019 	if (fDuration == 0)
1020 		return 0;
1021 
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;
1032 
1033 	return frame * fDuration / _FrameDuration();
1034 }
1035 
1036 
1037 int64
1038 Controller::_FrameDuration() const
1039 {
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);
1046 }
1047 
1048 
1049 // #pragma mark - Notifications
1050 
1051 
1052 void
1053 Controller::_NotifyFileChanged(PlaylistItem* item, status_t result) const
1054 {
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);
1060 	}
1061 }
1062 
1063 
1064 void
1065 Controller::_NotifyFileFinished() const
1066 {
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();
1072 	}
1073 }
1074 
1075 
1076 void
1077 Controller::_NotifyVideoTrackChanged(int32 index) const
1078 {
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);
1084 	}
1085 }
1086 
1087 
1088 void
1089 Controller::_NotifyAudioTrackChanged(int32 index) const
1090 {
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);
1096 	}
1097 }
1098 
1099 
1100 void
1101 Controller::_NotifySubTitleTrackChanged(int32 index) const
1102 {
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);
1108 	}
1109 }
1110 
1111 
1112 void
1113 Controller::_NotifyVideoStatsChanged() const
1114 {
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();
1120 	}
1121 }
1122 
1123 
1124 void
1125 Controller::_NotifyAudioStatsChanged() const
1126 {
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();
1132 	}
1133 }
1134 
1135 
1136 void
1137 Controller::_NotifyPlaybackStateChanged(uint32 state) const
1138 {
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);
1144 	}
1145 }
1146 
1147 
1148 void
1149 Controller::_NotifyPositionChanged(float position) const
1150 {
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);
1156 	}
1157 }
1158 
1159 
1160 void
1161 Controller::_NotifySeekHandled(int64 seekFrame) const
1162 {
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);
1168 	}
1169 }
1170 
1171 
1172 void
1173 Controller::_NotifyVolumeChanged(float volume) const
1174 {
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);
1180 	}
1181 }
1182 
1183 
1184 void
1185 Controller::_NotifyMutedChanged(bool muted) const
1186 {
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);
1192 	}
1193 }
1194 
1195 
1196 void
1197 Controller::NotifyPlayModeChanged(int32 mode) const
1198 {
1199 	uint32 state = _PlaybackState(mode);
1200 	if (fVideoView)
1201 		fVideoView->SetPlaying(state == PLAYBACK_STATE_PLAYING);
1202 	_NotifyPlaybackStateChanged(state);
1203 }
1204 
1205 
1206 void
1207 Controller::NotifyLoopModeChanged(int32 mode) const
1208 {
1209 }
1210 
1211 
1212 void
1213 Controller::NotifyLoopingEnabledChanged(bool enabled) const
1214 {
1215 }
1216 
1217 
1218 void
1219 Controller::NotifyVideoBoundsChanged(BRect bounds) const
1220 {
1221 }
1222 
1223 
1224 void
1225 Controller::NotifyFPSChanged(float fps) const
1226 {
1227 }
1228 
1229 
1230 void
1231 Controller::NotifyCurrentFrameChanged(int64 frame) const
1232 {
1233 	fCurrentFrame = frame;
1234 	bigtime_t timePosition = _TimePosition();
1235 	_NotifyPositionChanged((float)timePosition / fDuration);
1236 
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);
1243 	}
1244 }
1245 
1246 
1247 void
1248 Controller::NotifySpeedChanged(float speed) const
1249 {
1250 }
1251 
1252 
1253 void
1254 Controller::NotifyFrameDropped() const
1255 {
1256 //	printf("Controller::NotifyFrameDropped()\n");
1257 }
1258 
1259 
1260 void
1261 Controller::NotifyStopFrameReached() const
1262 {
1263 	// Currently, this means we reached the end of the current
1264 	// file and should play the next file
1265 	_NotifyFileFinished();
1266 }
1267 
1268 
1269 void
1270 Controller::NotifySeekHandled(int64 seekedFrame) const
1271 {
1272 	if (fPendingSeekRequests == 0)
1273 		return;
1274 
1275 	fPendingSeekRequests--;
1276 	if (fPendingSeekRequests == 0) {
1277 		fSeekFrame = -1;
1278 		fRequestedSeekFrame = -1;
1279 	}
1280 
1281 	_NotifySeekHandled(seekedFrame);
1282 }
1283 
1284