galaxy 1.0.0
Real-Time C++23 Game Programming Framework. Built on data-driven design principles and agile software engineering.
Loading...
Searching...
No Matches
Video.cpp
Go to the documentation of this file.
1
7
8#include <glad/glad.h>
9
10#include "galaxy/core/ServiceLocator.hpp"
13#include "galaxy/utils/Globals.hpp"
14
15#include "Video.hpp"
16
17#undef ERROR
18
19thread_local const float vertices[] = {0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f};
20
21thread_local const unsigned int indices[] = {0, 1, 2, 0, 2, 3};
22
23namespace galaxy
24{
25 namespace media
26 {
27 void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
28 {
29 auto buffer = static_cast<RingBuffer*>(pDevice->pUserData);
30
31 const int frames_needed = frameCount * 2;
32 if (buffer->available_bytes() >= frames_needed)
33 {
34 const float* read = buffer->direct_read_pointer(frames_needed);
35 auto output = static_cast<float*>(pOutput);
36
37 for (auto i = 0; i < frames_needed; i++)
38 {
39 output[i] = read[i] * buffer->get_volume();
40 }
41 }
42 else
43 {
44 std::memset(pOutput, 0, frames_needed * sizeof(float));
45 }
46 }
47
49 : m_plm {nullptr}
50 , m_audio {nullptr}
51 , m_audio_buffer {nullptr}
52 , m_texture_y {0}
53 , m_texture_cb {0}
54 , m_texture_cr {0}
55 , m_vao {0}
56 , m_vbo {0}
57 , m_ibo {0}
58 {
59 }
60
62 {
63 glDeleteVertexArrays(1, &m_vao);
64 glDeleteBuffers(1, &m_vbo);
65 glDeleteBuffers(1, &m_ibo);
66
67 if (m_plm)
68 {
69 plm_destroy(m_plm);
70 m_plm = nullptr;
71 }
72
73 if (m_audio)
74 {
75 ma_device_uninit(m_audio);
76 m_audio = nullptr;
77 }
78
80 {
81 m_audio_buffer.reset();
82 m_audio_buffer = nullptr;
83 }
84
85 if (m_texture_y != 0)
86 {
87 glDeleteTextures(1, &m_texture_y);
88 }
89
90 if (m_texture_cb != 0)
91 {
92 glDeleteTextures(1, &m_texture_cb);
93 }
94
95 if (m_texture_cr != 0)
96 {
97 glDeleteTextures(1, &m_texture_cr);
98 }
99 }
100
101 bool Video::load(const std::string& file)
102 {
103 auto success = true;
104
105 auto& fs = core::ServiceLocator<fs::VirtualFileSystem>::ref();
106 m_buffer = fs.read_binary(file);
107 if (!m_buffer.empty())
108 {
109 m_plm = plm_create_with_memory(m_buffer.data(), m_buffer.size(), false);
110 if (m_plm)
111 {
112 plm_set_video_decode_callback(
113 m_plm,
114 [](plm_t* self, plm_frame_t* frame, void* user) {
115 auto video = static_cast<Video*>(user);
116
117 video->update_texture(GL_TEXTURE0, video->m_texture_y, &frame->y);
118 video->update_texture(GL_TEXTURE1, video->m_texture_cb, &frame->cb);
119 video->update_texture(GL_TEXTURE2, video->m_texture_cr, &frame->cr);
120 },
121 this
122 );
123
124 plm_set_audio_decode_callback(
125 m_plm,
126 [](plm_t* self, plm_samples_t* samples, void* user) {
127 auto buffer = static_cast<RingBuffer*>(user);
128 buffer->write(samples->interleaved, samples->count * 2);
129 },
130 m_audio_buffer.get()
131 );
132
133 if (plm_get_num_audio_streams(m_plm) > 0)
134 {
135 m_audio_buffer = std::make_unique<RingBuffer>(plm_get_samplerate(m_plm));
136
137 ma_device_config config = ma_device_config_init(ma_device_type_playback);
138 config.playback.format = ma_format_f32;
139 config.playback.channels = 2;
140 config.sampleRate = plm_get_samplerate(m_plm);
141 config.pUserData = m_audio_buffer.get();
142 config.dataCallback = data_callback;
143
144 if (ma_device_init(nullptr, &config, m_audio) != MA_SUCCESS)
145 {
146 plm_set_audio_enabled(m_plm, false);
147 plm_set_loop(m_plm, false);
148 plm_set_audio_stream(m_plm, 0);
149 plm_set_audio_enabled(m_plm, true);
150
152 {
153 GALAXY_LOG(GALAXY_ERROR, "Failed to load plm video shader '{0}'.", file);
154 success = false;
155 }
156 }
157 }
158 else
159 {
160 plm_set_audio_enabled(m_plm, false);
161 }
162 }
163 else
164 {
165 GALAXY_LOG(GALAXY_ERROR, "Failed to create PLM object with video file '{0}'.", file);
166 success = false;
167 }
168 }
169 else
170 {
171 GALAXY_LOG(GALAXY_ERROR, "Failed to find video file '{0}' in vfs.", file);
172 success = false;
173 }
174
175 return success;
176 }
177
179 {
180 glCreateVertexArrays(1, &m_vao);
181 glCreateBuffers(1, &m_vbo);
182 glCreateBuffers(1, &m_ibo);
183
184 glNamedBufferData(m_vbo, sizeof(vertices), vertices, GL_STATIC_DRAW);
185 glNamedBufferData(m_ibo, sizeof(indices), indices, GL_STATIC_DRAW);
186
187 glVertexArrayVertexBuffer(m_vao, 0, m_vbo, 0, 2 * sizeof(float));
188 glVertexArrayElementBuffer(m_vao, m_ibo);
189
190 glEnableVertexArrayAttrib(m_vao, 0);
191 glVertexArrayAttribFormat(m_vao, 0, 2, GL_FLOAT, GL_FALSE, 0);
192 glVertexArrayAttribBinding(m_vao, 0, 0);
193
194 m_texture_y = create_texture(0, "texture_y");
195 m_texture_cb = create_texture(1, "texture_cb");
196 m_texture_cr = create_texture(2, "texture_cr");
197 }
198
200 {
201 if (m_plm)
202 {
203 if (!ma_device_is_started(m_audio))
204 {
205 ma_device_start(m_audio);
206 }
207
208 plm_decode(m_plm, GALAXY_DT);
209 }
210 }
211
213 {
214 m_shader.bind();
215 glBindVertexArray(m_vao);
216 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
217 glBindVertexArray(0);
218 glUseProgram(0);
219 }
220
222 {
223 if (m_plm)
224 {
225 return plm_has_ended(m_plm);
226 }
227
228 return true;
229 }
230
231 double Video::get_time() const
232 {
233 if (m_plm)
234 {
235 return plm_get_time(m_plm);
236 }
237
238 return 0.0;
239 }
240
241 double Video::get_framerate() const
242 {
243 if (m_plm)
244 {
245 return plm_get_framerate(m_plm);
246 }
247
248 return 0.0;
249 }
250
252 {
253 if (m_plm)
254 {
255 return plm_get_samplerate(m_plm);
256 }
257
258 return 0;
259 }
260
261 double Video::get_duration() const
262 {
263 if (m_plm)
264 {
265 return plm_get_duration(m_plm);
266 }
267
268 return 0.0;
269 }
270
271 unsigned int Video::create_texture(unsigned int index, const char* uniform)
272 {
273 unsigned int texture = 0;
274 glCreateTextures(GL_TEXTURE_2D, 1, &texture);
275
276 glBindTexture(GL_TEXTURE_2D, texture);
277 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
278 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
279 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
280 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
281
282 constexpr const int swizzleMask[] = {GL_ZERO, GL_ZERO, GL_ZERO, GL_RED};
283 glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
284
285 glBindTexture(GL_TEXTURE_2D, 0);
286
287 m_shader.set_uniform(uniform, index);
288
289 return texture;
290 }
291
292 void Video::update_texture(unsigned int unit, unsigned int texture, const plm_plane_t* plane)
293 {
294 glActiveTexture(unit);
295 glBindTexture(GL_TEXTURE_2D, texture);
296 glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, plane->width, plane->height, 0, GL_RED, GL_UNSIGNED_BYTE, plane->data);
297 }
298 } // namespace media
299} // namespace galaxy
#define GALAXY_LOG(level, msg,...)
Definition Log.hpp:28
#define GALAXY_ERROR
Definition Log.hpp:24
thread_local const float vertices[]
Video.cpp galaxy.
Definition Video.cpp:19
thread_local const unsigned int indices[]
Definition Video.cpp:21
bool parse(const std::string &src)
Loads a combined raw shader.
Definition Shader.cpp:100
void set_uniform(const std::string &name, const Uniforms &... args)
Specialized variadic template for setting shader uniforms.
void bind() const
Make active shader.
Definition Shader.cpp:227
Plays an MPEG-1 video.
Definition Video.hpp:27
void build()
Build opengl data.
Definition Video.cpp:178
void render()
Render video.
Definition Video.cpp:212
Video()
Constructor.
Definition Video.cpp:48
double get_time() const
Get current playtime.
Definition Video.cpp:231
double get_framerate() const
Get video framerate.
Definition Video.cpp:241
~Video()
Destructor.
Definition Video.cpp:61
meta::vector< uint8_t > m_buffer
Video data buffer.
Definition Video.hpp:138
unsigned int m_texture_cb
PLM video frame cb.
Definition Video.hpp:153
std::unique_ptr< RingBuffer > m_audio_buffer
Buffer for audio decoding.
Definition Video.hpp:143
unsigned int m_vao
PLM video frame vertex array object.
Definition Video.hpp:163
ma_device * m_audio
Audio data.
Definition Video.hpp:133
plm_t * m_plm
PLM decoder data.
Definition Video.hpp:128
graphics::Shader m_shader
PLM video shader.
Definition Video.hpp:178
bool is_finished() const
Check if video is finished.
Definition Video.cpp:221
unsigned int m_texture_cr
PLM video frame cr.
Definition Video.hpp:158
double get_duration() const
Get video duration.
Definition Video.cpp:261
void update()
Update video decoder.
Definition Video.cpp:199
unsigned int create_texture(unsigned int index, const char *uniform)
Internal function to generate video frame texture.
Definition Video.cpp:271
bool load(const std::string &file)
Load a MPEG-1 from video file.
Definition Video.cpp:101
unsigned int m_ibo
PLM video frame index buffer.
Definition Video.hpp:173
unsigned int m_vbo
PLM video frame vertex buffer.
Definition Video.hpp:168
unsigned int m_texture_y
PLM video frame y.
Definition Video.hpp:148
void update_texture(unsigned int unit, unsigned int texture, const plm_plane_t *plane)
Internal function to update video frame data.
Definition Video.cpp:292
int get_samplerate() const
Get video sample rate.
Definition Video.cpp:251
void data_callback(ma_device *pDevice, void *pOutput, const void *pInput, ma_uint32 frameCount)
Definition Video.cpp:27
constexpr const auto video_vert_shader
Video vertex shader.
constexpr const auto video_frag_shader
Video frag shader.
Animated.cpp galaxy.
Definition Animated.cpp:16