Working CMoviePlayer (video only for now)

This commit is contained in:
Jack Andersen 2016-03-07 12:48:54 -10:00
parent b2ccf420f8
commit bba30a25bf
10 changed files with 158 additions and 66 deletions

View File

@ -19,6 +19,7 @@ ProjectResourceFactory::ProjectResourceFactory()
void ProjectResourceFactory::BuildObjectMap(const hecl::Database::Project::ProjectDataSpec &spec)
{
#if 0
m_tagToPath.clear();
m_catalogNameToTag.clear();
hecl::SystemString catalogPath = hecl::ProjectPath(spec.cookedPath, hecl::SystemString(spec.spec.m_name) + _S("/catalog.yaml")).getAbsolutePath();
@ -45,6 +46,7 @@ void ProjectResourceFactory::BuildObjectMap(const hecl::Database::Project::Proje
{
RecursiveAddDirObjects(spec.cookedPath);
}
#endif
}
std::unique_ptr<urde::IObj> ProjectResourceFactory::Build(const urde::SObjectTag& tag,

View File

@ -30,8 +30,7 @@ void ViewManager::BuildTestPART(urde::IObjectStore& objStore)
m_lineRenderer.reset(new urde::CLineRenderer(urde::CLineRenderer::EPrimitiveMode::LineStrip, 4, nullptr, true));
*/
m_particleView.reset(new ParticleView(*this, m_viewResources, *m_rootView));
hecl::ProjectPath thpPath(m_projManager.project()->getProjectWorkingPath(), _S("out/MP1/Video/creditBG.thp"));
m_moviePlayer.reset(new CMoviePlayer(thpPath.getAbsolutePathUTF8().c_str(), 0.f, true, true));
m_moviePlayer.reset(new CMoviePlayer("Video/00_first_start.thp", -1.f, true, false));
//m_rootView->accessContentViews().clear();
m_rootView->accessContentViews().push_back(m_particleView.get());
@ -70,6 +69,11 @@ void ViewManager::ParticleView::draw(boo::IGraphicsCommandQueue *gfxQ)
m_vm.m_lineRenderer->Render();
*/
}
if (m_vm.m_moviePlayer)
{
m_vm.m_moviePlayer->Update(1.f / 60.f);
m_vm.m_moviePlayer->DrawFrame();
}
}
specter::View* ViewManager::BuildSpaceViews()
@ -280,6 +284,7 @@ bool ViewManager::proc()
m_rootSpaceView->setMultiplyColor(zeus::CColor::lerp({1,1,1,0}, {1,1,1,1}, m_editorFrames / 30.0));
m_rootView->draw(gfxQ);
CGraphics::EndScene();
gfxQ->execute();
m_mainWindow->waitForRetrace();
@ -291,6 +296,7 @@ void ViewManager::stop()
CElementGen::Shutdown();
CMoviePlayer::Shutdown();
CLineRenderer::Shutdown();
CDvdFile::Shutdown();
m_iconsToken.doDestroy();
m_viewResources.destroyResData();
m_fontCache.destroyAtlases();

View File

