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