mirror of
https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git
synced 2025-07-18 19:29:09 +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; }
|
||||
|
||||
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 (!fCurrentBlock)
|
||||
@ -146,7 +146,7 @@ public:
|
||||
{
|
||||
const mkvparser::Block* block = fCurrentBlock->GetBlock();
|
||||
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
|
||||
frames.reserve(frames.size() + block->GetFrameCount());
|
||||
@ -180,8 +180,7 @@ plMoviePlayer::plMoviePlayer() :
|
||||
fLastFrameTime(0),
|
||||
fPosition(hsPoint2()),
|
||||
fPlaying(false),
|
||||
fPaused(false),
|
||||
fOpusDecoder(nullptr)
|
||||
fPaused(false)
|
||||
{
|
||||
fScale.Set(1.0f, 1.0f);
|
||||
}
|
||||
@ -192,8 +191,6 @@ plMoviePlayer::~plMoviePlayer()
|
||||
// The plPlate owns the Mipmap Texture, so it destroys it for us
|
||||
plPlateManager::Instance().DestroyPlate(fPlate);
|
||||
#ifdef VIDEO_AVAILABLE
|
||||
if (fOpusDecoder)
|
||||
opus_decoder_destroy(fOpusDecoder);
|
||||
if (fReader)
|
||||
{
|
||||
fReader->Close();
|
||||
@ -255,6 +252,60 @@ bool plMoviePlayer::IOpenMovie()
|
||||
#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)
|
||||
{
|
||||
auto codes = plLocalization::GetLanguageCodes(plLocalization::GetLanguage());
|
||||
@ -299,28 +350,6 @@ void plMoviePlayer::IProcessVideoFrame(const std::vector<blkbuf_t>& frames)
|
||||
#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()
|
||||
{
|
||||
if (fPlaying)
|
||||
@ -357,29 +386,12 @@ bool plMoviePlayer::Start()
|
||||
plateMgr.SetPlatePixelSize(fPlate, plateWidth, plateHeight);
|
||||
fTexture = fPlate->CreateMaterial(static_cast<uint32_t>(video->GetWidth()), static_cast<uint32_t>(video->GetHeight()), false);
|
||||
|
||||
// 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!");
|
||||
// Decode the audio track and load it into a sound buffer
|
||||
if (!ILoadAudio())
|
||||
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());
|
||||
fAudioSound->Play();
|
||||
fPlaying = true;
|
||||
|
||||
return true;
|
||||
@ -404,20 +416,8 @@ bool plMoviePlayer::NextFrame()
|
||||
// Get our current timecode
|
||||
fMovieTime += frameTimeDelta;
|
||||
|
||||
std::vector<blkbuf_t> audio;
|
||||
std::vector<blkbuf_t> video;
|
||||
uint8_t tracksWithData = 0;
|
||||
if (fAudioTrack)
|
||||
{
|
||||
if (fAudioTrack->GetFrames(fReader, fMovieTime, audio))
|
||||
tracksWithData++;
|
||||
}
|
||||
if (fVideoTrack)
|
||||
{
|
||||
if (fVideoTrack->GetFrames(fReader, fMovieTime, video))
|
||||
tracksWithData++;
|
||||
}
|
||||
if (!tracksWithData)
|
||||
if (!fVideoTrack || !fVideoTrack->GetFrames(fReader, fMovieTime * 1000000, video))
|
||||
{
|
||||
Stop();
|
||||
return false;
|
||||
@ -425,7 +425,7 @@ bool plMoviePlayer::NextFrame()
|
||||
|
||||
// Show our mess
|
||||
IProcessVideoFrame(video);
|
||||
IProcessAudioFrame(audio);
|
||||
fAudioSound->RefreshVolume();
|
||||
|
||||
return true;
|
||||
#else
|
||||
@ -438,6 +438,7 @@ bool plMoviePlayer::Pause(bool on)
|
||||
if (!fPlaying)
|
||||
return false;
|
||||
|
||||
fAudioSound->Pause(on);
|
||||
fPaused = on;
|
||||
return true;
|
||||
}
|
||||
@ -449,6 +450,7 @@ bool plMoviePlayer::Stop()
|
||||
fAudioSound->Stop();
|
||||
if (fPlate)
|
||||
fPlate->SetVisible(false);
|
||||
|
||||
for (int i = 0; i < fCallbacks.size(); i++)
|
||||
fCallbacks[i]->Send();
|
||||
fCallbacks.clear();
|
||||
|
@ -75,11 +75,9 @@ protected:
|
||||
std::unique_ptr<mkvparser::Segment> fSegment;
|
||||
std::unique_ptr<class TrackMgr> fAudioTrack, fVideoTrack; // TODO: vector of tracks?
|
||||
std::unique_ptr<class plWin32VideoSound> fAudioSound;
|
||||
|
||||
std::unique_ptr<class VPX> fVpx;
|
||||
class OpusDecoder* fOpusDecoder;
|
||||
|
||||
int64_t fMovieTime, fLastFrameTime;
|
||||
int64_t fMovieTime, fLastFrameTime; // in ms
|
||||
hsPoint2 fPosition, fScale;
|
||||
plFileName fMoviePath;
|
||||
|
||||
@ -87,9 +85,9 @@ protected:
|
||||
bool fPaused;
|
||||
|
||||
bool IOpenMovie();
|
||||
bool ILoadAudio();
|
||||
bool ICheckLanguage(const mkvparser::Track* track);
|
||||
void IProcessVideoFrame(const std::vector<blkbuf_t>& frames);
|
||||
void IProcessAudioFrame(const std::vector<blkbuf_t>& frames);
|
||||
|
||||
public:
|
||||
plMoviePlayer();
|
||||
|
Reference in New Issue
Block a user