xref: /haiku/src/apps/mediaplayer/Controller.cpp (revision 21258e2674226d6aa732321b6f8494841895af5f)
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 <Catalog.h>
21 #include <Debug.h>
22 #include <Path.h>
23 #include <Window.h> // for debugging only
24 
25 #include "AutoDeleter.h"
26 #include "ControllerView.h"
27 #include "MainApp.h"
28 #include "PlaybackState.h"
29 #include "Settings.h"
30 #include "VideoView.h"
31 
32 // suppliers
33 #include "AudioTrackSupplier.h"
34 #include "MediaTrackAudioSupplier.h"
35 #include "MediaTrackVideoSupplier.h"
36 #include "ProxyAudioSupplier.h"
37 #include "ProxyVideoSupplier.h"
38 #include "SubTitles.h"
39 #include "TrackSupplier.h"
40 #include "VideoTrackSupplier.h"
41 
42 
43 #undef B_TRANSLATION_CONTEXT
44 #define B_TRANSLATION_CONTEXT "MediaPlayer-Controller"
45 #define MIN_WIDTH 250
46 
47 using std::nothrow;
48 
49 
50 class TrackSupplierReleaser {
51 public:
52 	TrackSupplierReleaser(PlaylistItemRef& owner)
53 		:
54 		fOwner(owner),
55 		fRelease(true)
56 		{}
57 
58 	virtual ~TrackSupplierReleaser()
59 	{
60 		if (fRelease)
61 			fOwner.Get()->ReleaseTrackSupplier();
62 	}
63 
64 	void Detach()
65 	{
66 		fRelease = false;
67 	}
68 
69 private:
70 	PlaylistItemRef&	fOwner;
71 	bool				fRelease;
72 };
73 
74 
75 void
76 HandleError(const char *text, status_t err)
77 {
78 	if (err != B_OK) {
79 		printf("%s. error 0x%08x (%s)\n",text, (int)err, strerror(err));
80 		fflush(NULL);
81 		exit(1);
82 	}
83 }
84 
85 
86 // #pragma mark - Controller::Listener
87 
88 
89 Controller::Listener::Listener() {}
90 Controller::Listener::~Listener() {}
91 void Controller::Listener::FileFinished() {}
92 void Controller::Listener::FileChanged(PlaylistItem* item, status_t result) {}
93 void Controller::Listener::VideoTrackChanged(int32) {}
94 void Controller::Listener::AudioTrackChanged(int32) {}
95 void Controller::Listener::SubTitleTrackChanged(int32) {}
96 void Controller::Listener::VideoStatsChanged() {}
97 void Controller::Listener::AudioStatsChanged() {}
98 void Controller::Listener::PlaybackStateChanged(uint32) {}
99 void Controller::Listener::PositionChanged(float) {}
100 void Controller::Listener::SeekHandled(int64 seekFrame) {}
101 void Controller::Listener::VolumeChanged(float) {}
102 void Controller::Listener::MutedChanged(bool) {}
103 
104 
105 // #pragma mark - Controller
106 
107 
108 enum {
109 	MSG_SET_TO = 'stto'
110 };
111 
112 
113 Controller::Controller()
114 	:
115 	NodeManager(),
116 	fVideoView(NULL),
117 	fVolume(1.0),
118 	fActiveVolume(1.0),
119 	fMuted(false),
120 
121 	fItem(NULL),
122 
123 	fVideoSupplier(new ProxyVideoSupplier()),
124 	fAudioSupplier(new ProxyAudioSupplier(this)),
125 	fVideoTrackSupplier(NULL),
126 	fAudioTrackSupplier(NULL),
127 	fSubTitles(NULL),
128 	fSubTitlesIndex(-1),
129 
130 	fCurrentFrame(0),
131 	fDuration(0),
132 	fVideoFrameRate(25.0),
133 
134 	fPendingSeekRequests(0),
135 	fSeekFrame(-1),
136 	fRequestedSeekFrame(-1),
137 
138 	fGlobalSettingsListener(this),
139 
140 	fListeners(4)
141 {
142 	Settings::Default()->AddListener(&fGlobalSettingsListener);
143 	_AdoptGlobalSettings();
144 
145 	fAutoplay = fAutoplaySetting;
146 }
147 
148 
149 Controller::~Controller()
150 {
151 	Settings::Default()->RemoveListener(&fGlobalSettingsListener);
152 	SetTo(NULL);
153 }
154 
155 
156 // #pragma mark - NodeManager interface
157 
158 
159 void
160 Controller::MessageReceived(BMessage* message)
161 {
162 	switch (message->what) {
163 		case MSG_OBJECT_CHANGED:
164 			// received from fGlobalSettingsListener
165 			// TODO: find out which object, if we ever watch more than
166 			// the global settings instance...
167 			_AdoptGlobalSettings();
168 			break;
169 
170 		case MSG_SET_TO:
171 		{
172 			PlaylistItem* item;
173 			if (message->FindPointer("item", (void**)&item) == B_OK) {
174 				PlaylistItemRef itemRef(item, true);
175 					// The reference was passed with the message.
176 				SetTo(itemRef);
177 			} else
178 				_NotifyFileChanged(NULL, B_BAD_VALUE);
179 
180 			break;
181 		}
182 
183 		default:
184 			NodeManager::MessageReceived(message);
185 	}
186 }
187 
188 
189 int64
190 Controller::Duration()
191 {
192 	return _FrameDuration();
193 }
194 
195 
196 VideoTarget*
197 Controller::CreateVideoTarget()
198 {
199 	return fVideoView;
200 }
201 
202 
203 VideoSupplier*
204 Controller::CreateVideoSupplier()
205 {
206 	return fVideoSupplier;
207 }
208 
209 
210 AudioSupplier*
211 Controller::CreateAudioSupplier()
212 {
213 	return fAudioSupplier;
214 }
215 
216 
217 // #pragma mark -
218 
219 
220 status_t
221 Controller::SetToAsync(const PlaylistItemRef& item)
222 {
223 	PlaylistItemRef additionalReference(item);
224 
225 	BMessage message(MSG_SET_TO);
226 	status_t ret = message.AddPointer("item", item.Get());
227 	if (ret != B_OK)
228 		return ret;
229 
230 	ret = PostMessage(&message);
231 	if (ret != B_OK)
232 		return ret;
233 
234 	// The additional reference is now passed along with the message...
235 	additionalReference.Detach();
236 
237 	return B_OK;
238 }
239 
240 
241 status_t
242 Controller::SetTo(const PlaylistItemRef& item)
243 {
244 	BAutolock _(this);
245 
246 	if (fItem == item) {
247 		if (InitCheck() == B_OK) {
248 			if (fAutoplay) {
249 				SetPosition(0.0);
250 				StartPlaying(true);
251 			}
252 		}
253 		return B_OK;
254 	}
255 
256 	fAudioSupplier->SetSupplier(NULL, fVideoFrameRate);
257 	fVideoSupplier->SetSupplier(NULL);
258 
259 	if (fItem != NULL)
260 		TrackSupplierReleaser oldSupplierReleaser(fItem);
261 
262 	fItem = item;
263 
264 	// Do not delete the supplier chain until after we called
265 	// NodeManager::Init() to setup a new media node chain
266 	ObjectDeleter<VideoTrackSupplier> videoSupplierDeleter(
267 		fVideoTrackSupplier);
268 	ObjectDeleter<AudioTrackSupplier> audioSupplierDeleter(
269 		fAudioTrackSupplier);
270 
271 	fVideoTrackSupplier = NULL;
272 	fAudioTrackSupplier = NULL;
273 	fSubTitles = NULL;
274 	fSubTitlesIndex = -1;
275 
276 	fCurrentFrame = 0;
277 	fDuration = 0;
278 	fVideoFrameRate = 25.0;
279 
280 	fPendingSeekRequests = 0;
281 	fSeekFrame = -1;
282 	fRequestedSeekFrame = -1;
283 
284 	if (fItem.Get() == NULL)
285 		return B_BAD_VALUE;
286 
287 	TrackSupplier* trackSupplier = fItem->GetTrackSupplier();
288 	if (trackSupplier == NULL) {
289 		_NotifyFileChanged(item.Get(), B_NO_MEMORY);
290 		return B_NO_MEMORY;
291 	}
292 	TrackSupplierReleaser trackSupplierReleaser(fItem);
293 
294 	status_t err = trackSupplier->InitCheck();
295 	if (err != B_OK) {
296 		printf("Controller::SetTo: InitCheck failed\n");
297 		_NotifyFileChanged(item.Get(), err);
298 		return err;
299 	}
300 
301 	if (trackSupplier->CountAudioTracks() == 0
302 		&& trackSupplier->CountVideoTracks() == 0) {
303 		_NotifyFileChanged(item.Get(), B_MEDIA_NO_HANDLER);
304 		return B_MEDIA_NO_HANDLER;
305 	}
306 
307 	SelectAudioTrack(0);
308 	SelectVideoTrack(0);
309 
310 	if (fAudioTrackSupplier == NULL && fVideoTrackSupplier == NULL) {
311 		printf("Controller::SetTo: no audio or video tracks found or "
312 			"no decoders\n");
313 		_NotifyFileChanged(item.Get(), B_MEDIA_NO_HANDLER);
314 		return B_MEDIA_NO_HANDLER;
315 	}
316 
317 	trackSupplierReleaser.Detach();
318 
319 	// prevent blocking the creation of new overlay buffers
320 	if (fVideoView)
321 		fVideoView->DisableOverlay();
322 
323 	// get video properties (if there is video at all)
324 	bool useOverlays = fVideoView ? fVideoView->UseOverlays() : true;
325 
326 	int width;
327 	int height;
328 	GetSize(&width, &height);
329 	color_space preferredVideoFormat = B_NO_COLOR_SPACE;
330 	if (fVideoTrackSupplier != NULL) {
331 		const media_format& format = fVideoTrackSupplier->Format();
332 		preferredVideoFormat = format.u.raw_video.display.format;
333 	}
334 
335 	uint32 enabledNodes;
336 	if (!fVideoTrackSupplier)
337 		enabledNodes = AUDIO_ONLY;
338 	else if (!fAudioTrackSupplier)
339 		enabledNodes = VIDEO_ONLY;
340 	else
341 		enabledNodes = AUDIO_AND_VIDEO;
342 
343 	float audioFrameRate = 44100.0f;
344 	uint32 audioChannels = 2;
345 	if (fAudioTrackSupplier != NULL) {
346 		const media_format& audioTrackFormat = fAudioTrackSupplier->Format();
347 		audioFrameRate = audioTrackFormat.u.raw_audio.frame_rate;
348 		audioChannels = audioTrackFormat.u.raw_audio.channel_count;
349 	}
350 
351 	if (InitCheck() != B_OK) {
352 		Init(BRect(0, 0, width - 1, height - 1), fVideoFrameRate,
353 			preferredVideoFormat, audioFrameRate, audioChannels, LOOPING_ALL,
354 			false, 1.0, enabledNodes, useOverlays);
355 	} else {
356 		FormatChanged(BRect(0, 0, width - 1, height - 1), fVideoFrameRate,
357 			preferredVideoFormat, audioFrameRate, audioChannels, enabledNodes,
358 			useOverlays);
359 	}
360 
361 	_NotifyFileChanged(item.Get(), B_OK);
362 
363 	if (fAutoplay)
364 		StartPlaying(true);
365 
366 	return B_OK;
367 }
368 
369 
370 void
371 Controller::PlayerActivated(bool active)
372 {
373 	if (LockWithTimeout(5000) != B_OK)
374 		return;
375 
376 	if (active && gMainApp->PlayerCount() > 1) {
377 		if (fActiveVolume != fVolume)
378 			SetVolume(fActiveVolume);
379 	} else {
380 		fActiveVolume = fVolume;
381 		if (gMainApp->PlayerCount() > 1)
382 			switch (fBackgroundMovieVolumeMode) {
383 				case mpSettings::BG_MOVIES_MUTED:
384 					SetVolume(0.0);
385 					break;
386 				case mpSettings::BG_MOVIES_HALF_VLUME:
387 					SetVolume(fVolume * 0.25);
388 					break;
389 				case mpSettings::BG_MOVIES_FULL_VOLUME:
390 				default:
391 					break;
392 			}
393 	}
394 
395 	Unlock();
396 }
397 
398 
399 void
400 Controller::GetSize(int *width, int *height, int* _widthAspect,
401 	int* _heightAspect)
402 {
403 	BAutolock _(this);
404 
405 	if (fVideoTrackSupplier) {
406 		media_format format = fVideoTrackSupplier->Format();
407 		*height = format.u.raw_video.display.line_count;
408 		*width = format.u.raw_video.display.line_width;
409 		int widthAspect = 0;
410 		int heightAspect = 0;
411 		// Ignore format aspect when both values are 1. If they have been
412 		// intentionally at 1:1 then no harm is done for quadratic videos,
413 		// only if the video is indeed encoded anamorphotic, but supposed
414 		// to be displayed quadratic... extremely unlikely.
415 		if (format.u.raw_video.pixel_width_aspect
416 			!= format.u.raw_video.pixel_height_aspect
417 			&& format.u.raw_video.pixel_width_aspect != 1) {
418 			widthAspect = format.u.raw_video.pixel_width_aspect;
419 			heightAspect = format.u.raw_video.pixel_height_aspect;
420 		}
421 		if (_widthAspect != NULL)
422 			*_widthAspect = widthAspect;
423 		if (_heightAspect != NULL)
424 			*_heightAspect = heightAspect;
425 	} else {
426 		*height = 0;
427 		*width = 0;
428 		if (_widthAspect != NULL)
429 			*_widthAspect = 1;
430 		if (_heightAspect != NULL)
431 			*_heightAspect = 1;
432 	}
433 }
434 
435 
436 int
437 Controller::AudioTrackCount()
438 {
439 	BAutolock _(this);
440 
441 	if (fItem != NULL && fItem->HasTrackSupplier())
442 		return fItem->GetTrackSupplier()->CountAudioTracks();
443 	return 0;
444 }
445 
446 
447 int
448 Controller::VideoTrackCount()
449 {
450 	BAutolock _(this);
451 
452 	if (fItem != NULL && fItem->HasTrackSupplier())
453 		return fItem->GetTrackSupplier()->CountVideoTracks();
454 	return 0;
455 }
456 
457 
458 int
459 Controller::SubTitleTrackCount()
460 {
461 	BAutolock _(this);
462 
463 	if (fItem != NULL && fItem->HasTrackSupplier())
464 		return fItem->GetTrackSupplier()->CountSubTitleTracks();
465 	return 0;
466 }
467 
468 
469 status_t
470 Controller::SelectAudioTrack(int n)
471 {
472 	BAutolock _(this);
473 	if (fItem == NULL || !fItem->HasTrackSupplier())
474 		return B_NO_INIT;
475 
476 	ObjectDeleter<AudioTrackSupplier> deleter(fAudioTrackSupplier);
477 	fAudioTrackSupplier
478 		= fItem->GetTrackSupplier()->CreateAudioTrackForIndex(n);
479 	if (fAudioTrackSupplier == NULL)
480 		return B_BAD_INDEX;
481 
482 	bigtime_t a = fAudioTrackSupplier->Duration();
483 	bigtime_t v = fVideoTrackSupplier != NULL
484 		? fVideoTrackSupplier->Duration() : 0;
485 	fDuration = max_c(a, v);
486 	DurationChanged();
487 	// TODO: notify duration changed!
488 
489 	fAudioSupplier->SetSupplier(fAudioTrackSupplier, fVideoFrameRate);
490 
491 	_NotifyAudioTrackChanged(n);
492 	return B_OK;
493 }
494 
495 
496 int
497 Controller::CurrentAudioTrack()
498 {
499 	BAutolock _(this);
500 
501 	if (fAudioTrackSupplier == NULL)
502 		return -1;
503 
504 	return fAudioTrackSupplier->TrackIndex();
505 }
506 
507 
508 int
509 Controller::AudioTrackChannelCount()
510 {
511 	media_format format;
512 	if (GetEncodedAudioFormat(&format) == B_OK)
513 		return format.u.encoded_audio.output.channel_count;
514 
515 	return 2;
516 }
517 
518 
519 status_t
520 Controller::SelectVideoTrack(int n)
521 {
522 	BAutolock _(this);
523 
524 	if (fItem == NULL || !fItem->HasTrackSupplier())
525 		return B_NO_INIT;
526 
527 	ObjectDeleter<VideoTrackSupplier> deleter(fVideoTrackSupplier);
528 	fVideoTrackSupplier
529 		= fItem->GetTrackSupplier()->CreateVideoTrackForIndex(n);
530 	if (fVideoTrackSupplier == NULL)
531 		return B_BAD_INDEX;
532 
533 	bigtime_t a = fAudioTrackSupplier ? fAudioTrackSupplier->Duration() : 0;
534 	bigtime_t v = fVideoTrackSupplier->Duration();
535 	fDuration = max_c(a, v);
536 	fVideoFrameRate = fVideoTrackSupplier->Format().u.raw_video.field_rate;
537 	if (fVideoFrameRate <= 0.0) {
538 		printf("Controller::SelectVideoTrack(%d) - invalid video frame rate: %.1f\n",
539 			n, fVideoFrameRate);
540 		fVideoFrameRate = 25.0;
541 	}
542 
543 	DurationChanged();
544 	// TODO: notify duration changed!
545 
546 	fVideoSupplier->SetSupplier(fVideoTrackSupplier);
547 
548 	_NotifyVideoTrackChanged(n);
549 	return B_OK;
550 }
551 
552 
553 int
554 Controller::CurrentVideoTrack()
555 {
556 	BAutolock _(this);
557 
558 	if (fVideoTrackSupplier == NULL)
559 		return -1;
560 
561 	return fVideoTrackSupplier->TrackIndex();
562 }
563 
564 
565 status_t
566 Controller::SelectSubTitleTrack(int n)
567 {
568 	BAutolock _(this);
569 
570 	if (fItem == NULL || !fItem->HasTrackSupplier())
571 		return B_NO_INIT;
572 
573 	fSubTitlesIndex = n;
574 	fSubTitles =
575 		fItem->GetTrackSupplier()->SubTitleTrackForIndex(n);
576 
577 	const SubTitle* subTitle = NULL;
578 	if (fSubTitles != NULL)
579 		subTitle = fSubTitles->SubTitleAt(_TimePosition());
580 	if (subTitle != NULL)
581 		fVideoView->SetSubTitle(subTitle->text.String());
582 	else
583 		fVideoView->SetSubTitle(NULL);
584 
585 	_NotifySubTitleTrackChanged(n);
586 	return B_OK;
587 }
588 
589 
590 int
591 Controller::CurrentSubTitleTrack()
592 {
593 	BAutolock _(this);
594 
595 	if (fSubTitles == NULL)
596 		return -1;
597 
598 	return fSubTitlesIndex;
599 }
600 
601 
602 const char*
603 Controller::SubTitleTrackName(int n)
604 {
605 	BAutolock _(this);
606 
607 	if (fItem == NULL || !fItem->HasTrackSupplier())
608 		return NULL;
609 
610 	const SubTitles* subTitles
611 		= fItem->GetTrackSupplier()->SubTitleTrackForIndex(n);
612 	if (subTitles == NULL)
613 		return NULL;
614 
615 	return subTitles->Name();
616 }
617 
618 
619 // #pragma mark -
620 
621 
622 void
623 Controller::Stop()
624 {
625 	//printf("Controller::Stop\n");
626 
627 	BAutolock _(this);
628 
629 	StopPlaying();
630 	SetPosition(0.0);
631 
632 	fAutoplay = fAutoplaySetting;
633 }
634 
635 
636 void
637 Controller::Play()
638 {
639 	//printf("Controller::Play\n");
640 
641 	BAutolock _(this);
642 
643 	StartPlaying();
644 	fAutoplay = true;
645 }
646 
647 
648 void
649 Controller::Pause()
650 {
651 //	printf("Controller::Pause\n");
652 
653 	BAutolock _(this);
654 
655 	PausePlaying();
656 
657 	fAutoplay = fAutoplaySetting;
658 }
659 
660 
661 void
662 Controller::TogglePlaying()
663 {
664 //	printf("Controller::TogglePlaying\n");
665 
666 	BAutolock _(this);
667 
668 	if (InitCheck() == B_OK) {
669 		NodeManager::TogglePlaying();
670 
671 		fAutoplay = IsPlaying() || fAutoplaySetting;
672 	}
673 }
674 
675 
676 uint32
677 Controller::PlaybackState()
678 {
679 	BAutolock _(this);
680 
681 	return _PlaybackState(PlaybackManager::PlayMode());
682 }
683 
684 
685 bigtime_t
686 Controller::TimeDuration()
687 {
688 	BAutolock _(this);
689 
690 	return fDuration;
691 }
692 
693 
694 bigtime_t
695 Controller::TimePosition()
696 {
697 	BAutolock _(this);
698 
699 	return _TimePosition();
700 }
701 
702 
703 status_t
704 Controller::SaveState(bool reset)
705 {
706 	if (fItem.Get() == NULL)
707 		return B_OK;
708 	if (reset)
709 		fCurrentFrame = 0;
710 	status_t status = fItem.Get()->SetLastVolume(fVolume);
711 	if (status == B_OK)
712 		status = fItem.Get()->SetLastFrame(fCurrentFrame);
713 	else
714 		fItem.Get()->SetLastFrame(fCurrentFrame);
715 	return status;
716 }
717 
718 
719 void
720 Controller::RestoreState()
721 {
722 	PlaylistItem *item =fItem.Get();
723 	if (item == NULL)
724 		return;
725 
726 	int lastFrame = item->LastFrame();
727 	float lastVolume = item->LastVolume();
728 
729 	// Don't Pause()/Play() if we have nothing to do.
730 	if (lastFrame <= 0 && lastVolume < 0)
731 		return;
732 
733 	Pause();
734 
735 	if (lastFrame > 0) {
736 		bool resume = fResume == mpSettings::RESUME_ALWAYS;
737 		if (fResume == mpSettings::RESUME_ASK) {
738 			BString label;
739 			int32 time = (int32)((float)lastFrame * TimeDuration()
740 					/ (1000000 * _FrameDuration()));
741 			label.SetToFormat(B_TRANSLATE("Do you want to resume %s at %dm%ds?"),
742 					item->Name().String(), time / 60, time % 60);
743 			BAlert *alert = new BAlert(B_TRANSLATE("Resume?"), label,
744 					B_TRANSLATE("Resume"), B_TRANSLATE("Reset"));
745 			resume = alert->Go() == 0;
746 		}
747 
748 		if (resume)
749 			SetFramePosition(lastFrame);
750 	}
751 
752 	if (lastVolume >= 0)
753 		SetVolume(lastVolume);
754 
755 	Play();
756 }
757 
758 
759 void
760 Controller::SetVolume(float value)
761 {
762 //	printf("Controller::SetVolume %.4f\n", value);
763 	BAutolock _(this);
764 
765 	value = max_c(0.0, min_c(2.0, value));
766 
767 	if (fVolume != value) {
768 		if (fMuted)
769 			ToggleMute();
770 
771 		fVolume = value;
772 		fAudioSupplier->SetVolume(fVolume);
773 
774 		_NotifyVolumeChanged(fVolume);
775 	}
776 }
777 
778 
779 void
780 Controller::VolumeUp()
781 {
782 	// TODO: linear <-> exponential
783 	SetVolume(Volume() + 0.05);
784 }
785 
786 
787 void
788 Controller::VolumeDown()
789 {
790 	// TODO: linear <-> exponential
791 	SetVolume(Volume() - 0.05);
792 }
793 
794 
795 void
796 Controller::ToggleMute()
797 {
798 	BAutolock _(this);
799 
800 	fMuted = !fMuted;
801 
802 	if (fMuted)
803 		fAudioSupplier->SetVolume(0.0);
804 	else
805 		fAudioSupplier->SetVolume(fVolume);
806 
807 	_NotifyMutedChanged(fMuted);
808 }
809 
810 
811 float
812 Controller::Volume()
813 {
814 	BAutolock _(this);
815 
816 	return fVolume;
817 }
818 
819 
820 int64
821 Controller::SetPosition(float value)
822 {
823 	BAutolock _(this);
824 
825 	return SetFramePosition(_FrameDuration() * value);
826 }
827 
828 
829 int64
830 Controller::SetFramePosition(int64 value)
831 {
832 	BAutolock _(this);
833 
834 	fPendingSeekRequests++;
835 	fRequestedSeekFrame = max_c(0, min_c(_FrameDuration(), value));
836 	fSeekFrame = fRequestedSeekFrame;
837 
838 	int64 currentFrame = CurrentFrame();
839 
840 	// Snap to a video keyframe, since that will be the fastest
841 	// to display and seeking will feel more snappy. Note that we
842 	// don't store this change in fSeekFrame, since we still want
843 	// to report the originally requested seek frame in TimePosition()
844 	// until we could reach that frame.
845 	if (Duration() > 240 && fVideoTrackSupplier != NULL
846 		&& abs(value - currentFrame) > 5) {
847 		fVideoTrackSupplier->FindKeyFrameForFrame(&fSeekFrame);
848 	}
849 
850 //printf("SetFramePosition(%lld) -> %lld (current: %lld, duration: %lld) "
851 //"(video: %p)\n", value, fSeekFrame, currentFrame, _FrameDuration(),
852 //fVideoTrackSupplier);
853 	if (fSeekFrame != currentFrame) {
854 		int64 seekFrame = fSeekFrame;
855 		SetCurrentFrame(fSeekFrame);
856 			// May trigger the notification and reset fSeekFrame,
857 			// if next current frame == seek frame.
858 		return seekFrame;
859 	} else
860 		NotifySeekHandled(fRequestedSeekFrame);
861 	return currentFrame;
862 }
863 
864 
865 int64
866 Controller::SetTimePosition(bigtime_t value)
867 {
868 	BAutolock _(this);
869 
870 	return SetPosition((float)value / TimeDuration());
871 }
872 
873 
874 // #pragma mark -
875 
876 
877 bool
878 Controller::HasFile()
879 {
880 	// you need to hold the data lock
881 	return fItem != NULL && fItem->HasTrackSupplier();
882 }
883 
884 
885 status_t
886 Controller::GetFileFormatInfo(media_file_format* fileFormat)
887 {
888 	// you need to hold the data lock
889 	if (fItem == NULL || !fItem->HasTrackSupplier())
890 		return B_NO_INIT;
891 	return fItem->GetTrackSupplier()->GetFileFormatInfo(fileFormat);
892 }
893 
894 
895 status_t
896 Controller::GetCopyright(BString* copyright)
897 {
898 	// you need to hold the data lock
899 	if (fItem == NULL || !fItem->HasTrackSupplier())
900 		return B_NO_INIT;
901 	return fItem->GetTrackSupplier()->GetCopyright(copyright);
902 }
903 
904 
905 status_t
906 Controller::GetLocation(BString* location)
907 {
908 	// you need to hold the data lock
909 	if (fItem.Get() == NULL)
910 		return B_NO_INIT;
911 	*location = fItem->LocationURI();
912 	return B_OK;
913 }
914 
915 
916 status_t
917 Controller::GetName(BString* name)
918 {
919 	// you need to hold the data lock
920 	if (fItem.Get() == NULL)
921 		return B_NO_INIT;
922 	*name = fItem->Name();
923 	return B_OK;
924 }
925 
926 
927 status_t
928 Controller::GetEncodedVideoFormat(media_format* format)
929 {
930 	// you need to hold the data lock
931 	if (fVideoTrackSupplier)
932 		return fVideoTrackSupplier->GetEncodedFormat(format);
933 	return B_NO_INIT;
934 }
935 
936 
937 status_t
938 Controller::GetVideoCodecInfo(media_codec_info* info)
939 {
940 	// you need to hold the data lock
941 	if (fVideoTrackSupplier)
942 		return fVideoTrackSupplier->GetCodecInfo(info);
943 	return B_NO_INIT;
944 }
945 
946 
947 status_t
948 Controller::GetEncodedAudioFormat(media_format* format)
949 {
950 	// you need to hold the data lock
951 	if (fAudioTrackSupplier)
952 		return fAudioTrackSupplier->GetEncodedFormat(format);
953 	return B_NO_INIT;
954 }
955 
956 
957 status_t
958 Controller::GetAudioCodecInfo(media_codec_info* info)
959 {
960 	// you need to hold the data lock
961 	if (fAudioTrackSupplier)
962 		return fAudioTrackSupplier->GetCodecInfo(info);
963 	return B_NO_INIT;
964 }
965 
966 
967 status_t
968 Controller::GetMetaData(BMessage* metaData)
969 {
970 	// you need to hold the data lock
971 	if (fItem == NULL || !fItem->HasTrackSupplier())
972 		return B_NO_INIT;
973 	return fItem->GetTrackSupplier()->GetMetaData(metaData);
974 }
975 
976 
977 status_t
978 Controller::GetVideoMetaData(int32 index, BMessage* metaData)
979 {
980 	// you need to hold the data lock
981 	if (fItem == NULL || !fItem->HasTrackSupplier())
982 		return B_NO_INIT;
983 	return fItem->GetTrackSupplier()->GetVideoMetaData(index, metaData);
984 }
985 
986 
987 status_t
988 Controller::GetAudioMetaData(int32 index, BMessage* metaData)
989 {
990 	// you need to hold the data lock
991 	if (fItem == NULL || !fItem->HasTrackSupplier())
992 		return B_NO_INIT;
993 	return fItem->GetTrackSupplier()->GetAudioMetaData(index, metaData);
994 }
995 
996 
997 // #pragma mark -
998 
999 
1000 void
1001 Controller::SetVideoView(VideoView *view)
1002 {
1003 	BAutolock _(this);
1004 
1005 	fVideoView = view;
1006 }
1007 
1008 
1009 bool
1010 Controller::IsOverlayActive()
1011 {
1012 	if (fVideoView)
1013 		return fVideoView->IsOverlayActive();
1014 
1015 	return false;
1016 }
1017 
1018 
1019 // #pragma mark -
1020 
1021 
1022 bool
1023 Controller::AddListener(Listener* listener)
1024 {
1025 	BAutolock _(this);
1026 
1027 	if (listener && !fListeners.HasItem(listener))
1028 		return fListeners.AddItem(listener);
1029 	return false;
1030 }
1031 
1032 
1033 void
1034 Controller::RemoveListener(Listener* listener)
1035 {
1036 	BAutolock _(this);
1037 
1038 	fListeners.RemoveItem(listener);
1039 }
1040 
1041 
1042 // #pragma mark - Private
1043 
1044 
1045 void
1046 Controller::_AdoptGlobalSettings()
1047 {
1048 	mpSettings settings;
1049 	Settings::Default()->Get(settings);
1050 
1051 	fAutoplaySetting = settings.autostart;
1052 	// not yet used:
1053 	fLoopMovies = settings.loopMovie;
1054 	fLoopSounds = settings.loopSound;
1055 	fBackgroundMovieVolumeMode = settings.backgroundMovieVolumeMode;
1056 	fResume = settings.resume;
1057 }
1058 
1059 
1060 uint32
1061 Controller::_PlaybackState(int32 playingMode) const
1062 {
1063 	uint32 state = 0;
1064 	switch (playingMode) {
1065 		case MODE_PLAYING_PAUSED_FORWARD:
1066 		case MODE_PLAYING_PAUSED_BACKWARD:
1067 			state = PLAYBACK_STATE_PAUSED;
1068 			break;
1069 		case MODE_PLAYING_FORWARD:
1070 		case MODE_PLAYING_BACKWARD:
1071 			state = PLAYBACK_STATE_PLAYING;
1072 			break;
1073 
1074 		default:
1075 			state = PLAYBACK_STATE_STOPPED;
1076 			break;
1077 	}
1078 	return state;
1079 }
1080 
1081 
1082 bigtime_t
1083 Controller::_TimePosition() const
1084 {
1085 	if (fDuration == 0)
1086 		return 0;
1087 
1088 	// Check if we are still waiting to reach the seekframe,
1089 	// pass the last pending seek frame back to the caller, so
1090 	// that the view of the current frame/time from the outside
1091 	// does not depend on the internal latency to reach requested
1092 	// frames asynchronously.
1093 	int64 frame;
1094 	if (fPendingSeekRequests > 0)
1095 		frame = fRequestedSeekFrame;
1096 	else
1097 		frame = fCurrentFrame;
1098 
1099 	return frame * fDuration / _FrameDuration();
1100 }
1101 
1102 
1103 int64
1104 Controller::_FrameDuration() const
1105 {
1106 	// This should really be total frames (video frames at that)
1107 	// TODO: It is not so nice that the MediaPlayer still measures
1108 	// in video frames if only playing audio. Here for example, it will
1109 	// return a duration of 0 if the audio clip happens to be shorter than
1110 	// one video frame at 25 fps.
1111 	return (int64)((double)fDuration * fVideoFrameRate / 1000000.0);
1112 }
1113 
1114 
1115 // #pragma mark - Notifications
1116 
1117 
1118 void
1119 Controller::_NotifyFileChanged(PlaylistItem* item, status_t result) const
1120 {
1121 	BList listeners(fListeners);
1122 	int32 count = listeners.CountItems();
1123 	for (int32 i = 0; i < count; i++) {
1124 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1125 		listener->FileChanged(item, result);
1126 	}
1127 }
1128 
1129 
1130 void
1131 Controller::_NotifyFileFinished() const
1132 {
1133 	BList listeners(fListeners);
1134 	int32 count = listeners.CountItems();
1135 	for (int32 i = 0; i < count; i++) {
1136 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1137 		listener->FileFinished();
1138 	}
1139 }
1140 
1141 
1142 void
1143 Controller::_NotifyVideoTrackChanged(int32 index) const
1144 {
1145 	BList listeners(fListeners);
1146 	int32 count = listeners.CountItems();
1147 	for (int32 i = 0; i < count; i++) {
1148 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1149 		listener->VideoTrackChanged(index);
1150 	}
1151 }
1152 
1153 
1154 void
1155 Controller::_NotifyAudioTrackChanged(int32 index) const
1156 {
1157 	BList listeners(fListeners);
1158 	int32 count = listeners.CountItems();
1159 	for (int32 i = 0; i < count; i++) {
1160 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1161 		listener->AudioTrackChanged(index);
1162 	}
1163 }
1164 
1165 
1166 void
1167 Controller::_NotifySubTitleTrackChanged(int32 index) const
1168 {
1169 	BList listeners(fListeners);
1170 	int32 count = listeners.CountItems();
1171 	for (int32 i = 0; i < count; i++) {
1172 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1173 		listener->SubTitleTrackChanged(index);
1174 	}
1175 }
1176 
1177 
1178 void
1179 Controller::_NotifyVideoStatsChanged() const
1180 {
1181 	BList listeners(fListeners);
1182 	int32 count = listeners.CountItems();
1183 	for (int32 i = 0; i < count; i++) {
1184 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1185 		listener->VideoStatsChanged();
1186 	}
1187 }
1188 
1189 
1190 void
1191 Controller::_NotifyAudioStatsChanged() const
1192 {
1193 	BList listeners(fListeners);
1194 	int32 count = listeners.CountItems();
1195 	for (int32 i = 0; i < count; i++) {
1196 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1197 		listener->AudioStatsChanged();
1198 	}
1199 }
1200 
1201 
1202 void
1203 Controller::_NotifyPlaybackStateChanged(uint32 state) const
1204 {
1205 	BList listeners(fListeners);
1206 	int32 count = listeners.CountItems();
1207 	for (int32 i = 0; i < count; i++) {
1208 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1209 		listener->PlaybackStateChanged(state);
1210 	}
1211 }
1212 
1213 
1214 void
1215 Controller::_NotifyPositionChanged(float position) const
1216 {
1217 	BList listeners(fListeners);
1218 	int32 count = listeners.CountItems();
1219 	for (int32 i = 0; i < count; i++) {
1220 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1221 		listener->PositionChanged(position);
1222 	}
1223 }
1224 
1225 
1226 void
1227 Controller::_NotifySeekHandled(int64 seekFrame) const
1228 {
1229 	BList listeners(fListeners);
1230 	int32 count = listeners.CountItems();
1231 	for (int32 i = 0; i < count; i++) {
1232 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1233 		listener->SeekHandled(seekFrame);
1234 	}
1235 }
1236 
1237 
1238 void
1239 Controller::_NotifyVolumeChanged(float volume) const
1240 {
1241 	BList listeners(fListeners);
1242 	int32 count = listeners.CountItems();
1243 	for (int32 i = 0; i < count; i++) {
1244 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1245 		listener->VolumeChanged(volume);
1246 	}
1247 }
1248 
1249 
1250 void
1251 Controller::_NotifyMutedChanged(bool muted) const
1252 {
1253 	BList listeners(fListeners);
1254 	int32 count = listeners.CountItems();
1255 	for (int32 i = 0; i < count; i++) {
1256 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1257 		listener->MutedChanged(muted);
1258 	}
1259 }
1260 
1261 
1262 void
1263 Controller::NotifyPlayModeChanged(int32 mode) const
1264 {
1265 	uint32 state = _PlaybackState(mode);
1266 	if (fVideoView)
1267 		fVideoView->SetPlaying(state == PLAYBACK_STATE_PLAYING);
1268 	_NotifyPlaybackStateChanged(state);
1269 }
1270 
1271 
1272 void
1273 Controller::NotifyLoopModeChanged(int32 mode) const
1274 {
1275 }
1276 
1277 
1278 void
1279 Controller::NotifyLoopingEnabledChanged(bool enabled) const
1280 {
1281 }
1282 
1283 
1284 void
1285 Controller::NotifyVideoBoundsChanged(BRect bounds) const
1286 {
1287 }
1288 
1289 
1290 void
1291 Controller::NotifyFPSChanged(float fps) const
1292 {
1293 }
1294 
1295 
1296 void
1297 Controller::NotifyCurrentFrameChanged(int64 frame) const
1298 {
1299 	fCurrentFrame = frame;
1300 	bigtime_t timePosition = _TimePosition();
1301 	_NotifyPositionChanged((float)timePosition / fDuration);
1302 
1303 	if (fSubTitles != NULL) {
1304 		const SubTitle* subTitle = fSubTitles->SubTitleAt(timePosition);
1305 		if (subTitle != NULL)
1306 			fVideoView->SetSubTitle(subTitle->text.String());
1307 		else
1308 			fVideoView->SetSubTitle(NULL);
1309 	}
1310 }
1311 
1312 
1313 void
1314 Controller::NotifySpeedChanged(float speed) const
1315 {
1316 }
1317 
1318 
1319 void
1320 Controller::NotifyFrameDropped() const
1321 {
1322 //	printf("Controller::NotifyFrameDropped()\n");
1323 }
1324 
1325 
1326 void
1327 Controller::NotifyStopFrameReached() const
1328 {
1329 	// Currently, this means we reached the end of the current
1330 	// file and should play the next file
1331 	_NotifyFileFinished();
1332 }
1333 
1334 
1335 void
1336 Controller::NotifySeekHandled(int64 seekedFrame) const
1337 {
1338 	if (fPendingSeekRequests == 0)
1339 		return;
1340 
1341 	fPendingSeekRequests--;
1342 	if (fPendingSeekRequests == 0) {
1343 		fSeekFrame = -1;
1344 		fRequestedSeekFrame = -1;
1345 	}
1346 
1347 	_NotifySeekHandled(seekedFrame);
1348 }
1349 
1350