Added VideoState and VideoFlags (instead of booleans), Added Get methods, and privated more variables

This commit is contained in:
2025-10-07 13:25:36 +03:00
parent eefea3ba13
commit cf8575a5c4
2 changed files with 65 additions and 29 deletions

View File

@@ -5,6 +5,7 @@
#include <cstdlib> #include <cstdlib>
#include <functional> #include <functional>
#include <map> #include <map>
#include <type_traits>
#include <vector> #include <vector>
#include <Corrade/Containers/Array.h> #include <Corrade/Containers/Array.h>
@@ -57,8 +58,12 @@ private:
class Video { class Video {
public: public:
// Enums & Flags
enum class State { Playing, Finished, Paused, Idle };
enum class Flags : uint32_t { None = 0, Looping = 1 << 0 };
Video(std::string path, ChargeAudio::Engine *audioEngine = nullptr, Video(std::string path, ChargeAudio::Engine *audioEngine = nullptr,
bool ShouldVideoLoop = true, float BufferSizeInSeconds = 1.0f); Flags videoFlags = Flags::None, float bufferSizeInSeconds = 1.0f);
~Video(); ~Video();
// Manual Control // Manual Control
@@ -67,19 +72,19 @@ public:
// Automatic play // Automatic play
void Play(); void Play();
void Pause(); void Pause();
void StopLooping(); void SwitchLooping();
void StartLooping();
void Restart(); void Restart();
// Info
const double GetDuration();
const double GetPlaybackTime();
const Vector2i GetDimensions();
State GetState();
Flags GetFlags();
// Frame and buffer // Frame and buffer
GL::Texture2D CurrentFrame; GL::Texture2D CurrentFrame;
float BufferLenghtInSeconds = 1;
bool isVideoLooping = true, isVideoOver = false, isVideoPaused = false;
// SAR and Scaling
Vector2i Dimensions{0, 0};
// Audio // Audio
ChargeAudio::SoundContainer Sound; ChargeAudio::SoundContainer Sound;
@@ -92,7 +97,11 @@ private:
_ffmpeg::AVStream *videoStream, *audioStream; _ffmpeg::AVStream *videoStream, *audioStream;
struct _ffmpeg::SwsContext *swsCtx = NULL; // Visual struct _ffmpeg::SwsContext *swsCtx = NULL; // Visual
struct _ffmpeg::SwrContext *swrCtx = NULL; // Audio struct _ffmpeg::SwrContext *swrCtx = NULL; // Audio
// State
int8_t videoStreamNum = -1, audioStreamNum = -1; int8_t videoStreamNum = -1, audioStreamNum = -1;
State videoState;
Flags videoFlags;
uint16_t ID = 0; uint16_t ID = 0;
// Time specific // Time specific
@@ -112,9 +121,11 @@ private:
// SAR / Sizing // SAR / Sizing
uint32_t scaleFactor = 1; uint32_t scaleFactor = 1;
Vector2i Dimensions{0, 0};
// Frame handling // Frame handling
bool frameSet = false; bool frameSet = false;
float bufferLenghtInSeconds;
// Methods // Methods
void continueVideo(); void continueVideo();
@@ -132,5 +143,23 @@ private:
void loadTexture(ImageView2D image); void loadTexture(ImageView2D image);
Image2D loadImage(Containers::Array<char> data); Image2D loadImage(Containers::Array<char> data);
}; };
inline Video::Flags operator|(Video::Flags x, Video::Flags y) {
return static_cast<Video::Flags>(
static_cast<std::underlying_type_t<Video::Flags>>(x) |
static_cast<std::underlying_type_t<Video::Flags>>(y));
}
inline Video::Flags operator&(Video::Flags x, Video::Flags y) {
return static_cast<Video::Flags>(
static_cast<std::underlying_type_t<Video::Flags>>(x) &
static_cast<std::underlying_type_t<Video::Flags>>(y));
}
inline Video::Flags operator^(Video::Flags x, Video::Flags y) {
return static_cast<Video::Flags>(
static_cast<std::underlying_type_t<Video::Flags>>(x) ^
static_cast<std::underlying_type_t<Video::Flags>>(y));
}
} // namespace ChargeVideo } // namespace ChargeVideo
#endif #endif

View File

