CRM64Pro GDK v0.80.0
A free cross-platform game development kit built on top of SDL 3.0
Loading...
Searching...
No Matches
Tutorial 14: Video

Overview

This tutorial loads an external video through VideoMgr, reads its metadata, assigns the default screen as its render target and calculates an aspect-ratio-preserving viewport.

The event loop demonstrates play, pause, resume, stop, restart and relative seeking. Video audio uses the music tag, while a HUD displays playback state, timing, codecs and gain.

Final result

CRM64Pro Tutorial 14 video playback

Runtime controls

  • Space: Play, pause or resume.
  • S: Stop playback.
  • R: Restart from the beginning.
  • Left / Right: Seek backward or forward by five seconds.
  • V: Change viewport size.
  • Minus / Equals: Decrease or increase video audio gain.
  • D: Show or hide the debug window.
  • Grave key: Show or hide the built-in console.
  • Q or ESC: Exit the tutorial.

Prerequisites

  • CRM64Pro GDK installed and configured with a supported C++17 compiler.
  • Tutorial package downloaded and fully extracted, preserving its folder structure.
  • Run Tutorials 02 and 04 first so Tutorial.cdc contains the background and cursor resources.
  • Included assets available under bin/Base/: Video/h264-360p-30fps-acc.mov.
  • A working audio device and a renderer supported by the video subsystem.

What you will learn

  • Initialize audio before loading video audio streams.
  • Load media with VideoMgr::loadFromFile().
  • Read dimensions and codec metadata.
  • Assign a target and aspect-ratio viewport.
  • Control playback and relative seeking.
  • Change video audio through the music tag gain.

Step by step

1. Initialize video audio

Initialize audio before loading the media. This tutorial routes its video audio through the music tag.

mLog.msg(LL_INFO, " Initialize audio ... ");
if(!mC64.configMgr().audioInit())
{
logTaskFailed(mLog);
Main::terminate();
return -1;
}
logTaskOk(mLog);
// Video audio uses the music tag in this tutorial.
mC64.configMgr().audioSetMasterGain(1.0f);
mC64.configMgr().audioSetTagGain(ATT_MUSIC, state.fVideoGain);

2. Load the video

VideoMgr owns the media object. Pass the music tag at load time and validate the borrowed pointer.

// VideoMgr owns the loaded media object. The returned Video pointer is borrowed.
mLog.msg(LL_INFO, " Load video file: %s ... ", RESOURCE_VIDEO_FILE);
state.idVideo = mC64.videoMgr().loadFromFile(RESOURCE_VIDEO_FILE, "TutorialVideo", ATT_MUSIC);
Video* pVideo = mC64.videoMgr().get(state.idVideo);
if(state.idVideo < 0 || pVideo == nullptr)
{
logTaskFailed(mLog, state.idVideo);
Main::terminate();
return -1;
}
logTaskOk(mLog);

3. Read metadata

Store video dimensions and codec information for diagnostics and viewport placement.

// Metadata is useful for diagnostics and for deciding how to place the video.
mLog.msg(LL_INFO, " Read video metadata ... ");
if(!pVideo->getInfo(&state.VI))
{
logTaskFailed(mLog);
Main::terminate();
return -1;
}
logTaskOk(mLog);

4. Preserve the aspect ratio

Fit the source dimensions inside the selected destination area, center the result, then assign the screen target and viewport.

// Keep the video aspect ratio while changing only the destination area.
static bool applyVideoViewport(Screen* pScreen, Video* pVideo, bool bLargeViewport)
{
if(!pScreen || !pVideo) return false;
const float fScreenW = static_cast<float>(pScreen->getWidth());
const float fAreaX = bLargeViewport ? 30.0f : 120.0f;
const float fAreaY = bLargeViewport ? 130.0f : 155.0f;
const float fAreaW = fScreenW - (fAreaX * 2.0f);
const float fAreaH = bLargeViewport ? 295.0f : 245.0f;
const float fVideoW = static_cast<float>(pVideo->getWidth());
const float fVideoH = static_cast<float>(pVideo->getHeight());
if(fVideoW <= 0.0f || fVideoH <= 0.0f) return false;
const float fScale = SDL_min(fAreaW / fVideoW, fAreaH / fVideoH);
SDL_FRect rDst;
rDst.w = fVideoW * fScale;
rDst.h = fVideoH * fScale;
rDst.x = fAreaX + ((fAreaW - rDst.w) * 0.5f);
rDst.y = fAreaY + ((fAreaH - rDst.h) * 0.5f);
return pVideo->setTarget() && pVideo->setViewport(&rDst);
}

5. Start playback safely

Validate the initial play request so setup cannot report a running tutorial when playback failed.

mLog.msg(LL_INFO, "\nPLAYBACK\n");
mLog.msg(LL_INFO, " Start video ... ");
if(pVideo->play(0) < 0)
{
logTaskFailed(mLog);
Main::terminate();
return -1;
}
setLastAction(state, "Started video");
logTaskOk(mLog);

6. Play, pause or resume

Choose the operation from the current status and update the HUD only with the real result.