@ -7,6 +7,16 @@
#include "ViewManager.hpp"
#include "Runtime/Particle/CElementGen.hpp"
static logvisor::Module AthenaLog("Athena");
static void AthenaExc(athena::error::Level level, const char* file,
const char*, int line, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
AthenaLog.reportSource(logvisor::Level(level), file, line, fmt, ap);
va_end(ap);
}
namespace urde
{
static logvisor::Module Log{"URDE"};
@ -101,6 +111,7 @@ int main(int argc, const boo::SystemChar** argv)
#endif
{
logvisor::RegisterConsoleLogger();
atSetExceptionHandler(AthenaExc);
urde::Application appCb;
int ret = boo::ApplicationRun(boo::IApplication::EPlatformType::Auto,
appCb, _S("urde"), _S("URDE"), argc, argv, false);

View File

@ -25,7 +25,7 @@ public:
{
while (!m_complete && !m_cancel)
{
std::unique_lock<std::mutex> lk(CDvdFile::m_WorkerMutex);
std::unique_lock<std::mutex> lk(CDvdFile::m_WaitMutex);
}
}
bool IsComplete() {return m_complete;}
@ -61,6 +61,7 @@ public:
std::thread CDvdFile::m_WorkerThread;
std::mutex CDvdFile::m_WorkerMutex;
std::condition_variable CDvdFile::m_WorkerCV;
std::mutex CDvdFile::m_WaitMutex;
bool CDvdFile::m_WorkerRun = false;
std::vector<std::shared_ptr<IDvdRequest>> CDvdFile::m_RequestQueue;
void CDvdFile::WorkerProc()
@ -68,26 +69,30 @@ void CDvdFile::WorkerProc()
while (m_WorkerRun)
{
std::unique_lock<std::mutex> lk(CDvdFile::m_WorkerMutex);
if (CDvdFile::m_RequestQueue.size())
while (CDvdFile::m_RequestQueue.size())
{
std::vector<std::shared_ptr<IDvdRequest>> swapQueue;
swapQueue.swap(CDvdFile::m_RequestQueue);
lk.unlock();
std::unique_lock<std::mutex> waitlk(CDvdFile::m_WaitMutex);
for (std::shared_ptr<IDvdRequest>& req : swapQueue)
{
CFileDvdRequest& concreteReq = static_cast<CFileDvdRequest&>(*req);
concreteReq.DoRequest();
}
waitlk.unlock();
lk.lock();
}
if (!m_WorkerRun)
break;
m_WorkerCV.wait(lk);
}
}
std::shared_ptr<IDvdRequest> CDvdFile::AsyncSeekRead(void* buf, u32 len, ESeekOrigin whence, int off)
{
CFileDvdRequest* req = new CFileDvdRequest(*this, buf, len, whence, off);
std::shared_ptr<IDvdRequest> ret(req);
std::shared_ptr<IDvdRequest> ret =
std::make_shared<CFileDvdRequest>(*this, buf, len, whence, off);
std::unique_lock<std::mutex> lk(CDvdFile::m_WorkerMutex);
m_RequestQueue.emplace_back(ret);
lk.unlock();

View File

@ -33,6 +33,7 @@ class CDvdFile
static std::thread m_WorkerThread;
static std::mutex m_WorkerMutex;
static std::condition_variable m_WorkerCV;
static std::mutex m_WaitMutex;
static bool m_WorkerRun;
static std::vector<std::shared_ptr<IDvdRequest>> m_RequestQueue;
static void WorkerProc();

View File

@ -71,7 +71,15 @@ void CGraphics::EndScene()
/* ++g_NumBreakpointsWaiting; */
/* GXCopyDisp to g_CurrenFrameBuf with clear enabled */
/* Register next breakpoint with GP FIFO */
/* g_LastFrameUsedAbove = g_InterruptLastFrameUsedAbove; */
/* Yup, GX had fences long before D3D12 and Vulkan
* (same functionality implemented in boo's execute method) */
/* This usually comes from VI register during interrupt;
* we don't care in the era of progressive-scan dominance,
* so simulate field-flipping with XOR instead */
g_InterruptLastFrameUsedAbove ^= 1;
g_LastFrameUsedAbove = g_InterruptLastFrameUsedAbove;
}
void CGraphics::SetAlphaCompare(ERglAlphaFunc comp0, u8 ref0, ERglAlphaOp op, ERglAlphaFunc comp1, u8 ref1)

View File

@ -7,8 +7,6 @@
#include "CDvdRequest.hpp"
#include <turbojpeg.h>
#define THP_BUFFER_FRAMES 30
namespace urde
{
@ -124,7 +122,7 @@ SPECTER_METAL_VIEW_VERT_BLOCK
static const char* FS_METAL_YUV =
"#include <metal_stdlib>\n"
"using namespace metal;\n"
"constexpr sampler samp(address::repeat);\n"
"constexpr sampler samp(address::repeat, filter::linear);\n"
"struct VertToFrag\n"
"{\n"
" float4 position [[ position ]];\n"
@ -269,7 +267,7 @@ void CMoviePlayer::THPAudioFrameHeader::swapBig()
}
}
/* Slightly modified THPAudioDecode present in SDK, always interleaves */
/* Slightly modified from THPAudioDecode present in SDK; always interleaves */
u32 CMoviePlayer::THPAudioDecode(s16* buffer, const u8* audioFrame, bool stereo)
{
THPAudioFrameHeader header = *((const THPAudioFrameHeader*)audioFrame);
@ -350,6 +348,11 @@ CMoviePlayer::CMoviePlayer(const char* path, float preLoadSeconds, bool loop, bo
}
}
xb4_nextReadOff = x28_thpHead.firstFrameOffset;
xb0_nextReadSize = x28_thpHead.firstFrameSize;
xb8_readSizeWrapped = x28_thpHead.firstFrameSize;
xbc_readOffWrapped = x28_thpHead.firstFrameOffset;
xe4_totalSeconds = x28_thpHead.numFrames / x28_thpHead.fps;
if (xec_preLoadSeconds < 0.f)
{
@ -368,15 +371,18 @@ CMoviePlayer::CMoviePlayer(const char* path, float preLoadSeconds, bool loop, bo
if (xf0_preLoadFrames > 0)
xa0_bufferQueue.reserve(xf0_preLoadFrames);
m_blockBuf = CGraphics::g_BooFactory->newDynamicBuffer(boo::BufferUse::Vertex, sizeof(m_viewVertBlock), 1);
m_blockBuf = CGraphics::g_BooFactory->newDynamicBuffer(boo::BufferUse::Uniform,
sizeof(m_viewVertBlock), 1);
m_vertBuf = CGraphics::g_BooFactory->newDynamicBuffer(boo::BufferUse::Vertex,
sizeof(specter::View::TexShaderVert), 4);
boo::IVertexFormat* vtxFmt = YUVVTXFmt;
if (CGraphics::g_BooFactory->bindingNeedsVertexFormat())
{
boo::VertexElementDescriptor texvdescs[] =
{
{m_blockBuf, nullptr, boo::VertexSemantic::Position4},
{m_blockBuf, nullptr, boo::VertexSemantic::UV4}
{m_vertBuf, nullptr, boo::VertexSemantic::Position4},
{m_vertBuf, nullptr, boo::VertexSemantic::UV4}
};
vtxFmt = CGraphics::g_BooFactory->newVertexFormat(2, texvdescs);
}
@ -405,7 +411,7 @@ CMoviePlayer::CMoviePlayer(const char* path, float preLoadSeconds, bool loop, bo
for (int j=0 ; j<2 ; ++j)
{
boo::ITexture* texs[] = {set.Y[j], set.U, set.V};
set.binding[j] = CGraphics::g_BooFactory->newShaderDataBinding(YUVShaderPipeline, vtxFmt, m_blockBuf,
set.binding[j] = CGraphics::g_BooFactory->newShaderDataBinding(YUVShaderPipeline, vtxFmt, m_vertBuf,
nullptr, nullptr, 1, bufs, 3, texs);
}
}
@ -423,7 +429,7 @@ CMoviePlayer::CMoviePlayer(const char* path, float preLoadSeconds, bool loop, bo
boo::IGraphicsBuffer* bufs[] = {m_blockBuf};
boo::ITexture* texs[] = {set.Y[0], set.U, set.V};
set.binding[0] = CGraphics::g_BooFactory->newShaderDataBinding(YUVShaderPipeline, vtxFmt, m_blockBuf,
set.binding[0] = CGraphics::g_BooFactory->newShaderDataBinding(YUVShaderPipeline, vtxFmt, m_vertBuf,
nullptr, nullptr, 1, bufs, 3, texs);
}
if (xf4_25_hasAudio)
@ -434,6 +440,14 @@ CMoviePlayer::CMoviePlayer(const char* path, float preLoadSeconds, bool loop, bo
m_token = CGraphics::CommitResources();
PostDVDReadRequestIfNeeded();
m_frame[0].m_uv = {0.f, 0.f};
m_frame[1].m_uv = {0.f, 1.f};
m_frame[2].m_uv = {1.f, 0.f};
m_frame[3].m_uv = {1.f, 1.f};
SetFrame({-0.5f, 0.5f, 0.f}, {-0.5f, -0.5f, 0.f}, {0.5f, -0.5f, 0.f}, {0.5f, 0.5f, 0.f});
m_blockBuf->load(&m_viewVertBlock, sizeof(m_viewVertBlock));
}
void CMoviePlayer::VerifyCallbackStatus()
@ -467,34 +481,51 @@ void CMoviePlayer::Rewind()
xb0_nextReadSize = x28_thpHead.firstFrameSize;
xb4_nextReadOff = x28_thpHead.firstFrameOffset;
xb8_readSize = x28_thpHead.firstFrameSize;
xbc_readOff = x28_thpHead.firstFrameOffset;
xb8_readSizeWrapped = x28_thpHead.firstFrameSize;
xbc_readOffWrapped = x28_thpHead.firstFrameOffset;
xc0_loadedFrames = 0;
xc4_ = 0;
xc0_curLoadFrame = 0;
xc4_requestFrameWrapped = 0;
xc8_curFrame = 0;
xcc_decodedTexSlot = 0;
xd0_ = -1;
xd0_drawTexSlot = -1;
xd4_ = -1;
xd8_ = 0;
xd8_decodedTexCount = 0;
xdc_frameRem = 0.f;
xe8_curSeconds = 0.f;
}
void CMoviePlayer::DrawFrame(const CVector3f& a, const CVector3f& b,
const CVector3f& c, const CVector3f& d)
void CMoviePlayer::SetFrame(const zeus::CVector3f& a, const zeus::CVector3f& b,
const zeus::CVector3f& c, const zeus::CVector3f& d)
{
m_frame[0].m_pos = a;
m_frame[1].m_pos = b;
m_frame[2].m_pos = d;
m_frame[3].m_pos = c;
m_vertBuf->load(m_frame, sizeof(m_frame));
}
void CMoviePlayer::DrawFrame()
{
if (xd0_drawTexSlot == -1)
return;
CTHPTextureSet& tex = x80_textures[xd0_drawTexSlot];
CGraphics::g_BooMainCommandQueue->setShaderDataBinding(tex.binding[m_deinterlace ? xf4_26_fieldFlip : 0]);
CGraphics::g_BooMainCommandQueue->draw(0, 4);
if (!xfc_fieldIndex && CGraphics::g_LastFrameUsedAbove)
xf4_26_fieldFlip = true;
++xfc_fieldIndex;
}
void CMoviePlayer::Update(float dt)
{
if (xc0_loadedFrames < xf0_preLoadFrames)
if (xc0_curLoadFrame < xf0_preLoadFrames)
{
if (x98_request && x98_request->IsComplete())
{
ReadCompleted();
if (xc0_loadedFrames >= xa0_bufferQueue.size() &&
xc0_loadedFrames < xf0_preLoadFrames &&
if (xc0_curLoadFrame >= xa0_bufferQueue.size() &&
xc0_curLoadFrame < xf0_preLoadFrames &&
xa0_bufferQueue.size() < x28_thpHead.numFrames)
{
PostDVDReadRequestIfNeeded();
@ -506,17 +537,18 @@ void CMoviePlayer::Update(float dt)
if (x98_request)
{
bool flag = false;
if (xc4_ >= xa0_bufferQueue.size() && xc0_loadedFrames >= xa0_bufferQueue.size())
if (xc4_requestFrameWrapped >= xa0_bufferQueue.size() &&
xc0_curLoadFrame >= xa0_bufferQueue.size())
flag = true;
if (x98_request->IsComplete() && xd8_ < 2 && flag)
if (x98_request->IsComplete() && xd8_decodedTexCount < 2 && flag)
{
DecodeFromRead(x90_requestBuf.get());
ReadCompleted();
PostDVDReadRequestIfNeeded();
++xd8_;
++xc4_;
if (xc4_ >= x28_thpHead.numFrames && xf4_24_loop)
xc4_ = 0;
++xd8_decodedTexCount;
++xc4_requestFrameWrapped;
if (xc4_requestFrameWrapped >= x28_thpHead.numFrames && xf4_24_loop)
xc4_requestFrameWrapped = 0;
}
}
}
@ -527,23 +559,23 @@ void CMoviePlayer::Update(float dt)
PostDVDReadRequestIfNeeded();
}
if (xd8_ < 2)
if (xd8_decodedTexCount < 2)
{
if (xe0_playMode == EPlayMode::Playing && xc4_ < xf0_preLoadFrames)
if (xe0_playMode == EPlayMode::Playing && xc4_requestFrameWrapped < xf0_preLoadFrames)
{
u32 minFrame = std::min(u32(xa0_bufferQueue.size()) - 1, xc4_);
u32 minFrame = std::min(u32(xa0_bufferQueue.size()) - 1, xc4_requestFrameWrapped);
if (minFrame == -1)
return;
std::unique_ptr<uint8_t[]>& frameData = xa0_bufferQueue[minFrame];
DecodeFromRead(frameData.get());
++xd8_;
++xc4_;
if (xc4_ >= x28_thpHead.numFrames && xf4_24_loop)
xc4_ = 0;
++xd8_decodedTexCount;
++xc4_requestFrameWrapped;
if (xc4_requestFrameWrapped >= x28_thpHead.numFrames && xf4_24_loop)
xc4_requestFrameWrapped = 0;
}
}
if (xd8_ <= 0 || xe0_playMode != EPlayMode::Playing)
if (xd8_decodedTexCount <= 0 || xe0_playMode != EPlayMode::Playing)
return;
xe8_curSeconds += dt;
@ -558,17 +590,17 @@ void CMoviePlayer::Update(float dt)
{
if (!xf4_26_fieldFlip)
{
++xd0_;
if (xd0_ >= x80_textures.size())
xd0_ = 0;
++xd0_drawTexSlot;
if (xd0_drawTexSlot >= x80_textures.size())
xd0_drawTexSlot = 0;
if (xd4_ == -1)
xd4_ = 0;
--xd8_;
--xd8_decodedTexCount;
++xc8_curFrame;
if (xc8_curFrame == x28_thpHead.numFrames && xf4_24_loop)
xc8_curFrame = 0;
rem += frameDt;
xfc_ = 0;
xfc_fieldIndex = 0;
}
else
{
@ -650,11 +682,40 @@ void CMoviePlayer::DecodeFromRead(const void* data)
void CMoviePlayer::ReadCompleted()
{
const THPFrameHeader* frameHeader =
reinterpret_cast<const THPFrameHeader*>(x90_requestBuf.get());
if (xc0_curLoadFrame == xa0_bufferQueue.size() && xf0_preLoadFrames > xc0_curLoadFrame)
xa0_bufferQueue.push_back(std::move(x90_requestBuf));
xb4_nextReadOff += xb0_nextReadSize;
xb0_nextReadSize = hecl::SBig(frameHeader->nextSize);
++xc0_curLoadFrame;
if (xc0_curLoadFrame == xf0_preLoadFrames)
{
if (x28_thpHead.numFrames == xc0_curLoadFrame)
{
xb8_readSizeWrapped = x28_thpHead.firstFrameSize;
xbc_readOffWrapped = x28_thpHead.firstFrameOffset;
}
else
{
xb8_readSizeWrapped = xb0_nextReadSize;
xbc_readOffWrapped = xb4_nextReadOff;
}
}
if (xc0_curLoadFrame >= x28_thpHead.numFrames && xf4_24_loop)
{
xb4_nextReadOff = xbc_readOffWrapped;
xb0_nextReadSize = xb8_readSizeWrapped;
xc0_curLoadFrame = xf0_preLoadFrames;
}
}
void CMoviePlayer::PostDVDReadRequestIfNeeded()
{
if (xc0_loadedFrames < x28_thpHead.numFrames)
if (xc0_curLoadFrame < x28_thpHead.numFrames)
{
x90_requestBuf.reset(new uint8_t[xb0_nextReadSize]);
x98_request = AsyncSeekRead(x90_requestBuf.get(), xb0_nextReadSize,

View File

@ -5,10 +5,10 @@
#include "CDvdFile.hpp"
#include "boo/graphicsdev/IGraphicsDataFactory.hpp"
#include "specter/View.hpp"
#include "zeus/CVector3f.hpp"
namespace urde
{
class CVector3f;
class CMoviePlayer : public CDvdFile
{
@ -96,15 +96,15 @@ private:
u32 xb0_nextReadSize = 0;
u32 xb4_nextReadOff = 0;
u32 xb8_readSize = 0;
u32 xbc_readOff = 0;
u32 xc0_loadedFrames = 0;
u32 xc4_ = 0;
u32 xb8_readSizeWrapped = 0;
u32 xbc_readOffWrapped = 0;
u32 xc0_curLoadFrame = 0;
u32 xc4_requestFrameWrapped = 0;
u32 xc8_curFrame = 0;
u32 xcc_decodedTexSlot = 0;
u32 xd0_ = 0;
u32 xd4_ = 0;
s32 xd8_ = 0;
u32 xd0_drawTexSlot = -1;
u32 xd4_ = -1;
s32 xd8_decodedTexCount = 0;
float xdc_frameRem = 0.f;
EPlayMode xe0_playMode = EPlayMode::Playing;
float xe4_totalSeconds = 0.f;
@ -112,7 +112,7 @@ private:
float xec_preLoadSeconds;
u32 xf0_preLoadFrames = 0;
u32 xf8_ = 0;
u32 xfc_ = 0;
u32 xfc_fieldIndex = 0;
boo::GraphicsDataToken m_token;
std::unique_ptr<uint8_t[]> m_yuvBuf;
@ -127,15 +127,11 @@ private:
u8 m_dummy = 0;
};
struct ViewBlock
{
zeus::CMatrix4f m_mv;
zeus::CColor m_color = zeus::CColor::skWhite;
} m_viewVertBlock;
specter::View::ViewBlock m_viewVertBlock;
boo::IGraphicsBufferD* m_blockBuf;
boo::IGraphicsBufferD* m_vertBuf;
uint64_t m_loadedFrameCount = 0;
uint64_t m_playedFrameCount = 0;
specter::View::TexShaderVert m_frame[4];
public:
@ -161,7 +157,9 @@ public:
float GetPlayedSeconds() const {return xdc_frameRem + xe8_curSeconds;}
float GetTotalSeconds() const {return xe4_totalSeconds;}
void SetPlayMode(EPlayMode mode) {xe0_playMode = mode;}
void DrawFrame(const CVector3f& a, const CVector3f& b, const CVector3f& c, const CVector3f& d);
void SetFrame(const zeus::CVector3f& a, const zeus::CVector3f& b,
const zeus::CVector3f& c, const zeus::CVector3f& d);
void DrawFrame();
void Update(float dt);
void DecodeFromRead(const void* data);
void ReadCompleted();

2
hecl

@ -1 +1 @@
Subproject commit 3e3e34414087d9427bf98cef992dad279ebd988e
Subproject commit f1f3bb641d52a584011bfe2113a797833421ba92

@ -1 +1 @@
Subproject commit 3b1128bbfa4602888e7d08d1b58ed64737f12640
Subproject commit ba1b4ecc5120455bd6c65a76f18fd6abf93e049c