xref: /haiku/src/apps/mediaplayer/Controller.cpp (revision c9060eb991e10e477ece52478d6743fc7691c143)
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 Fredrik Modéen <fredrik@modeen.se>
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 #include "Controller.h"
23 
24 #include <new>
25 #include <stdio.h>
26 #include <string.h>
27 
28 #include <Autolock.h>
29 #include <Bitmap.h>
30 #include <Debug.h>
31 #include <MediaFile.h>
32 #include <MediaTrack.h>
33 #include <Path.h>
34 #include <Window.h> // for debugging only
35 
36 #include "AutoDeleter.h"
37 #include "ControllerView.h"
38 #include "PlaybackState.h"
39 #include "VideoView.h"
40 
41 // suppliers
42 #include "AudioTrackSupplier.h"
43 #include "MediaTrackAudioSupplier.h"
44 #include "MediaTrackVideoSupplier.h"
45 #include "ProxyAudioSupplier.h"
46 #include "ProxyVideoSupplier.h"
47 #include "VideoTrackSupplier.h"
48 
49 using std::nothrow;
50 
51 
52 void
53 HandleError(const char *text, status_t err)
54 {
55 	if (err != B_OK) {
56 		printf("%s. error 0x%08x (%s)\n",text, (int)err, strerror(err));
57 		fflush(NULL);
58 		exit(1);
59 	}
60 }
61 
62 
63 // #pragma mark - Controller::Listener
64 
65 
66 Controller::Listener::Listener() {}
67 Controller::Listener::~Listener() {}
68 void Controller::Listener::FileFinished() {}
69 void Controller::Listener::FileChanged() {}
70 void Controller::Listener::VideoTrackChanged(int32) {}
71 void Controller::Listener::AudioTrackChanged(int32) {}
72 void Controller::Listener::VideoStatsChanged() {}
73 void Controller::Listener::AudioStatsChanged() {}
74 void Controller::Listener::PlaybackStateChanged(uint32) {}
75 void Controller::Listener::PositionChanged(float) {}
76 void Controller::Listener::VolumeChanged(float) {}
77 void Controller::Listener::MutedChanged(bool) {}
78 
79 
80 // #pragma mark - Controller
81 
82 
83 Controller::Controller()
84  :	NodeManager()
85  ,	fVideoView(NULL)
86  ,	fVolume(1.0)
87  ,	fMuted(false)
88 
89  ,	fRef()
90  ,	fMediaFile(NULL)
91 
92  ,	fVideoSupplier(new ProxyVideoSupplier())
93  ,	fAudioSupplier(new ProxyAudioSupplier(this))
94  ,	fVideoTrackSupplier(NULL)
95  ,	fAudioTrackSupplier(NULL)
96 
97  ,	fAudioTrackList(4)
98  ,	fVideoTrackList(2)
99 
100  ,	fPosition(0)
101  ,	fDuration(0)
102  ,	fVideoFrameRate(25.0)
103 
104  ,	fAutoplay(true)
105  ,	fPauseAtEndOfStream(false)
106  ,	fSeekToStartAfterPause(false)
107 
108  ,	fListeners(4)
109 {
110 	fStopped = fAutoplay ? false : true;
111 }
112 
113 
114 Controller::~Controller()
115 {
116 	if (fMediaFile)
117 		fMediaFile->ReleaseAllTracks();
118 	delete fMediaFile;
119 }
120 
121 
122 // #pragma mark - NodeManager interface
123 
124 
125 int64
126 Controller::Duration()
127 {
128 	// TODO: It is not so nice that the MediaPlayer still measures
129 	// in video frames if only playing audio. Here for example, it will
130 	// return a duration of 0 if the audio clip happens to be shorter than
131 	// one video frame at 25 fps.
132 	return (int64)((double)fDuration * fVideoFrameRate / 1000000.0);
133 }
134 
135 
136 VideoTarget*
137 Controller::CreateVideoTarget()
138 {
139 	return fVideoView;
140 }
141 
142 
143 VideoSupplier*
144 Controller::CreateVideoSupplier()
145 {
146 	return fVideoSupplier;
147 }
148 
149 
150 AudioSupplier*
151 Controller::CreateAudioSupplier()
152 {
153 	return fAudioSupplier;
154 }
155 
156 
157 // #pragma mark -
158 
159 
160 status_t
161 Controller::SetTo(const entry_ref &ref)
162 {
163 	BAutolock _(this);
164 
165 	if (fRef == ref) {
166 		if (InitCheck() == B_OK) {
167 			SetCurrentFrame(0);
168 			StartPlaying();
169 		}
170 		return B_OK;
171 	}
172 
173 	fRef = ref;
174 
175 	fAudioSupplier->SetSupplier(NULL, fVideoFrameRate);
176 	fVideoSupplier->SetSupplier(NULL);
177 
178 	fAudioTrackList.MakeEmpty();
179 	fVideoTrackList.MakeEmpty();
180 
181 	ObjectDeleter<BMediaFile> oldMediaFileDeleter(fMediaFile);
182 		// BMediaFile destructor will call ReleaseAllTracks()
183 	fMediaFile = NULL;
184 
185 	// Do not delete the supplier chain until after we called
186 	// NodeManager::Init() to setup a new media node chain
187 	ObjectDeleter<VideoTrackSupplier> videoSupplierDeleter(
188 		fVideoTrackSupplier);
189 	ObjectDeleter<AudioTrackSupplier> audioSupplierDeleter(
190 		fAudioTrackSupplier);
191 
192 	fVideoTrackSupplier = NULL;
193 	fAudioTrackSupplier = NULL;
194 
195 	fPauseAtEndOfStream = false;
196 	fSeekToStartAfterPause = false;
197 	fDuration = 0;
198 	fVideoFrameRate = 25.0;
199 
200 	status_t err;
201 
202 	BMediaFile* mf = new BMediaFile(&ref);
203 	ObjectDeleter<BMediaFile> mediaFileDeleter(mf);
204 
205 	err = mf->InitCheck();
206 	if (err != B_OK) {
207 		printf("Controller::SetTo: initcheck failed\n");
208 		_NotifyFileChanged();
209 		return err;
210 	}
211 
212 	int trackcount = mf->CountTracks();
213 	if (trackcount <= 0) {
214 		printf("Controller::SetTo: trackcount %d\n", trackcount);
215 		_NotifyFileChanged();
216 		return B_MEDIA_NO_HANDLER;
217 	}
218 
219 	for (int i = 0; i < trackcount; i++) {
220 		BMediaTrack* t = mf->TrackAt(i);
221 		media_format f;
222 		err = t->EncodedFormat(&f);
223 		if (err != B_OK || t->Duration() <= 0) {
224 			printf("Controller::SetTo: EncodedFormat failed for track index %d, error 0x%08lx (%s)\n",
225 				i, err, strerror(err));
226 			mf->ReleaseTrack(t);
227 			continue;
228 		}
229 		if (f.IsAudio()) {
230 			if (!fAudioTrackList.AddItem(t))
231 				return B_NO_MEMORY;
232 		} else if (f.IsVideo()) {
233 			if (!fVideoTrackList.AddItem(t))
234 				return B_NO_MEMORY;
235 		} else {
236 			printf("Controller::SetTo: track index %d has unknown type\n", i);
237 			mf->ReleaseTrack(t);
238 		}
239 	}
240 
241 	printf("Controller::SetTo: %d audio track, %d video track\n",
242 		AudioTrackCount(), VideoTrackCount());
243 
244 	fMediaFile = mf;
245 	mediaFileDeleter.Detach();
246 
247 	SelectAudioTrack(0);
248 	SelectVideoTrack(0);
249 
250 	if (fAudioTrackSupplier == NULL && fVideoTrackSupplier == NULL) {
251 		printf("Controller::SetTo: no audio or video tracks found or "
252 			"no decoders\n");
253 		_NotifyFileChanged();
254 		delete fMediaFile;
255 		fMediaFile = NULL;
256 		return B_MEDIA_NO_HANDLER;
257 	}
258 
259 	// prevent blocking the creation of new overlay buffers
260 	fVideoView->DisableOverlay();
261 
262 	// get video properties (if there is video at all)
263 	int width;
264 	int height;
265 	GetSize(&width, &height);
266 	color_space preferredVideoFormat = B_NO_COLOR_SPACE;
267 	if (fVideoTrackSupplier) {
268 		const media_format& format = fVideoTrackSupplier->Format();
269 		preferredVideoFormat = format.u.raw_video.display.format;
270 	}
271 
272 	if (InitCheck() != B_OK) {
273 		Init(BRect(0, 0, width - 1, height - 1), fVideoFrameRate,
274 			preferredVideoFormat, LOOPING_ALL, false);
275 	} else {
276 		FormatChanged(BRect(0, 0, width - 1, height - 1), fVideoFrameRate,
277 			preferredVideoFormat);
278 	}
279 
280 	_NotifyFileChanged();
281 
282 	SetCurrentFrame(0);
283 	if (fAutoplay)
284 		StartPlaying(true);
285 
286 	return B_OK;
287 }
288 
289 
290 void
291 Controller::GetSize(int *width, int *height)
292 {
293 	BAutolock _(this);
294 
295 	if (fVideoTrackSupplier) {
296 		media_format format = fVideoTrackSupplier->Format();
297 		// TODO: take aspect ratio into account!
298 		*height = format.u.raw_video.display.line_count;
299 		*width = format.u.raw_video.display.line_width;
300 	} else {
301 		*height = 0;
302 		*width = 0;
303 	}
304 }
305 
306 
307 int
308 Controller::AudioTrackCount()
309 {
310 	BAutolock _(this);
311 
312 	return fAudioTrackList.CountItems();
313 }
314 
315 
316 int
317 Controller::VideoTrackCount()
318 {
319 	BAutolock _(this);
320 
321 	return fVideoTrackList.CountItems();
322 }
323 
324 
325 status_t
326 Controller::SelectAudioTrack(int n)
327 {
328 	BAutolock _(this);
329 
330 	BMediaTrack* track = (BMediaTrack *)fAudioTrackList.ItemAt(n);
331 	if (!track)
332 		return B_ERROR;
333 
334 	ObjectDeleter<AudioTrackSupplier> deleter(fAudioTrackSupplier);
335 	fAudioTrackSupplier = new MediaTrackAudioSupplier(track, n);
336 
337 	bigtime_t a = fAudioTrackSupplier->Duration();
338 	bigtime_t v = fVideoTrackSupplier ? fVideoTrackSupplier->Duration() : 0;;
339 	fDuration = max_c(a, v);
340 	DurationChanged();
341 	// TODO: notify duration changed!
342 
343 	fAudioSupplier->SetSupplier(fAudioTrackSupplier, fVideoFrameRate);
344 
345 	_NotifyAudioTrackChanged(n);
346 	return B_OK;
347 }
348 
349 
350 int
351 Controller::CurrentAudioTrack()
352 {
353 	BAutolock _(this);
354 
355 	if (fAudioTrackSupplier == NULL)
356 		return -1;
357 
358 	return fAudioTrackSupplier->TrackIndex();
359 }
360 
361 
362 status_t
363 Controller::SelectVideoTrack(int n)
364 {
365 	BAutolock _(this);
366 
367 	BMediaTrack* track = (BMediaTrack *)fVideoTrackList.ItemAt(n);
368 	if (!track)
369 		return B_ERROR;
370 
371 	status_t initStatus;
372 	ObjectDeleter<VideoTrackSupplier> deleter(fVideoTrackSupplier);
373 	fVideoTrackSupplier = new MediaTrackVideoSupplier(track, n, initStatus);
374 	if (initStatus < B_OK) {
375 		delete fVideoTrackSupplier;
376 		fVideoTrackSupplier = NULL;
377 		return initStatus;
378 	}
379 
380 	bigtime_t a = fAudioTrackSupplier ? fAudioTrackSupplier->Duration() : 0;
381 	bigtime_t v = fVideoTrackSupplier->Duration();
382 	fDuration = max_c(a, v);
383 	fVideoFrameRate = fVideoTrackSupplier->Format().u.raw_video.field_rate;
384 	if (fVideoFrameRate <= 0.0) {
385 		printf("Controller::SelectVideoTrack(%d) - invalid video frame rate: %.1f\n", n,
386 			fVideoFrameRate);
387 		fVideoFrameRate = 25.0;
388 	}
389 
390 	DurationChanged();
391 	// TODO: notify duration changed!
392 
393 	fVideoSupplier->SetSupplier(fVideoTrackSupplier);
394 
395 	_NotifyVideoTrackChanged(n);
396 	return B_OK;
397 }
398 
399 
400 int
401 Controller::CurrentVideoTrack()
402 {
403 	BAutolock _(this);
404 
405 	if (fVideoTrackSupplier == NULL)
406 		return -1;
407 
408 	return fVideoTrackSupplier->TrackIndex();
409 }
410 
411 
412 // #pragma mark -
413 
414 
415 void
416 Controller::Stop()
417 {
418 	printf("Controller::Stop\n");
419 
420 	BAutolock _(this);
421 
422 	StopPlaying();
423 	SetCurrentFrame(0);
424 }
425 
426 
427 void
428 Controller::Play()
429 {
430 	printf("Controller::Play\n");
431 
432 	BAutolock _(this);
433 
434 	if (fSeekToStartAfterPause) {
435 printf("seeking to start after pause\n");
436 		SetPosition(0);
437 		fSeekToStartAfterPause = false;
438 	}
439 
440 	StartPlaying();
441 }
442 
443 
444 void
445 Controller::Pause()
446 {
447 	printf("Controller::Pause\n");
448 
449 	BAutolock _(this);
450 
451 	PausePlaying();
452 }
453 
454 
455 void
456 Controller::TogglePlaying()
457 {
458 	printf("Controller::TogglePlaying\n");
459 
460 	BAutolock _(this);
461 
462 	NodeManager::TogglePlaying();
463 }
464 
465 
466 uint32
467 Controller::PlaybackState()
468 {
469 	BAutolock _(this);
470 
471 	return _PlaybackState(PlaybackManager::PlayMode());
472 }
473 
474 
475 bigtime_t
476 Controller::TimeDuration()
477 {
478 	BAutolock _(this);
479 
480 	return fDuration;
481 }
482 
483 
484 bigtime_t
485 Controller::TimePosition()
486 {
487 	BAutolock _(this);
488 
489 	return fPosition;
490 }
491 
492 
493 void
494 Controller::SetVolume(float value)
495 {
496 	printf("Controller::SetVolume %.4f\n", value);
497 	if (!Lock())
498 		return;
499 
500 	value = max_c(0.0, min_c(2.0, value));
501 
502 	if (fVolume != value) {
503 		if (fMuted)
504 			ToggleMute();
505 
506 		fVolume = value;
507 		fAudioSupplier->SetVolume(fVolume);
508 
509 		_NotifyVolumeChanged(fVolume);
510 	}
511 
512 	Unlock();
513 }
514 
515 void
516 Controller::VolumeUp()
517 {
518 	// TODO: linear <-> exponential
519 	SetVolume(Volume() + 0.05);
520 }
521 
522 void
523 Controller::VolumeDown()
524 {
525 	// TODO: linear <-> exponential
526 	SetVolume(Volume() - 0.05);
527 }
528 
529 void
530 Controller::ToggleMute()
531 {
532 	if (!Lock())
533 		return;
534 
535 	fMuted = !fMuted;
536 
537 	if (fMuted)
538 		fAudioSupplier->SetVolume(0.0);
539 	else
540 		fAudioSupplier->SetVolume(fVolume);
541 
542 	_NotifyMutedChanged(fMuted);
543 
544 	Unlock();
545 }
546 
547 
548 float
549 Controller::Volume()
550 {
551 	BAutolock _(this);
552 
553 	return fVolume;
554 }
555 
556 
557 void
558 Controller::SetPosition(float value)
559 {
560 	BAutolock _(this);
561 
562 	SetCurrentFrame(Duration() * value);
563 
564 	fSeekToStartAfterPause = false;
565 }
566 
567 
568 // #pragma mark -
569 
570 
571 bool
572 Controller::HasFile()
573 {
574 	// you need to hold the data lock
575 	return fMediaFile != NULL;
576 }
577 
578 
579 status_t
580 Controller::GetFileFormatInfo(media_file_format* fileFormat)
581 {
582 	// you need to hold the data lock
583 	if (!fMediaFile)
584 		return B_NO_INIT;
585 	return fMediaFile->GetFileFormatInfo(fileFormat);
586 }
587 
588 
589 status_t
590 Controller::GetCopyright(BString* copyright)
591 {
592 	// you need to hold the data lock
593 	if (!fMediaFile)
594 		return B_NO_INIT;
595 	*copyright = fMediaFile->Copyright();
596 	return B_OK;
597 }
598 
599 
600 status_t
601 Controller::GetLocation(BString* location)
602 {
603 	// you need to hold the data lock
604 	if (!fMediaFile)
605 		return B_NO_INIT;
606 	BPath path(&fRef);
607 	status_t ret = path.InitCheck();
608 	if (ret < B_OK)
609 		return ret;
610 	*location = "";
611 	*location << "file://" << path.Path();
612 	return B_OK;
613 }
614 
615 
616 status_t
617 Controller::GetName(BString* name)
618 {
619 	// you need to hold the data lock
620 	if (!fMediaFile)
621 		return B_NO_INIT;
622 	*name = fRef.name;
623 	return B_OK;
624 }
625 
626 
627 status_t
628 Controller::GetEncodedVideoFormat(media_format* format)
629 {
630 	// you need to hold the data lock
631 	if (fVideoTrackSupplier)
632 		return fVideoTrackSupplier->GetEncodedFormat(format);
633 	return B_NO_INIT;
634 }
635 
636 
637 status_t
638 Controller::GetVideoCodecInfo(media_codec_info* info)
639 {
640 	// you need to hold the data lock
641 	if (fVideoTrackSupplier)
642 		return fVideoTrackSupplier->GetCodecInfo(info);
643 	return B_NO_INIT;
644 }
645 
646 
647 status_t
648 Controller::GetEncodedAudioFormat(media_format* format)
649 {
650 	// you need to hold the data lock
651 	if (fAudioTrackSupplier)
652 		return fAudioTrackSupplier->GetEncodedFormat(format);
653 	return B_NO_INIT;
654 }
655 
656 
657 status_t
658 Controller::GetAudioCodecInfo(media_codec_info* info)
659 {
660 	// you need to hold the data lock
661 	if (fAudioTrackSupplier)
662 		return fAudioTrackSupplier->GetCodecInfo(info);
663 	return B_NO_INIT;
664 }
665 
666 
667 // #pragma mark -
668 
669 
670 void
671 Controller::SetVideoView(VideoView *view)
672 {
673 	BAutolock _(this);
674 
675 	fVideoView = view;
676 }
677 
678 
679 bool
680 Controller::IsOverlayActive()
681 {
682 	if (fVideoView)
683 		return fVideoView->IsOverlayActive();
684 
685 	return false;
686 }
687 
688 
689 // #pragma mark -
690 
691 
692 bool
693 Controller::AddListener(Listener* listener)
694 {
695 	BAutolock _(this);
696 
697 	if (listener && !fListeners.HasItem(listener))
698 		return fListeners.AddItem(listener);
699 	return false;
700 }
701 
702 
703 void
704 Controller::RemoveListener(Listener* listener)
705 {
706 	BAutolock _(this);
707 
708 	fListeners.RemoveItem(listener);
709 }
710 
711 
712 // #pragma mark - Private
713 
714 
715 uint32
716 Controller::_PlaybackState(int32 playingMode) const
717 {
718 	uint32 state = 0;
719 	switch (playingMode) {
720 		case MODE_PLAYING_PAUSED_FORWARD:
721 		case MODE_PLAYING_PAUSED_BACKWARD:
722 			state = PLAYBACK_STATE_PAUSED;
723 			break;
724 		case MODE_PLAYING_FORWARD:
725 		case MODE_PLAYING_BACKWARD:
726 			state = PLAYBACK_STATE_PLAYING;
727 			break;
728 
729 		default:
730 			state = PLAYBACK_STATE_STOPPED;
731 			break;
732 	}
733 	return state;
734 }
735 
736 
737 // #pragma mark - Notifications
738 
739 
740 void
741 Controller::_NotifyFileChanged() const
742 {
743 	BList listeners(fListeners);
744 	int32 count = listeners.CountItems();
745 	for (int32 i = 0; i < count; i++) {
746 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
747 		listener->FileChanged();
748 	}
749 }
750 
751 
752 void
753 Controller::_NotifyFileFinished() const
754 {
755 	BList listeners(fListeners);
756 	int32 count = listeners.CountItems();
757 	for (int32 i = 0; i < count; i++) {
758 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
759 		listener->FileFinished();
760 	}
761 }
762 
763 
764 void
765 Controller::_NotifyVideoTrackChanged(int32 index) const
766 {
767 	BList listeners(fListeners);
768 	int32 count = listeners.CountItems();
769 	for (int32 i = 0; i < count; i++) {
770 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
771 		listener->VideoTrackChanged(index);
772 	}
773 }
774 
775 
776 void
777 Controller::_NotifyAudioTrackChanged(int32 index) const
778 {
779 	BList listeners(fListeners);
780 	int32 count = listeners.CountItems();
781 	for (int32 i = 0; i < count; i++) {
782 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
783 		listener->AudioTrackChanged(index);
784 	}
785 }
786 
787 
788 void
789 Controller::_NotifyVideoStatsChanged() const
790 {
791 	BList listeners(fListeners);
792 	int32 count = listeners.CountItems();
793 	for (int32 i = 0; i < count; i++) {
794 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
795 		listener->VideoStatsChanged();
796 	}
797 }
798 
799 
800 void
801 Controller::_NotifyAudioStatsChanged() const
802 {
803 	BList listeners(fListeners);
804 	int32 count = listeners.CountItems();
805 	for (int32 i = 0; i < count; i++) {
806 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
807 		listener->AudioStatsChanged();
808 	}
809 }
810 
811 
812 void
813 Controller::_NotifyPlaybackStateChanged(uint32 state) const
814 {
815 	BList listeners(fListeners);
816 	int32 count = listeners.CountItems();
817 	for (int32 i = 0; i < count; i++) {
818 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
819 		listener->PlaybackStateChanged(state);
820 	}
821 }
822 
823 
824 void
825 Controller::_NotifyPositionChanged(float position) const
826 {
827 	BList listeners(fListeners);
828 	int32 count = listeners.CountItems();
829 	for (int32 i = 0; i < count; i++) {
830 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
831 		listener->PositionChanged(position);
832 	}
833 }
834 
835 
836 void
837 Controller::_NotifyVolumeChanged(float volume) const
838 {
839 	BList listeners(fListeners);
840 	int32 count = listeners.CountItems();
841 	for (int32 i = 0; i < count; i++) {
842 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
843 		listener->VolumeChanged(volume);
844 	}
845 }
846 
847 
848 void
849 Controller::_NotifyMutedChanged(bool muted) const
850 {
851 	BList listeners(fListeners);
852 	int32 count = listeners.CountItems();
853 	for (int32 i = 0; i < count; i++) {
854 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
855 		listener->MutedChanged(muted);
856 	}
857 }
858 
859 
860 void
861 Controller::NotifyPlayModeChanged(int32 mode) const
862 {
863 	_NotifyPlaybackStateChanged(_PlaybackState(mode));
864 }
865 
866 
867 void
868 Controller::NotifyLoopModeChanged(int32 mode) const
869 {
870 }
871 
872 
873 void
874 Controller::NotifyLoopingEnabledChanged(bool enabled) const
875 {
876 }
877 
878 
879 void
880 Controller::NotifyVideoBoundsChanged(BRect bounds) const
881 {
882 }
883 
884 
885 void
886 Controller::NotifyFPSChanged(float fps) const
887 {
888 }
889 
890 
891 void
892 Controller::NotifyCurrentFrameChanged(int32 frame) const
893 {
894 	float position = 0.0;
895 	double duration = (double)fDuration * fVideoFrameRate / 1000000.0;
896 	if (duration > 0)
897 		position = (float)frame / duration;
898 	fPosition = (bigtime_t)(position * fDuration + 0.5);
899 	_NotifyPositionChanged(position);
900 }
901 
902 
903 void
904 Controller::NotifySpeedChanged(float speed) const
905 {
906 }
907 
908 
909 void
910 Controller::NotifyFrameDropped() const
911 {
912 //	printf("Controller::NotifyFrameDropped()\n");
913 }
914 
915 
916 void
917 Controller::NotifyStopFrameReached() const
918 {
919 	// Currently, this means we reached the end of the current
920 	// file and should play the next file
921 	_NotifyFileFinished();
922 }
923 
924