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