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