mirror of
https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git
synced 2025-07-18 11:19:10 +00:00
Decode the whole audio track on startup
This commit is contained in:
@ -135,7 +135,7 @@ public:
|
|||||||
|
|
||||||
const mkvparser::Track* GetTrack() { return fTrack; }
|
const mkvparser::Track* GetTrack() { return fTrack; }
|
||||||
|
|
||||||
bool GetFrames(mkvparser::MkvReader* reader, int64_t movieTime, std::vector<blkbuf_t>& frames)
|
bool GetFrames(mkvparser::MkvReader* reader, int64_t movieTimeNs, std::vector<blkbuf_t>& frames)
|
||||||
{
|
{
|
||||||
// If we have no block yet, grab the first one
|
// If we have no block yet, grab the first one
|
||||||
if (!fCurrentBlock)
|
if (!fCurrentBlock)
|
||||||
@ -146,7 +146,7 @@ public:
|
|||||||
{
|
{
|
||||||
const mkvparser::Block* block = fCurrentBlock->GetBlock();
|
const mkvparser::Block* block = fCurrentBlock->GetBlock();
|
||||||
int64_t time = block->GetTime(fCurrentBlock->GetCluster()) - fTrack->GetCodecDelay();
|
int64_t time = block->GetTime(fCurrentBlock->GetCluster()) - fTrack->GetCodecDelay();
|
||||||
if (time <= movieTime * 1000000) // Block time is nano seconds
|
if (time <= movieTimeNs)
|
||||||
{
|
{
|
||||||
// We want to play this block, add it to the frames buffer
|
// We want to play this block, add it to the frames buffer
|
||||||
frames.reserve(frames.size() + block->GetFrameCount());
|
frames.reserve(frames.size() + block->GetFrameCount());
|
||||||
@ -180,8 +180,7 @@ plMoviePlayer::plMoviePlayer() :
|
|||||||
fLastFrameTime(0),
|
fLastFrameTime(0),
|
||||||
fPosition(hsPoint2()),
|
fPosition(hsPoint2()),
|
||||||
fPlaying(false),
|
fPlaying(false),
|
||||||
fPaused(false),
|
fPaused(false)
|
||||||
fOpusDecoder(nullptr)
|
|
||||||
{
|
{
|
||||||
fScale.Set(1.0f, 1.0f);
|
fScale.Set(1.0f, 1.0f);
|
||||||
}
|
}
|
||||||
@ -192,8 +191,6 @@ plMoviePlayer::~plMoviePlayer()
|
|||||||
// The plPlate owns the Mipmap Texture, so it destroys it for us
|
// The plPlate owns the Mipmap Texture, so it destroys it for us
|
||||||
plPlateManager::Instance().DestroyPlate(fPlate);
|
plPlateManager::Instance().DestroyPlate(fPlate);
|
||||||
#ifdef VIDEO_AVAILABLE
|
#ifdef VIDEO_AVAILABLE
|
||||||
if (fOpusDecoder)
|
|
||||||
opus_decoder_destroy(fOpusDecoder);
|
|
||||||
if (fReader)
|
if (fReader)
|
||||||
{
|
{
|
||||||
fReader->Close();
|
fReader->Close();
|
||||||
@ -255,6 +252,60 @@ bool plMoviePlayer::IOpenMovie()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool plMoviePlayer::ILoadAudio()
|
||||||
|
{
|
||||||
|
#ifdef VIDEO_AVAILABLE
|
||||||
|
// Fetch audio track information
|
||||||
|
const mkvparser::AudioTrack* audio = static_cast<const mkvparser::AudioTrack*>(fAudioTrack->GetTrack());
|
||||||
|
plWAVHeader header;
|
||||||
|
header.fFormatTag = plWAVHeader::kPCMFormatTag;
|
||||||
|
header.fNumChannels = audio->GetChannels();
|
||||||
|
header.fBitsPerSample = audio->GetBitDepth() == 8 ? 8 : 16;
|
||||||
|
header.fNumSamplesPerSec = 48000; // OPUS specs say we shall always decode at 48kHz
|
||||||
|
header.fBlockAlign = header.fNumChannels * header.fBitsPerSample / 8;
|
||||||
|
header.fAvgBytesPerSec = header.fNumSamplesPerSec * header.fBlockAlign;
|
||||||
|
fAudioSound.reset(new plWin32VideoSound(header));
|
||||||
|
|
||||||
|
// Initialize Opus
|
||||||
|
if (strcmp(audio->GetCodecId(), WEBM_CODECID_OPUS) != 0)
|
||||||
|
{
|
||||||
|
hsAssert(false, "Not an Opus audio track!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int error;
|
||||||
|
OpusDecoder* opus = opus_decoder_create(48000, audio->GetChannels(), &error);
|
||||||
|
if (error != OPUS_OK)
|
||||||
|
hsAssert(false, "Error occured initalizing opus");
|
||||||
|
|
||||||
|
// Decode audio track
|
||||||
|
std::vector<blkbuf_t> frames;
|
||||||
|
fAudioTrack->GetFrames(fReader, fSegment->GetDuration(), frames);
|
||||||
|
static const int maxFrameSize = 5760; // for max packet duration at 48kHz
|
||||||
|
std::vector<int16_t> decoded;
|
||||||
|
decoded.reserve(frames.size() * audio->GetChannels() * maxFrameSize);
|
||||||
|
|
||||||
|
for (auto it = frames.begin(); it != frames.end(); ++it)
|
||||||
|
{
|
||||||
|
const std::unique_ptr<uint8_t>& buf = std::get<0>(*it);
|
||||||
|
int32_t size = std::get<1>(*it);
|
||||||
|
|
||||||
|
int16_t* pcm = new int16_t[maxFrameSize * audio->GetChannels()];
|
||||||
|
int samples = opus_decode(opus, buf.get(), size, pcm, maxFrameSize, 0);
|
||||||
|
if (samples < 0)
|
||||||
|
hsAssert(false, "opus error");
|
||||||
|
for (size_t i = 0; i < samples * audio->GetChannels(); i++)
|
||||||
|
decoded.push_back(pcm[i]);
|
||||||
|
delete[] pcm;
|
||||||
|
}
|
||||||
|
|
||||||
|
fAudioSound->FillSoundBuffer(reinterpret_cast<uint8_t*>(decoded.data()), decoded.size() * sizeof(int16_t));
|
||||||
|
opus_decoder_destroy(opus);
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
bool plMoviePlayer::ICheckLanguage(const mkvparser::Track* track)
|
bool plMoviePlayer::ICheckLanguage(const mkvparser::Track* track)
|
||||||
{
|
{
|
||||||
auto codes = plLocalization::GetLanguageCodes(plLocalization::GetLanguage());
|
auto codes = plLocalization::GetLanguageCodes(plLocalization::GetLanguage());
|
||||||
@ -299,28 +350,6 @@ void plMoviePlayer::IProcessVideoFrame(const std::vector<blkbuf_t>& frames)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void plMoviePlayer::IProcessAudioFrame(const std::vector<blkbuf_t>& frames)
|
|
||||||
{
|
|
||||||
#ifdef VIDEO_AVAILABLE
|
|
||||||
const uint8_t* data = nullptr;
|
|
||||||
int32_t size = 0;
|
|
||||||
for (auto it = frames.begin(); it != frames.end(); ++it)
|
|
||||||
{
|
|
||||||
const std::unique_ptr<uint8_t>& buf = std::get<0>(*it);
|
|
||||||
data = buf.get();
|
|
||||||
size = std::get<1>(*it);
|
|
||||||
|
|
||||||
static const int frameSize = 5760; //max packet duration at 48kHz
|
|
||||||
const mkvparser::AudioTrack* audio = static_cast<const mkvparser::AudioTrack*>(fAudioTrack->GetTrack());
|
|
||||||
int16_t* pcm = new int16_t[frameSize * audio->GetChannels() * sizeof(int16_t)];
|
|
||||||
int samples = opus_decode(fOpusDecoder, data, size, pcm, frameSize, 0);
|
|
||||||
if (samples < 0)
|
|
||||||
hsAssert(false, "opus error");
|
|
||||||
fAudioSound->UpdateSoundBuffer(reinterpret_cast<uint8_t*>(pcm), samples * audio->GetChannels() * sizeof(int16_t));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool plMoviePlayer::Start()
|
bool plMoviePlayer::Start()
|
||||||
{
|
{
|
||||||
if (fPlaying)
|
if (fPlaying)
|
||||||
@ -357,29 +386,12 @@ bool plMoviePlayer::Start()
|
|||||||
plateMgr.SetPlatePixelSize(fPlate, plateWidth, plateHeight);
|
plateMgr.SetPlatePixelSize(fPlate, plateWidth, plateHeight);
|
||||||
fTexture = fPlate->CreateMaterial(static_cast<uint32_t>(video->GetWidth()), static_cast<uint32_t>(video->GetHeight()), false);
|
fTexture = fPlate->CreateMaterial(static_cast<uint32_t>(video->GetWidth()), static_cast<uint32_t>(video->GetHeight()), false);
|
||||||
|
|
||||||
// Fetch audio track information
|
// Decode the audio track and load it into a sound buffer
|
||||||
const mkvparser::AudioTrack* audio = static_cast<const mkvparser::AudioTrack*>(fAudioTrack->GetTrack());
|
if (!ILoadAudio())
|
||||||
plWAVHeader header;
|
|
||||||
header.fFormatTag = plWAVHeader::kPCMFormatTag;
|
|
||||||
header.fNumChannels = audio->GetChannels();
|
|
||||||
header.fBitsPerSample = audio->GetBitDepth() == 8 ? 8 : 16;
|
|
||||||
header.fNumSamplesPerSec = 48000; // OPUS specs say we shall always decode at 48kHz
|
|
||||||
header.fBlockAlign = header.fNumChannels * header.fBitsPerSample / 8;
|
|
||||||
header.fAvgBytesPerSec = header.fNumSamplesPerSec * header.fBlockAlign;
|
|
||||||
fAudioSound.reset(new plWin32VideoSound(header));
|
|
||||||
|
|
||||||
// Initialize Opus
|
|
||||||
if (strcmp(audio->GetCodecId(), WEBM_CODECID_OPUS) != 0)
|
|
||||||
{
|
|
||||||
hsAssert(false, "Not an Opus audio track!");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
int error;
|
|
||||||
fOpusDecoder = opus_decoder_create(48000, audio->GetChannels(), &error);
|
|
||||||
if (error != OPUS_OK)
|
|
||||||
hsAssert(false, "Error occured initalizing opus");
|
|
||||||
|
|
||||||
fLastFrameTime = static_cast<int64_t>(hsTimer::GetMilliSeconds());
|
fLastFrameTime = static_cast<int64_t>(hsTimer::GetMilliSeconds());
|
||||||
|
fAudioSound->Play();
|
||||||
fPlaying = true;
|
fPlaying = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -404,20 +416,8 @@ bool plMoviePlayer::NextFrame()
|
|||||||
// Get our current timecode
|
// Get our current timecode
|
||||||
fMovieTime += frameTimeDelta;
|
fMovieTime += frameTimeDelta;
|
||||||
|
|
||||||
std::vector<blkbuf_t> audio;
|
|
||||||
std::vector<blkbuf_t> video;
|
std::vector<blkbuf_t> video;
|
||||||
uint8_t tracksWithData = 0;
|
if (!fVideoTrack || !fVideoTrack->GetFrames(fReader, fMovieTime * 1000000, video))
|
||||||
if (fAudioTrack)
|
|
||||||
{
|
|
||||||
if (fAudioTrack->GetFrames(fReader, fMovieTime, audio))
|
|
||||||
tracksWithData++;
|
|
||||||
}
|
|
||||||
if (fVideoTrack)
|
|
||||||
{
|
|
||||||
if (fVideoTrack->GetFrames(fReader, fMovieTime, video))
|
|
||||||
tracksWithData++;
|
|
||||||
}
|
|
||||||
if (!tracksWithData)
|
|
||||||
{
|
{
|
||||||
Stop();
|
Stop();
|
||||||
return false;
|
return false;
|
||||||
@ -425,7 +425,7 @@ bool plMoviePlayer::NextFrame()
|
|||||||
|
|
||||||
// Show our mess
|
// Show our mess
|
||||||
IProcessVideoFrame(video);
|
IProcessVideoFrame(video);
|
||||||
IProcessAudioFrame(audio);
|
fAudioSound->RefreshVolume();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else
|
||||||
@ -438,6 +438,7 @@ bool plMoviePlayer::Pause(bool on)
|
|||||||
if (!fPlaying)
|
if (!fPlaying)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
fAudioSound->Pause(on);
|
||||||
fPaused = on;
|
fPaused = on;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -449,6 +450,7 @@ bool plMoviePlayer::Stop()
|
|||||||
fAudioSound->Stop();
|
fAudioSound->Stop();
|
||||||
if (fPlate)
|
if (fPlate)
|
||||||
fPlate->SetVisible(false);
|
fPlate->SetVisible(false);
|
||||||
|
|
||||||
for (int i = 0; i < fCallbacks.size(); i++)
|
for (int i = 0; i < fCallbacks.size(); i++)
|
||||||
fCallbacks[i]->Send();
|
fCallbacks[i]->Send();
|
||||||
fCallbacks.clear();
|
fCallbacks.clear();
|
||||||
|
@ -75,11 +75,9 @@ protected:
|
|||||||
std::unique_ptr<mkvparser::Segment> fSegment;
|
std::unique_ptr<mkvparser::Segment> fSegment;
|
||||||
std::unique_ptr<class TrackMgr> fAudioTrack, fVideoTrack; // TODO: vector of tracks?
|
std::unique_ptr<class TrackMgr> fAudioTrack, fVideoTrack; // TODO: vector of tracks?
|
||||||
std::unique_ptr<class plWin32VideoSound> fAudioSound;
|
std::unique_ptr<class plWin32VideoSound> fAudioSound;
|
||||||
|
|
||||||
std::unique_ptr<class VPX> fVpx;
|
std::unique_ptr<class VPX> fVpx;
|
||||||
class OpusDecoder* fOpusDecoder;
|
|
||||||
|
|
||||||
int64_t fMovieTime, fLastFrameTime;
|
int64_t fMovieTime, fLastFrameTime; // in ms
|
||||||
hsPoint2 fPosition, fScale;
|
hsPoint2 fPosition, fScale;
|
||||||
plFileName fMoviePath;
|
plFileName fMoviePath;
|
||||||
|
|
||||||
@ -87,9 +85,9 @@ protected:
|
|||||||
bool fPaused;
|
bool fPaused;
|
||||||
|
|
||||||
bool IOpenMovie();
|
bool IOpenMovie();
|
||||||
|
bool ILoadAudio();
|
||||||
bool ICheckLanguage(const mkvparser::Track* track);
|
bool ICheckLanguage(const mkvparser::Track* track);
|
||||||
void IProcessVideoFrame(const std::vector<blkbuf_t>& frames);
|
void IProcessVideoFrame(const std::vector<blkbuf_t>& frames);
|
||||||
void IProcessAudioFrame(const std::vector<blkbuf_t>& frames);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
plMoviePlayer();
|
plMoviePlayer();
|
||||||
|
@ -619,6 +619,16 @@ void plDSoundBuffer::Play( void )
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//// Pause ///////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void plDSoundBuffer::Pause()
|
||||||
|
{
|
||||||
|
if (!source)
|
||||||
|
return;
|
||||||
|
alSourcePause(source);
|
||||||
|
alGetError();
|
||||||
|
}
|
||||||
|
|
||||||
//// Stop ////////////////////////////////////////////////////////////////////
|
//// Stop ////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void plDSoundBuffer::Stop( void )
|
void plDSoundBuffer::Stop( void )
|
||||||
|
@ -73,8 +73,9 @@ public:
|
|||||||
|
|
||||||
void Play( void );
|
void Play( void );
|
||||||
void Stop( void );
|
void Stop( void );
|
||||||
void Rewind() ;
|
void Rewind();
|
||||||
|
void Pause();
|
||||||
|
|
||||||
uint32_t GetLengthInBytes( void ) const;
|
uint32_t GetLengthInBytes( void ) const;
|
||||||
void SetScalarVolume( float volume ); // Sets the volume, but on a range from 0 to 1
|
void SetScalarVolume( float volume ); // Sets the volume, but on a range from 0 to 1
|
||||||
|
|
||||||
|
@ -47,16 +47,15 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
|||||||
#include "plDSoundBuffer.h"
|
#include "plDSoundBuffer.h"
|
||||||
|
|
||||||
static int uniqueID = 0;
|
static int uniqueID = 0;
|
||||||
plWin32VideoSound::plWin32VideoSound(plWAVHeader& header) : plWin32Sound()
|
plWin32VideoSound::plWin32VideoSound(const plWAVHeader& header) : plWin32Sound()
|
||||||
{
|
{
|
||||||
fCurrVolume = 1.0f;
|
fCurrVolume = 1.0f;
|
||||||
fDesiredVol = 1.0f;
|
fDesiredVol = 1.0f;
|
||||||
fSoftVolume = 1.0f;
|
fSoftVolume = 1.0f;
|
||||||
fType = kGUISound;
|
fType = kGUISound;
|
||||||
|
|
||||||
fDSoundBuffer = new plDSoundBuffer(0, header, false, false, false, true);
|
fWAVHeader = header;
|
||||||
fDSoundBuffer->SetupVoiceSource();
|
fDSoundBuffer = new plDSoundBuffer(0, fWAVHeader, false, false);
|
||||||
fDSoundBuffer->SetScalarVolume(1.0f);
|
|
||||||
|
|
||||||
uniqueID++;
|
uniqueID++;
|
||||||
hsgResMgr::ResMgr()->NewKey(plFormat("videosound#{}", uniqueID), this, plLocation::kGlobalFixedLoc);
|
hsgResMgr::ResMgr()->NewKey(plFormat("videosound#{}", uniqueID), this, plLocation::kGlobalFixedLoc);
|
||||||
@ -68,24 +67,26 @@ plWin32VideoSound::~plWin32VideoSound()
|
|||||||
delete fDSoundBuffer;
|
delete fDSoundBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void plWin32VideoSound::UpdateSoundBuffer(void* buffer, size_t size)
|
void plWin32VideoSound::Play()
|
||||||
{
|
{
|
||||||
uint32_t bufferId;
|
|
||||||
uint32_t chunk;
|
|
||||||
|
|
||||||
fDSoundBuffer->UnQueueVoiceBuffers();
|
|
||||||
while (size > 0)
|
|
||||||
{
|
|
||||||
chunk = size < STREAM_BUFFER_SIZE ? size : STREAM_BUFFER_SIZE;
|
|
||||||
if (!fDSoundBuffer->GetAvailableBufferId(&bufferId))
|
|
||||||
break;
|
|
||||||
|
|
||||||
fDSoundBuffer->VoiceFillBuffer(buffer, chunk, bufferId);
|
|
||||||
size -= chunk;
|
|
||||||
}
|
|
||||||
IActuallyPlay();
|
IActuallyPlay();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void plWin32VideoSound::Pause(bool on)
|
||||||
|
{
|
||||||
|
if (on)
|
||||||
|
fDSoundBuffer->Pause();
|
||||||
|
else if (!fReallyPlaying)
|
||||||
|
fDSoundBuffer->Play();
|
||||||
|
fReallyPlaying = !on;
|
||||||
|
}
|
||||||
|
|
||||||
|
void plWin32VideoSound::FillSoundBuffer(void* buffer, size_t size)
|
||||||
|
{
|
||||||
|
fDSoundBuffer->FillBuffer(buffer, size, &fWAVHeader);
|
||||||
|
fDSoundBuffer->SetScalarVolume(1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
void plWin32VideoSound::IDerivedActuallyPlay()
|
void plWin32VideoSound::IDerivedActuallyPlay()
|
||||||
{
|
{
|
||||||
if (!fReallyPlaying)
|
if (!fReallyPlaying)
|
||||||
|
@ -48,10 +48,12 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
|||||||
class plWin32VideoSound : public plWin32Sound
|
class plWin32VideoSound : public plWin32Sound
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
plWin32VideoSound(plWAVHeader& header);
|
plWin32VideoSound(const plWAVHeader& header);
|
||||||
virtual ~plWin32VideoSound();
|
virtual ~plWin32VideoSound();
|
||||||
|
|
||||||
void UpdateSoundBuffer(void* buffer, size_t size);
|
virtual void Play();
|
||||||
|
virtual void Pause(bool on);
|
||||||
|
void FillSoundBuffer(void* buffer, size_t size);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void IDerivedActuallyPlay(void);
|
void IDerivedActuallyPlay(void);
|
||||||
@ -60,5 +62,6 @@ protected:
|
|||||||
float GetActualTimeSec();
|
float GetActualTimeSec();
|
||||||
void ISetActualTime(double t);
|
void ISetActualTime(double t);
|
||||||
|
|
||||||
|
plWAVHeader fWAVHeader;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user