Rewrote audio decoding to provide timing information
that is used to sync with video. Separated audio decoding and playing into two threads, the same applies to video decoding and playback. This was inspired from code written by Stephan. Added video decoding and display, added play/pause/stop. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17533 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+440
-137
@@ -21,6 +21,9 @@
|
||||
#include <string.h>
|
||||
#include <Debug.h>
|
||||
#include <Entry.h>
|
||||
#include <Window.h>
|
||||
#include <Bitmap.h>
|
||||
#include <Autolock.h>
|
||||
#include <MediaFile.h>
|
||||
#include <MediaTrack.h>
|
||||
|
||||
@@ -30,8 +33,10 @@
|
||||
#include "SoundOutput.h"
|
||||
|
||||
|
||||
#define AUDIO_PRIORITY 10
|
||||
#define VIDEO_PRIORITY 10
|
||||
#define AUDIO_PLAY_PRIORITY 10
|
||||
#define VIDEO_PLAY_PRIORITY 10
|
||||
#define AUDIO_DECODE_PRIORITY 10
|
||||
#define VIDEO_DECODE_PRIORITY 10
|
||||
|
||||
void
|
||||
HandleError(const char *text, status_t err)
|
||||
@@ -53,36 +58,61 @@ Controller::Controller()
|
||||
, fMediaFile(0)
|
||||
, fAudioTrack(0)
|
||||
, fVideoTrack(0)
|
||||
, fAudioTrackLock("audio track lock")
|
||||
, fVideoTrackLock("video track lock")
|
||||
, fAudioTrackList(new BList)
|
||||
, fVideoTrackList(new BList)
|
||||
, fPosition(0)
|
||||
, fAudioPlaySem(create_sem(1, "audio playing"))
|
||||
, fVideoPlaySem(create_sem(1, "video playing"))
|
||||
, fAudioDecodeSem(-1)
|
||||
, fVideoDecodeSem(-1)
|
||||
, fAudioPlaySem(-1)
|
||||
, fVideoPlaySem(-1)
|
||||
, fAudioDecodeThread(-1)
|
||||
, fVideoDecodeThread(-1)
|
||||
, fAudioPlayThread(-1)
|
||||
, fVideoPlayThread(-1)
|
||||
, fStopAudioPlayback(false)
|
||||
, fStopVideoPlayback(false)
|
||||
, fSoundOutput(NULL)
|
||||
, fSeekAudio(false)
|
||||
, fSeekVideo(false)
|
||||
, fSeekPosition(0)
|
||||
, fDuration(0)
|
||||
, fAudioBufferCount(MAX_AUDIO_BUFFERS)
|
||||
, fAudioBufferReadIndex(0)
|
||||
, fAudioBufferWriteIndex(0)
|
||||
, fVideoBufferCount(MAX_VIDEO_BUFFERS)
|
||||
, fVideoBufferReadIndex(0)
|
||||
, fVideoBufferWriteIndex(0)
|
||||
, fTimeSourceLock("time source lock")
|
||||
, fTimeSourceSysTime(0)
|
||||
, fTimeSourcePerfTime(0)
|
||||
, fAutoplay(true)
|
||||
, fCurrentBitmap(NULL)
|
||||
{
|
||||
for (int i = 0; i < MAX_AUDIO_BUFFERS; i++) {
|
||||
fAudioBuffer[i].bitmap = NULL;
|
||||
fAudioBuffer[i].buffer = NULL;
|
||||
fAudioBuffer[i].sizeMax = 0;
|
||||
}
|
||||
for (int i = 0; i < MAX_VIDEO_BUFFERS; i++) {
|
||||
fVideoBuffer[i].bitmap = NULL;
|
||||
fVideoBuffer[i].buffer = NULL;
|
||||
fVideoBuffer[i].sizeMax = 0;
|
||||
}
|
||||
|
||||
fStopped = fAutoplay ? false : true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
Controller::~Controller()
|
||||
{
|
||||
StopAudioPlayback();
|
||||
StopVideoPlayback();
|
||||
StopThreads();
|
||||
|
||||
if (fMediaFile)
|
||||
fMediaFile->ReleaseAllTracks();
|
||||
delete fMediaFile;
|
||||
delete fAudioTrackList;
|
||||
delete fVideoTrackList;
|
||||
delete_sem(fVideoPlaySem);
|
||||
delete_sem(fAudioPlaySem);
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +120,7 @@ void
|
||||
Controller::SetVideoView(VideoView *view)
|
||||
{
|
||||
fVideoView = view;
|
||||
fVideoView->SetController(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -103,11 +134,12 @@ Controller::SetControllerView(ControllerView *view)
|
||||
status_t
|
||||
Controller::SetTo(const entry_ref &ref)
|
||||
{
|
||||
acquire_sem(fAudioPlaySem);
|
||||
acquire_sem(fVideoPlaySem);
|
||||
|
||||
StopAudioPlayback();
|
||||
StopVideoPlayback();
|
||||
StopThreads();
|
||||
|
||||
UpdatePosition(0);
|
||||
|
||||
BAutolock al(fAudioTrackLock);
|
||||
BAutolock vl(fVideoTrackLock);
|
||||
|
||||
fAudioTrackList->MakeEmpty();
|
||||
fVideoTrackList->MakeEmpty();
|
||||
@@ -118,11 +150,13 @@ Controller::SetTo(const entry_ref &ref)
|
||||
fVideoTrack = 0;
|
||||
fMediaFile = 0;
|
||||
fPosition = 0;
|
||||
fSeekAudio = false;
|
||||
fSeekVideo = false;
|
||||
fPaused = false;
|
||||
fStopped = true;
|
||||
fStopped = fAutoplay ? false : true;
|
||||
fDuration = 0;
|
||||
fName = ref.name;
|
||||
|
||||
|
||||
status_t err;
|
||||
|
||||
BMediaFile *mf = new BMediaFile(&ref);
|
||||
@@ -130,8 +164,6 @@ Controller::SetTo(const entry_ref &ref)
|
||||
if (err != B_OK) {
|
||||
printf("Controller::SetTo: initcheck failed\n");
|
||||
delete mf;
|
||||
release_sem(fAudioPlaySem);
|
||||
release_sem(fVideoPlaySem);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -139,8 +171,6 @@ Controller::SetTo(const entry_ref &ref)
|
||||
if (trackcount <= 0) {
|
||||
printf("Controller::SetTo: trackcount %d\n", trackcount);
|
||||
delete mf;
|
||||
release_sem(fAudioPlaySem);
|
||||
release_sem(fVideoPlaySem);
|
||||
return B_MEDIA_NO_HANDLER;
|
||||
}
|
||||
|
||||
@@ -167,8 +197,6 @@ Controller::SetTo(const entry_ref &ref)
|
||||
if (AudioTrackCount() == 0 && VideoTrackCount() == 0) {
|
||||
printf("Controller::SetTo: no audio or video tracks found\n");
|
||||
delete mf;
|
||||
release_sem(fAudioPlaySem);
|
||||
release_sem(fVideoPlaySem);
|
||||
return B_MEDIA_NO_HANDLER;
|
||||
}
|
||||
|
||||
@@ -178,14 +206,34 @@ Controller::SetTo(const entry_ref &ref)
|
||||
|
||||
SelectAudioTrack(0);
|
||||
SelectVideoTrack(0);
|
||||
|
||||
release_sem(fAudioPlaySem);
|
||||
release_sem(fVideoPlaySem);
|
||||
|
||||
StartThreads();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Controller::GetSize(int *width, int *height)
|
||||
{
|
||||
/*
|
||||
media_format fmt;
|
||||
buffer->mediaFormat.type = B_MEDIA_RAW_VIDEO;
|
||||
buffer->mediaFormat.u.raw_video = media_raw_video_format::wildcard;
|
||||
buffer->mediaFormat.u.raw_video.display.format = IsOverlayActive() ? B_YCbCr422 : B_RGB32;
|
||||
if (fVideoTrack || B_OK != fVideoTrack->DecodedFormat(&fmt)) {
|
||||
*/
|
||||
*height = 480;
|
||||
*width = 640;
|
||||
/*
|
||||
} else {
|
||||
*height = fmt.u.raw_video.display.line_count;
|
||||
*width = fmt.u.raw_video.display.line_width;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Controller::VideoTrackCount()
|
||||
{
|
||||
@@ -202,9 +250,9 @@ Controller::AudioTrackCount()
|
||||
|
||||
status_t
|
||||
Controller::SelectAudioTrack(int n)
|
||||
{
|
||||
StopAudioPlayback();
|
||||
|
||||
{
|
||||
BAutolock al(fAudioTrackLock);
|
||||
|
||||
BMediaTrack *t = (BMediaTrack *)fAudioTrackList->ItemAt(n);
|
||||
if (!t)
|
||||
return B_ERROR;
|
||||
@@ -214,7 +262,6 @@ Controller::SelectAudioTrack(int n)
|
||||
bigtime_t v = fVideoTrack ? fVideoTrack->Duration() : 0;
|
||||
fDuration = max_c(a, v);
|
||||
|
||||
StartAudioPlayback();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -222,7 +269,7 @@ Controller::SelectAudioTrack(int n)
|
||||
status_t
|
||||
Controller::SelectVideoTrack(int n)
|
||||
{
|
||||
StopVideoPlayback();
|
||||
BAutolock vl(fVideoTrackLock);
|
||||
|
||||
BMediaTrack *t = (BMediaTrack *)fVideoTrackList->ItemAt(n);
|
||||
if (!t)
|
||||
@@ -233,7 +280,6 @@ Controller::SelectVideoTrack(int n)
|
||||
bigtime_t v = fVideoTrack ? fVideoTrack->Duration() : 0;
|
||||
fDuration = max_c(a, v);
|
||||
|
||||
StartVideoPlayback();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -307,7 +353,8 @@ Controller::UpdatePosition(float value)
|
||||
bool
|
||||
Controller::IsOverlayActive()
|
||||
{
|
||||
return true;
|
||||
// return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -326,47 +373,51 @@ Controller::UnlockBitmap()
|
||||
BBitmap *
|
||||
Controller::Bitmap()
|
||||
{
|
||||
return NULL;
|
||||
return fCurrentBitmap;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Controller::Stop()
|
||||
{
|
||||
printf("Controller::Stop\n");
|
||||
|
||||
if (fStopped)
|
||||
return;
|
||||
|
||||
acquire_sem(fAudioPlaySem);
|
||||
acquire_sem(fVideoPlaySem);
|
||||
|
||||
fPaused = false;
|
||||
fStopped = true;
|
||||
fPosition = 0;
|
||||
|
||||
// böse...
|
||||
snooze(30000);
|
||||
fSeekAudio = true;
|
||||
fSeekVideo = true;
|
||||
fSeekPosition = 0;
|
||||
snooze(30000);
|
||||
UpdatePosition(0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Controller::Play()
|
||||
{
|
||||
printf("Controller::Play\n");
|
||||
|
||||
if (!fPaused && !fStopped)
|
||||
return;
|
||||
|
||||
fStopped =
|
||||
fPaused = false;
|
||||
|
||||
release_sem(fAudioPlaySem);
|
||||
release_sem(fVideoPlaySem);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Controller::Pause()
|
||||
{
|
||||
printf("Controller::Pause\n");
|
||||
|
||||
if (fStopped || fPaused)
|
||||
return;
|
||||
|
||||
acquire_sem(fAudioPlaySem);
|
||||
acquire_sem(fVideoPlaySem);
|
||||
|
||||
fPaused = true;
|
||||
}
|
||||
@@ -379,6 +430,351 @@ Controller::IsPaused()
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Controller::IsStopped()
|
||||
{
|
||||
return fStopped;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Controller::AudioDecodeThread()
|
||||
{
|
||||
BMediaTrack *lastTrack = 0;
|
||||
size_t bufferSize = 0;
|
||||
size_t frameSize = 0;
|
||||
bool decodeError = false;
|
||||
status_t status;
|
||||
|
||||
printf("audio decode start\n");
|
||||
if (fAudioTrack == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
while (acquire_sem(fAudioDecodeSem) == B_OK) {
|
||||
//printf("audio decoding..\n");
|
||||
buffer_info *buffer = &fAudioBuffer[fAudioBufferWriteIndex];
|
||||
fAudioBufferWriteIndex = (fAudioBufferWriteIndex + 1) % fAudioBufferCount;
|
||||
BAutolock lock(fAudioTrackLock);
|
||||
if (lastTrack != fAudioTrack) {
|
||||
//printf("audio track changed\n");
|
||||
lastTrack = fAudioTrack;
|
||||
buffer->formatChanged = true;
|
||||
buffer->mediaFormat.type = B_MEDIA_RAW_AUDIO;
|
||||
buffer->mediaFormat.u.raw_audio = media_multi_audio_format::wildcard;
|
||||
#ifdef __HAIKU__
|
||||
buffer->mediaFormat.u.raw_audio.format = media_multi_audio_format::B_AUDIO_FLOAT;
|
||||
#endif
|
||||
status = fAudioTrack->DecodedFormat(&buffer->mediaFormat);
|
||||
if (status != B_OK) {
|
||||
printf("audio decoded format status %08x %s\n", status, strerror(status));
|
||||
return;
|
||||
}
|
||||
bufferSize = buffer->mediaFormat.u.raw_audio.buffer_size;
|
||||
frameSize = (buffer->mediaFormat.u.raw_audio.format & 0xf) * buffer->mediaFormat.u.raw_audio.channel_count;
|
||||
} else {
|
||||
buffer->formatChanged = false;
|
||||
}
|
||||
if (buffer->sizeMax < bufferSize) {
|
||||
delete buffer->buffer;
|
||||
buffer->buffer = new char [bufferSize];
|
||||
buffer->sizeMax = bufferSize;;
|
||||
}
|
||||
|
||||
if (fSeekAudio) {
|
||||
bigtime_t pos = fSeekPosition;
|
||||
fAudioTrack->SeekToTime(&pos);
|
||||
fSeekAudio = false;
|
||||
decodeError = false;
|
||||
}
|
||||
|
||||
int64 frames;
|
||||
media_header mh;
|
||||
if (!decodeError) {
|
||||
decodeError = B_OK != fAudioTrack->ReadFrames(buffer->buffer, &frames, &mh);
|
||||
}
|
||||
if (!decodeError) {
|
||||
buffer->sizeUsed = frames * frameSize;
|
||||
buffer->startTime = mh.start_time;
|
||||
} else {
|
||||
buffer->sizeUsed = 0;
|
||||
buffer->startTime = 0;
|
||||
}
|
||||
|
||||
release_sem(fAudioPlaySem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Controller::AudioPlayThread()
|
||||
{
|
||||
SoundOutput *output = NULL;
|
||||
bigtime_t bufferDuration = 0;
|
||||
status_t status;
|
||||
|
||||
|
||||
printf("audio play start\n");
|
||||
if (fAudioTrack == 0) {
|
||||
fTimeSourceSysTime = 0;
|
||||
fTimeSourcePerfTime = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
while (acquire_sem(fAudioPlaySem) == B_OK) {
|
||||
//printf("audio playing..\n");
|
||||
buffer_info *buffer = &fAudioBuffer[fAudioBufferReadIndex];
|
||||
fAudioBufferReadIndex = (fAudioBufferReadIndex + 1) % fAudioBufferCount;
|
||||
wait:
|
||||
if (fPaused || fStopped) {
|
||||
//printf("waiting..\n");
|
||||
status = acquire_sem_etc(fThreadWaitSem, 1, B_RELATIVE_TIMEOUT, 50000);
|
||||
if (status != B_TIMED_OUT)
|
||||
break;
|
||||
goto wait;
|
||||
}
|
||||
if (buffer->formatChanged) {
|
||||
//printf("format changed..\n");
|
||||
delete output;
|
||||
output = new SoundOutput(fName.String(), buffer->mediaFormat.u.raw_audio);
|
||||
bufferDuration = bigtime_t(1000000.0 * (buffer->mediaFormat.u.raw_audio.buffer_size / (buffer->mediaFormat.u.raw_audio.channel_count * (buffer->mediaFormat.u.raw_audio.format & 0xf))) / buffer->mediaFormat.u.raw_audio.frame_rate);
|
||||
printf("audio format changed, new buffer duration %Ld\n", bufferDuration);
|
||||
fSoundOutput = output; // hack...
|
||||
}
|
||||
if (output) {
|
||||
if (buffer->sizeUsed)
|
||||
output->Play(buffer->buffer, buffer->sizeUsed);
|
||||
BAutolock lock(fTimeSourceLock);
|
||||
fTimeSourceSysTime = system_time() + output->Latency() - bufferDuration;
|
||||
fTimeSourcePerfTime = buffer->startTime;
|
||||
// printf("timesource: sys: %Ld perf: %Ld\n", fTimeSourceSysTime, fTimeSourcePerfTime);
|
||||
UpdatePosition(buffer->startTime / (float)Duration());
|
||||
} else {
|
||||
debugger("kein SoundOutput");
|
||||
}
|
||||
release_sem(fAudioDecodeSem);
|
||||
}
|
||||
delete output;
|
||||
fSoundOutput = NULL; // hack...
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Controller::VideoDecodeThread()
|
||||
{
|
||||
BMediaTrack *lastTrack = 0;
|
||||
size_t bufferSize = 0;
|
||||
size_t bytePerRow = 0;
|
||||
int lineWidth = 0;
|
||||
int lineCount = 0;
|
||||
bool decodeError = false;
|
||||
status_t status;
|
||||
|
||||
printf("video decode start\n");
|
||||
if (fVideoTrack == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (acquire_sem(fVideoDecodeSem) == B_OK) {
|
||||
buffer_info *buffer = &fVideoBuffer[fVideoBufferWriteIndex];
|
||||
fVideoBufferWriteIndex = (fVideoBufferWriteIndex + 1) % fVideoBufferCount;
|
||||
BAutolock lock(fVideoTrackLock);
|
||||
if (lastTrack != fVideoTrack) {
|
||||
//printf("Video track changed\n");
|
||||
lastTrack = fVideoTrack;
|
||||
buffer->formatChanged = true;
|
||||
buffer->mediaFormat.type = B_MEDIA_RAW_VIDEO;
|
||||
buffer->mediaFormat.u.raw_video = media_raw_video_format::wildcard;
|
||||
buffer->mediaFormat.u.raw_video.display.format = IsOverlayActive() ? B_YCbCr422 : B_RGB32;
|
||||
status = fVideoTrack->DecodedFormat(&buffer->mediaFormat);
|
||||
if (status != B_OK) {
|
||||
printf("video decoded format status %08x %s\n", status, strerror(status));
|
||||
return;
|
||||
}
|
||||
bytePerRow = buffer->mediaFormat.u.raw_video.display.bytes_per_row;
|
||||
lineWidth = buffer->mediaFormat.u.raw_video.display.line_width;
|
||||
lineCount = buffer->mediaFormat.u.raw_video.display.line_count;
|
||||
bufferSize = lineCount * bytePerRow;
|
||||
} else {
|
||||
buffer->formatChanged = false;
|
||||
}
|
||||
if (buffer->sizeMax != bufferSize) {
|
||||
BRect r(0, 0, lineWidth - 1, lineCount - 1);
|
||||
delete buffer->bitmap;
|
||||
printf("allocating bitmap %d %d %d\n", lineWidth, lineCount, bytePerRow);
|
||||
if (IsOverlayActive())
|
||||
buffer->bitmap = new BBitmap(r, B_BITMAP_WILL_OVERLAY | (fVideoBufferWriteIndex == 1) ? B_BITMAP_RESERVE_OVERLAY_CHANNEL : 0, IsOverlayActive() ? B_YCbCr422 : B_RGB32, bytePerRow);
|
||||
else
|
||||
buffer->bitmap = new BBitmap(r, 0, B_RGB32, bytePerRow);
|
||||
status = buffer->bitmap->InitCheck();
|
||||
if (status != B_OK) {
|
||||
printf("video decoded format status %08x %s\n", status, strerror(status));
|
||||
return;
|
||||
}
|
||||
buffer->buffer = (char *)buffer->bitmap->Bits();
|
||||
buffer->sizeMax = bufferSize;
|
||||
}
|
||||
|
||||
if (fSeekVideo) {
|
||||
bigtime_t pos = fSeekPosition;
|
||||
fVideoTrack->SeekToTime(&pos);
|
||||
fSeekVideo = false;
|
||||
decodeError = false;
|
||||
}
|
||||
|
||||
int64 frames;
|
||||
media_header mh;
|
||||
if (!decodeError) {
|
||||
// printf("reading video frame...\n");
|
||||
decodeError = B_OK != fVideoTrack->ReadFrames(buffer->buffer, &frames, &mh);
|
||||
}
|
||||
if (!decodeError) {
|
||||
buffer->sizeUsed = buffer->sizeMax;
|
||||
buffer->startTime = mh.start_time;
|
||||
} else {
|
||||
buffer->sizeUsed = 0;
|
||||
buffer->startTime = 0;
|
||||
}
|
||||
|
||||
release_sem(fVideoPlaySem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Controller::VideoPlayThread()
|
||||
{
|
||||
status_t status;
|
||||
printf("video decode start\n");
|
||||
if (fVideoTrack == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (acquire_sem(fVideoPlaySem) == B_OK) {
|
||||
|
||||
buffer_info *buffer = &fVideoBuffer[fVideoBufferReadIndex];
|
||||
fVideoBufferReadIndex = (fVideoBufferReadIndex + 1) % fVideoBufferCount;
|
||||
wait:
|
||||
if (fPaused || fStopped) {
|
||||
//printf("waiting..\n");
|
||||
status = acquire_sem_etc(fThreadWaitSem, 1, B_RELATIVE_TIMEOUT, 50000);
|
||||
if (status != B_TIMED_OUT)
|
||||
break;
|
||||
goto wait;
|
||||
}
|
||||
|
||||
bigtime_t waituntil;
|
||||
bigtime_t waitdelta;
|
||||
char test[100];
|
||||
{
|
||||
BAutolock lock(fTimeSourceLock);
|
||||
|
||||
waituntil = fTimeSourceSysTime - fTimeSourcePerfTime + buffer->startTime;
|
||||
waitdelta = waituntil - system_time();
|
||||
/*
|
||||
sprintf(test, "sys %.6f perf %.6f, vid %.6f, waituntil %.6f, waitdelta %.6f",
|
||||
fTimeSourceSysTime / 1000000.0f,
|
||||
fTimeSourcePerfTime / 1000000.0f,
|
||||
buffer->startTime / 1000000.0f,
|
||||
waituntil / 1000000.0f,
|
||||
waitdelta / 1000000.0f);
|
||||
*/
|
||||
// if (status != B_TIMED_OUT)
|
||||
}
|
||||
/*
|
||||
if (fVideoView->LockLooperWithTimeout(5000) == B_OK) {
|
||||
fVideoView->Window()->SetTitle(test);
|
||||
fVideoView->UnlockLooper();
|
||||
}
|
||||
*/
|
||||
status = acquire_sem_etc(fThreadWaitSem, 1, B_ABSOLUTE_TIMEOUT, waituntil);
|
||||
if (status != B_TIMED_OUT)
|
||||
break;
|
||||
|
||||
fCurrentBitmap = buffer->bitmap;
|
||||
fVideoView->DrawFrame();
|
||||
|
||||
// snooze(60000);
|
||||
release_sem(fVideoDecodeSem);
|
||||
}
|
||||
|
||||
// status_t status = acquire_sem_etc(fThreadWaitSem, 1, B_ABSOLUTE_TIMEOUT, buffer->startTime);
|
||||
// if (status != B_TIMED_OUT)
|
||||
// return;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Controller::StartThreads()
|
||||
{
|
||||
if (fAudioDecodeSem > 0)
|
||||
return;
|
||||
|
||||
fAudioBufferReadIndex = 0;
|
||||
fAudioBufferWriteIndex = 0;
|
||||
fVideoBufferReadIndex = 0;
|
||||
fVideoBufferWriteIndex = 0;
|
||||
fAudioDecodeSem = create_sem(fAudioBufferCount, "audio decode sem");
|
||||
fVideoDecodeSem = create_sem(fVideoBufferCount - 2, "video decode sem");
|
||||
fAudioPlaySem = create_sem(0, "audio play sem");
|
||||
fVideoPlaySem = create_sem(0, "video play sem");
|
||||
fThreadWaitSem = create_sem(0, "thread wait sem");
|
||||
fAudioDecodeThread = spawn_thread(audio_decode_thread, "audio decode", AUDIO_DECODE_PRIORITY, this);
|
||||
fVideoDecodeThread = spawn_thread(video_decode_thread, "video decode", VIDEO_DECODE_PRIORITY, this);
|
||||
fAudioPlayThread = spawn_thread(audio_play_thread, "audio play", AUDIO_PLAY_PRIORITY, this);
|
||||
fVideoPlayThread = spawn_thread(video_play_thread, "video play", VIDEO_PLAY_PRIORITY, this);
|
||||
resume_thread(fAudioDecodeThread);
|
||||
resume_thread(fVideoDecodeThread);
|
||||
resume_thread(fAudioPlayThread);
|
||||
resume_thread(fVideoPlayThread);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Controller::StopThreads()
|
||||
{
|
||||
if (fAudioDecodeSem < 0)
|
||||
return;
|
||||
|
||||
delete_sem(fAudioDecodeSem);
|
||||
delete_sem(fVideoDecodeSem);
|
||||
delete_sem(fAudioPlaySem);
|
||||
delete_sem(fVideoPlaySem);
|
||||
delete_sem(fThreadWaitSem);
|
||||
|
||||
status_t dummy;
|
||||
wait_for_thread(fAudioDecodeThread, &dummy);
|
||||
wait_for_thread(fVideoDecodeThread, &dummy);
|
||||
wait_for_thread(fAudioPlayThread, &dummy);
|
||||
wait_for_thread(fVideoPlayThread, &dummy);
|
||||
fAudioDecodeThread = -1;
|
||||
fVideoDecodeThread = -1;
|
||||
fAudioPlayThread = -1;
|
||||
fVideoPlayThread = -1;
|
||||
fThreadWaitSem = -1;
|
||||
fAudioDecodeSem = -1;
|
||||
fVideoDecodeSem = -1;
|
||||
fAudioPlaySem = -1;
|
||||
fVideoPlaySem = -1;
|
||||
}
|
||||
|
||||
int32
|
||||
Controller::audio_decode_thread(void *self)
|
||||
{
|
||||
static_cast<Controller *>(self)->AudioDecodeThread();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
Controller::video_decode_thread(void *self)
|
||||
{
|
||||
static_cast<Controller *>(self)->VideoDecodeThread();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
Controller::audio_play_thread(void *self)
|
||||
{
|
||||
@@ -393,96 +789,3 @@ Controller::video_play_thread(void *self)
|
||||
static_cast<Controller *>(self)->VideoPlayThread();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Controller::AudioPlayThread()
|
||||
{
|
||||
// this is a test...
|
||||
media_format fmt;
|
||||
fmt.type = B_MEDIA_RAW_AUDIO;
|
||||
fmt.u.raw_audio = media_multi_audio_format::wildcard;
|
||||
#ifdef __HAIKU__
|
||||
fmt.u.raw_audio.format = media_multi_audio_format::B_AUDIO_FLOAT;
|
||||
#endif
|
||||
fAudioTrack->DecodedFormat(&fmt);
|
||||
|
||||
SoundOutput out(fName.String(), fmt.u.raw_audio);
|
||||
|
||||
out.SetVolume(1.0);
|
||||
UpdateVolume(1.0);
|
||||
|
||||
|
||||
int frame_size = (fmt.u.raw_audio.format & 0xf) * fmt.u.raw_audio.channel_count;
|
||||
uint8 buffer[fmt.u.raw_audio.buffer_size];
|
||||
int64 frames;
|
||||
media_header mh;
|
||||
|
||||
fSoundOutput = &out;
|
||||
while (!fStopAudioPlayback) {
|
||||
if (B_OK == fAudioTrack->ReadFrames(buffer, &frames, &mh)) {
|
||||
out.Play(buffer, frames * frame_size);
|
||||
UpdatePosition(mh.start_time / (float)Duration());
|
||||
} else {
|
||||
snooze(50000);
|
||||
}
|
||||
if (fSeekAudio) {
|
||||
bigtime_t pos = fSeekPosition;
|
||||
fAudioTrack->SeekToTime(&pos);
|
||||
fSeekAudio = false;
|
||||
}
|
||||
}
|
||||
fSoundOutput = NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Controller::VideoPlayThread()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Controller::StartAudioPlayback()
|
||||
{
|
||||
if (fAudioPlayThread > 0)
|
||||
return;
|
||||
fStopAudioPlayback = false;
|
||||
fAudioPlayThread = spawn_thread(audio_play_thread, "audio playback", AUDIO_PRIORITY, this);
|
||||
resume_thread(fAudioPlayThread);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Controller::StartVideoPlayback()
|
||||
{
|
||||
if (fVideoPlayThread > 0)
|
||||
return;
|
||||
fStopVideoPlayback = false;
|
||||
fVideoPlayThread = spawn_thread(video_play_thread, "video playback", VIDEO_PRIORITY, this);
|
||||
resume_thread(fVideoPlayThread);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Controller::StopAudioPlayback()
|
||||
{
|
||||
if (fAudioPlayThread < 0)
|
||||
return;
|
||||
fStopAudioPlayback = true;
|
||||
status_t dummy;
|
||||
wait_for_thread(fAudioPlayThread, &dummy);
|
||||
fAudioPlayThread = -1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Controller::StopVideoPlayback()
|
||||
{
|
||||
if (fVideoPlayThread < 0)
|
||||
return;
|
||||
fStopVideoPlayback = true;
|
||||
status_t dummy;
|
||||
wait_for_thread(fVideoPlayThread, &dummy);
|
||||
fVideoPlayThread = -1;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include <MediaDefs.h>
|
||||
#include <MediaNode.h>
|
||||
#include <Locker.h>
|
||||
#include <String.h>
|
||||
|
||||
class BBitmap;
|
||||
@@ -38,6 +39,7 @@ public:
|
||||
virtual ~Controller();
|
||||
|
||||
status_t SetTo(const entry_ref &ref);
|
||||
void GetSize(int *width, int *height);
|
||||
|
||||
int AudioTrackCount();
|
||||
int VideoTrackCount();
|
||||
@@ -54,6 +56,7 @@ public:
|
||||
void Play();
|
||||
void Pause();
|
||||
bool IsPaused();
|
||||
bool IsStopped();
|
||||
|
||||
void SetVideoView(VideoView *view);
|
||||
void SetControllerView(ControllerView *view);
|
||||
@@ -75,43 +78,89 @@ public:
|
||||
void UpdatePosition(float value);
|
||||
|
||||
private:
|
||||
static int32 audio_decode_thread(void *self);
|
||||
static int32 video_decode_thread(void *self);
|
||||
static int32 audio_play_thread(void *self);
|
||||
static int32 video_play_thread(void *self);
|
||||
|
||||
void AudioDecodeThread();
|
||||
void VideoDecodeThread();
|
||||
void AudioPlayThread();
|
||||
void VideoPlayThread();
|
||||
|
||||
void StartThreads();
|
||||
void StopThreads();
|
||||
|
||||
void StartAudioPlayback();
|
||||
void StartVideoPlayback();
|
||||
void StopAudioPlayback();
|
||||
void StopVideoPlayback();
|
||||
|
||||
private:
|
||||
|
||||
enum {
|
||||
MAX_AUDIO_BUFFERS = 8,
|
||||
MAX_VIDEO_BUFFERS = 3,
|
||||
};
|
||||
|
||||
struct buffer_info {
|
||||
char * buffer;
|
||||
BBitmap * bitmap;
|
||||
size_t sizeUsed;
|
||||
size_t sizeMax;
|
||||
bigtime_t startTime;
|
||||
bool formatChanged;
|
||||
media_format mediaFormat;
|
||||
};
|
||||
|
||||
VideoView * fVideoView;
|
||||
ControllerView * fControllerView;
|
||||
BString fName;
|
||||
bool fPaused;
|
||||
bool fStopped;
|
||||
volatile bool fPaused;
|
||||
volatile bool fStopped;
|
||||
BMediaFile * fMediaFile;
|
||||
BMediaTrack * fAudioTrack;
|
||||
BMediaTrack * fVideoTrack;
|
||||
|
||||
BLocker fAudioTrackLock;
|
||||
BLocker fVideoTrackLock;
|
||||
|
||||
BList * fAudioTrackList;
|
||||
BList * fVideoTrackList;
|
||||
bigtime_t fPosition;
|
||||
media_format fAudioFormat;
|
||||
media_format fVideoFormat;
|
||||
|
||||
sem_id fAudioDecodeSem;
|
||||
sem_id fVideoDecodeSem;
|
||||
sem_id fAudioPlaySem;
|
||||
sem_id fVideoPlaySem;
|
||||
sem_id fThreadWaitSem;
|
||||
thread_id fAudioDecodeThread;
|
||||
thread_id fVideoDecodeThread;
|
||||
thread_id fAudioPlayThread;
|
||||
thread_id fVideoPlayThread;
|
||||
volatile bool fStopAudioPlayback;
|
||||
volatile bool fStopVideoPlayback;
|
||||
|
||||
SoundOutput * fSoundOutput;
|
||||
volatile bool fSeekAudio;
|
||||
volatile bool fSeekVideo;
|
||||
volatile bigtime_t fSeekPosition;
|
||||
bigtime_t fDuration;
|
||||
|
||||
int32 fAudioBufferCount;
|
||||
int32 fAudioBufferReadIndex;
|
||||
int32 fAudioBufferWriteIndex;
|
||||
int32 fVideoBufferCount;
|
||||
int32 fVideoBufferReadIndex;
|
||||
int32 fVideoBufferWriteIndex;
|
||||
|
||||
buffer_info fAudioBuffer[MAX_AUDIO_BUFFERS];
|
||||
buffer_info fVideoBuffer[MAX_VIDEO_BUFFERS];
|
||||
|
||||
BLocker fTimeSourceLock;
|
||||
bigtime_t fTimeSourceSysTime;
|
||||
bigtime_t fTimeSourcePerfTime;
|
||||
bool fAutoplay;
|
||||
|
||||
BBitmap * fCurrentBitmap;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ void
|
||||
ControllerView::TogglePlaying()
|
||||
{
|
||||
printf("ControllerView::TogglePlaying()\n");
|
||||
if (fController->IsPaused())
|
||||
if (fController->IsPaused() || fController->IsStopped())
|
||||
fController->Play();
|
||||
else
|
||||
fController->Pause();
|
||||
|
||||
@@ -199,10 +199,9 @@ MainWin::SetupWindow()
|
||||
fVideoMenu->ItemAt(0)->SetMarked(true);
|
||||
|
||||
if (fHasVideo) {
|
||||
fSourceWidth = 320;
|
||||
fSourceHeight = 240;
|
||||
fWidthScale = 1.24;
|
||||
fHeightScale = 1.35;
|
||||
fController->GetSize(&fSourceWidth, &fSourceHeight);
|
||||
fWidthScale = 1.0;
|
||||
fHeightScale = 1.0;
|
||||
} else {
|
||||
fSourceWidth = 0;
|
||||
fSourceHeight = 0;
|
||||
|
||||
@@ -108,7 +108,7 @@ void
|
||||
SoundOutput::PlayBuffer(void *buffer)
|
||||
{
|
||||
if (acquire_sem_etc(fBufferReadable, 1, B_RELATIVE_TIMEOUT, fBufferDuration / 2) != B_OK) {
|
||||
printf("SoundOutput: buffer not ready, playing silence\n");
|
||||
// printf("SoundOutput: buffer not ready, playing silence\n");
|
||||
memset(buffer, 0, fBufferSize);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -29,8 +29,10 @@ VideoView::VideoView(BRect frame, const char *name, uint32 resizeMask, uint32 fl
|
||||
, fController(NULL)
|
||||
, fOverlayActive(false)
|
||||
{
|
||||
// SetViewColor(B_TRANSPARENT_COLOR);
|
||||
SetViewColor(127,255,127);
|
||||
SetViewColor(B_TRANSPARENT_COLOR);
|
||||
// SetViewColor(127,255,127);
|
||||
rgb_color r = {255, 0, 0, 255};
|
||||
fOverlayKeyColor = r;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +41,13 @@ VideoView::~VideoView()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
VideoView::SetController(Controller *controller)
|
||||
{
|
||||
fController = controller;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
VideoView::AttachedToWindow()
|
||||
{
|
||||
@@ -163,12 +172,13 @@ VideoView::DrawFrame()
|
||||
printf("can't ClearViewOverlay, as LockLooperWithTimeout failed\n");
|
||||
}
|
||||
}
|
||||
if (want_overlay && !fOverlayActive) {
|
||||
if (want_overlay && !fOverlayActive ) {
|
||||
fController->LockBitmap();
|
||||
BBitmap *bmp = 0; // fController->Bitmap();
|
||||
BBitmap *bmp = fController->Bitmap();
|
||||
if (bmp && LockLooperWithTimeout(50000) == B_OK) {
|
||||
SetViewOverlay(bmp, bmp->Bounds(), Bounds(), &fOverlayKeyColor,
|
||||
B_FOLLOW_ALL, B_OVERLAY_FILTER_HORIZONTAL | B_OVERLAY_FILTER_VERTICAL);
|
||||
B_FOLLOW_ALL,
|
||||
/*B_OVERLAY_TRANSFER_CHANNEL | */B_OVERLAY_FILTER_HORIZONTAL | B_OVERLAY_FILTER_VERTICAL );
|
||||
fOverlayActive = true;
|
||||
|
||||
Invalidate();
|
||||
@@ -228,7 +238,7 @@ VideoView::IsOverlaySupported()
|
||||
|
||||
bool supported = false;
|
||||
for (int i = 0; colspace[i].name; i++) {
|
||||
BBitmap *test = new BBitmap(BRect(0,0,320,240), B_BITMAP_WILL_OVERLAY | B_BITMAP_RESERVE_OVERLAY_CHANNEL, colspace[i].colspace);
|
||||
BBitmap *test = new BBitmap(BRect(0,0,319,239), B_BITMAP_WILL_OVERLAY | B_BITMAP_RESERVE_OVERLAY_CHANNEL, colspace[i].colspace);
|
||||
if (test->InitCheck() == B_OK) {
|
||||
printf("Display supports %s (0x%08x) overlay\n", colspace[i].name, colspace[i].colspace);
|
||||
supported = true;
|
||||
|
||||
@@ -28,6 +28,8 @@ class VideoView : public BView
|
||||
public:
|
||||
VideoView(BRect frame, const char *name, uint32 resizeMask, uint32 flags);
|
||||
~VideoView();
|
||||
|
||||
void SetController(Controller *controller);
|
||||
|
||||
void RemoveVideoDisplay();
|
||||
void RemoveOverlay();
|
||||
|
||||
Reference in New Issue
Block a user