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