1
0
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:
Florian Meißner
2014-10-31 14:28:11 +01:00
parent 639819a0e5
commit 5563b803c4
6 changed files with 103 additions and 88 deletions

View File

@ -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();

View File

@ -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();