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