// Start, pause, or resume the current video.
static void playPauseOrResume(Video* pVideo, TutorialState& rState)
{
if(!pVideo) return;
if(pVideo->status() == PS_PLAYING)
{
setLastAction(rState, pVideo->pause() ? "Paused video" : "Pause failed");
}
else if(pVideo->status() == PS_PAUSED)
{
setLastAction(rState, pVideo->resume() ? "Resumed video" : "Resume failed");
}
else
{
setLastAction(rState, pVideo->play(0) >= 0 ? "Started video" : "Play failed");
}
}

7. Seek within valid bounds

Clamp the requested position to the available duration and report a failed seek instead of displaying a false target.

// Move the video position by the requested time.
static void seekRelative(Video* pVideo, TutorialState& rState, Sint32 iDeltaMS)
{
if(!pVideo) return;
const Sint32 iDuration = pVideo->getDuration();
Sint32 iTarget = pVideo->getPlaybackPosition() + iDeltaMS;
if(iTarget < 0) iTarget = 0;
if(iDuration > 0 && iTarget > iDuration) iTarget = iDuration;
if(!pVideo->seek(iTarget))
{
setLastAction(rState, "Seek failed");
return;
}
char szAction[128];
snprintf(szAction, sizeof(szAction), "Seek to %d ms", iTarget);
setLastAction(rState, szAction);
}

8. Change the viewport transactionally

Calculate the requested mode first and commit it to tutorial state only after the video accepts the viewport.

else if(event.key.key == SDLK_V)
{
const bool bLargeViewport = !state.bLargeViewport;
if(applyVideoViewport(pScreen, pVideo, bLargeViewport))
{
state.bLargeViewport = bLargeViewport;
setLastAction(state, state.bLargeViewport ? "Large viewport" : "Normal viewport");
}
else setLastAction(state, "Viewport change failed");
}

9. Change tagged audio gain

Clamp gain to the supported range, then update the music tag used by this video.

else if(event.key.key == SDLK_MINUS)
{
state.fVideoGain = clampGain(state.fVideoGain - fGainStep);
mC64.configMgr().audioSetTagGain(ATT_MUSIC, state.fVideoGain);
setLastAction(state, "Reduced video audio gain");
}
else if(event.key.key == SDLK_EQUALS)
{
state.fVideoGain = clampGain(state.fVideoGain + fGainStep);
mC64.configMgr().audioSetTagGain(ATT_MUSIC, state.fVideoGain);
setLastAction(state, "Increased video audio gain");
}

10. Finish cleanly

Exit before another state update, then close videos before shutting down audio.

if(!bRunning) break;
refreshRuntimeState(mC64, pVideo, state);
updateLogic(state);
mLog.msg(LL_INFO, " Close videos ... ");
mC64.videoMgr().close(0);
logTaskOk(mLog);
mLog.msg(LL_INFO, " Close audio ... ");
mC64.configMgr().audioClose();
logTaskOk(mLog);

Complete source

The tutorial source is authoritative. The following listing is included directly from validation/source/Tutorial_14_Video.cpp.

