Path: blob/master/RSDKv5/RSDK/Graphics/Video.cpp
1163 views
#include "RSDK/Core/RetroEngine.hpp"12using namespace RSDK;34FileInfo VideoManager::file;56ogg_sync_state VideoManager::oy;7ogg_page VideoManager::og;8ogg_packet VideoManager::op;9ogg_stream_state VideoManager::vo;10ogg_stream_state VideoManager::to;11th_info VideoManager::ti;12th_comment VideoManager::tc;13th_dec_ctx *VideoManager::td = NULL;14th_setup_info *VideoManager::ts = NULL;1516th_pixel_fmt VideoManager::pixelFormat;17ogg_int64_t VideoManager::granulePos = 0;18bool32 VideoManager::initializing = false;1920bool32 RSDK::LoadVideo(const char *filename, double startDelay, bool32 (*skipCallback)())21{22if (ENGINE_VERSION == 5 && sceneInfo.state == ENGINESTATE_VIDEOPLAYBACK)23return false;24#if RETRO_REV0U25if (ENGINE_VERSION == 3 && RSDK::Legacy::gameMode == RSDK::Legacy::v3::ENGINE_VIDEOWAIT)26return false;27#endif2829char fullFilePath[0x80];30sprintf_s(fullFilePath, sizeof(fullFilePath), "Data/Video/%s", filename);3132InitFileInfo(&VideoManager::file);33if (LoadFile(&VideoManager::file, fullFilePath, FMODE_RB)) {34// Init35ogg_sync_init(&VideoManager::oy);3637th_comment_init(&VideoManager::tc);38th_info_init(&VideoManager::ti);3940int32 theora_p = 0;41char *buffer = NULL;4243// Parse header stuff44bool32 finishedHeader = false;45while (!finishedHeader) {46buffer = ogg_sync_buffer(&VideoManager::oy, 0x1000);47int32 ret = (int32)ReadBytes(&VideoManager::file, buffer, 0x1000);48ogg_sync_wrote(&VideoManager::oy, 0x1000);4950if (ret == 0)51break;5253while (ogg_sync_pageout(&VideoManager::oy, &VideoManager::og) > 0) {54ogg_stream_state test;5556/* is this a mandated initial header? If not, stop parsing */57if (!ogg_page_bos(&VideoManager::og)) {58/* don't leak the page; get it into the appropriate stream */59ogg_stream_pagein(&VideoManager::to, &VideoManager::og);60finishedHeader = true;61break;62}6364ogg_stream_init(&test, ogg_page_serialno(&VideoManager::og));65ogg_stream_pagein(&test, &VideoManager::og);66ogg_stream_packetout(&test, &VideoManager::op);6768// identify codec69if (!theora_p && th_decode_headerin(&VideoManager::ti, &VideoManager::tc, &VideoManager::ts, &VideoManager::op) >= 0) {70// theora71memcpy(&VideoManager::to, &test, sizeof(test));72theora_p = 1;73}74else {75// we dont care (possibly vorbis)76ogg_stream_clear(&test);77}78}79}8081if (theora_p) {82VideoManager::ts = NULL;83theora_p = 1;84while (theora_p && theora_p < 3) {85int32 ret;8687while (theora_p && (theora_p < 3) && (ret = ogg_stream_packetout(&VideoManager::to, &VideoManager::op))) {88if (ret < 0) {89#if !RETRO_USE_ORIGINAL_CODE90PrintLog(PRINT_NORMAL, "ERROR: failed to parse theora stream headers. corrupted stream?");91#endif9293theora_p = 0;94break;95}9697if (!th_decode_headerin(&VideoManager::ti, &VideoManager::tc, &VideoManager::ts, &VideoManager::op)) {98#if !RETRO_USE_ORIGINAL_CODE99PrintLog(PRINT_NORMAL, "ERROR: failed to parse theora stream headers. corrupted stream?");100#endif101102theora_p = 0;103break;104}105106theora_p++;107}108109if (!theora_p)110break;111112/* The header pages/packets will arrive before anything else we113care about, or the stream is not obeying spec */114115if (ogg_sync_pageout(&VideoManager::oy, &VideoManager::og) > 0) {116ogg_stream_pagein(&VideoManager::to, &VideoManager::og);117}118else {119buffer = ogg_sync_buffer(&VideoManager::oy, 0x1000);120int32 ret = (int32)ReadBytes(&VideoManager::file, buffer, 0x1000);121ogg_sync_wrote(&VideoManager::oy, 0x1000);122if (ret == 0) {123#if !RETRO_USE_ORIGINAL_CODE124PrintLog(PRINT_NORMAL, "ERROR: Reached end of file while searching for codec headers.");125#endif126127theora_p = 0;128}129}130}131132if (!theora_p) {133th_info_clear(&VideoManager::ti);134th_comment_clear(&VideoManager::tc);135th_setup_free(VideoManager::ts);136}137else {138VideoManager::td = th_decode_alloc(&VideoManager::ti, VideoManager::ts);139VideoManager::pixelFormat = VideoManager::ti.pixel_fmt;140141int32 ppLevelMax = 0;142th_decode_ctl(VideoManager::td, TH_DECCTL_GET_PPLEVEL_MAX, &ppLevelMax, sizeof(int32));143int32 ppLevel = 0;144th_decode_ctl(VideoManager::td, TH_DECCTL_SET_PPLEVEL, &ppLevel, sizeof(int32));145146th_setup_free(VideoManager::ts);147148engine.storedShaderID = videoSettings.shaderID;149videoSettings.screenCount = 0;150151if (ENGINE_VERSION == 5)152engine.storedState = sceneInfo.state;153#if RETRO_REV0U154else if (ENGINE_VERSION == 3)155engine.storedState = RSDK::Legacy::gameMode;156#endif157engine.displayTime = 0.0;158VideoManager::initializing = true;159VideoManager::granulePos = 0;160161engine.displayTime = 0.0;162engine.videoStartDelay = 0.0;163if (AudioDevice::audioState == 1)164engine.videoStartDelay = startDelay;165166switch (VideoManager::pixelFormat) {167default: break;168case TH_PF_420: videoSettings.shaderID = SHADER_YUV_420; break;169case TH_PF_422: videoSettings.shaderID = SHADER_YUV_422; break;170case TH_PF_444: videoSettings.shaderID = SHADER_YUV_444; break;171}172173engine.skipCallback = NULL;174ProcessVideo();175engine.skipCallback = skipCallback;176177changedVideoSettings = false;178if (ENGINE_VERSION == 5)179sceneInfo.state = ENGINESTATE_VIDEOPLAYBACK;180#if RETRO_REV0U181else if (ENGINE_VERSION == 3)182RSDK::Legacy::gameMode = RSDK::Legacy::v3::ENGINE_VIDEOWAIT;183#endif184185return true;186}187}188189CloseFile(&VideoManager::file);190}191192return false;193}194195void RSDK::ProcessVideo()196{197bool32 finished = false;198double curTime = 0;199if (!VideoManager::initializing) {200double streamPos = GetVideoStreamPos();201202if (streamPos <= -1.0)203engine.displayTime += (1.0 / 60.0); // deltaTime frame-step204else205engine.displayTime = streamPos;206207curTime = th_granule_time(VideoManager::td, VideoManager::granulePos);208209#if RETRO_USE_MOD_LOADER210RunModCallbacks(MODCB_ONVIDEOSKIPCB, (void *)engine.skipCallback);211#endif212if (engine.skipCallback && engine.skipCallback()) {213finished = true;214}215}216217if (!finished && (VideoManager::initializing || engine.displayTime >= engine.videoStartDelay + curTime)) {218while (ogg_stream_packetout(&VideoManager::to, &VideoManager::op) <= 0) {219char *buffer = ogg_sync_buffer(&VideoManager::oy, 0x1000);220// if we're playing and reached the end of file221if (!ReadBytes(&VideoManager::file, buffer, 0x1000) && !VideoManager::initializing) {222finished = true;223break;224}225226ogg_sync_wrote(&VideoManager::oy, 0x1000);227228while (ogg_sync_pageout(&VideoManager::oy, &VideoManager::og) > 0) ogg_stream_pagein(&VideoManager::to, &VideoManager::og);229}230231if (!finished && !th_decode_packetin(VideoManager::td, &VideoManager::op, &VideoManager::granulePos)) {232th_ycbcr_buffer yuv;233th_decode_ycbcr_out(VideoManager::td, yuv);234235int32 dataPos = (VideoManager::ti.pic_x & 0xFFFFFFFE) + (VideoManager::ti.pic_y & 0xFFFFFFFE) * yuv[0].stride;236switch (VideoManager::pixelFormat) {237default: break;238239case TH_PF_444:240RenderDevice::SetupVideoTexture_YUV444(yuv[0].width, yuv[0].height, &yuv[0].data[dataPos], &yuv[1].data[dataPos],241&yuv[2].data[dataPos], yuv[0].stride, yuv[1].stride, yuv[2].stride);242break;243244case TH_PF_422:245RenderDevice::SetupVideoTexture_YUV422(yuv[0].width, yuv[0].height, &yuv[0].data[dataPos],246&yuv[1].data[yuv[1].stride * VideoManager::ti.pic_y + (VideoManager::ti.pic_x >> 1)],247&yuv[2].data[yuv[1].stride * VideoManager::ti.pic_y + (VideoManager::ti.pic_x >> 1)],248yuv[0].stride, yuv[1].stride, yuv[2].stride);249break;250251case TH_PF_420:252RenderDevice::SetupVideoTexture_YUV420(253yuv[0].width, yuv[0].height, &yuv[0].data[dataPos],254&yuv[1].data[yuv[1].stride * (VideoManager::ti.pic_y >> 1) + (VideoManager::ti.pic_x >> 1)],255&yuv[2].data[yuv[1].stride * (VideoManager::ti.pic_y >> 1) + (VideoManager::ti.pic_x >> 1)], yuv[0].stride, yuv[1].stride,256yuv[2].stride);257break;258}259}260261VideoManager::initializing = false;262}263264if (finished) {265CloseFile(&VideoManager::file);266267// Flush everything out268while (ogg_sync_pageout(&VideoManager::oy, &VideoManager::og) > 0) ogg_stream_pagein(&VideoManager::to, &VideoManager::og);269270ogg_stream_clear(&VideoManager::to);271th_decode_free(VideoManager::td);272th_comment_clear(&VideoManager::tc);273th_info_clear(&VideoManager::ti);274ogg_sync_clear(&VideoManager::oy);275276videoSettings.shaderID = engine.storedShaderID;277videoSettings.screenCount = 1;278if (ENGINE_VERSION == 5)279sceneInfo.state = engine.storedState;280#if RETRO_REV0U281else if (ENGINE_VERSION == 3)282RSDK::Legacy::gameMode = engine.storedState;283#endif284}285}286287288