@@ -24,11 +24,13 @@ using namespace _ffmpeg;
#include <string> #include <string>
// ================== Video Construct/Destruct ================== // ================== Video Construct/Destruct ==================
// ShouldVideoLoop default is true Video::Video(std::string path, ChargeAudio::Engine *engine, Flags videoF,
Video::Video(std::string path, ChargeAudio::Engine *engine, float bufferS)
bool ShouldVideoLoop, float BufferSizeInSeconds) : audioEngine(engine) {
: BufferLenghtInSeconds(BufferSizeInSeconds), // Have to do it here since ordering of init in the header class
isVideoLooping(ShouldVideoLoop), audioEngine(engine) { bufferLenghtInSeconds = bufferS;
videoFlags = videoF;
// Context to hold our data // Context to hold our data
ctx = avformat_alloc_context(); ctx = avformat_alloc_context();
if (!ctx) { if (!ctx) {
@@ -102,7 +104,7 @@ Video::Video(std::string path, ChargeAudio::Engine *engine,
Sound = audioEngine->CreateSound(10); Sound = audioEngine->CreateSound(10);
} }
bufferMaxFrames = av_q2d(videoStream->avg_frame_rate) * BufferLenghtInSeconds; bufferMaxFrames = av_q2d(videoStream->avg_frame_rate) * bufferLenghtInSeconds;
timeBase = av_q2d(videoStream->time_base); timeBase = av_q2d(videoStream->time_base);
} }
@@ -125,8 +127,7 @@ void Video::Play() {
if (audioStreamNum != -1) { if (audioStreamNum != -1) {
Sound->Play(); Sound->Play();
} }
isVideoPaused = false; videoState = State::Playing;
isVideoOver = false;
} }
void Video::Pause() { void Video::Pause() {
@@ -138,7 +139,7 @@ void Video::Pause() {
Sound->Pause(); Sound->Pause();
} }
ID = 0; ID = 0;
isVideoPaused = true; videoState = State::Paused;
} }
void Video::Restart() { void Video::Restart() {
@@ -148,18 +149,24 @@ void Video::Restart() {
restartVideo(); restartVideo();
} }
void Video::StopLooping() { isVideoLooping = false; } const double Video::GetDuration() { return timeBase * videoStream->duration; }
const double Video::GetPlaybackTime() { return clock; }
void Video::StartLooping() { isVideoLooping = true; } const Vector2i Video::GetDimensions() { return Dimensions; }
Video::State Video::GetState() { return videoState; }
Video::Flags Video::GetFlags() { return videoFlags; }
void Video::SwitchLooping() { videoFlags = videoFlags ^ Flags::Looping; }
// ================== Private Video Controls ================== // ================== Private Video Controls ==================
void Video::continueVideo() { void Video::continueVideo() {
bool finishedDecoding = currentFrameNumber >= videoStream->nb_frames - 2,
bufferEmpty = frameBuffer.empty(),
isNotLooping = (videoFlags & Flags::Looping) != Flags::Looping;
// Looping handling // Looping handling
if (currentFrameNumber >= videoStream->nb_frames - 2) { if (finishedDecoding && bufferEmpty) {
if (!isVideoLooping) { if (isNotLooping) {
isVideoOver = true; Pause();
Pause(); // Here we did that (check comment below) videoState = State::Finished;
return; // We remove what we are returning TO return;
} }
restartVideo(); restartVideo();
} }
@@ -175,19 +182,19 @@ void Video::continueVideo() {
// Load frame // Load frame
auto nextFrame = frameBuffer.begin(); auto nextFrame = frameBuffer.begin();
if (frameBuffer.size() > 0 && nextFrame->first <= clock) { if (!bufferEmpty && nextFrame->first <= clock) {
loadTexture(nextFrame->second); loadTexture(nextFrame->second);
frameBuffer.erase(nextFrame); frameBuffer.erase(nextFrame);
} }
if (frameBuffer.size() < bufferMaxFrames) { if (!finishedDecoding && frameBuffer.size() < bufferMaxFrames) {
auto frameData = loadNextFrame(); auto frameData = loadNextFrame();
frameBuffer.insert_or_assign(frameData.first, frameBuffer.insert_or_assign(frameData.first,
loadImage(std::move(frameData.second))); loadImage(std::move(frameData.second)));
} }
if (audioStreamNum != -1 && if (audioStreamNum != -1 &&
Sound->GetState() != ChargeAudio::Sound::SoundState::Playing) Sound->GetState() != ChargeAudio::Sound::State::Playing)
Sound->Play(); Sound->Play();
} }