Added VideoState and VideoFlags (instead of booleans), Added Get methods, and privated more variables
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user