xref: /haiku/src/apps/mediaplayer/Controller.cpp (revision d9cebac2b77547b7064f22497514eecd2d047160)
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 Stephan Aßmus <superstippi@gmx.de>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * version 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  *
20  */
21 #include "Controller.h"
22 
23 #include <new>
24 #include <stdio.h>
25 #include <string.h>
26 
27 #include <Autolock.h>
28 #include <Bitmap.h>
29 #include <Debug.h>
30 #include <MediaFile.h>
31 #include <MediaTrack.h>
32 #include <Path.h>
33 #include <Window.h> // for debugging only
34 
35 #include "ControllerView.h"
36 #include "PlaybackState.h"
37 #include "SoundOutput.h"
38 #include "VideoView.h"
39 
40 // suppliers
41 #include "AudioSupplier.h"
42 #include "MediaTrackAudioSupplier.h"
43 #include "MediaTrackVideoSupplier.h"
44 #include "VideoSupplier.h"
45 
46 using std::nothrow;
47 
48 
49 #define AUDIO_PLAY_PRIORITY		110
50 #define VIDEO_PLAY_PRIORITY		20
51 #define AUDIO_DECODE_PRIORITY	13
52 #define VIDEO_DECODE_PRIORITY	13
53 
54 void
55 HandleError(const char *text, status_t err)
56 {
57 	if (err != B_OK) {
58 		printf("%s. error 0x%08x (%s)\n",text, (int)err, strerror(err));
59 		fflush(NULL);
60 		exit(1);
61 	}
62 }
63 
64 
65 // #pragma mark -
66 
67 
68 Controller::Listener::Listener() {}
69 Controller::Listener::~Listener() {}
70 void Controller::Listener::FileFinished() {}
71 void Controller::Listener::FileChanged() {}
72 void Controller::Listener::VideoTrackChanged(int32) {}
73 void Controller::Listener::AudioTrackChanged(int32) {}
74 void Controller::Listener::VideoStatsChanged() {}
75 void Controller::Listener::AudioStatsChanged() {}
76 void Controller::Listener::PlaybackStateChanged(uint32) {}
77 void Controller::Listener::PositionChanged(float) {}
78 void Controller::Listener::VolumeChanged(float) {}
79 void Controller::Listener::MutedChanged(bool) {}
80 
81 
82 // #pragma mark -
83 
84 
85 Controller::Controller()
86  :	fVideoView(NULL)
87  ,	fPaused(false)
88  ,	fStopped(true)
89  ,	fVolume(1.0)
90  ,	fMuted(false)
91 
92  ,	fRef()
93  ,	fMediaFile(0)
94  ,	fDataLock("controller data lock")
95 
96  ,	fVideoSupplier(NULL)
97  ,	fAudioSupplier(NULL)
98 
99  ,	fVideoSupplierLock("video supplier lock")
100  ,	fAudioSupplierLock("audio supplier lock")
101 
102  ,	fAudioTrackList(new BList)
103  ,	fVideoTrackList(new BList)
104  ,	fAudioDecodeSem(-1)
105  ,	fVideoDecodeSem(-1)
106  ,	fAudioPlaySem(-1)
107  ,	fVideoPlaySem(-1)
108  ,	fAudioDecodeThread(-1)
109  ,	fVideoDecodeThread(-1)
110  ,	fAudioPlayThread(-1)
111  ,	fVideoPlayThread(-1)
112  ,	fSoundOutput(NULL)
113  ,	fSeekAudio(false)
114  ,	fSeekVideo(false)
115  ,	fSeekPosition(0)
116  ,	fPosition(0)
117  ,	fDuration(0)
118  ,	fAudioBufferCount(MAX_AUDIO_BUFFERS)
119  ,	fAudioBufferReadIndex(0)
120  ,	fAudioBufferWriteIndex(0)
121  ,	fVideoBufferCount(MAX_VIDEO_BUFFERS)
122  ,	fVideoBufferReadIndex(0)
123  ,	fVideoBufferWriteIndex(0)
124  ,	fTimeSourceLock("time source lock")
125  ,	fTimeSourceSysTime(0)
126  ,	fTimeSourcePerfTime(0)
127  ,	fAutoplay(true)
128  ,	fPauseAtEndOfStream(false)
129  ,	fSeekToStartAfterPause(false)
130  ,	fCurrentBitmap(NULL)
131  ,	fBitmapLock("bitmap lock")
132  ,	fListeners(4)
133 {
134 	for (int i = 0; i < MAX_AUDIO_BUFFERS; i++) {
135 		fAudioBuffer[i].bitmap = NULL;
136 		fAudioBuffer[i].buffer = NULL;
137 		fAudioBuffer[i].sizeMax = 0;
138 		fAudioBuffer[i].formatChanged = false;
139 		fAudioBuffer[i].endOfStream = false;
140 	}
141 	for (int i = 0; i < MAX_VIDEO_BUFFERS; i++) {
142 		fVideoBuffer[i].bitmap = NULL;
143 		fVideoBuffer[i].buffer = NULL;
144 		fVideoBuffer[i].sizeMax = 0;
145 		fVideoBuffer[i].formatChanged = false;
146 		fVideoBuffer[i].endOfStream = false;
147 	}
148 
149 	fStopped = fAutoplay ? false : true;
150 
151 	_StartThreads();
152 }
153 
154 
155 Controller::~Controller()
156 {
157 	_StopThreads();
158 
159 	if (fMediaFile)
160 		fMediaFile->ReleaseAllTracks();
161 	delete fMediaFile;
162 	delete fAudioTrackList;
163 	delete fVideoTrackList;
164 
165 	delete fSoundOutput;
166 }
167 
168 
169 // #pragma mark -
170 
171 
172 bool
173 Controller::Lock()
174 {
175 	return fDataLock.Lock();
176 }
177 
178 
179 status_t
180 Controller::LockWithTimeout(bigtime_t timeout)
181 {
182 	return fDataLock.LockWithTimeout(timeout);
183 }
184 
185 
186 void
187 Controller::Unlock()
188 {
189 	return fDataLock.Unlock();
190 }
191 
192 
193 // #pragma mark -
194 
195 
196 status_t
197 Controller::SetTo(const entry_ref &ref)
198 {
199 	BAutolock dl(fDataLock);
200 	BAutolock al(fVideoSupplierLock);
201 	BAutolock vl(fAudioSupplierLock);
202 
203 	if (fRef == ref)
204 		return B_OK;
205 
206 	fRef = ref;
207 
208 	fAudioTrackList->MakeEmpty();
209 	fVideoTrackList->MakeEmpty();
210 	if (fMediaFile)
211 		fMediaFile->ReleaseAllTracks();
212 	delete fMediaFile;
213 	fMediaFile = NULL;
214 	delete fVideoSupplier;
215 	fVideoSupplier = NULL;
216 	delete fAudioSupplier;
217 	fAudioSupplier = NULL;
218 
219 	fSeekAudio = true;
220 	fSeekVideo = true;
221 	fSeekPosition = 0;
222 	fPaused = false;
223 	fStopped = fAutoplay ? false : true;
224 	fPauseAtEndOfStream = false;
225 	fSeekToStartAfterPause = false;
226 	fTimeSourceSysTime = system_time();
227 	fTimeSourcePerfTime = 0;
228 	fDuration = 0;
229 
230 	_UpdatePosition(0);
231 
232 	status_t err;
233 
234 	BMediaFile *mf = new BMediaFile(&ref);
235 	err = mf->InitCheck();
236 	if (err != B_OK) {
237 		printf("Controller::SetTo: initcheck failed\n");
238 		delete mf;
239 		_NotifyFileChanged();
240 		return err;
241 	}
242 
243 	int trackcount = mf->CountTracks();
244 	if (trackcount <= 0) {
245 		printf("Controller::SetTo: trackcount %d\n", trackcount);
246 		delete mf;
247 		_NotifyFileChanged();
248 		return B_MEDIA_NO_HANDLER;
249 	}
250 
251 	for (int i = 0; i < trackcount; i++) {
252 		BMediaTrack *t = mf->TrackAt(i);
253 		media_format f;
254 		err = t->EncodedFormat(&f);
255 		if (err != B_OK) {
256 			printf("Controller::SetTo: EncodedFormat failed for track index %d, error 0x%08lx (%s)\n",
257 				i, err, strerror(err));
258 			mf->ReleaseTrack(t);
259 			continue;
260 		}
261 		if (f.IsAudio()) {
262 			fAudioTrackList->AddItem(t);
263 		} else if (f.IsVideo()) {
264 			fVideoTrackList->AddItem(t);
265 		} else {
266 			printf("Controller::SetTo: track index %d has unknown type\n", i);
267 			mf->ReleaseTrack(t);
268 		}
269 	}
270 
271 	if (AudioTrackCount() == 0 && VideoTrackCount() == 0) {
272 		printf("Controller::SetTo: no audio or video tracks found\n");
273 		delete mf;
274 		_NotifyFileChanged();
275 		return B_MEDIA_NO_HANDLER;
276 	}
277 
278 	printf("Controller::SetTo: %d audio track, %d video track\n", AudioTrackCount(), VideoTrackCount());
279 
280 	fMediaFile = mf;
281 
282 	SelectAudioTrack(0);
283 	SelectVideoTrack(0);
284 
285 	_NotifyFileChanged();
286 	_NotifyPlaybackStateChanged();
287 
288 	return B_OK;
289 }
290 
291 
292 void
293 Controller::GetSize(int *width, int *height)
294 {
295 	BAutolock _(fVideoSupplierLock);
296 
297 	if (fVideoSupplier) {
298 		media_format format = fVideoSupplier->Format();
299 		// TODO: take aspect ratio into account!
300 		*height = format.u.raw_video.display.line_count;
301 		*width = format.u.raw_video.display.line_width;
302 	} else {
303 		*height = 480;
304 		*width = 640;
305 	}
306 }
307 
308 
309 int
310 Controller::AudioTrackCount()
311 {
312 	BAutolock _(fDataLock);
313 
314 	return fAudioTrackList->CountItems();
315 }
316 
317 
318 int
319 Controller::VideoTrackCount()
320 {
321 	BAutolock _(fDataLock);
322 
323 	return fVideoTrackList->CountItems();
324 }
325 
326 
327 status_t
328 Controller::SelectAudioTrack(int n)
329 {
330 	BAutolock _(fAudioSupplierLock);
331 
332 	BMediaTrack* track = (BMediaTrack *)fAudioTrackList->ItemAt(n);
333 	if (!track)
334 		return B_ERROR;
335 
336 	delete fAudioSupplier;
337 	fAudioSupplier = new MediaTrackAudioSupplier(track);
338 
339 	bigtime_t a = fAudioSupplier->Duration();
340 	bigtime_t v = fVideoSupplier ? fVideoSupplier->Duration() : 0;;
341 	fDuration = max_c(a, v);
342 
343 	_NotifyAudioTrackChanged(n);
344 	return B_OK;
345 }
346 
347 
348 status_t
349 Controller::SelectVideoTrack(int n)
350 {
351 	BAutolock _(fVideoSupplierLock);
352 
353 	BMediaTrack* track = (BMediaTrack *)fVideoTrackList->ItemAt(n);
354 	if (!track)
355 		return B_ERROR;
356 
357 	delete fVideoSupplier;
358 	fVideoSupplier = new MediaTrackVideoSupplier(track,
359 		IsOverlayActive() ? B_YCbCr422 : B_RGB32);
360 
361 	bigtime_t a = fAudioSupplier ? fAudioSupplier->Duration() : 0;
362 	bigtime_t v = fVideoSupplier->Duration();
363 	fDuration = max_c(a, v);
364 
365 	_NotifyVideoTrackChanged(n);
366 	return B_OK;
367 }
368 
369 
370 // #pragma mark -
371 
372 
373 void
374 Controller::Stop()
375 {
376 	printf("Controller::Stop\n");
377 
378 	BAutolock _(fDataLock);
379 
380 	if (fStopped)
381 		return;
382 
383 	fPaused = false;
384 	fStopped = true;
385 
386 	fSeekAudio = true;
387 	fSeekVideo = true;
388 	fSeekPosition = 0;
389 
390 	_NotifyPlaybackStateChanged();
391 	_UpdatePosition(0, false, true);
392 }
393 
394 
395 void
396 Controller::Play()
397 {
398 	printf("Controller::Play\n");
399 
400 	BAutolock _(fDataLock);
401 
402 	if (!fPaused && !fStopped)
403 		return;
404 
405 	fStopped = false;
406 	fPaused = false;
407 
408 	if (fSeekToStartAfterPause) {
409 printf("seeking to start after pause\n");
410 		SetPosition(0);
411 		fSeekToStartAfterPause = false;
412 	}
413 
414 	_NotifyPlaybackStateChanged();
415 }
416 
417 
418 void
419 Controller::Pause()
420 {
421 	printf("Controller::Pause\n");
422 
423 	BAutolock _(fDataLock);
424 
425 	if (fStopped || fPaused)
426 		return;
427 
428 	fPaused = true;
429 
430 	_NotifyPlaybackStateChanged();
431 }
432 
433 
434 void
435 Controller::TogglePlaying()
436 {
437 	BAutolock _(fDataLock);
438 
439 	if (IsPaused() || IsStopped())
440 		Play();
441 	else
442 		Pause();
443 }
444 
445 
446 bool
447 Controller::IsPaused() const
448 {
449 	BAutolock _(fDataLock);
450 
451 	return fPaused;
452 }
453 
454 
455 bool
456 Controller::IsStopped() const
457 {
458 	BAutolock _(fDataLock);
459 
460 	return fStopped;
461 }
462 
463 
464 uint32
465 Controller::PlaybackState() const
466 {
467 	BAutolock _(fDataLock);
468 
469 	if (fStopped)
470 		return PLAYBACK_STATE_STOPPED;
471 	if (fPaused)
472 		return PLAYBACK_STATE_PAUSED;
473 	return PLAYBACK_STATE_PLAYING;
474 }
475 
476 
477 bigtime_t
478 Controller::Duration()
479 {
480 	BAutolock _(fDataLock);
481 
482 	return fDuration;
483 }
484 
485 
486 bigtime_t
487 Controller::Position()
488 {
489 	BAutolock _(fDataLock);
490 
491 	return fPosition;
492 }
493 
494 
495 void
496 Controller::SetVolume(float value)
497 {
498 	printf("Controller::SetVolume %.4f\n", value);
499 	if (!Lock())
500 		return;
501 
502 	value = max_c(0.0, min_c(2.0, value));
503 
504 	if (fVolume != value) {
505 		if (fMuted)
506 			ToggleMute();
507 
508 		fVolume = value;
509 		if (fSoundOutput)
510 			fSoundOutput->SetVolume(fVolume);
511 
512 		_NotifyVolumeChanged(fVolume);
513 	}
514 
515 	Unlock();
516 }
517 
518 void
519 Controller::VolumeUp()
520 {
521 	// TODO: linear <-> exponential
522 	SetVolume(Volume() + 0.05);
523 }
524 
525 void
526 Controller::VolumeDown()
527 {
528 	// TODO: linear <-> exponential
529 	SetVolume(Volume() - 0.05);
530 }
531 
532 void
533 Controller::ToggleMute()
534 {
535 	if (!Lock())
536 		return;
537 
538 	fMuted = !fMuted;
539 
540 	if (fSoundOutput) {
541 		if (fMuted)
542 			fSoundOutput->SetVolume(0.0);
543 		else
544 			fSoundOutput->SetVolume(fVolume);
545 	}
546 
547 	_NotifyMutedChanged(fMuted);
548 
549 	Unlock();
550 }
551 
552 
553 float
554 Controller::Volume() const
555 {
556 	BAutolock _(fDataLock);
557 
558 	return fVolume;
559 }
560 
561 
562 void
563 Controller::SetPosition(float value)
564 {
565 	printf("Controller::SetPosition %.4f\n", value);
566 
567 	BAutolock _(fDataLock);
568 
569 	fSeekPosition = bigtime_t(value * Duration());
570 	fSeekAudio = true;
571 	fSeekVideo = true;
572 
573 	fSeekToStartAfterPause = false;
574 
575 //	release_sem(fAudioWaitSem);
576 //	release_sem(fVideoWaitSem);
577 }
578 
579 
580 // #pragma mark -
581 
582 
583 bool
584 Controller::HasFile()
585 {
586 	// you need to hold the data lock
587 	return fMediaFile != NULL;
588 }
589 
590 
591 status_t
592 Controller::GetFileFormatInfo(media_file_format* fileFormat)
593 {
594 	// you need to hold the data lock
595 	if (!fMediaFile)
596 		return B_NO_INIT;
597 	return fMediaFile->GetFileFormatInfo(fileFormat);
598 }
599 
600 
601 status_t
602 Controller::GetCopyright(BString* copyright)
603 {
604 	// you need to hold the data lock
605 	if (!fMediaFile)
606 		return B_NO_INIT;
607 	*copyright = fMediaFile->Copyright();
608 	return B_OK;
609 }
610 
611 
612 status_t
613 Controller::GetLocation(BString* location)
614 {
615 	// you need to hold the data lock
616 	if (!fMediaFile)
617 		return B_NO_INIT;
618 	BPath path(&fRef);
619 	status_t ret = path.InitCheck();
620 	if (ret < B_OK)
621 		return ret;
622 	*location = "";
623 	*location << "file://" << path.Path();
624 	return B_OK;
625 }
626 
627 
628 status_t
629 Controller::GetName(BString* name)
630 {
631 	// you need to hold the data lock
632 	if (!fMediaFile)
633 		return B_NO_INIT;
634 	*name = fRef.name;
635 	return B_OK;
636 }
637 
638 
639 status_t
640 Controller::GetEncodedVideoFormat(media_format* format)
641 {
642 	// you need to hold the data lock
643 	if (fVideoSupplier)
644 		return fVideoSupplier->GetEncodedFormat(format);
645 	return B_NO_INIT;
646 }
647 
648 
649 status_t
650 Controller::GetVideoCodecInfo(media_codec_info* info)
651 {
652 	// you need to hold the data lock
653 	if (fVideoSupplier)
654 		return fVideoSupplier->GetCodecInfo(info);
655 	return B_NO_INIT;
656 }
657 
658 
659 status_t
660 Controller::GetEncodedAudioFormat(media_format* format)
661 {
662 	// you need to hold the data lock
663 	if (fAudioSupplier)
664 		return fAudioSupplier->GetEncodedFormat(format);
665 	return B_NO_INIT;
666 }
667 
668 
669 status_t
670 Controller::GetAudioCodecInfo(media_codec_info* info)
671 {
672 	// you need to hold the data lock
673 	if (fAudioSupplier)
674 		return fAudioSupplier->GetCodecInfo(info);
675 	return B_NO_INIT;
676 }
677 
678 
679 // #pragma mark -
680 
681 
682 void
683 Controller::SetVideoView(VideoView *view)
684 {
685 	BAutolock _(fDataLock);
686 
687 	fVideoView = view;
688 	fVideoView->SetController(this);
689 }
690 
691 
692 bool
693 Controller::IsOverlayActive()
694 {
695 //	return true;
696 	return false;
697 }
698 
699 
700 bool
701 Controller::LockBitmap()
702 {
703 	return fBitmapLock.Lock();
704 }
705 
706 
707 void
708 Controller::UnlockBitmap()
709 {
710 	fBitmapLock.Unlock();
711 }
712 
713 
714 BBitmap *
715 Controller::Bitmap()
716 {
717 	return fCurrentBitmap;
718 }
719 
720 
721 // #pragma mark -
722 
723 
724 bool
725 Controller::AddListener(Listener* listener)
726 {
727 	BAutolock _(fDataLock);
728 
729 	if (listener && !fListeners.HasItem(listener))
730 		return fListeners.AddItem(listener);
731 	return false;
732 }
733 
734 
735 void
736 Controller::RemoveListener(Listener* listener)
737 {
738 	BAutolock _(fDataLock);
739 
740 	fListeners.RemoveItem(listener);
741 }
742 
743 
744 // #pragma mark -
745 
746 
747 void
748 Controller::_AudioDecodeThread()
749 {
750 	AudioSupplier* lastSupplier = NULL;
751 	size_t bufferSize = 0;
752 	size_t frameSize = 0;
753 	bool decodeError = false;
754 
755 printf("audio decode start\n");
756 
757 	while (acquire_sem(fAudioDecodeSem) == B_OK) {
758 //printf("audio decoding..\n");
759 		buffer_info *buffer = &fAudioBuffer[fAudioBufferWriteIndex];
760 		fAudioBufferWriteIndex = (fAudioBufferWriteIndex + 1) % fAudioBufferCount;
761 
762 		if (!fAudioSupplierLock.Lock())
763 			return;
764 
765 		buffer->formatChanged = lastSupplier != fAudioSupplier;
766 		lastSupplier = fAudioSupplier;
767 
768 		if (!lastSupplier) {
769 			// no audio supplier
770 			buffer->sizeUsed = 0;
771 			buffer->startTime = 0;
772 
773 			fAudioSupplierLock.Unlock();
774 			snooze(10000);
775 			release_sem(fAudioPlaySem);
776 			continue;
777 		}
778 
779 		if (buffer->formatChanged) {
780 printf("audio format changed\n");
781 			buffer->mediaFormat = lastSupplier->Format();
782 			bufferSize = buffer->mediaFormat.u.raw_audio.buffer_size;
783 			frameSize = (buffer->mediaFormat.u.raw_audio.format & 0xf)
784 				* buffer->mediaFormat.u.raw_audio.channel_count;
785 		}
786 
787 		if (buffer->sizeMax < bufferSize) {
788 			delete[] buffer->buffer;
789 			buffer->buffer = new char [bufferSize];
790 			buffer->sizeMax = bufferSize;
791 		}
792 
793 		if (fSeekAudio) {
794 			bigtime_t pos = fSeekPosition;
795 			lastSupplier->SeekToTime(&pos);
796 			fSeekAudio = false;
797 			decodeError = false;
798 		}
799 
800 		int64 frames;
801 		if (!decodeError) {
802 			buffer->endOfStream = false;
803 			status_t ret = lastSupplier->ReadFrames(buffer->buffer,
804 				&frames, &buffer->startTime);
805 			decodeError = B_OK != ret;
806 if (ret != B_OK)
807 printf("audio decode error: %s\n", strerror(ret));
808 			if (ret == B_LAST_BUFFER_ERROR) {
809 				_EndOfStreamReached();
810 				buffer->endOfStream = true;
811 			}
812 		}
813 		if (!decodeError) {
814 			buffer->sizeUsed = frames * frameSize;
815 		} else {
816 			buffer->sizeUsed = 0;
817 			buffer->startTime = 0;
818 
819 			fAudioSupplierLock.Unlock();
820 			snooze(10000);
821 			release_sem(fAudioPlaySem);
822 			continue;
823 		}
824 
825 		fAudioSupplierLock.Unlock();
826 
827 		release_sem(fAudioPlaySem);
828 	}
829 }
830 
831 
832 void
833 Controller::_AudioPlayThread()
834 {
835 	bigtime_t bufferDuration = 0;
836 	bigtime_t audioLatency = 0;
837 	status_t status;
838 
839 printf("audio play start\n");
840 
841 	while (acquire_sem(fAudioPlaySem) == B_OK) {
842 //printf("audio playing..\n");
843 		buffer_info *buffer = &fAudioBuffer[fAudioBufferReadIndex];
844 		fAudioBufferReadIndex = (fAudioBufferReadIndex + 1) % fAudioBufferCount;
845 		wait:
846 		if (fPaused || fStopped) {
847 //printf("waiting..\n");
848 			status = acquire_sem_etc(fVideoWaitSem, 1, B_RELATIVE_TIMEOUT, 50000);
849 			if (status != B_OK && status != B_TIMED_OUT)
850 				break;
851 			goto wait;
852 		}
853 
854 		if (!fDataLock.Lock())
855 			return;
856 
857 		if (buffer->sizeUsed == 0) {
858 			bool pause = fPauseAtEndOfStream && buffer->endOfStream;
859 			fDataLock.Unlock();
860 			release_sem(fAudioDecodeSem);
861 			if (pause) {
862 				fPauseAtEndOfStream = false;
863 				fSeekToStartAfterPause = true;
864 				Pause();
865 			} else
866 				snooze(25000);
867 			continue;
868 		}
869 
870 		if (!fSoundOutput || buffer->formatChanged) {
871 			if (!fSoundOutput
872 				|| !(fSoundOutput->Format() == buffer->mediaFormat.u.raw_audio)) {
873 				delete fSoundOutput;
874 				fSoundOutput = new (nothrow) SoundOutput(fRef.name,
875 					buffer->mediaFormat.u.raw_audio);
876 				fSoundOutput->SetVolume(fVolume);
877 bufferDuration = bigtime_t(1000000.0
878 	* (buffer->mediaFormat.u.raw_audio.buffer_size
879 	/ (buffer->mediaFormat.u.raw_audio.channel_count
880 	* (buffer->mediaFormat.u.raw_audio.format & 0xf)))
881 	/ buffer->mediaFormat.u.raw_audio.frame_rate);
882 printf("audio format changed, new buffer duration %Ld\n", bufferDuration);
883 			}
884 		}
885 
886 		// TODO: fix performance time update (in case no audio)
887 		if (fTimeSourceLock.Lock()) {
888 			audioLatency = fSoundOutput->Latency();
889 			fTimeSourceSysTime = system_time() + audioLatency - bufferDuration;
890 			fTimeSourcePerfTime = buffer->startTime;
891 			fTimeSourceLock.Unlock();
892 		}
893 //		printf("timesource: sys: %Ld perf: %Ld\n", fTimeSourceSysTime,
894 //			fTimeSourcePerfTime);
895 
896 		if (fSoundOutput) {
897 			fSoundOutput->Play(buffer->buffer, buffer->sizeUsed);
898 			_UpdatePosition(buffer->startTime);
899 		}
900 
901 
902 		fDataLock.Unlock();
903 
904 		release_sem(fAudioDecodeSem);
905 	}
906 }
907 
908 
909 // #pragma mark -
910 
911 
912 void
913 Controller::_VideoDecodeThread()
914 {
915 	VideoSupplier* lastSupplier = NULL;
916 	size_t bufferSize = 0;
917 	size_t bytePerRow = 0;
918 	int lineWidth = 0;
919 	int lineCount = 0;
920 	bool decodeError = false;
921 	status_t status;
922 
923 printf("video decode start\n");
924 
925 	while (acquire_sem(fVideoDecodeSem) == B_OK) {
926 		buffer_info *buffer = &fVideoBuffer[fVideoBufferWriteIndex];
927 		fVideoBufferWriteIndex = (fVideoBufferWriteIndex + 1) % fVideoBufferCount;
928 
929 		if (!fVideoSupplierLock.Lock())
930 			return;
931 
932 		buffer->formatChanged = lastSupplier != fVideoSupplier;
933 		lastSupplier = fVideoSupplier;
934 
935 		if (!lastSupplier) {
936 			// no video supplier
937 			buffer->sizeUsed = 0;
938 			buffer->startTime = 0;
939 
940 			fVideoSupplierLock.Unlock();
941 			snooze(10000);
942 			release_sem(fVideoDecodeSem);
943 			continue;
944 		}
945 
946 
947 		if (buffer->formatChanged) {
948 //printf("Video track changed\n");
949 			buffer->mediaFormat = lastSupplier->Format();
950 
951 			bytePerRow = buffer->mediaFormat.u.raw_video.display.bytes_per_row;
952 			lineWidth = buffer->mediaFormat.u.raw_video.display.line_width;
953 			lineCount = buffer->mediaFormat.u.raw_video.display.line_count;
954 			bufferSize = lineCount * bytePerRow;
955 		}
956 
957 		if (buffer->sizeMax != bufferSize) {
958 			LockBitmap();
959 
960 			BRect r(0, 0, lineWidth - 1, lineCount - 1);
961 			if (buffer->bitmap == fCurrentBitmap)
962 				fCurrentBitmap = NULL;
963 			delete buffer->bitmap;
964 printf("allocating bitmap #%ld %d %d %ld\n",
965 	fVideoBufferWriteIndex, lineWidth, lineCount, bytePerRow);
966 			if (buffer->mediaFormat.u.raw_video.display.format == B_YCbCr422) {
967 				buffer->bitmap = new BBitmap(r, B_BITMAP_WILL_OVERLAY
968 					| (fVideoBufferWriteIndex == 0) ?
969 						B_BITMAP_RESERVE_OVERLAY_CHANNEL : 0,
970 					B_YCbCr422, bytePerRow);
971 			} else {
972 				buffer->bitmap = new BBitmap(r, 0, B_RGB32, bytePerRow);
973 			}
974 			status = buffer->bitmap->InitCheck();
975 			if (status != B_OK) {
976 				printf("bitmap init status %08lx %s\n", status, strerror(status));
977 				return;
978 			}
979 			buffer->buffer = (char *)buffer->bitmap->Bits();
980 			buffer->sizeMax = bufferSize;
981 
982 			UnlockBitmap();
983 		}
984 
985 		if (fSeekVideo) {
986 			bigtime_t pos = fSeekPosition;
987 			lastSupplier->SeekToTime(&pos);
988 			fSeekVideo = false;
989 			decodeError = false;
990 		}
991 
992 		if (!decodeError) {
993 //			printf("reading video frame...\n");
994 			status_t ret = lastSupplier->ReadFrame(buffer->buffer,
995 				&buffer->startTime);
996 			decodeError = B_OK != ret;
997 			if (ret == B_LAST_BUFFER_ERROR) {
998 				buffer->endOfStream = true;
999 				_EndOfStreamReached(true);
1000 			}
1001 		}
1002 		if (!decodeError) {
1003 			buffer->sizeUsed = buffer->sizeMax;
1004 		} else {
1005 			buffer->sizeUsed = 0;
1006 			buffer->startTime = 0;
1007 
1008 			fVideoSupplierLock.Unlock();
1009 			snooze(10000);
1010 			release_sem(fVideoPlaySem);
1011 			continue;
1012 		}
1013 
1014 		fVideoSupplierLock.Unlock();
1015 
1016 		release_sem(fVideoPlaySem);
1017 	}
1018 }
1019 
1020 
1021 void
1022 Controller::_VideoPlayThread()
1023 {
1024 	status_t status;
1025 printf("video decode start\n");
1026 
1027 	while (acquire_sem(fVideoPlaySem) == B_OK) {
1028 
1029 		buffer_info *buffer = &fVideoBuffer[fVideoBufferReadIndex];
1030 		fVideoBufferReadIndex = (fVideoBufferReadIndex + 1) % fVideoBufferCount;
1031 		wait:
1032 		if (fPaused || fStopped) {
1033 //printf("waiting..\n");
1034 			status = acquire_sem_etc(fVideoWaitSem, 1, B_RELATIVE_TIMEOUT, 50000);
1035 			if (status != B_OK && status != B_TIMED_OUT)
1036 				break;
1037 			goto wait;
1038 		}
1039 
1040 		bigtime_t waituntil;
1041 		bigtime_t waitdelta;
1042 		bigtime_t now;
1043 		if (fTimeSourceLock.Lock()) {
1044 			now = system_time();
1045 			waituntil = fTimeSourceSysTime - fTimeSourcePerfTime + buffer->startTime - 1000;
1046 			waitdelta = waituntil - now;
1047 			fTimeSourceLock.Unlock();
1048 		} else {
1049 			// puhh...
1050 		}
1051 
1052 #if 0
1053 		char test[100];
1054 		sprintf(test, "sys %.6f perf %.6f, vid %.6f, now %.6f, waituntil %.6f, waitdelta %.6f",
1055 				fTimeSourceSysTime / 1E6, fTimeSourcePerfTime / 1E6,
1056 				buffer->startTime / 1E6, now / 1E6,
1057 				waituntil / 1E6, waitdelta / 1E6);
1058 		if (fVideoView->LockLooperWithTimeout(5000) == B_OK) {
1059 			fVideoView->Window()->SetTitle(test);
1060 			fVideoView->UnlockLooper();
1061 		}
1062 #endif
1063 
1064 		if (fAudioSupplierLock.Lock()) {
1065 			if (!fAudioSupplier) {
1066 				fTimeSourceSysTime = system_time();
1067 				fTimeSourcePerfTime = buffer->startTime;
1068 			}
1069 			fAudioSupplierLock.Unlock();
1070 		} else {
1071 			// puhh...
1072 		}
1073 
1074 
1075 #if 1
1076 		if (waitdelta < -150000) {
1077 			printf("video: frame %.6f too late, dropped\n", waitdelta  / -1E6);
1078 			release_sem(fVideoDecodeSem);
1079 			continue;
1080 		}
1081 #endif
1082 
1083 		status = acquire_sem_etc(fVideoWaitSem, 1, B_ABSOLUTE_TIMEOUT, waituntil);
1084 		if (status == B_OK) { // interrupted by seeking
1085 			printf("video: video wait interruped\n");
1086 			continue;
1087 		}
1088 		if (status != B_TIMED_OUT)
1089 			break;
1090 
1091 		if (!fDataLock.Lock())
1092 			return;
1093 
1094 		if (fVideoView) {
1095 			if (buffer->sizeUsed == buffer->sizeMax) {
1096 				LockBitmap();
1097 				fCurrentBitmap = buffer->bitmap;
1098 				fVideoView->DrawFrame();
1099 				UnlockBitmap();
1100 
1101 				_UpdatePosition(buffer->startTime, true);
1102 			} else {
1103 				bool pause = fPauseAtEndOfStream && buffer->endOfStream;
1104 				fDataLock.Unlock();
1105 
1106 				release_sem(fVideoDecodeSem);
1107 
1108 				if (pause) {
1109 					fPauseAtEndOfStream = false;
1110 					fSeekToStartAfterPause = true;
1111 					Pause();
1112 				}
1113 //else
1114 //					snooze(25000);
1115 				continue;
1116 			}
1117 		} else
1118 			debugger("fVideoView == NULL");
1119 
1120 		fDataLock.Unlock();
1121 
1122 	//	snooze(60000);
1123 		release_sem(fVideoDecodeSem);
1124 	}
1125 
1126 //		status_t status = acquire_sem_etc(fVideoWaitSem, 1, B_ABSOLUTE_TIMEOUT, buffer->startTime);
1127 //		if (status != B_TIMED_OUT)
1128 //			return;
1129 }
1130 
1131 
1132 // #pragma mark -
1133 
1134 
1135 void
1136 Controller::_StartThreads()
1137 {
1138 	if (fAudioDecodeSem > 0)
1139 		return;
1140 
1141 	fAudioBufferReadIndex = 0;
1142 	fAudioBufferWriteIndex = 0;
1143 	fVideoBufferReadIndex = 0;
1144 	fVideoBufferWriteIndex = 0;
1145 	fAudioDecodeSem = create_sem(fAudioBufferCount, "audio decode sem");
1146 	fVideoDecodeSem = create_sem(fVideoBufferCount - 2, "video decode sem");
1147 	fAudioPlaySem = create_sem(0, "audio play sem");
1148 	fVideoPlaySem = create_sem(0, "video play sem");
1149 	fAudioWaitSem = create_sem(0, "audio wait sem");
1150 	fVideoWaitSem = create_sem(0, "video wait sem");
1151 	fAudioDecodeThread = spawn_thread(_AudioDecodeThreadEntry, "audio decode", AUDIO_DECODE_PRIORITY, this);
1152 	fVideoDecodeThread = spawn_thread(_VideoDecodeThreadEntry, "video decode", VIDEO_DECODE_PRIORITY, this);
1153 	fAudioPlayThread = spawn_thread(_AudioPlayThreadEntry, "audio play", AUDIO_PLAY_PRIORITY, this);
1154 	fVideoPlayThread = spawn_thread(_VideoPlayThreadEntry, "video play", VIDEO_PLAY_PRIORITY, this);
1155 	resume_thread(fAudioDecodeThread);
1156 	resume_thread(fVideoDecodeThread);
1157 	resume_thread(fAudioPlayThread);
1158 	resume_thread(fVideoPlayThread);
1159 }
1160 
1161 
1162 void
1163 Controller::_StopThreads()
1164 {
1165 	if (fAudioDecodeSem < 0)
1166 		return;
1167 
1168 	delete_sem(fAudioDecodeSem);
1169 	delete_sem(fVideoDecodeSem);
1170 	delete_sem(fAudioPlaySem);
1171 	delete_sem(fVideoPlaySem);
1172 	delete_sem(fAudioWaitSem);
1173 	delete_sem(fVideoWaitSem);
1174 
1175 	status_t dummy;
1176 	wait_for_thread(fAudioDecodeThread, &dummy);
1177 	wait_for_thread(fVideoDecodeThread, &dummy);
1178 	wait_for_thread(fAudioPlayThread, &dummy);
1179 	wait_for_thread(fVideoPlayThread, &dummy);
1180 	fAudioDecodeThread = -1;
1181 	fVideoDecodeThread = -1;
1182 	fAudioPlayThread = -1;
1183 	fVideoPlayThread = -1;
1184 	fAudioWaitSem = -1;
1185 	fVideoWaitSem = -1;
1186 	fAudioDecodeSem = -1;
1187 	fVideoDecodeSem = -1;
1188 	fAudioPlaySem = -1;
1189 	fVideoPlaySem = -1;
1190 }
1191 
1192 
1193 // #pragma mark -
1194 
1195 
1196 void
1197 Controller::_EndOfStreamReached(bool isVideo)
1198 {
1199 	// you need to hold the fDataLock
1200 
1201 	// prefer end of audio stream over end of video stream
1202 	if (isVideo && fAudioSupplier)
1203 		return;
1204 
1205 	// NOTE: executed in audio/video decode thread
1206 	if (!fStopped) {
1207 		fPauseAtEndOfStream = true;
1208 		_NotifyFileFinished();
1209 	}
1210 }
1211 
1212 
1213 void
1214 Controller::_UpdatePosition(bigtime_t position, bool isVideoPosition, bool force)
1215 {
1216 	// you need to hold the fDataLock
1217 
1218 	if (!force && fStopped)
1219 		return;
1220 
1221 	// prefer audio position over video position
1222 	if (isVideoPosition && fAudioSupplier)
1223 		return;
1224 
1225 //	BAutolock _(fTimeSourceLock);
1226 //	fTimeSourcePerfTime = position;
1227 
1228 	fPosition = position;
1229 	float scale = fDuration > 0 ? (float)fPosition / fDuration : 0.0;
1230 	_NotifyPositionChanged(scale);
1231 }
1232 
1233 
1234 // #pragma mark -
1235 
1236 
1237 int32
1238 Controller::_AudioDecodeThreadEntry(void *self)
1239 {
1240 	static_cast<Controller *>(self)->_AudioDecodeThread();
1241 	return 0;
1242 }
1243 
1244 
1245 int32
1246 Controller::_VideoDecodeThreadEntry(void *self)
1247 {
1248 	static_cast<Controller *>(self)->_VideoDecodeThread();
1249 	return 0;
1250 }
1251 
1252 
1253 int32
1254 Controller::_AudioPlayThreadEntry(void *self)
1255 {
1256 	static_cast<Controller *>(self)->_AudioPlayThread();
1257 	return 0;
1258 }
1259 
1260 
1261 int32
1262 Controller::_VideoPlayThreadEntry(void *self)
1263 {
1264 	static_cast<Controller *>(self)->_VideoPlayThread();
1265 	return 0;
1266 }
1267 
1268 
1269 // #pragma mark -
1270 
1271 
1272 void
1273 Controller::_NotifyFileChanged()
1274 {
1275 	BList listeners(fListeners);
1276 	int32 count = listeners.CountItems();
1277 	for (int32 i = 0; i < count; i++) {
1278 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1279 		listener->FileChanged();
1280 	}
1281 }
1282 
1283 
1284 void
1285 Controller::_NotifyFileFinished()
1286 {
1287 	BList listeners(fListeners);
1288 	int32 count = listeners.CountItems();
1289 	for (int32 i = 0; i < count; i++) {
1290 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1291 		listener->FileFinished();
1292 	}
1293 }
1294 
1295 
1296 void
1297 Controller::_NotifyVideoTrackChanged(int32 index)
1298 {
1299 	BList listeners(fListeners);
1300 	int32 count = listeners.CountItems();
1301 	for (int32 i = 0; i < count; i++) {
1302 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1303 		listener->VideoTrackChanged(index);
1304 	}
1305 }
1306 
1307 
1308 void
1309 Controller::_NotifyAudioTrackChanged(int32 index)
1310 {
1311 	BList listeners(fListeners);
1312 	int32 count = listeners.CountItems();
1313 	for (int32 i = 0; i < count; i++) {
1314 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1315 		listener->AudioTrackChanged(index);
1316 	}
1317 }
1318 
1319 
1320 void
1321 Controller::_NotifyVideoStatsChanged()
1322 {
1323 	BList listeners(fListeners);
1324 	int32 count = listeners.CountItems();
1325 	for (int32 i = 0; i < count; i++) {
1326 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1327 		listener->VideoStatsChanged();
1328 	}
1329 }
1330 
1331 
1332 void
1333 Controller::_NotifyAudioStatsChanged()
1334 {
1335 	BList listeners(fListeners);
1336 	int32 count = listeners.CountItems();
1337 	for (int32 i = 0; i < count; i++) {
1338 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1339 		listener->AudioStatsChanged();
1340 	}
1341 }
1342 
1343 
1344 void
1345 Controller::_NotifyPlaybackStateChanged()
1346 {
1347 	uint32 state = PlaybackState();
1348 	BList listeners(fListeners);
1349 	int32 count = listeners.CountItems();
1350 	for (int32 i = 0; i < count; i++) {
1351 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1352 		listener->PlaybackStateChanged(state);
1353 	}
1354 }
1355 
1356 
1357 void
1358 Controller::_NotifyPositionChanged(float position)
1359 {
1360 	BList listeners(fListeners);
1361 	int32 count = listeners.CountItems();
1362 	for (int32 i = 0; i < count; i++) {
1363 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1364 		listener->PositionChanged(position);
1365 	}
1366 }
1367 
1368 
1369 void
1370 Controller::_NotifyVolumeChanged(float volume)
1371 {
1372 	BList listeners(fListeners);
1373 	int32 count = listeners.CountItems();
1374 	for (int32 i = 0; i < count; i++) {
1375 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1376 		listener->VolumeChanged(volume);
1377 	}
1378 }
1379 
1380 
1381 void
1382 Controller::_NotifyMutedChanged(bool muted)
1383 {
1384 	BList listeners(fListeners);
1385 	int32 count = listeners.CountItems();
1386 	for (int32 i = 0; i < count; i++) {
1387 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1388 		listener->MutedChanged(muted);
1389 	}
1390 }
1391