xref: /haiku/src/apps/mediaplayer/Controller.cpp (revision 7eab6b486ebadb54ca3c306601f4b04dd92359fa)
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:
TrackSupplierReleaser(PlaylistItemRef & owner)52 	TrackSupplierReleaser(PlaylistItemRef& owner)
53 		:
54 		fOwner(owner),
55 		fRelease(true)
56 		{}
57 
~TrackSupplierReleaser()58 	virtual ~TrackSupplierReleaser()
59 	{
60 		if (fRelease)
61 			fOwner.Get()->ReleaseTrackSupplier();
62 	}
63 
Detach()64 	void Detach()
65 	{
66 		fRelease = false;
67 	}
68 
69 private:
70 	PlaylistItemRef&	fOwner;
71 	bool				fRelease;
72 };
73 
74 
75 void
HandleError(const char * text,status_t err)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 
Listener()89 Controller::Listener::Listener() {}
~Listener()90 Controller::Listener::~Listener() {}
FileFinished()91 void Controller::Listener::FileFinished() {}
FileChanged(PlaylistItem * item,status_t result)92 void Controller::Listener::FileChanged(PlaylistItem* item, status_t result) {}
VideoTrackChanged(int32)93 void Controller::Listener::VideoTrackChanged(int32) {}
AudioTrackChanged(int32)94 void Controller::Listener::AudioTrackChanged(int32) {}
SubTitleTrackChanged(int32)95 void Controller::Listener::SubTitleTrackChanged(int32) {}
VideoStatsChanged()96 void Controller::Listener::VideoStatsChanged() {}
AudioStatsChanged()97 void Controller::Listener::AudioStatsChanged() {}
PlaybackStateChanged(uint32)98 void Controller::Listener::PlaybackStateChanged(uint32) {}
PositionChanged(float)99 void Controller::Listener::PositionChanged(float) {}
SeekHandled(int64 seekFrame)100 void Controller::Listener::SeekHandled(int64 seekFrame) {}
VolumeChanged(float)101 void Controller::Listener::VolumeChanged(float) {}
MutedChanged(bool)102 void Controller::Listener::MutedChanged(bool) {}
103 
104 
105 // #pragma mark - Controller
106 
107 
108 enum {
109 	MSG_SET_TO = 'stto'
110 };
111 
112 
Controller()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 
~Controller()149 Controller::~Controller()
150 {
151 	Settings::Default()->RemoveListener(&fGlobalSettingsListener);
152 	SetTo(NULL);
153 }
154 
155 
156 // #pragma mark - NodeManager interface
157 
158 
159 void
MessageReceived(BMessage * message)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
Duration()190 Controller::Duration()
191 {
192 	return _FrameDuration();
193 }
194 
195 
196 VideoTarget*
CreateVideoTarget()197 Controller::CreateVideoTarget()
198 {
199 	return fVideoView;
200 }
201 
202 
203 VideoSupplier*
CreateVideoSupplier()204 Controller::CreateVideoSupplier()
205 {
206 	return fVideoSupplier;
207 }
208 
209 
210 AudioSupplier*
CreateAudioSupplier()211 Controller::CreateAudioSupplier()
212 {
213 	return fAudioSupplier;
214 }
215 
216 
217 // #pragma mark -
218 
219 
220 status_t
SetToAsync(const PlaylistItemRef & item)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
SetTo(const PlaylistItemRef & item)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.IsSet())
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
PlayerActivated(bool active)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
GetSize(int * width,int * height,int * _widthAspect,int * _heightAspect)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
AudioTrackCount()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
VideoTrackCount()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
SubTitleTrackCount()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
SelectAudioTrack(int n)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
CurrentAudioTrack()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
AudioTrackChannelCount()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
SelectVideoTrack(int n)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
CurrentVideoTrack()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
SelectSubTitleTrack(int n)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
CurrentSubTitleTrack()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*
SubTitleTrackName(int n)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
Stop()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
Play()637 Controller::Play()
638 {
639 	//printf("Controller::Play\n");
640 
641 	BAutolock _(this);
642 
643 	StartPlaying();
644 	fAutoplay = true;
645 }
646 
647 
648 void
Pause()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
TogglePlaying()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
PlaybackState()677 Controller::PlaybackState()
678 {
679 	BAutolock _(this);
680 
681 	return _PlaybackState(PlaybackManager::PlayMode());
682 }
683 
684 
685 bigtime_t
TimeDuration()686 Controller::TimeDuration()
687 {
688 	BAutolock _(this);
689 
690 	return fDuration;
691 }
692 
693 
694 bigtime_t
TimePosition()695 Controller::TimePosition()
696 {
697 	BAutolock _(this);
698 
699 	return _TimePosition();
700 }
701 
702 
703 status_t
SaveState(bool reset)704 Controller::SaveState(bool reset)
705 {
706 	if (!fItem.IsSet())
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
RestoreState()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 			int time = (int)((float)lastFrame * TimeDuration() / (1000000 * _FrameDuration()));
740 			label.SetToFormat(B_TRANSLATE("Do you want to resume %s at %dm%ds?"),
741 					item->Name().String(), time / 60, time % 60);
742 			BAlert *alert = new BAlert(B_TRANSLATE("Resume?"), label,
743 					B_TRANSLATE("Resume"), B_TRANSLATE("Reset"));
744 			resume = alert->Go() == 0;
745 		}
746 
747 		if (resume)
748 			SetFramePosition(lastFrame);
749 	}
750 
751 	if (lastVolume >= 0)
752 		SetVolume(lastVolume);
753 
754 	Play();
755 }
756 
757 
758 void
SetVolume(float value)759 Controller::SetVolume(float value)
760 {
761 //	printf("Controller::SetVolume %.4f\n", value);
762 	BAutolock _(this);
763 
764 	value = max_c(0.0, min_c(2.0, value));
765 
766 	if (fVolume != value) {
767 		if (fMuted)
768 			ToggleMute();
769 
770 		fVolume = value;
771 		fAudioSupplier->SetVolume(fVolume);
772 
773 		_NotifyVolumeChanged(fVolume);
774 	}
775 }
776 
777 
778 void
VolumeUp()779 Controller::VolumeUp()
780 {
781 	// TODO: linear <-> exponential
782 	SetVolume(Volume() + 0.05);
783 }
784 
785 
786 void
VolumeDown()787 Controller::VolumeDown()
788 {
789 	// TODO: linear <-> exponential
790 	SetVolume(Volume() - 0.05);
791 }
792 
793 
794 void
ToggleMute()795 Controller::ToggleMute()
796 {
797 	BAutolock _(this);
798 
799 	fMuted = !fMuted;
800 
801 	if (fMuted)
802 		fAudioSupplier->SetVolume(0.0);
803 	else
804 		fAudioSupplier->SetVolume(fVolume);
805 
806 	_NotifyMutedChanged(fMuted);
807 }
808 
809 
810 float
Volume()811 Controller::Volume()
812 {
813 	BAutolock _(this);
814 
815 	return fVolume;
816 }
817 
818 
819 int64
SetPosition(float value)820 Controller::SetPosition(float value)
821 {
822 	BAutolock _(this);
823 
824 	return SetFramePosition(_FrameDuration() * value);
825 }
826 
827 
828 int64
SetFramePosition(int64 value)829 Controller::SetFramePosition(int64 value)
830 {
831 	BAutolock _(this);
832 
833 	fPendingSeekRequests++;
834 	fRequestedSeekFrame = max_c(0, min_c(_FrameDuration(), value));
835 	fSeekFrame = fRequestedSeekFrame;
836 
837 	int64 currentFrame = CurrentFrame();
838 
839 	// Snap to a video keyframe, since that will be the fastest
840 	// to display and seeking will feel more snappy. Note that we
841 	// don't store this change in fSeekFrame, since we still want
842 	// to report the originally requested seek frame in TimePosition()
843 	// until we could reach that frame.
844 	if (Duration() > 240 && fVideoTrackSupplier != NULL
845 		&& abs(value - currentFrame) > 5) {
846 		fVideoTrackSupplier->FindKeyFrameForFrame(&fSeekFrame);
847 	}
848 
849 //printf("SetFramePosition(%lld) -> %lld (current: %lld, duration: %lld) "
850 //"(video: %p)\n", value, fSeekFrame, currentFrame, _FrameDuration(),
851 //fVideoTrackSupplier);
852 	if (fSeekFrame != currentFrame) {
853 		int64 seekFrame = fSeekFrame;
854 		SetCurrentFrame(fSeekFrame);
855 			// May trigger the notification and reset fSeekFrame,
856 			// if next current frame == seek frame.
857 		return seekFrame;
858 	} else
859 		NotifySeekHandled(fRequestedSeekFrame);
860 	return currentFrame;
861 }
862 
863 
864 int64
SetTimePosition(bigtime_t value)865 Controller::SetTimePosition(bigtime_t value)
866 {
867 	BAutolock _(this);
868 
869 	return SetPosition((float)value / TimeDuration());
870 }
871 
872 
873 // #pragma mark -
874 
875 
876 bool
HasFile()877 Controller::HasFile()
878 {
879 	// you need to hold the data lock
880 	return fItem != NULL && fItem->HasTrackSupplier();
881 }
882 
883 
884 status_t
GetFileFormatInfo(media_file_format * fileFormat)885 Controller::GetFileFormatInfo(media_file_format* fileFormat)
886 {
887 	// you need to hold the data lock
888 	if (fItem == NULL || !fItem->HasTrackSupplier())
889 		return B_NO_INIT;
890 	return fItem->GetTrackSupplier()->GetFileFormatInfo(fileFormat);
891 }
892 
893 
894 status_t
GetCopyright(BString * copyright)895 Controller::GetCopyright(BString* copyright)
896 {
897 	// you need to hold the data lock
898 	if (fItem == NULL || !fItem->HasTrackSupplier())
899 		return B_NO_INIT;
900 	return fItem->GetTrackSupplier()->GetCopyright(copyright);
901 }
902 
903 
904 status_t
GetLocation(BString * location)905 Controller::GetLocation(BString* location)
906 {
907 	// you need to hold the data lock
908 	if (!fItem.IsSet())
909 		return B_NO_INIT;
910 	*location = fItem->LocationURI();
911 	return B_OK;
912 }
913 
914 
915 status_t
GetName(BString * name)916 Controller::GetName(BString* name)
917 {
918 	// you need to hold the data lock
919 	if (!fItem.IsSet())
920 		return B_NO_INIT;
921 	*name = fItem->Name();
922 	return B_OK;
923 }
924 
925 
926 status_t
GetEncodedVideoFormat(media_format * format)927 Controller::GetEncodedVideoFormat(media_format* format)
928 {
929 	// you need to hold the data lock
930 	if (fVideoTrackSupplier)
931 		return fVideoTrackSupplier->GetEncodedFormat(format);
932 	return B_NO_INIT;
933 }
934 
935 
936 status_t
GetVideoCodecInfo(media_codec_info * info)937 Controller::GetVideoCodecInfo(media_codec_info* info)
938 {
939 	// you need to hold the data lock
940 	if (fVideoTrackSupplier)
941 		return fVideoTrackSupplier->GetCodecInfo(info);
942 	return B_NO_INIT;
943 }
944 
945 
946 status_t
GetEncodedAudioFormat(media_format * format)947 Controller::GetEncodedAudioFormat(media_format* format)
948 {
949 	// you need to hold the data lock
950 	if (fAudioTrackSupplier)
951 		return fAudioTrackSupplier->GetEncodedFormat(format);
952 	return B_NO_INIT;
953 }
954 
955 
956 status_t
GetAudioCodecInfo(media_codec_info * info)957 Controller::GetAudioCodecInfo(media_codec_info* info)
958 {
959 	// you need to hold the data lock
960 	if (fAudioTrackSupplier)
961 		return fAudioTrackSupplier->GetCodecInfo(info);
962 	return B_NO_INIT;
963 }
964 
965 
966 status_t
GetMetaData(BMessage * metaData)967 Controller::GetMetaData(BMessage* metaData)
968 {
969 	// you need to hold the data lock
970 	if (fItem == NULL || !fItem->HasTrackSupplier())
971 		return B_NO_INIT;
972 	return fItem->GetTrackSupplier()->GetMetaData(metaData);
973 }
974 
975 
976 status_t
GetVideoMetaData(int32 index,BMessage * metaData)977 Controller::GetVideoMetaData(int32 index, BMessage* metaData)
978 {
979 	// you need to hold the data lock
980 	if (fItem == NULL || !fItem->HasTrackSupplier())
981 		return B_NO_INIT;
982 	return fItem->GetTrackSupplier()->GetVideoMetaData(index, metaData);
983 }
984 
985 
986 status_t
GetAudioMetaData(int32 index,BMessage * metaData)987 Controller::GetAudioMetaData(int32 index, BMessage* metaData)
988 {
989 	// you need to hold the data lock
990 	if (fItem == NULL || !fItem->HasTrackSupplier())
991 		return B_NO_INIT;
992 	return fItem->GetTrackSupplier()->GetAudioMetaData(index, metaData);
993 }
994 
995 
996 // #pragma mark -
997 
998 
999 void
SetVideoView(VideoView * view)1000 Controller::SetVideoView(VideoView *view)
1001 {
1002 	BAutolock _(this);
1003 
1004 	fVideoView = view;
1005 }
1006 
1007 
1008 bool
IsOverlayActive()1009 Controller::IsOverlayActive()
1010 {
1011 	if (fVideoView)
1012 		return fVideoView->IsOverlayActive();
1013 
1014 	return false;
1015 }
1016 
1017 
1018 // #pragma mark -
1019 
1020 
1021 bool
AddListener(Listener * listener)1022 Controller::AddListener(Listener* listener)
1023 {
1024 	BAutolock _(this);
1025 
1026 	if (listener && !fListeners.HasItem(listener))
1027 		return fListeners.AddItem(listener);
1028 	return false;
1029 }
1030 
1031 
1032 void
RemoveListener(Listener * listener)1033 Controller::RemoveListener(Listener* listener)
1034 {
1035 	BAutolock _(this);
1036 
1037 	fListeners.RemoveItem(listener);
1038 }
1039 
1040 
1041 // #pragma mark - Private
1042 
1043 
1044 void
_AdoptGlobalSettings()1045 Controller::_AdoptGlobalSettings()
1046 {
1047 	mpSettings settings;
1048 	Settings::Default()->Get(settings);
1049 
1050 	fAutoplaySetting = settings.autostart;
1051 	// not yet used:
1052 	fLoopMovies = settings.loopMovie;
1053 	fLoopSounds = settings.loopSound;
1054 	fBackgroundMovieVolumeMode = settings.backgroundMovieVolumeMode;
1055 	fResume = settings.resume;
1056 }
1057 
1058 
1059 uint32
_PlaybackState(int32 playingMode) const1060 Controller::_PlaybackState(int32 playingMode) const
1061 {
1062 	uint32 state = 0;
1063 	switch (playingMode) {
1064 		case MODE_PLAYING_PAUSED_FORWARD:
1065 		case MODE_PLAYING_PAUSED_BACKWARD:
1066 			state = PLAYBACK_STATE_PAUSED;
1067 			break;
1068 		case MODE_PLAYING_FORWARD:
1069 		case MODE_PLAYING_BACKWARD:
1070 			state = PLAYBACK_STATE_PLAYING;
1071 			break;
1072 
1073 		default:
1074 			state = PLAYBACK_STATE_STOPPED;
1075 			break;
1076 	}
1077 	return state;
1078 }
1079 
1080 
1081 bigtime_t
_TimePosition() const1082 Controller::_TimePosition() const
1083 {
1084 	if (fDuration == 0)
1085 		return 0;
1086 
1087 	// Check if we are still waiting to reach the seekframe,
1088 	// pass the last pending seek frame back to the caller, so
1089 	// that the view of the current frame/time from the outside
1090 	// does not depend on the internal latency to reach requested
1091 	// frames asynchronously.
1092 	int64 frame;
1093 	if (fPendingSeekRequests > 0)
1094 		frame = fRequestedSeekFrame;
1095 	else
1096 		frame = fCurrentFrame;
1097 
1098 	return frame * fDuration / _FrameDuration();
1099 }
1100 
1101 
1102 int64
_FrameDuration() const1103 Controller::_FrameDuration() const
1104 {
1105 	// This should really be total frames (video frames at that)
1106 	// TODO: It is not so nice that the MediaPlayer still measures
1107 	// in video frames if only playing audio. Here for example, it will
1108 	// return a duration of 0 if the audio clip happens to be shorter than
1109 	// one video frame at 25 fps.
1110 	return (int64)((double)fDuration * fVideoFrameRate / 1000000.0);
1111 }
1112 
1113 
1114 // #pragma mark - Notifications
1115 
1116 
1117 void
_NotifyFileChanged(PlaylistItem * item,status_t result) const1118 Controller::_NotifyFileChanged(PlaylistItem* item, status_t result) const
1119 {
1120 	BList listeners(fListeners);
1121 	int32 count = listeners.CountItems();
1122 	for (int32 i = 0; i < count; i++) {
1123 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1124 		listener->FileChanged(item, result);
1125 	}
1126 }
1127 
1128 
1129 void
_NotifyFileFinished() const1130 Controller::_NotifyFileFinished() const
1131 {
1132 	BList listeners(fListeners);
1133 	int32 count = listeners.CountItems();
1134 	for (int32 i = 0; i < count; i++) {
1135 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1136 		listener->FileFinished();
1137 	}
1138 }
1139 
1140 
1141 void
_NotifyVideoTrackChanged(int32 index) const1142 Controller::_NotifyVideoTrackChanged(int32 index) const
1143 {
1144 	BList listeners(fListeners);
1145 	int32 count = listeners.CountItems();
1146 	for (int32 i = 0; i < count; i++) {
1147 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1148 		listener->VideoTrackChanged(index);
1149 	}
1150 }
1151 
1152 
1153 void
_NotifyAudioTrackChanged(int32 index) const1154 Controller::_NotifyAudioTrackChanged(int32 index) const
1155 {
1156 	BList listeners(fListeners);
1157 	int32 count = listeners.CountItems();
1158 	for (int32 i = 0; i < count; i++) {
1159 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1160 		listener->AudioTrackChanged(index);
1161 	}
1162 }
1163 
1164 
1165 void
_NotifySubTitleTrackChanged(int32 index) const1166 Controller::_NotifySubTitleTrackChanged(int32 index) const
1167 {
1168 	BList listeners(fListeners);
1169 	int32 count = listeners.CountItems();
1170 	for (int32 i = 0; i < count; i++) {
1171 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1172 		listener->SubTitleTrackChanged(index);
1173 	}
1174 }
1175 
1176 
1177 void
_NotifyVideoStatsChanged() const1178 Controller::_NotifyVideoStatsChanged() const
1179 {
1180 	BList listeners(fListeners);
1181 	int32 count = listeners.CountItems();
1182 	for (int32 i = 0; i < count; i++) {
1183 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1184 		listener->VideoStatsChanged();
1185 	}
1186 }
1187 
1188 
1189 void
_NotifyAudioStatsChanged() const1190 Controller::_NotifyAudioStatsChanged() const
1191 {
1192 	BList listeners(fListeners);
1193 	int32 count = listeners.CountItems();
1194 	for (int32 i = 0; i < count; i++) {
1195 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1196 		listener->AudioStatsChanged();
1197 	}
1198 }
1199 
1200 
1201 void
_NotifyPlaybackStateChanged(uint32 state) const1202 Controller::_NotifyPlaybackStateChanged(uint32 state) const
1203 {
1204 	BList listeners(fListeners);
1205 	int32 count = listeners.CountItems();
1206 	for (int32 i = 0; i < count; i++) {
1207 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1208 		listener->PlaybackStateChanged(state);
1209 	}
1210 }
1211 
1212 
1213 void
_NotifyPositionChanged(float position) const1214 Controller::_NotifyPositionChanged(float position) const
1215 {
1216 	BList listeners(fListeners);
1217 	int32 count = listeners.CountItems();
1218 	for (int32 i = 0; i < count; i++) {
1219 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1220 		listener->PositionChanged(position);
1221 	}
1222 }
1223 
1224 
1225 void
_NotifySeekHandled(int64 seekFrame) const1226 Controller::_NotifySeekHandled(int64 seekFrame) const
1227 {
1228 	BList listeners(fListeners);
1229 	int32 count = listeners.CountItems();
1230 	for (int32 i = 0; i < count; i++) {
1231 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1232 		listener->SeekHandled(seekFrame);
1233 	}
1234 }
1235 
1236 
1237 void
_NotifyVolumeChanged(float volume) const1238 Controller::_NotifyVolumeChanged(float volume) const
1239 {
1240 	BList listeners(fListeners);
1241 	int32 count = listeners.CountItems();
1242 	for (int32 i = 0; i < count; i++) {
1243 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1244 		listener->VolumeChanged(volume);
1245 	}
1246 }
1247 
1248 
1249 void
_NotifyMutedChanged(bool muted) const1250 Controller::_NotifyMutedChanged(bool muted) const
1251 {
1252 	BList listeners(fListeners);
1253 	int32 count = listeners.CountItems();
1254 	for (int32 i = 0; i < count; i++) {
1255 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1256 		listener->MutedChanged(muted);
1257 	}
1258 }
1259 
1260 
1261 void
NotifyPlayModeChanged(int32 mode) const1262 Controller::NotifyPlayModeChanged(int32 mode) const
1263 {
1264 	uint32 state = _PlaybackState(mode);
1265 	if (fVideoView)
1266 		fVideoView->SetPlaying(state == PLAYBACK_STATE_PLAYING);
1267 	_NotifyPlaybackStateChanged(state);
1268 }
1269 
1270 
1271 void
NotifyLoopModeChanged(int32 mode) const1272 Controller::NotifyLoopModeChanged(int32 mode) const
1273 {
1274 }
1275 
1276 
1277 void
NotifyLoopingEnabledChanged(bool enabled) const1278 Controller::NotifyLoopingEnabledChanged(bool enabled) const
1279 {
1280 }
1281 
1282 
1283 void
NotifyVideoBoundsChanged(BRect bounds) const1284 Controller::NotifyVideoBoundsChanged(BRect bounds) const
1285 {
1286 }
1287 
1288 
1289 void
NotifyFPSChanged(float fps) const1290 Controller::NotifyFPSChanged(float fps) const
1291 {
1292 }
1293 
1294 
1295 void
NotifyCurrentFrameChanged(int64 frame) const1296 Controller::NotifyCurrentFrameChanged(int64 frame) const
1297 {
1298 	fCurrentFrame = frame;
1299 	bigtime_t timePosition = _TimePosition();
1300 	_NotifyPositionChanged((float)timePosition / fDuration);
1301 
1302 	if (fSubTitles != NULL) {
1303 		const SubTitle* subTitle = fSubTitles->SubTitleAt(timePosition);
1304 		if (subTitle != NULL)
1305 			fVideoView->SetSubTitle(subTitle->text.String());
1306 		else
1307 			fVideoView->SetSubTitle(NULL);
1308 	}
1309 }
1310 
1311 
1312 void
NotifySpeedChanged(float speed) const1313 Controller::NotifySpeedChanged(float speed) const
1314 {
1315 }
1316 
1317 
1318 void
NotifyFrameDropped() const1319 Controller::NotifyFrameDropped() const
1320 {
1321 //	printf("Controller::NotifyFrameDropped()\n");
1322 }
1323 
1324 
1325 void
NotifyStopFrameReached() const1326 Controller::NotifyStopFrameReached() const
1327 {
1328 	// Currently, this means we reached the end of the current
1329 	// file and should play the next file
1330 	_NotifyFileFinished();
1331 }
1332 
1333 
1334 void
NotifySeekHandled(int64 seekedFrame) const1335 Controller::NotifySeekHandled(int64 seekedFrame) const
1336 {
1337 	if (fPendingSeekRequests == 0)
1338 		return;
1339 
1340 	fPendingSeekRequests--;
1341 	if (fPendingSeekRequests == 0) {
1342 		fSeekFrame = -1;
1343 		fRequestedSeekFrame = -1;
1344 	}
1345 
1346 	_NotifySeekHandled(seekedFrame);
1347 }
1348 
1349