Tscope5
video.c
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // __ ______
4 // / /_______________ ____ ___ / ____/
5 // / __/ ___/ ___/ __ \/ __ \/ _ \ /___ )
6 // / /_(__ ) /__/ /_/ / /_/ / __/ ____/ /
7 // \__/____/\___/\____/ .___/\___/ /_____/
8 // /_/
9 //
10 /// \file video.c
11 /// Definitions of video functions.
12 /// \example video01.c
13 ////////////////////////////////////////////////////////////////////////////////
14 
15 #include "../include/tscope5/video.h"
16 #include "../include/tscope5/video_internal.h"
17 #include "../include/tscope5/system_internal.h"
18 
19 
20 ////////////////////////////////////////////////////////////////////////////////
21 /// @name Loading videos
22 ///
23 /// Videos can be read from a file using the functions below.
24 //@{
25 ////////////////////////////////////////////////////////////////////////////////
26 
27 
28 ////////////////////////////////////////////////////////////////////////////////
29 /// Open a video from a file.
30 ///
31 /// \param file Path to the video file.
32 ///
33 /// \return A pointer to the newly created video.
34 ///
35 /// Available video types are: ogv.
36 ////////////////////////////////////////////////////////////////////////////////
37 TS5_VIDEO *ts5_read_video(const char *file)
38 {
39  ts5_check_video("ts5_read_video");
40  ts5_log(TS5_LOGLEVEL_2, "ts5_read_video(%s)\n", file);
41 
42  TS5_VIDEO *video = NULL;
43  video = (TS5_VIDEO *)al_malloc(sizeof(TS5_VIDEO));
44 
45  if (!video) {
46  ts5_fatal("ts5_read_video: could not allocate video\n");
47  }
48 
49  video->isplaying = 0;
50  video->ispaused = 0;
51 
52  video->video = al_open_video(file);
53 
54  if (!video->video) {
55  ts5_fatal("ts5_read_video: could not read video\n");
56  }
57 
58 
59  video->mixer = al_create_mixer(_ts5_status.audio.samplerate,
60  ALLEGRO_AUDIO_DEPTH_FLOAT32,
61  al_get_voice_channels(_ts5_data.audio.voice));
62 
63  if (!video->mixer) {
64  ts5_fatal("ts5_read_video: could not create mixer\n");
65  }
66 
67  if (!al_attach_mixer_to_mixer(video->mixer,
68  _ts5_data.audio.mixer)) {
69  ts5_fatal("ts5_read_video: could not attach mixer to voice\n");
70  }
71 
72  double w = al_get_video_width(video->video);
73  double h = al_get_video_height(video->video);
74 
75  video->nbuffers = 12;
76  video->buffer = al_malloc(video->nbuffers * sizeof(ALLEGRO_BITMAP *));
77  if (!video->buffer) {
78  ts5_fatal("ts5_read_video: could not create video buffer\n");
79  }
80 
81  int i;
82  for(i=0; i<video->nbuffers; i++) {
83  video->buffer[i] = al_create_bitmap(w, h);
84  if (!video->buffer[i]) {
85  ts5_fatal("ts5_read_video: could not create video buffer\n");
86  }
87  }
88 
89  return video;
90 }
91 
92 
93 ////////////////////////////////////////////////////////////////////////////////
94 /// Free the memory used by a video.
95 ///
96 /// \param video Pointer to the video that will be freed.
97 ///
98 /// This function should be called at the end of the program for
99 /// each video allocated or read by the user.
100 ////////////////////////////////////////////////////////////////////////////////
101 void ts5_free_video(TS5_VIDEO *video)
102 {
103  ts5_check_video("ts5_free_video");
104  ts5_log(TS5_LOGLEVEL_2, "ts5_free_video(%p)\n", video->video);
105 
106  int i;
107  for(i=0; i<video->nbuffers; i++) {
108  al_destroy_bitmap(video->buffer[i]);
109  }
110  al_free(video->buffer);
111 
112  //al_detach_mixer(video->mixer);
113  //al_destroy_mixer(video->mixer);
114  video->mixer = NULL;
115 
116  al_close_video(video->video);
117  al_free(video);
118  video = NULL;
119 }
120 
121 
122 ////////////////////////////////////////////////////////////////////////////////
123 //@}
124 ////////////////////////////////////////////////////////////////////////////////
125 
126 
127 ////////////////////////////////////////////////////////////////////////////////
128 /// @name Playing videos
129 /// Videos can be played using the functions below.
130 ///
131 /// The audio part is played in the background automatically
132 /// so the user doesn't need to do anything special do make
133 /// the audio audible.
134 ///
135 /// The video is not displayed automatically but
136 /// is provided frame by frame as a TS5_BITMAP.
137 ///
138 /// The user will need to draw each frame on the screen
139 /// using the bitmap drawing functions to make the
140 /// video visible.
141 ///
142 /// see video01.c for an example that shows how this works.
143 //@{
144 ////////////////////////////////////////////////////////////////////////////////
145 
146 
147 ////////////////////////////////////////////////////////////////////////////////
148 /// Start playing a video.
149 ///
150 /// \param video Pointer to the video that will be played.
151 ////////////////////////////////////////////////////////////////////////////////
152 void ts5_play_video(TS5_VIDEO *video)
153 {
154  ts5_check_video("ts5_play_video");
155  ts5_log(TS5_LOGLEVEL_5, "ts5_play_video(%p)\n", video);
156 
157  if (!video) {
158  ts5_fatal("ts5_play_video: video pointer is null\n");
159  }
160 
161  if(!video->ispaused) {
162  al_start_video(video->video, video->mixer);
163  video->isplaying = 1;
164  }
165  else {
166  al_pause_video(video->video, 0);
167  }
168  video->ispaused = 0;
169 }
170 
171 
172 ////////////////////////////////////////////////////////////////////////////////
173 /// Pause playing a video.
174 ///
175 /// \param video Pointer to the video that will be paused.
176 ////////////////////////////////////////////////////////////////////////////////
177 void ts5_pause_video(TS5_VIDEO *video)
178 {
179  ts5_check_video("ts5_pause_video");
180  ts5_log(TS5_LOGLEVEL_5, "ts5_pause_video(%p)\n", video);
181 
182  if (!video) {
183  ts5_fatal("ts5_pause_video: video pointer is null\n");
184  }
185 
186  if (video->isplaying) {
187  al_pause_video(video->video, 1);
188  video->ispaused = 1;
189  }
190 }
191 
192 
193 ////////////////////////////////////////////////////////////////////////////////
194 /// Stop playing a video.
195 ///
196 /// \param video Pointer to the video that will be stopped.
197 ////////////////////////////////////////////////////////////////////////////////
198 void ts5_stop_video(TS5_VIDEO *video)
199 {
200  ts5_check_video("ts5_stop_video");
201  ts5_log(TS5_LOGLEVEL_5, "ts5_stop_video(%p)\n", video);
202 
203  if (!video) {
204  ts5_fatal("ts5_stop_video: video pointer is null\n");
205  }
206 
207  if (video->isplaying) {
208  al_pause_video(video->video, 1);
209  video->ispaused = 1;
210  video->isplaying = 0;
211  }
212 }
213 
214 
215 ////////////////////////////////////////////////////////////////////////////////
216 /// Get the next frame of a video.
217 ///
218 /// \param video Pointer to the video that will be queried.
219 ////////////////////////////////////////////////////////////////////////////////
220 TS5_BITMAP *ts5_get_video_frame(TS5_VIDEO *video)
221 {
222  ts5_check_video("ts5_get_video_frame");
223  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_frame(%p)\n", video);
224 
225  if (!video) {
226  ts5_fatal("ts5_get_video_frame: video pointer is null\n");
227  }
228 
229  // delay some frames
230  static long int num_frames_processed=0;
231  int inbuf = (num_frames_processed + video->nbuffers - 1) % video->nbuffers;
232  int outbuf = num_frames_processed % video->nbuffers;
233 
234  ALLEGRO_BITMAP *frame = al_get_video_frame(video->video);
235 
236  if (frame) {
237  ALLEGRO_BITMAP *screen = al_get_target_bitmap();
238  al_set_target_bitmap(video->buffer[inbuf]);
239  al_draw_bitmap(frame, 0.0, 0.0, 0);
240  al_set_target_bitmap(screen);
241  num_frames_processed++;
242  }
243 
244  return video->buffer[outbuf];
245 }
246 
247 
248 ////////////////////////////////////////////////////////////////////////////////
249 //@}
250 ////////////////////////////////////////////////////////////////////////////////
251 
252 
253 ////////////////////////////////////////////////////////////////////////////////
254 /// @name Video parameters
255 /// For each video the parameters can be queried/set using the functions below:
256 ///
257 /// Video position and video gain can be adjusted
258 /// at any time, even when the video is playing.
259 ///
260 /// There is no function available to query the length of a video.
261 //@{
262 ////////////////////////////////////////////////////////////////////////////////
263 
264 
265 ////////////////////////////////////////////////////////////////////////////////
266 /// Query whether a video is playing.
267 ///
268 /// \param video Pointer to the video that will queried.
269 ///
270 /// \return 1 if the video is playing, 0 if not.
271 ////////////////////////////////////////////////////////////////////////////////
272 int ts5_get_video_status(TS5_VIDEO *video)
273 {
274  ts5_check_video("ts5_get_video_status");
275  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_status(%p)\n", video);
276 
277  if (!video) {
278  ts5_fatal("ts5_get_video_status: video pointer is null\n");
279  }
280 
281  return (video->isplaying && !video->ispaused);
282 }
283 
284 
285 ////////////////////////////////////////////////////////////////////////////////
286 /// Get the aspect ratio of a video.
287 ///
288 /// \param video Pointer to the video that will queried.
289 ///
290 /// \return aspect ratio of the video.
291 ////////////////////////////////////////////////////////////////////////////////
292 double ts5_get_video_aspect_ratio(TS5_VIDEO *video)
293 {
294  ts5_check_video("ts5_get_video_status");
295  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_status(%p)\n", video);
296 
297  if (!video) {
298  ts5_fatal("ts5_get_video_status: video pointer is null\n");
299  }
300 
301  return al_get_video_aspect_ratio(video->video);
302 }
303 
304 
305 ////////////////////////////////////////////////////////////////////////////////
306 /// Get the width of a video.
307 ///
308 /// \param video Pointer to the video that will queried.
309 ///
310 /// \return width of the video in pixels.
311 ////////////////////////////////////////////////////////////////////////////////
312 double ts5_get_video_width(TS5_VIDEO *video)
313 {
314  ts5_check_video("ts5_get_video_width");
315  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_width(%p)\n", video);
316 
317  if (!video) {
318  ts5_fatal("ts5_get_video_width: video pointer is null\n");
319  }
320 
321  return al_get_video_width(video->video);
322 }
323 
324 
325 ////////////////////////////////////////////////////////////////////////////////
326 /// Get the height of a video.
327 ///
328 /// \param video Pointer to the video that will queried.
329 ///
330 /// \return height of the video in pixels.
331 ////////////////////////////////////////////////////////////////////////////////
332 double ts5_get_video_height(TS5_VIDEO *video)
333 {
334  ts5_check_video("ts5_get_video_height");
335  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_height(%p)\n", video);
336 
337  if (!video) {
338  ts5_fatal("ts5_get_video_height: video pointer is null\n");
339  }
340 
341  return al_get_video_height(video->video);
342 }
343 
344 
345 ////////////////////////////////////////////////////////////////////////////////
346 /// Get the audio samplerate of a video.
347 ///
348 /// \param video Pointer to the video that will queried.
349 ///
350 /// \return audio samplerate of the video.
351 ////////////////////////////////////////////////////////////////////////////////
352 double ts5_get_video_samplerate(TS5_VIDEO *video)
353 {
354  ts5_check_video("ts5_get_video_samplerate");
355  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_samplerate(%p)\n", video);
356 
357  if (!video) {
358  ts5_fatal("ts5_get_video_samplerate: video pointer is null\n");
359  }
360 
361  return al_get_video_audio_rate(video->video);
362 }
363 
364 
365 ////////////////////////////////////////////////////////////////////////////////
366 /// Get the framerate of a video.
367 ///
368 /// \param video Pointer to the video that will queried.
369 ///
370 /// \return frame rate of the video.
371 ////////////////////////////////////////////////////////////////////////////////
372 double ts5_get_video_framerate(TS5_VIDEO *video)
373 {
374  ts5_check_video("ts5_get_video_framerate");
375  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_framerate(%p)\n", video);
376 
377  if (!video) {
378  ts5_fatal("ts5_get_video_framerate: video pointer is null\n");
379  }
380 
381  return al_get_video_fps(video->video);
382 }
383 
384 
385 ////////////////////////////////////////////////////////////////////////////////
386 /// Set the playback position of a video.
387 ///
388 /// \param video Pointer to the video that will be adjusted.
389 /// \param position The new playback position.
390 ///
391 /// \return the old playback position of the video in seconds.
392 ////////////////////////////////////////////////////////////////////////////////
393 double ts5_set_video_position(TS5_VIDEO *video, double position)
394 {
395  ts5_check_video("ts5_set_video_position");
396  ts5_log(TS5_LOGLEVEL_5, "ts5_set_video_position(%p,%f)\n", video, position);
397 
398  if (!video) {
399  ts5_fatal("ts5_set_video_position: video pointer is null\n");
400  }
401 
402  double retval = al_get_video_position(video->video, 0);
403 
404  al_seek_video(video->video, position);
405 
406  return retval;
407 }
408 
409 
410 ////////////////////////////////////////////////////////////////////////////////
411 /// Get the playback position of a video.
412 ///
413 /// \param video Pointer to the video that will be queried.
414 ///
415 /// \return the current playback position of the video in seconds.
416 ////////////////////////////////////////////////////////////////////////////////
417 double ts5_get_video_position(TS5_VIDEO *video)
418 {
419  ts5_check_video("ts5_get_video_position");
420  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_position(%p)\n", video);
421 
422  if (!video) {
423  ts5_fatal("ts5_get_video_position: video pointer is null\n");
424  }
425 
426  return al_get_video_position(video->video, 0);
427 }
428 
429 
430 ////////////////////////////////////////////////////////////////////////////////
431 /// Set the playback gain of a video.
432 ///
433 /// \param video Pointer to the video that will be adjusted.
434 /// \param gain The new playback gain (1.0 is normal gain).
435 ///
436 /// \return The old gain setting.
437 ////////////////////////////////////////////////////////////////////////////////
438 double ts5_set_video_gain(TS5_VIDEO *video, double gain)
439 {
440  ts5_check_video("ts5_set_video_gain");
441  ts5_log(TS5_LOGLEVEL_5, "ts5_set_video_gain(%p,%f)\n", video, gain);
442 
443  if (!video) {
444  ts5_fatal("ts5_set_video_gain: video pointer is null\n");
445  }
446 
447  double retval = al_get_mixer_gain(video->mixer);
448  al_set_mixer_gain(video->mixer, gain);
449 
450  return retval;
451 }
452 
453 
454 ////////////////////////////////////////////////////////////////////////////////
455 /// Get the playback gain of a video.
456 ///
457 /// \param video Pointer to the video that will be queried.
458 ///
459 /// \return the current playback gain.
460 ////////////////////////////////////////////////////////////////////////////////
461 double ts5_get_video_gain(TS5_VIDEO *video)
462 {
463  ts5_check_video("ts5_get_video_gain");
464  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_gain(%p)\n", video);
465 
466  if (!video) {
467  ts5_fatal("ts5_get_video_gain: video pointer is null\n");
468  }
469 
470  return al_get_mixer_gain(video->mixer);;
471 }
472 
473 
474 ////////////////////////////////////////////////////////////////////////////////
475 //@}
476 ////////////////////////////////////////////////////////////////////////////////
477 
void ts5_play_video(TS5_VIDEO *video)
Start playing a video.
Definition: video.c:152
void ts5_free_video(TS5_VIDEO *video)
Free the memory used by a video.
Definition: video.c:101
double ts5_get_video_position(TS5_VIDEO *video)
Get the playback position of a video.
Definition: video.c:417
TS5_VIDEO * ts5_read_video(const char *file)
Open a video from a file.
Definition: video.c:37
double ts5_get_video_framerate(TS5_VIDEO *video)
Get the framerate of a video.
Definition: video.c:372
double ts5_get_video_height(TS5_VIDEO *video)
Get the height of a video.
Definition: video.c:332
void ts5_pause_video(TS5_VIDEO *video)
Pause playing a video.
Definition: video.c:177
double ts5_set_video_position(TS5_VIDEO *video, double position)
Set the playback position of a video.
Definition: video.c:393
double ts5_set_video_gain(TS5_VIDEO *video, double gain)
Set the playback gain of a video.
Definition: video.c:438
void ts5_check_video(char *calling_function)
Do some checks at the start of each video function.
TS5_BITMAP * ts5_get_video_frame(TS5_VIDEO *video)
Get the next frame of a video.
Definition: video.c:220
double ts5_get_video_aspect_ratio(TS5_VIDEO *video)
Get the aspect ratio of a video.
Definition: video.c:292
double ts5_get_video_width(TS5_VIDEO *video)
Get the width of a video.
Definition: video.c:312
void ts5_stop_video(TS5_VIDEO *video)
Stop playing a video.
Definition: video.c:198
void ts5_log(const unsigned int level, const char *format,...)
Send info to a logging window.
Definition: system.c:45
double ts5_get_video_gain(TS5_VIDEO *video)
Get the playback gain of a video.
Definition: video.c:461
void ts5_fatal(const char *format,...)
Exit safely with an error message.
Definition: system.c:529
double ts5_get_video_samplerate(TS5_VIDEO *video)
Get the audio samplerate of a video.
Definition: video.c:352
int ts5_get_video_status(TS5_VIDEO *video)
Query whether a video is playing.
Definition: video.c:272