mirror of
https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git
synced 2025-07-18 19:29:09 +00:00
Make audio work
Includes some reorganization and cleanup
This commit is contained in:
@ -12,6 +12,11 @@ include_directories(${OPENSSL_INCLUDE_DIR})
|
||||
include_directories(${PYTHON_INCLUDE_DIR})
|
||||
include_directories(${CURL_INCLUDE_DIR})
|
||||
|
||||
if (VIDEO_AVAILABLE)
|
||||
include_directories(${VPX_INCLUDE_DIR})
|
||||
include_directories(${Opus_INCLUDE_DIR})
|
||||
endif (VIDEO_AVAILABLE)
|
||||
|
||||
# Test for Python Interpreter, which will be used for extra build scripts if available
|
||||
find_package(PythonInterp)
|
||||
if(PYTHONINTERP_FOUND)
|
||||
@ -161,15 +166,15 @@ target_link_libraries(plClient ${Ogg_LIBRARIES})
|
||||
target_link_libraries(plClient ${Vorbis_LIBRARIES})
|
||||
target_link_libraries(plClient ${DirectX_LIBRARIES})
|
||||
target_link_libraries(plClient ${CURL_LIBRARY})
|
||||
target_link_libraries(plClient ${Opus_LIBRARIES})
|
||||
|
||||
if(USE_VLD)
|
||||
target_link_libraries(plClient ${VLD_LIBRARY})
|
||||
endif()
|
||||
|
||||
if (VPX_AVAILABLE)
|
||||
if (VIDEO_AVAILABLE)
|
||||
target_link_libraries(plClient ${VPX_LIBRARY})
|
||||
endif (VPX_AVAILABLE)
|
||||
target_link_libraries(plClient ${Opus_LIBRARIES})
|
||||
endif (VIDEO_AVAILABLE)
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(plClient rpcrt4)
|
||||
|
@ -825,18 +825,18 @@ bool plClient::IHandleMovieMsg(plMovieMsg* mov)
|
||||
if (mov->GetFileName().IsEmpty())
|
||||
return true;
|
||||
|
||||
int i = fMovies.GetCount();
|
||||
size_t i = fMovies.size();
|
||||
if (!(mov->GetCmd() & plMovieMsg::kMake))
|
||||
{
|
||||
for (i = 0; i < fMovies.GetCount(); i++)
|
||||
for (i = 0; i < fMovies.size(); i++)
|
||||
{
|
||||
if (mov->GetFileName().CompareI(fMovies[i]->GetFileName().AsString()) == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == fMovies.GetCount())
|
||||
if (i == fMovies.size())
|
||||
{
|
||||
fMovies.Append(new plMoviePlayer);
|
||||
fMovies.push_back(new plMoviePlayer());
|
||||
fMovies[i]->SetFileName(mov->GetFileName());
|
||||
}
|
||||
|
||||
@ -892,7 +892,8 @@ bool plClient::IHandleMovieMsg(plMovieMsg* mov)
|
||||
if (!fMovies[i]->GetFileName().IsValid())
|
||||
{
|
||||
delete fMovies[i];
|
||||
fMovies.Remove(i);
|
||||
fMovies[i] = fMovies.back();
|
||||
fMovies.pop_back();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1827,13 +1828,13 @@ bool plClient::IDraw()
|
||||
|
||||
void plClient::IServiceMovies()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < fMovies.GetCount(); i++)
|
||||
for (size_t i = 0; i < fMovies.size(); i++)
|
||||
{
|
||||
if (!fMovies[i]->NextFrame())
|
||||
{
|
||||
delete fMovies[i];
|
||||
fMovies.Remove(i);
|
||||
fMovies[i] = fMovies.back();
|
||||
fMovies.pop_back();
|
||||
i--;
|
||||
}
|
||||
}
|
||||
@ -1841,9 +1842,9 @@ void plClient::IServiceMovies()
|
||||
|
||||
void plClient::IKillMovies()
|
||||
{
|
||||
for (int i = 0; i < fMovies.GetCount(); i++)
|
||||
for (size_t i = 0; i < fMovies.size(); i++)
|
||||
delete fMovies[i];
|
||||
fMovies.Reset();
|
||||
fMovies.clear();
|
||||
}
|
||||
|
||||
bool plClient::IPlayIntroMovie(const char* movieName, float endDelay, float posX, float posY, float scaleX, float scaleY, float volume /* = 1.0 */)
|
||||
|
@ -147,7 +147,7 @@ protected:
|
||||
int fQuality;
|
||||
|
||||
bool fQuitIntro;
|
||||
hsTArray<plMoviePlayer*> fMovies;
|
||||
std::vector<plMoviePlayer*> fMovies;
|
||||
|
||||
plMessagePumpProc fMessagePumpProc;
|
||||
|
||||
|
@ -3,10 +3,10 @@ include_directories(../../NucleusLib)
|
||||
include_directories(../../NucleusLib/inc)
|
||||
include_directories(../../PubUtilLib)
|
||||
|
||||
if (VPX_AVAILABLE)
|
||||
if (VIDEO_AVAILABLE)
|
||||
include_directories(${VPX_INCLUDE_DIR})
|
||||
include_directories(${Opus_INCLUDE_DIR})
|
||||
endif (VPX_AVAILABLE)
|
||||
endif (VIDEO_AVAILABLE)
|
||||
|
||||
set(pfMoviePlayer_SOURCES
|
||||
plMoviePlayer.cpp
|
||||
|
@ -41,18 +41,15 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
*==LICENSE==*/
|
||||
|
||||
#include "plMoviePlayer.h"
|
||||
#include <tuple>
|
||||
#include <memory>
|
||||
|
||||
#ifdef VPX_AVAILABLE
|
||||
#ifdef VIDEO_AVAILABLE
|
||||
# define VPX_CODEC_DISABLE_COMPAT 1
|
||||
# include <vpx/vpx_decoder.h>
|
||||
# include <vpx/vp8dx.h>
|
||||
# define iface (vpx_codec_vp9_dx())
|
||||
# include <opus.h>
|
||||
#endif
|
||||
|
||||
#include <opus.h>
|
||||
|
||||
#include "plGImage/plMipmap.h"
|
||||
#include "pnKeyedObject/plUoid.h"
|
||||
#include "plPipeline/hsGDeviceRef.h"
|
||||
@ -61,12 +58,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
#include "hsResMgr.h"
|
||||
#include "hsTimer.h"
|
||||
#include "plAudio/plWin32VideoSound.h"
|
||||
#include "../Apps/plClient/plClient.h"
|
||||
#include "plScene/plSceneNode.h"
|
||||
#include "pnSceneObject/plSceneObject.h"
|
||||
#include "pnSceneObject/plAudioInterface.h"
|
||||
#include "pnMessage/plSoundMsg.h"
|
||||
#include "plgDispatch.h"
|
||||
|
||||
#include "webm/mkvreader.hpp"
|
||||
#include "webm/mkvparser.hpp"
|
||||
@ -88,6 +79,7 @@ class VPX
|
||||
{
|
||||
VPX() { }
|
||||
|
||||
#ifdef VIDEO_AVAILABLE
|
||||
public:
|
||||
vpx_codec_ctx_t codec;
|
||||
|
||||
@ -121,6 +113,7 @@ public:
|
||||
// if this proves false, move decoder function into IProcessVideoFrame
|
||||
return vpx_codec_get_frame(&codec, &iter);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
// =====================================================
|
||||
@ -133,57 +126,46 @@ class TrackMgr
|
||||
bool PeekNextBlockEntry(const std::unique_ptr<mkvparser::Segment>& segment)
|
||||
{
|
||||
// Assume that if blk_entry == nullptr, we need to start from the beginning
|
||||
// Load the current cluster
|
||||
const mkvparser::Cluster* cluster;
|
||||
if (blk_entry)
|
||||
cluster = blk_entry->GetCluster();
|
||||
else
|
||||
cluster = segment->GetFirst();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (cluster->EOS() && cluster != NULL)
|
||||
{
|
||||
cluster = segment->GetNext(cluster);
|
||||
blk_entry = nullptr;
|
||||
if (!cluster)
|
||||
return false;
|
||||
}
|
||||
if (blk_entry)
|
||||
{
|
||||
SAFE_OP(cluster->GetNext(blk_entry, blk_entry), "get next block");
|
||||
}
|
||||
else if (cluster->m_pSegment != NULL)
|
||||
// As long as we have clusters, they contain blocks that we have to process
|
||||
while (cluster && !cluster->EOS()) {
|
||||
// If we have no block yet, get the first one, otherwise the next one
|
||||
if (!blk_entry)
|
||||
{
|
||||
SAFE_OP(cluster->GetFirst(blk_entry), "get first block");
|
||||
}
|
||||
else
|
||||
{
|
||||
blk_entry = nullptr;
|
||||
return false; //reached end of movie. I hope.
|
||||
SAFE_OP(cluster->GetNext(blk_entry, blk_entry), "get next block");
|
||||
}
|
||||
|
||||
if (blk_entry)
|
||||
{
|
||||
if (blk_entry->EOS())
|
||||
continue;
|
||||
// Are there any blocks left?
|
||||
while (blk_entry && !blk_entry->EOS()) {
|
||||
// Is this the next block we want for our track? Awesome, we're done!
|
||||
if (blk_entry->GetBlock()->GetTrackNumber() == number)
|
||||
return true;
|
||||
SAFE_OP(cluster->GetNext(blk_entry, blk_entry), "get next block");
|
||||
}
|
||||
else
|
||||
{
|
||||
cluster = segment->GetNext(cluster);
|
||||
blk_entry = nullptr;
|
||||
if (!cluster)
|
||||
return false;
|
||||
}
|
||||
|
||||
// No blocks left, go to next cluster
|
||||
blk_entry = nullptr;
|
||||
cluster = segment->GetNext(cluster);
|
||||
}
|
||||
return false; // if this happens, boom.
|
||||
|
||||
// That's it, nothing left...
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
uint32_t number;
|
||||
int32_t number;
|
||||
|
||||
TrackMgr(uint32_t num) : blk_entry(nullptr), valid(true), number(num) { }
|
||||
TrackMgr(int32_t num) : blk_entry(nullptr), valid(true), number(num) { }
|
||||
|
||||
bool GetFrames(plMoviePlayer* p, int64_t movieTime, std::vector<blkbuf_t>& frames)
|
||||
{
|
||||
@ -204,7 +186,8 @@ public:
|
||||
data.Read(p->fReader, buf);
|
||||
frames.push_back(std::make_tuple(std::unique_ptr<uint8_t>(buf), static_cast<int32_t>(data.len)));
|
||||
}
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
blk_entry = prev;
|
||||
return true;
|
||||
@ -213,42 +196,6 @@ public:
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
bool Advance(plMoviePlayer* p, int64_t movieTime=0)
|
||||
{
|
||||
if (!valid)
|
||||
return false;
|
||||
|
||||
// This keeps us from getting behind due to freezes
|
||||
// Assumption: Audio will not skip ahead in time. FIXME?
|
||||
while ((valid = PeekNextBlockEntry(p->fSegment)))
|
||||
{
|
||||
const mkvparser::Block* blk = blk_entry->GetBlock();
|
||||
if (blk->GetTime(blk_entry->GetCluster()) < movieTime)
|
||||
continue;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
return false; // ran out of blocks
|
||||
}
|
||||
|
||||
int32_t GetBlockData(plMoviePlayer* p, std::vector<blkbuf_t>& frames) const
|
||||
{
|
||||
const mkvparser::Block* block = blk_entry->GetBlock();
|
||||
|
||||
// Return the frames
|
||||
frames.reserve(block->GetFrameCount());
|
||||
for (int32_t i = 0; i < block->GetFrameCount(); ++i)
|
||||
{
|
||||
const mkvparser::Block::Frame frame = block->GetFrame(i);
|
||||
std::shared_ptr<uint8_t> data(new uint8_t[frame.len]);
|
||||
frame.Read(p->fReader, data.get());
|
||||
frames.push_back(std::make_tuple(data, frame.len));
|
||||
}
|
||||
return block->GetFrameCount();
|
||||
}
|
||||
#endif 0
|
||||
};
|
||||
|
||||
// =====================================================
|
||||
@ -257,44 +204,27 @@ plMoviePlayer::plMoviePlayer() :
|
||||
fPlate(nullptr),
|
||||
fTexture(nullptr),
|
||||
fReader(nullptr),
|
||||
fTimeScale(0),
|
||||
fStartTime(0),
|
||||
fAudioPlayer(),
|
||||
fPosition(hsPoint2()),
|
||||
fAudioInterface(),
|
||||
fPlaying(true),
|
||||
fOpusDecoder(nil)
|
||||
fPlaying(false),
|
||||
fOpusDecoder(nullptr)
|
||||
{
|
||||
fScale.Set(1.0f, 1.0f);
|
||||
|
||||
|
||||
fAudioSound = std::shared_ptr<plWin32VideoSound>(new plWin32VideoSound());
|
||||
fAudioPlayer.SetSound(fAudioSound);
|
||||
plSceneNode* sceneNode = plClient::GetInstance()->GetCurrentScene();
|
||||
if (sceneNode != nullptr)
|
||||
{
|
||||
hsTArray<plSceneObject*>& sceneObjects = sceneNode->GetSceneObjects();
|
||||
for (int i = 0; i < sceneObjects.GetCount(); ++i)
|
||||
{
|
||||
if (sceneObjects[i]->GetAudioInterface() == nullptr)
|
||||
{
|
||||
fAudioInterface.ISetAudible(&fAudioPlayer);
|
||||
sceneObjects[i]->SetAudioInterface(&fAudioInterface);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plMoviePlayer::~plMoviePlayer()
|
||||
{
|
||||
opus_decoder_destroy(fOpusDecoder);
|
||||
if (fPlate)
|
||||
// The plPlate owns the Mipmap Texture, so it destroys it for us
|
||||
plPlateManager::Instance().DestroyPlate(fPlate);
|
||||
#ifdef VPX_AVAILABLE
|
||||
#ifdef VIDEO_AVAILABLE
|
||||
if (fOpusDecoder)
|
||||
opus_decoder_destroy(fOpusDecoder);
|
||||
if (fReader)
|
||||
{
|
||||
fReader->Close();
|
||||
delete fReader;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -305,7 +235,7 @@ int64_t plMoviePlayer::GetMovieTime() const
|
||||
|
||||
bool plMoviePlayer::IOpenMovie()
|
||||
{
|
||||
#ifdef VPX_AVAILABLE
|
||||
#ifdef VIDEO_AVAILABLE
|
||||
if (!plFileInfo(fMoviePath).Exists())
|
||||
{
|
||||
hsAssert(false, "Tried to play a movie that doesn't exist");
|
||||
@ -326,9 +256,6 @@ bool plMoviePlayer::IOpenMovie()
|
||||
SAFE_OP(seg->Load(), "load segment from webm");
|
||||
fSegment.reset(seg);
|
||||
|
||||
// Just in case someone gives us a weird file, find out the timecode offset
|
||||
fTimeScale = fSegment->GetInfo()->GetTimeCodeScale();
|
||||
|
||||
// TODO: Figure out video and audio based on current language
|
||||
// For now... just take the first one.
|
||||
const mkvparser::Tracks* tracks = fSegment->GetTracks();
|
||||
@ -360,8 +287,9 @@ bool plMoviePlayer::IOpenMovie()
|
||||
#endif
|
||||
}
|
||||
|
||||
bool plMoviePlayer::IProcessVideoFrame(const std::vector<blkbuf_t>& frames)
|
||||
void plMoviePlayer::IProcessVideoFrame(const std::vector<blkbuf_t>& frames)
|
||||
{
|
||||
#ifdef VIDEO_AVAILABLE
|
||||
vpx_image_t* img = nullptr;
|
||||
|
||||
// We have to decode all the frames, but we only want to display the most recent one to the user.
|
||||
@ -390,34 +318,45 @@ bool plMoviePlayer::IProcessVideoFrame(const std::vector<blkbuf_t>& frames)
|
||||
// Flush new data to the device
|
||||
if (fTexture->GetDeviceRef())
|
||||
fTexture->GetDeviceRef()->SetDirty(true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void plMoviePlayer::IProcessAudioFrame(const std::vector<blkbuf_t>& frames)
|
||||
{
|
||||
#ifdef VIDEO_AVAILABLE
|
||||
const unsigned char* 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*>(fSegment->GetTracks()->GetTrackByNumber(fAudioTrack->number));
|
||||
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()
|
||||
{
|
||||
plSceneNode* sceneNode = plClient::GetInstance()->GetCurrentScene();
|
||||
if (sceneNode != nullptr)
|
||||
sceneNode->GetKey();
|
||||
|
||||
#ifdef VPX_AVAILABLE
|
||||
#ifdef VIDEO_AVAILABLE
|
||||
if (!IOpenMovie())
|
||||
return false;
|
||||
hsAssert(fVideoTrack, "nil video track -- expect bad things to happen!");
|
||||
|
||||
// Initialize VP8
|
||||
// Initialize VPX
|
||||
if (VPX* vpx = VPX::Create())
|
||||
fVpx.reset(vpx);
|
||||
else
|
||||
return false;
|
||||
|
||||
//initialize opus
|
||||
int error;
|
||||
fOpusDecoder = opus_decoder_create(48000, 1, &error);
|
||||
if (error != OPUS_OK)
|
||||
hsAssert(false, "Error occured initalizing opus");
|
||||
|
||||
// Need to figure out scaling based on pipe size.
|
||||
plPlateManager& plateMgr = plPlateManager::Instance();
|
||||
const mkvparser::VideoTrack* video = static_cast<const mkvparser::VideoTrack*>(fSegment->GetTracks()->GetTrackByNumber(fVideoTrack->number));
|
||||
@ -428,19 +367,34 @@ bool plMoviePlayer::Start()
|
||||
fPlate->SetVisible(true);
|
||||
fTexture = fPlate->CreateMaterial(static_cast<uint32_t>(video->GetWidth()), static_cast<uint32_t>(video->GetHeight()), nullptr);
|
||||
|
||||
//initialize opus
|
||||
const mkvparser::AudioTrack* audio = static_cast<const mkvparser::AudioTrack*>(fSegment->GetTracks()->GetTrackByNumber(fAudioTrack->number));
|
||||
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 / 2;
|
||||
header.fAvgBytesPerSec = header.fNumSamplesPerSec * header.fBlockAlign;
|
||||
fAudioSound.reset(new plWin32VideoSound(header));
|
||||
int error;
|
||||
fOpusDecoder = opus_decoder_create(48000, audio->GetChannels(), &error);
|
||||
if (error != OPUS_OK)
|
||||
hsAssert(false, "Error occured initalizing opus");
|
||||
|
||||
fPlaying = true;
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif // VPX_AVAILABLE
|
||||
#endif // VIDEO_AVAILABLE
|
||||
}
|
||||
|
||||
bool plMoviePlayer::NextFrame()
|
||||
{
|
||||
if (fPlaying)
|
||||
{
|
||||
#ifdef VPX_AVAILABLE
|
||||
#ifdef VIDEO_AVAILABLE
|
||||
// Get our current timecode
|
||||
int64_t movieTime = 0;
|
||||
if (fStartTime == 0)
|
||||
@ -450,23 +404,21 @@ bool plMoviePlayer::NextFrame()
|
||||
|
||||
std::vector<blkbuf_t> audio;
|
||||
std::vector<blkbuf_t> video;
|
||||
uint8_t tracksWithData = 0;
|
||||
if (fAudioTrack)
|
||||
{
|
||||
uint8_t tracksWithData = 0;
|
||||
if (fAudioTrack)
|
||||
{
|
||||
if (fAudioTrack->GetFrames(this, movieTime, audio))
|
||||
tracksWithData++;
|
||||
}
|
||||
if (fVideoTrack)
|
||||
{
|
||||
if (fVideoTrack->GetFrames(this, movieTime, video))
|
||||
tracksWithData++;
|
||||
}
|
||||
if (tracksWithData == 0)
|
||||
{
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
if (fAudioTrack->GetFrames(this, movieTime, audio))
|
||||
tracksWithData++;
|
||||
}
|
||||
if (fVideoTrack)
|
||||
{
|
||||
if (fVideoTrack->GetFrames(this, movieTime, video))
|
||||
tracksWithData++;
|
||||
}
|
||||
if (!tracksWithData)
|
||||
{
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Show our mess
|
||||
@ -476,7 +428,7 @@ bool plMoviePlayer::NextFrame()
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif // VPX_AVAILABLE
|
||||
#endif // VIDEO_AVAILABLE
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -484,36 +436,10 @@ bool plMoviePlayer::NextFrame()
|
||||
bool plMoviePlayer::Stop()
|
||||
{
|
||||
fPlaying = false;
|
||||
if (fAudioSound)
|
||||
fAudioSound->Stop();
|
||||
for (int i = 0; i < fCallbacks.size(); i++)
|
||||
fCallbacks[i]->Send();
|
||||
fCallbacks.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool plMoviePlayer::IProcessAudioFrame(const std::vector<blkbuf_t>& frames)
|
||||
{
|
||||
const unsigned char* data = NULL;
|
||||
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);
|
||||
|
||||
int error;
|
||||
const int frameSize = 5760; //max packet duration at 48kHz
|
||||
opus_int16* pcm = new opus_int16[frameSize * 1 * sizeof(opus_int16)];
|
||||
error = opus_decode(fOpusDecoder, data, size, pcm, frameSize, 0);
|
||||
if (error < 0)
|
||||
hsAssert(false, "opus error");
|
||||
fAudioSound->UpdateSoundBuffer(reinterpret_cast<unsigned char*>(pcm), error);
|
||||
if (plClient::GetInstance()->GetCurrentScene() != nullptr)
|
||||
{
|
||||
plSoundMsg* soundMsg = new plSoundMsg();
|
||||
soundMsg->SetCmd(plSoundMsg::kPlay);
|
||||
soundMsg->SetBCastFlag(plMessage::kBCastByType);
|
||||
fAudioInterface.MsgReceive(soundMsg);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -48,16 +48,11 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
#include "hsPoint2.h"
|
||||
#include "hsColorRGBA.h"
|
||||
#include "plMessage/plMovieMsg.h"
|
||||
#include "plAudio/plWin32VideoSound.h"
|
||||
#include "plAudible/plVideoAudible.h"
|
||||
#include "pnSceneObject/plAudioInterface.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
|
||||
#include <opus.h>
|
||||
|
||||
namespace mkvparser
|
||||
{
|
||||
class BlockEntry;
|
||||
@ -79,23 +74,21 @@ protected:
|
||||
mkvparser::MkvReader* fReader;
|
||||
std::unique_ptr<mkvparser::Segment> fSegment;
|
||||
std::unique_ptr<class TrackMgr> fAudioTrack, fVideoTrack; // TODO: vector of tracks?
|
||||
std::unique_ptr<class VPX> fVpx;
|
||||
int64_t fTimeScale, fStartTime;
|
||||
std::unique_ptr<class plWin32VideoSound> fAudioSound;
|
||||
|
||||
std::unique_ptr<class VPX> fVpx;
|
||||
class OpusDecoder* fOpusDecoder;
|
||||
|
||||
int64_t fStartTime;
|
||||
hsPoint2 fPosition, fScale;
|
||||
plFileName fMoviePath;
|
||||
|
||||
OpusDecoder* fOpusDecoder;
|
||||
std::shared_ptr<plWin32VideoSound> fAudioSound;
|
||||
plVideoAudible fAudioPlayer;
|
||||
plAudioInterface fAudioInterface;
|
||||
|
||||
bool fPlaying;
|
||||
|
||||
int64_t GetMovieTime() const;
|
||||
bool IOpenMovie();
|
||||
bool IProcessVideoFrame(const std::vector<blkbuf_t>& frames);
|
||||
bool IProcessAudioFrame(const std::vector<blkbuf_t>& frames);
|
||||
void IProcessVideoFrame(const std::vector<blkbuf_t>& frames);
|
||||
void IProcessAudioFrame(const std::vector<blkbuf_t>& frames);
|
||||
|
||||
public:
|
||||
plMoviePlayer();
|
||||
|
@ -1,47 +1,98 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
/*==LICENSE==*
|
||||
|
||||
#include "hsResMgr.h"
|
||||
#include "plFormat.h"
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
#include "plDSoundBuffer.h"
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#include "plWin32VideoSound.h"
|
||||
|
||||
#include "hsResMgr.h"
|
||||
#include "plFormat.h"
|
||||
#include "plDSoundBuffer.h"
|
||||
|
||||
static int uniqueID = 0;
|
||||
plWin32VideoSound::plWin32VideoSound() : plWin32Sound()
|
||||
plWin32VideoSound::plWin32VideoSound(plWAVHeader& header) : plWin32Sound()
|
||||
{
|
||||
plWAVHeader header;
|
||||
header.fFormatTag = 0x1;
|
||||
header.fNumChannels = 1;
|
||||
header.fBitsPerSample = 16;
|
||||
fCurrVolume = 1.0f;
|
||||
fDesiredVol = 1.0f;
|
||||
fSoftVolume = 1.0f;
|
||||
fType = kGUISound;
|
||||
|
||||
fDSoundBuffer = new plDSoundBuffer(0, header, false, false, false, true);
|
||||
fDSoundBuffer->SetupVoiceSource();
|
||||
fDSoundBuffer->SetScalarVolume(1.0f);
|
||||
|
||||
uniqueID++;
|
||||
hsgResMgr::ResMgr()->NewKey(plFormat("videosound#{}", uniqueID), this, plLocation::kGlobalFixedLoc);
|
||||
fSoftVolume = 1.0f;
|
||||
}
|
||||
|
||||
plWin32VideoSound::~plWin32VideoSound()
|
||||
{
|
||||
delete fDSoundBuffer;
|
||||
if (fDSoundBuffer)
|
||||
delete fDSoundBuffer;
|
||||
}
|
||||
|
||||
void plWin32VideoSound::UpdateSoundBuffer(unsigned char* buffer, size_t size)
|
||||
void plWin32VideoSound::UpdateSoundBuffer(void* buffer, size_t size)
|
||||
{
|
||||
unsigned int bufferID = 0;
|
||||
uint32_t bufferId;
|
||||
uint32_t chunk;
|
||||
|
||||
if (fDSoundBuffer->GetAvailableBufferId(&bufferID))
|
||||
fDSoundBuffer->UnQueueVoiceBuffers();
|
||||
while (size > 0)
|
||||
{
|
||||
fDSoundBuffer->VoiceFillBuffer(buffer, size, bufferID);
|
||||
IActuallyPlay();
|
||||
chunk = size < STREAM_BUFFER_SIZE ? size : STREAM_BUFFER_SIZE;
|
||||
if (!fDSoundBuffer->GetAvailableBufferId(&bufferId))
|
||||
break;
|
||||
|
||||
fDSoundBuffer->VoiceFillBuffer(buffer, chunk, bufferId);
|
||||
size -= chunk;
|
||||
}
|
||||
IActuallyPlay();
|
||||
}
|
||||
|
||||
void plWin32VideoSound::IDerivedActuallyPlay()
|
||||
{
|
||||
if (!fDSoundBuffer->IsPlaying())
|
||||
if (!fReallyPlaying)
|
||||
{
|
||||
fDSoundBuffer->Play();
|
||||
fReallyPlaying = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool plWin32VideoSound::LoadSound(bool is3D)
|
||||
@ -66,4 +117,4 @@ float plWin32VideoSound::GetActualTimeSec()
|
||||
void plWin32VideoSound::ISetActualTime(double t)
|
||||
{
|
||||
hsAssert(false, "unimplemented cause unnecessary for this class");
|
||||
}
|
||||
}
|
||||
|
@ -33,12 +33,13 @@ the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#ifndef plWin32VideoSound_h
|
||||
#define plWin32VideoSound_h
|
||||
|
||||
@ -47,10 +48,10 @@ Mead, WA 99021
|
||||
class plWin32VideoSound : public plWin32Sound
|
||||
{
|
||||
public:
|
||||
plWin32VideoSound();
|
||||
plWin32VideoSound(plWAVHeader& header);
|
||||
virtual ~plWin32VideoSound();
|
||||
|
||||
void UpdateSoundBuffer(unsigned char* buffer, size_t size);
|
||||
void UpdateSoundBuffer(void* buffer, size_t size);
|
||||
|
||||
protected:
|
||||
void IDerivedActuallyPlay(void);
|
||||
|
Reference in New Issue
Block a user