/* ----------------------------------------------------------------------
CRM64Pro GDK - Roberto Prieto
Copyright (C) 2013-2026 MegaStorm Systems
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
------------------------------------------------------------------------
Tutorial 14: Video
------------------------------------------------------------------------
Overview:
This tutorial introduces video playback.
It loads a video file, assigns a viewport, plays the video with its audio
stream, and renders a small HUD with playback state and timing.
Key concepts:
- Initialize audio before playing videos that include audio streams.
- Load a video from an external media file with VideoMgr::loadFromFile().
- Read video metadata with Video::getInfo().
- Control playback with play(), pause(), resume(), stop() and seek().
- Set the automatic render target viewport with Video::setViewport().
- Use the audio tag gain system for video audio volume.
Controls:
- Space: Play, pause or resume.
- S: Stop playback.
- R: Restart from the beginning.
- Left / Right: Seek backward or forward.
- V: Toggle viewport size.
- + / -: Change video audio gain.
- D: Toggle debug window.
- Grave: Toggle console.
- Q / ESC: Quit.
Loop order:
- Process input events.
- Run one fixed logic update.
- Let Main::update() call the screen render callback.
- Let VideoMgr render the active video after the screen callback.
------------------------------------------------------------------------ */
#include "CRM64Pro.h"
#include "RunParameter.h"
using namespace CRM64Pro;
#define BASEDIR "Base/"
#ifdef CRM64PRO_PLATFORM_WINDOWS
#define OUTPUTDIR "Win64/"
#elif defined(CRM64PRO_PLATFORM_LINUX)
#define OUTPUTDIR "Linux/"
#elif defined(CRM64PRO_PLATFORM_MACOS)
#define OUTPUTDIR "macOS/"
#endif
#define RESOURCE_VIDEO_FILE BASEDIR"Video/h264-360p-30fps-acc.mov"
#define RESOURCE_BG_CDC_NAME "Tutorial_bg"
#define RESOURCE_CURSOR_CDC_NAME "Tutorial_cursor"
#define OUTPUT_CDC OUTPUTDIR"Tutorial.cdc"
// Render rate 0 lets the screen render as often as possible.
// Logic rate controls video and GUI updates.
static const Sint32 iLogicRate = 20;
static const Sint32 iRenderRate = 0;
// Window size.
static const Sint32 iScreenW = 960;
static const Sint32 iScreenH = 540;
// Tutorial playback settings.
static const Sint32 iSeekStepMS = 5000;
static const float fGainStep = 0.10f;
// Values changed while the tutorial runs.
struct TutorialState
{
Sint32 idBgImage = -1;
Sint32 idCursor = -1;
Sint32 idVideo = -1;
Sint32 idBuiltInFont = -1;
Sint32 idDebugWindow = -1;
VideoInfo VI = {};
bool bLargeViewport = false;
float fMouseX = 0.0f;
float fMouseY = 0.0f;
float fVideoGain = 1.0f;
Sint32 iPlaybackPosition = 0;
Sint32 iPlaybackDuration = 0;
Sint32 iCurrentRenderRate = 0;
Sint32 iCurrentLogicRate = 0;
Sint32 iLogicFrames = 0;
char szLastAction[128] = "Ready";
};
// Helper functions used by the setup log messages.
static void logTaskOk(Log& mLog)
{
mLog.msg(LL_DEBUG, "OK\n");
}
// Record a failed tutorial task.
static void logTaskFailed(Log& mLog, Sint32 iCode)
{
mLog.msg(LL_ERROR, "FAILED (Code %d)\n", iCode);
}
// Record a failed tutorial task.
static void logTaskFailed(Log& mLog)
{
mLog.msg(LL_ERROR, "FAILED\n");
}
// Store the action shown by the tutorial.
static void setLastAction(TutorialState& rState, const char* szAction)
{
snprintf(rState.szLastAction, sizeof(rState.szLastAction), "%s", szAction);
}
// Return the text for a playback status.
static const char* playbackStatusName(ePlaybackStatus eStatus)
{
if(eStatus == PS_PLAYING) return "Playing";
if(eStatus == PS_PAUSED) return "Paused";
if(eStatus == PS_FINISHED) return "Finished";
return "Stopped";
}
// Update the tutorial state for the current frame.
static void updateLogic(TutorialState& rState)
{
rState.iLogicFrames++;
}
// Draw text at the requested screen position.
static void renderText(Font* pFont, Sint32 iX, Sint32 iY, const char* szText)
{
if(!pFont) return;
pFont->setPosition(iX, iY);
pFont->render(szText);
}
// Read the current video playback state.
static void refreshVideoState(Video* pVideo, TutorialState& rState)
{
if(!pVideo)
{
rState.iPlaybackPosition = 0;
rState.iPlaybackDuration = 0;
return;
}
rState.iPlaybackPosition = pVideo->getPlaybackPosition();
rState.iPlaybackDuration = pVideo->getDuration();
}
// Refresh the video state used by the tutorial.
static void refreshRuntimeState(Main& mC64, Video* pVideo, TutorialState& rState)
{
refreshVideoState(pVideo, rState);
rState.fMouseX = mC64.cursorMgr().getX();
rState.fMouseY = mC64.cursorMgr().getY();
rState.iCurrentRenderRate = static_cast<Sint32>(mC64.timer().getCurrentRFR());
rState.iCurrentLogicRate = static_cast<Sint32>(mC64.timer().getCurrentLFR());
}
// The video is rendered by VideoMgr after this callback.
// Keep the HUD outside the viewport so the video does not cover the text.
static void renderHUD(Font* pBuiltInFont, const TutorialState& rState, ePlaybackStatus eStatus)
{
if(!pBuiltInFont) return;
char szLine[180];
snprintf(szLine, sizeof(szLine), "Tutorial 14: Video Render: %d fps Logic: %d fps", rState.iCurrentRenderRate, rState.iCurrentLogicRate);
renderText(pBuiltInFont, 10, 10, szLine);
snprintf(szLine, sizeof(szLine), "File: %s", RESOURCE_VIDEO_FILE);
renderText(pBuiltInFont, 10, 40, szLine);
snprintf(szLine, sizeof(szLine), "Status: %s Position: %d / %d ms Gain: %.1f",
playbackStatusName(eStatus), rState.iPlaybackPosition, rState.iPlaybackDuration, rState.fVideoGain);
renderText(pBuiltInFont, 10, 70, szLine);
snprintf(szLine, sizeof(szLine), "Video: %dx%d Codec: %s Audio: %s",
rState.VI.iWidth, rState.VI.iHeight, rState.VI.szCodec, rState.VI.szAudioCodec);
renderText(pBuiltInFont, 10, 100, szLine);
renderText(pBuiltInFont, 10, 455, "Space play/pause S stop R restart Left/Right seek V viewport +/- gain D debug");
snprintf(szLine, sizeof(szLine), "Last action: %s", rState.szLastAction);
renderText(pBuiltInFont, 10, 485, szLine);
}
// Draw the current frame. CursorMgr draws the selected cursor automatically.
static void renderFrame(Image* pBgImage, Font* pBuiltInFont, Video* pVideo, const TutorialState& rState)
{
if(pBgImage) pBgImage->render();
renderHUD(pBuiltInFont, rState, pVideo ? pVideo->status() : PS_STOPPED);
}
// Screen render callback.
// Main::update() calls this before the automatic video and GUI rendering passes.
// Runtime values are cached from the logic loop; render only draws that state.
static Sint32 renderWrapper(Sint32, void* pObj)
{
TutorialState* pState = static_cast<TutorialState*>(pObj);
if(!pState) return 0;
Main& mC64 = Main::instance();
Image* pBgImage = mC64.imageMgr().get(pState->idBgImage);
Font* pBuiltInFont = mC64.fontMgr().get(pState->idBuiltInFont);
Video* pVideo = mC64.videoMgr().get(pState->idVideo);
renderFrame(pBgImage, pBuiltInFont, pVideo, *pState);
return 0;
}
// Show or hide the debug window.
static void toggleDebugWindow(DebugWindow* pDebug)
{
if(!pDebug) return;
if(pDebug->baseWidget().status() == GS_SHOWN) pDebug->baseWidget().hide();
else pDebug->baseWidget().show();
}
// Keep the audio gain within its valid range.
static float clampGain(float fGain)
{
if(fGain < 0.0f) return 0.0f;
if(fGain > 2.0f) return 2.0f;
return fGain;
}
// Keep the video aspect ratio while changing only the destination area.
static bool applyVideoViewport(Screen* pScreen, Video* pVideo, bool bLargeViewport)
{
if(!pScreen || !pVideo) return false;
const float fScreenW = static_cast<float>(pScreen->getWidth());
const float fAreaX = bLargeViewport ? 30.0f : 120.0f;
const float fAreaY = bLargeViewport ? 130.0f : 155.0f;
const float fAreaW = fScreenW - (fAreaX * 2.0f);
const float fAreaH = bLargeViewport ? 295.0f : 245.0f;
const float fVideoW = static_cast<float>(pVideo->getWidth());
const float fVideoH = static_cast<float>(pVideo->getHeight());
if(fVideoW <= 0.0f || fVideoH <= 0.0f) return false;
const float fScale = SDL_min(fAreaW / fVideoW, fAreaH / fVideoH);
SDL_FRect rDst;
rDst.w = fVideoW * fScale;
rDst.h = fVideoH * fScale;
rDst.x = fAreaX + ((fAreaW - rDst.w) * 0.5f);
rDst.y = fAreaY + ((fAreaH - rDst.h) * 0.5f);
return pVideo->setTarget() && pVideo->setViewport(&rDst);
}
// Start, pause, or resume the current video.
static void playPauseOrResume(Video* pVideo, TutorialState& rState)
{
if(!pVideo) return;
if(pVideo->status() == PS_PLAYING)
{
setLastAction(rState, pVideo->pause() ? "Paused video" : "Pause failed");
}
else if(pVideo->status() == PS_PAUSED)
{
setLastAction(rState, pVideo->resume() ? "Resumed video" : "Resume failed");
}
else
{
setLastAction(rState, pVideo->play(0) >= 0 ? "Started video" : "Play failed");
}
}
// Move the video position by the requested time.
static void seekRelative(Video* pVideo, TutorialState& rState, Sint32 iDeltaMS)
{
if(!pVideo) return;
const Sint32 iDuration = pVideo->getDuration();
Sint32 iTarget = pVideo->getPlaybackPosition() + iDeltaMS;
if(iTarget < 0) iTarget = 0;
if(iDuration > 0 && iTarget > iDuration) iTarget = iDuration;
if(!pVideo->seek(iTarget))
{
setLastAction(rState, "Seek failed");
return;
}
char szAction[128];
snprintf(szAction, sizeof(szAction), "Seek to %d ms", iTarget);
setLastAction(rState, szAction);
}
// Run the tutorial application and release its resources.
int main(int argc, char* argv[])
{
if(!runParameterReadRender(argc, argv, eRenderer)) return 1;
// Start CRM64Pro memory tracking before creating engine resources.
// atexit() releases memory tracking data when the program exits.
atexit(CMem::destroy);
// Main gives access to the CRM64Pro managers.
Main& mC64 = Main::instance();
Log& mLog = *mC64.logMgr().get();
TutorialState state;
// Write log output to stdout and to a file under validation/bin.
mLog.init("Tutorial_14_Video", LL_DEBUG, LM_FILE | LM_STDOUT, OUTPUTDIR"Tutorial_14_Video.log");
mLog.msg(LL_INFO, "\nSETUP: screen, timer and audio\n");
// Initialize the timer before calling Main::update().
// setRate() receives render frames per second, then logic frames per second.
mLog.msg(LL_INFO, " Initialize timer ... ");
if(!mC64.timer().init())
{
logTaskFailed(mLog);
return -1;
}
logTaskOk(mLog);
mLog.msg(LL_INFO, " Set frame rates (render=%d, logic=%d) ... ", iRenderRate, iLogicRate);
if(!mC64.timer().setRate(iRenderRate, iLogicRate))
{
logTaskFailed(mLog);
return -1;
}
logTaskOk(mLog);
// Add a 1 ms idle delay inside Main::update().
// Configure and show the default screen.
Screen* pScreen = mC64.configMgr().get();
pScreen->setSize(iScreenW, iScreenH);
pScreen->setDriver(eRenderer);
pScreen->setTitle("CRM64Pro - Tutorial 14: Video");
mLog.msg(LL_INFO, " Create screen (%dx%d) ... ", iScreenW, iScreenH);
if(pScreen->show() < 0)
{
mLog.msg(LL_CRITICAL, "FAILED\n");
return -1;
}
logTaskOk(mLog);
mLog.msg(LL_INFO, " Initialize audio ... ");
if(!mC64.configMgr().audioInit())
{
logTaskFailed(mLog);
return -1;
}
logTaskOk(mLog);
// Video audio uses the music tag in this tutorial.
mC64.configMgr().audioSetTagGain(ATT_MUSIC, state.fVideoGain);
mLog.msg(LL_INFO, " Set render callback ... ");
if(!pScreen->setRenderCallback([&state](Sint32 iMode) { return renderWrapper(iMode, &state); }))
{
logTaskFailed(mLog);
return -1;
}
logTaskOk(mLog);
mLog.msg(LL_INFO, "\nRESOURCES: background, cursor, font and video\n");
// Earlier tutorials store the reusable graphics resources in Tutorial.cdc.
mLog.msg(LL_INFO, " Load background image from CDC ... ");
state.idBgImage = mC64.imageMgr().load(OUTPUT_CDC, RESOURCE_BG_CDC_NAME);
if(state.idBgImage < 0)
{
logTaskFailed(mLog, state.idBgImage);
return -1;
}
logTaskOk(mLog);
mLog.msg(LL_INFO, " Load cursor from CDC ... ");
state.idCursor = mC64.cursorMgr().load(OUTPUT_CDC, RESOURCE_CURSOR_CDC_NAME);
Cursor* pCursor = mC64.cursorMgr().get(state.idCursor);
if(state.idCursor < 0 || pCursor == nullptr)
{
logTaskFailed(mLog, state.idCursor);
return -1;
}
logTaskOk(mLog);
mLog.msg(LL_INFO, " Select cursor ... ");
if(mC64.cursorMgr().select(state.idCursor) < 0 || !mC64.cursorMgr().show())
{
logTaskFailed(mLog);
return -1;
}
logTaskOk(mLog);
mLog.msg(LL_INFO, " Load content font ... ");
state.idBuiltInFont = mC64.fontMgr().getBuiltin("CourierNew10White");
if(state.idBuiltInFont < 0 || mC64.fontMgr().get(state.idBuiltInFont) == nullptr)
{
logTaskFailed(mLog, state.idBuiltInFont);
return -1;
}
logTaskOk(mLog);
// VideoMgr owns the loaded media object. The returned Video pointer is borrowed.
mLog.msg(LL_INFO, " Load video file: %s ... ", RESOURCE_VIDEO_FILE);
state.idVideo = mC64.videoMgr().loadFromFile(RESOURCE_VIDEO_FILE, "TutorialVideo", ATT_MUSIC);
Video* pVideo = mC64.videoMgr().get(state.idVideo);
if(state.idVideo < 0 || pVideo == nullptr)
{
logTaskFailed(mLog, state.idVideo);
return -1;
}
logTaskOk(mLog);
// Metadata is useful for diagnostics and for deciding how to place the video.
mLog.msg(LL_INFO, " Read video metadata ... ");
if(!pVideo->getInfo(&state.VI))
{
logTaskFailed(mLog);
return -1;
}
logTaskOk(mLog);
mLog.msg(LL_INFO, " Set video viewport ... ");
if(!applyVideoViewport(pScreen, pVideo, state.bLargeViewport))
{
logTaskFailed(mLog);
return -1;
}
logTaskOk(mLog);
mLog.msg(LL_INFO, "\nTOOLS: debug window and console\n");
// The DebugWindow shows playback values while the HUD remains minimal.
mLog.msg(LL_INFO, " Create debug window ... ");
state.idDebugWindow = mC64.guiMgr().create("Debug", CRM64PRO_GUI_DEBUGWINDOW);
DebugWindow* pDebug = mC64.guiMgr().getDebugWindow(state.idDebugWindow);
if(!pDebug)
{
logTaskFailed(mLog, state.idDebugWindow);
return -1;
}
pDebug->addWatch("Mouse X", nullptr, &state.fMouseX);
pDebug->addWatch("Mouse Y", nullptr, &state.fMouseY);
pDebug->addWatch("Position", &state.iPlaybackPosition);
pDebug->addWatch("Duration", &state.iPlaybackDuration);
pDebug->addWatch("Audio gain", nullptr, &state.fVideoGain);
pDebug->addWatch("Render fps", &state.iCurrentRenderRate);
pDebug->addWatch("Logic fps", &state.iCurrentLogicRate);
pDebug->addWatch("Logic frames", &state.iLogicFrames);
pDebug->baseWidget().hide();
logTaskOk(mLog);
// Main creates the default Console. Log output is also sent there.
Console* pConsole = mC64.guiMgr().getConsole();
if(pConsole) pConsole->print("Tutorial 14: Video ready. Press ` to toggle the console.\n");
mLog.msg(LL_INFO, "\nPLAYBACK\n");
mLog.msg(LL_INFO, " Start video ... ");
if(pVideo->play(0) < 0)
{
logTaskFailed(mLog);
return -1;
}
setLastAction(state, "Started video");
logTaskOk(mLog);
mLog.msg(LL_INFO, "\nCONTROLS\n");
mLog.msg(LL_INFO, " [Space] Play / pause / resume\n");
mLog.msg(LL_INFO, " [S] Stop [R] Restart [Left]/[Right] Seek\n");
mLog.msg(LL_INFO, " [V] Toggle viewport [-]/[=] Change audio gain\n");
mLog.msg(LL_INFO, " [D] Toggle debug window [`] Toggle console\n");
mLog.msg(LL_INFO, " [Q] / [ESC] Quit\n");
mLog.msg(LL_INFO, "\nRUNNING\n");
SDL_Event event;
bool bRunning = true;
while(bRunning)
{
// Main::update() processes input, runs internal GUI logic, advances video
// playback and calls the screen render callback when a render frame is ready.
while(mC64.update(&event))
{
if(event.type == SDL_EVENT_QUIT)
{
bRunning = false;
}
else if(event.type == SDL_EVENT_KEY_DOWN)
{
if(event.key.key == SDLK_Q || event.key.key == SDLK_ESCAPE)
{
bRunning = false;
}
else if(event.key.key == SDLK_SPACE)
{
playPauseOrResume(pVideo, state);
}
else if(event.key.key == SDLK_S)
{
pVideo->stop();
setLastAction(state, "Stopped video");
}
else if(event.key.key == SDLK_R)
{
pVideo->stop();
setLastAction(state, pVideo->play(0) >= 0 ? "Restarted video" : "Restart failed");
}
else if(event.key.key == SDLK_LEFT)
{
seekRelative(pVideo, state, -iSeekStepMS);
}
else if(event.key.key == SDLK_RIGHT)
{
seekRelative(pVideo, state, iSeekStepMS);
}
else if(event.key.key == SDLK_V)
{
const bool bLargeViewport = !state.bLargeViewport;
if(applyVideoViewport(pScreen, pVideo, bLargeViewport))
{
state.bLargeViewport = bLargeViewport;
setLastAction(state, state.bLargeViewport ? "Large viewport" : "Normal viewport");
}
else setLastAction(state, "Viewport change failed");
}
else if(event.key.key == SDLK_MINUS)
{
state.fVideoGain = clampGain(state.fVideoGain - fGainStep);
mC64.configMgr().audioSetTagGain(ATT_MUSIC, state.fVideoGain);
setLastAction(state, "Reduced video audio gain");
}
else if(event.key.key == SDLK_EQUALS)
{
state.fVideoGain = clampGain(state.fVideoGain + fGainStep);
mC64.configMgr().audioSetTagGain(ATT_MUSIC, state.fVideoGain);
setLastAction(state, "Increased video audio gain");
}
else if(event.key.key == SDLK_D)
{
toggleDebugWindow(pDebug);
}
}
}
if(!bRunning) break;
refreshRuntimeState(mC64, pVideo, state);
updateLogic(state);
}
// Close resources owned by this tutorial.
mC64.videoMgr().info();
mLog.msg(LL_INFO, "\nCLEANUP\n");
mLog.msg(LL_INFO, " Close debug window ... ");
mC64.guiMgr().close(state.idDebugWindow);
logTaskOk(mLog);
mLog.msg(LL_INFO, " Close videos ... ");
mC64.videoMgr().close(0);
logTaskOk(mLog);
mLog.msg(LL_INFO, " Close audio ... ");
logTaskOk(mLog);
mLog.msg(LL_INFO, " Close fonts ... ");
mC64.fontMgr().close(0);
logTaskOk(mLog);
mLog.msg(LL_INFO, " Close cursors ... ");
mC64.cursorMgr().close(0);
logTaskOk(mLog);
mLog.msg(LL_INFO, " Close images ... ");
mC64.imageMgr().close(0);
logTaskOk(mLog);
mLog.msg(LL_INFO, " Close CDC archives ... ");
mC64.archiveMgr().close(0);
logTaskOk(mLog);
return 0;
}
Sint32 close(Sint32 idCDC) override
Close and destroy a CDC object.
Definition CoreArchive.cpp:2476
bool audioInit(eConfigAudioFreq eAF=CAF_DEFAULT, eConfigAudioSample eAS=CAS_DEFAULT, eConfigAudioMode eAM=CAM_DEFAULT)
Initialize the audio system.
Definition CoreConfig.cpp:1195
bool audioClose()
Close the audio system.
Definition CoreConfig.cpp:1283
Screen * get(Sint32 idScreen=0)
Get a pointer to the screen using its handle.
Definition CoreConfig.cpp:1497
void setMTFriendly(Uint8 iDelayMS)
Set the multithread-friendly scheduler yield.
Definition CoreConfig.cpp:1183
bool audioSetTagGain(eAudioTrackTag eTag, float fGain)
Set Gain (Volume) for a specific audio track tag category.
Definition CoreConfig.cpp:1353
bool audioSetMasterGain(float fGain)
Set Master gain (Volume).
Definition CoreConfig.cpp:1331
Console Object class.
Definition CRM64Pro.h:9678
Cursor Object class.
Definition CRM64Pro.h:3734
float getY() const
Get the mouse cursor Y position.
Definition GraphicsCursor.cpp:1041
Sint32 select(Sint32 idCursor)
Select a mouse cursor.
Definition GraphicsCursor.cpp:968
bool show()
Make visible the selected mouse cursor.
Definition GraphicsCursor.cpp:1001
Sint32 load(const string &sCDCFile, const string &sName)
Load a cursor stored in a CDC file.
Definition GraphicsCursor.cpp:1115
Sint32 close(Sint32 idCursor) override
Close and destroy a cursor.
Definition GraphicsCursor.cpp:897
Cursor * get(Sint32 idCursor)
Get a pointer to the cursor using its handle.
Definition GraphicsCursor.cpp:962
float getX() const
Get the mouse cursor X position.
Definition GraphicsCursor.cpp:1035
DebugWindow Object class.
Definition CRM64Pro.h:9810
Font Object class.
Definition CRM64Pro.h:4741
Sint32 render(const string &sText, bool bShowCursor=false, Sint32 iCurPos=-1, Sint32 idRes=0)
Render a text using this font.
Definition GraphicsFont.cpp:1095
bool setPosition(const Position &rPosX, const Position &rPosY, bool bInterpolate=false)
Set the font position.
Definition GraphicsFont.cpp:1037
Sint32 getBuiltin(const string &sName)
Get a built-in embedded font id using its name.
Definition GraphicsFont.cpp:1436
Sint32 close(Sint32 idFont) override
Close and destroy a font.
Definition GraphicsFont.cpp:1363
Font * get(const string &sName)
Get a pointer to the font using its name.
Definition GraphicsFont.cpp:1235
Image Object class.
Definition CRM64Pro.h:3356
Sint32 render(Sint32 idRes=0, SDL_FRect *pSrc=nullptr, SDL_FRect *pDst=nullptr)
Render the image.
Definition GraphicsImage.cpp:1575
Image * get(Sint32 idImg)
Get a pointer to the image using its handle.
Definition GraphicsImage.cpp:2279
Sint32 load(const string &sCDCFile, const string &sName)
Load an image stored in a CDC file.
Definition GraphicsImage.cpp:2476
Sint32 close(Sint32 idImg) override
Close and destroy an image.
Definition GraphicsImage.cpp:2178
Log Object class.
Definition CRM64Pro.h:771
CRM64Pro GDK Main class.
Definition CRM64Pro.h:502
Screen Object class.
Definition CRM64Pro.h:1055
Sint32 show()
Show the screen.
Definition CoreConfig.cpp:362
Sint32 getWidth() const
Get the screen width.
Definition CoreConfig.cpp:549
Sint32 setDriver(eConfigRendererDriver eCRD)
Set the renderer driver.
Definition CoreConfig.cpp:454
bool setRenderCallback(RenderCallback fnCallback)
Set a callback function for rendering graphics at Render Frame Rate.
Definition CoreConfig.cpp:765
Sint32 setSize(Sint32 iWidth, Sint32 iHeight)
Set the size of the screen.
Definition CoreConfig.cpp:526
bool setTitle(const string &sName)
Set the title.
Definition CoreConfig.cpp:674
Video Object class.
Definition CRM64Pro.h:6151
@ ATT_MUSIC
Background music track.
Definition CRM64Pro.h:1043
void setStatsLevel(eMemStatsLevel eMSL)
Set the memory stats gathering level.
Definition CMemoryManager.cpp:618
void destroy()
Releases the internal heap and displays final stats.
Definition CMemoryManager.cpp:954
@ MSL_NORMAL
Collect allocations per module (CRM64Pro and user). Default for debug builds.
Definition CRM64Pro.h:386
eConfigRendererDriver
Screen renderer drivers.
Definition CRM64Pro.h:1013
@ CRD_SOFTWARE
Screen::setDriver(): software renderer driver. Slow but works on all platforms.
Definition CRM64Pro.h:1015
Sint32 create(const string &sName, Uint32 iType=CRM64PRO_GUI_PANEL) override
Creates a new GUI object.
Definition GUI.cpp:1051
Sint32 addWatch(const string &sName, Sint32 *iIntegerVar, float *fFloatVar=nullptr)
Add a watch.
Definition GUIDebugWindow.cpp:275
#define CRM64PRO_GUI_DEBUGWINDOW
Definition CRM64Pro.h:9195
Widget & baseWidget()
Get the reference to base Widget for this object.
Definition GUIDebugWindow.cpp:269
Sint32 print(const char *format,...)
Print a formatted message to the console.
Definition GUIConsole.cpp:403
Console * getConsole(Sint32 idGUI=CRM64PRO_GUI_CONSOLE)
Get a pointer to a Console using its handle.
Definition GUI.cpp:1366
DebugWindow * getDebugWindow(Sint32 idGUI)
Get a pointer to a DebugWindow using its handle.
Definition GUI.cpp:1375
Sint32 close(Sint32 idGUI) override
Close and destroy a GUI object.
Definition GUI.cpp:1168
eGeneralStatus status() const
Get the widget status.
Definition GUIWidget.cpp:1772
bool hide()
Hide a widget.
Definition GUIWidget.cpp:1729
bool show()
Show a widget.
Definition GUIWidget.cpp:1671
Sint32 setPosition(const Position &rPosX=Position(PH_CENTER), const Position &rPosY=Position(PH_CENTER))
Set the position.
Definition GUIWidget.cpp:1923
Log * get(Sint32 idLog=0)
Get a pointer to the log object.
Definition CoreLog.cpp:921
bool init(const string &sAppname, eLogLevel eLL, eLogMode eLM, const string &sFilename="", const string &sAuthor="", const string &sEmail="", const string &sWeb="")
Initialize the log object.
Definition CoreLog.cpp:338
@ LM_FILE
Log output mode for the 'lm' parameter in CRM64Pro::Log::init(). Output to a file and overwrite exist...
Definition CRM64Pro.h:748
@ LM_STDOUT
Log output mode for the 'lm' parameter in CRM64Pro::Log::init(). Output to standard output (stdout).
Definition CRM64Pro.h:750
@ LL_INFO
Runtime events (startup/shutdown). Messages without timestamp.
Definition CRM64Pro.h:764
@ LL_DEBUG
Detailed information for flow control.
Definition CRM64Pro.h:765
@ LL_CRITICAL
Fatal errors, application crash, or assertions.
Definition CRM64Pro.h:761
@ LL_ERROR
Runtime errors that do not require immediate termination.
Definition CRM64Pro.h:762
GUIMgr & guiMgr()
Get reference to GUI Manager.
Definition CoreMain.cpp:808
Timer & timer()
Get reference to Timer module.
Definition CoreMain.cpp:730
Sint32 update(SDL_Event *evUser=nullptr)
Manage the GDK update cycle with a fixed virtual logic frame rate.
Definition CoreMain.cpp:451
ImageMgr & imageMgr()
Get reference to Image Manager.
Definition CoreMain.cpp:754
CursorMgr & cursorMgr()
Get reference to Cursor Manager.
Definition CoreMain.cpp:760
ePlaybackStatus
Playback status for audio and video objects.
Definition CRM64Pro.h:308
static void terminate()
Main explicit destructor.
Definition CoreMain.cpp:266
static Main & instance()
Access the Main singleton.
Definition CoreMain.cpp:252
LogMgr & logMgr()
Get reference to Log Manager.
Definition CoreMain.cpp:724
VideoMgr & videoMgr()
Get reference to Video Manager.
Definition CoreMain.cpp:796
ArchiveMgr & archiveMgr()
Get reference to Archive Manager.
Definition CoreMain.cpp:736
FontMgr & fontMgr()
Get reference to Font Manager.
Definition CoreMain.cpp:778
ConfigMgr & configMgr()
Get reference to Config Manager.
Definition CoreMain.cpp:712
@ GS_SHOWN
General status: enabled and shown.
Definition CRM64Pro.h:300
@ PS_PLAYING
Playback is active.
Definition CRM64Pro.h:310
@ PS_PAUSED
Playback is paused.
Definition CRM64Pro.h:311
@ PS_FINISHED
Playback reached the end.
Definition CRM64Pro.h:312
@ PS_STOPPED
Playback is stopped or no playback instance is active.
Definition CRM64Pro.h:309
@ PH_RIGHT
Widget/Font: right with optional offset. Scene: align to map right/end (MapWidth - ViewportWidth)....
Definition CRM64Pro.h:340
@ PH_TOP
Widget/Font: top with optional offset. Scene: align to map top/begin (0.0). Valid for Y axis.
Definition CRM64Pro.h:337
bool init(eTimerState eState=TS_INIT)
Initialize the timer system.
Definition CoreTimer.cpp:543
bool setRate(Uint16 iR, Uint16 iL)
Set preferred Render and Logic Frame Rate.
Definition CoreTimer.cpp:556
Sint32 getWidth() const
Get the native video width.
Definition GraphicsVideo.cpp:1950
Sint32 getHeight() const
Get the native video height.
Definition GraphicsVideo.cpp:1956
Sint32 getPlaybackPosition() const
Get current playback position.
Definition GraphicsVideo.cpp:1914
bool pause()
Pause the video playback.
Definition GraphicsVideo.cpp:1851
bool setViewport(const SDL_FRect *pRect=nullptr)
Set the target viewport used for automatic video rendering.
Definition GraphicsVideo.cpp:2237
bool setTarget(Sint32 idRes=0)
Set the video render target.
Definition GraphicsVideo.cpp:2228
bool stop()
Stop video playback and reset to the beginning.
Definition GraphicsVideo.cpp:1879
bool seek(Sint32 iTimeMS)
Seek to a playback position.
Definition GraphicsVideo.cpp:1925
Video * get(Sint32 idVideo)
Get a pointer to the video using its handle.
Definition GraphicsVideo.cpp:2394
bool resume()
Resume video from a paused state.
Definition GraphicsVideo.cpp:1865
Sint32 close(Sint32 idVideo=0) override
Close and destroy a video object.
Definition GraphicsVideo.cpp:2362
bool info(Sint32 iMode=0) override
Request Video Manager information.
Definition GraphicsVideo.cpp:2323
Sint32 getDuration() const
Get total duration.
Definition GraphicsVideo.cpp:1908
ePlaybackStatus status() const
Get the video status.
Definition GraphicsVideo.cpp:1902
Sint32 loadFromFile(const string &sFile, const string &sName="", eAudioTrackTag eTag=ATT_MUSIC)
Load a video from an external file.
Definition GraphicsVideo.cpp:2417
Sint32 play(Sint32 iRepeats=0)
Play the video.
Definition GraphicsVideo.cpp:1817
bool getInfo(VideoInfo *pVI) const
Get video detailed information.
Definition GraphicsVideo.cpp:2040
CRM64Pro GDK.
Definition AudioTrack.cpp:36
Absolute coordinate or helper-relative position used by layout APIs.
Definition CRM64Pro.h:346
Video metadata and statistics.
Definition CRM64Pro.h:6130

Navigation

Previous: Tutorial 13 - XML

Back to the tutorials index

Next: Tutorial 15 - Network