1 /* This is just a quick hack. But good enough for our use of displaying
2 * a short intro video when our game starts up - so might as well share
3 * it.
4 *
5 * Known bugs:
6 *
7 * - Only very crude synching. Audio is slightly delayed and some
8 * videos seem to constantly drift off and then the audio gets all
9 * distorted...
10 *
11 * - Seeking/Pausing doesn't really work.
12 *
13 * - Memory leaks. Easy to fix but don't have time right now.
14 *
15 * Missing features:
16 *
17 * - Stream information. For example allow selection of one of several
18 * audio streams or subtitle overlay streams.
19 *
20 * - Non audio/video streams. For example something like:
21 * ALLEGRO_USTR *al_get_video_subtitle(float *x, float *y);
22 *
23 * - Buffering. Right now buffering is hardcoded to a fixed size which
24 * seemed enough for streaming 720p from disk in my tests. Obviously
25 * when streaming higher bandwidth or from a source with high
26 * fluctuation like an internet stream this won't work at all.
27 *
28 * - Provide an audio stream for the audio. Then could use this to
29 * stream audio files. Right now opening an .mp3 with the video
30 * addon will play it but only with the video API instead of Allegro's
31 * normal audio streaming API...
32 *
33 * - Audio/Video sync. For a game user-controlled sync is probably not
34 * too important as it can just ship with a properly synchronizeded
35 * video. However right now the audio delay is completely ignored.
36 *
37 * - Additional drivers. Also redo the API a bit so not everything
38 * has to be done by the driver.
39 */
40
41 #include "allegro5/allegro5.h"
42 #include "allegro5/allegro_video.h"
43 #include "allegro5/internal/aintern_video.h"
44 #include "allegro5/internal/aintern_video_cfg.h"
45 #include "allegro5/internal/aintern_exitfunc.h"
46
47 ALLEGRO_DEBUG_CHANNEL("video")
48
49
50 /* globals */
51 static bool video_inited = false;
52
53 typedef struct VideoHandler {
54 struct VideoHandler *next;
55 const char *extension;
56 ALLEGRO_VIDEO_INTERFACE *vtable;
57 } VideoHandler;
58
59 static VideoHandler *handlers;
60
find_handler(const char * extension)61 static ALLEGRO_VIDEO_INTERFACE *find_handler(const char *extension)
62 {
63 VideoHandler *v = handlers;
64 while (v) {
65 if (!strcmp(extension, v->extension)) {
66 return v->vtable;
67 }
68 v = v->next;
69 }
70 return NULL;
71 }
72
add_handler(const char * extension,ALLEGRO_VIDEO_INTERFACE * vtable)73 static void add_handler(const char *extension, ALLEGRO_VIDEO_INTERFACE *vtable)
74 {
75 VideoHandler *v;
76 if (handlers == NULL) {
77 handlers = al_calloc(1, sizeof(VideoHandler));
78 v = handlers;
79 }
80 else {
81 v = handlers;
82 while (v->next) {
83 v = v->next;
84 }
85 v->next = al_calloc(1, sizeof(VideoHandler));
86 v = v->next;
87 }
88 v->extension = extension;
89 v->vtable = vtable;
90 }
91
92 /* Function: al_open_video
93 */
al_open_video(char const * filename)94 ALLEGRO_VIDEO *al_open_video(char const *filename)
95 {
96 ALLEGRO_VIDEO *video;
97 const char *extension = filename + strlen(filename) - 1;
98
99 while ((extension >= filename) && (*extension != '.'))
100 extension--;
101 video = al_calloc(1, sizeof *video);
102
103 video->vtable = find_handler(extension);
104
105 if (video->vtable == NULL) {
106 ALLEGRO_ERROR("No handler for video extension %s - "
107 "therefore not trying to load %s.\n", extension, filename);
108 al_free(video);
109 return NULL;
110 }
111
112 video->filename = al_create_path(filename);
113 video->playing = true;
114
115 if (!video->vtable->open_video(video)) {
116 ALLEGRO_ERROR("Could not open %s.\n", filename);
117 al_destroy_path(video->filename);
118 al_free(video);
119 return NULL;
120 }
121
122 al_init_user_event_source(&video->es);
123 video->es_inited = true;
124
125 return video;
126 }
127
128 /* Function: al_close_video
129 */
al_close_video(ALLEGRO_VIDEO * video)130 void al_close_video(ALLEGRO_VIDEO *video)
131 {
132 if (video) {
133 video->vtable->close_video(video);
134 if (video->es_inited) {
135 al_destroy_user_event_source(&video->es);
136 }
137 al_destroy_path(video->filename);
138 al_free(video);
139 }
140 }
141
142 /* Function: al_get_video_event_source
143 */
al_get_video_event_source(ALLEGRO_VIDEO * video)144 ALLEGRO_EVENT_SOURCE *al_get_video_event_source(ALLEGRO_VIDEO *video)
145 {
146 ASSERT(video);
147 return &video->es;
148 }
149
150 /* Function: al_start_video
151 */
al_start_video(ALLEGRO_VIDEO * video,ALLEGRO_MIXER * mixer)152 void al_start_video(ALLEGRO_VIDEO *video, ALLEGRO_MIXER *mixer)
153 {
154 ASSERT(video);
155
156 /* XXX why is this not just a parameter? */
157 video->mixer = mixer;
158 video->vtable->start_video(video);
159 }
160
161 /* Function: al_start_video_with_voice
162 */
al_start_video_with_voice(ALLEGRO_VIDEO * video,ALLEGRO_VOICE * voice)163 void al_start_video_with_voice(ALLEGRO_VIDEO *video, ALLEGRO_VOICE *voice)
164 {
165 ASSERT(video);
166
167 /* XXX why is voice not just a parameter? */
168 video->voice = voice;
169 video->vtable->start_video(video);
170 }
171
172 /* Function: al_set_video_playing
173 */
al_set_video_playing(ALLEGRO_VIDEO * video,bool play)174 void al_set_video_playing(ALLEGRO_VIDEO *video, bool play)
175 {
176 ASSERT(video);
177
178 if (play != video->playing) {
179 video->playing = play;
180 video->vtable->set_video_playing(video);
181 }
182 }
183
184 /* Function: al_is_video_playing
185 */
al_is_video_playing(ALLEGRO_VIDEO * video)186 bool al_is_video_playing(ALLEGRO_VIDEO *video)
187 {
188 ASSERT(video);
189
190 return video->playing;
191 }
192
193 /* Function: al_get_video_frame
194 */
al_get_video_frame(ALLEGRO_VIDEO * video)195 ALLEGRO_BITMAP *al_get_video_frame(ALLEGRO_VIDEO *video)
196 {
197 ASSERT(video);
198
199 video->vtable->update_video(video);
200 return video->current_frame;
201 }
202
203 /* Function: al_get_video_position
204 */
al_get_video_position(ALLEGRO_VIDEO * video,ALLEGRO_VIDEO_POSITION_TYPE which)205 double al_get_video_position(ALLEGRO_VIDEO *video, ALLEGRO_VIDEO_POSITION_TYPE which)
206 {
207 ASSERT(video);
208
209 if (which == ALLEGRO_VIDEO_POSITION_VIDEO_DECODE)
210 return video->video_position;
211 if (which == ALLEGRO_VIDEO_POSITION_AUDIO_DECODE)
212 return video->audio_position;
213 return video->position;
214 }
215
216 /* Function: al_seek_video
217 */
al_seek_video(ALLEGRO_VIDEO * video,double pos_in_seconds)218 bool al_seek_video(ALLEGRO_VIDEO *video, double pos_in_seconds)
219 {
220 ASSERT(video);
221
222 return video->vtable->seek_video(video, pos_in_seconds);
223 }
224
225 /* Function: al_get_video_audio_rate
226 */
al_get_video_audio_rate(ALLEGRO_VIDEO * video)227 double al_get_video_audio_rate(ALLEGRO_VIDEO *video)
228 {
229 ASSERT(video);
230 return video->audio_rate;
231 }
232
233 /* Function: al_get_video_fps
234 */
al_get_video_fps(ALLEGRO_VIDEO * video)235 double al_get_video_fps(ALLEGRO_VIDEO *video)
236 {
237 ASSERT(video);
238 return video->fps;
239 }
240
241 /* Function: al_get_video_scaled_width
242 */
al_get_video_scaled_width(ALLEGRO_VIDEO * video)243 float al_get_video_scaled_width(ALLEGRO_VIDEO *video)
244 {
245 ASSERT(video);
246 return video->scaled_width;
247 }
248
249 /* Function: al_get_video_scaled_height
250 */
al_get_video_scaled_height(ALLEGRO_VIDEO * video)251 float al_get_video_scaled_height(ALLEGRO_VIDEO *video)
252 {
253 ASSERT(video);
254 return video->scaled_height;
255 }
256
257 /* Function: al_init_video_addon
258 */
al_init_video_addon(void)259 bool al_init_video_addon(void)
260 {
261 if (video_inited)
262 return true;
263
264 #ifdef ALLEGRO_CFG_VIDEO_HAVE_OGV
265 add_handler(".ogv", _al_video_ogv_vtable());
266 #endif
267
268 if (handlers == NULL) {
269 ALLEGRO_WARN("No video handlers available!\n");
270 return false;
271 }
272
273 _al_add_exit_func(al_shutdown_video_addon, "al_shutdown_video_addon");
274
275 return true;
276 }
277
278
279 /* Function: al_is_video_addon_initialized
280 */
al_is_video_addon_initialized(void)281 bool al_is_video_addon_initialized(void)
282 {
283 return video_inited;
284 }
285
286
287 /* Function: al_shutdown_video_addon
288 */
al_shutdown_video_addon(void)289 void al_shutdown_video_addon(void)
290 {
291 if (!video_inited)
292 return;
293
294 VideoHandler *v = handlers;
295 while (v) {
296 VideoHandler *next = v->next;
297 al_free(v);
298 v = next;
299 }
300 video_inited = false;
301 handlers = NULL;
302 }
303
304
305 /* Function: al_get_allegro_video_version
306 */
al_get_allegro_video_version(void)307 uint32_t al_get_allegro_video_version(void)
308 {
309 return ALLEGRO_VERSION_INT;
310 }
311
312 /* The returned width and height are always greater than or equal to the frame
313 * width and height. */
_al_compute_scaled_dimensions(int frame_w,int frame_h,float aspect_ratio,float * scaled_w,float * scaled_h)314 void _al_compute_scaled_dimensions(int frame_w, int frame_h, float aspect_ratio,
315 float *scaled_w, float *scaled_h)
316 {
317 if (aspect_ratio > 1.0) {
318 *scaled_w = frame_h * aspect_ratio;
319 *scaled_h = frame_h;
320 }
321 else {
322 *scaled_w = frame_w;
323 *scaled_h = frame_w / aspect_ratio;
324 }
325 }
326
327 /* vim: set sts=3 sw=3 et: */
328