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 
73  double w, h;
74 
75  #if ALLEGRO_WIP_VERSION <= 11
76  w = al_get_video_width(video->video);
77  h = al_get_video_height(video->video);
78 
79  #else
80  w = al_get_video_scaled_width(video->video);
81  h = al_get_video_scaled_height(video->video);
82 
83  #endif
84 
85 
86  video->nbuffers = 12;
87  video->buffer = al_malloc(video->nbuffers * sizeof(ALLEGRO_BITMAP *));
88  if (!video->buffer) {
89  ts5_fatal("ts5_read_video: could not create video buffer\n");
90  }
91 
92  int i;
93  for(i=0; i<video->nbuffers; i++) {
94  video->buffer[i] = al_create_bitmap(w, h);
95  if (!video->buffer[i]) {
96  ts5_fatal("ts5_read_video: could not create video buffer\n");
97  }
98  }
99 
100  return video;
101 }
102 
103 
104 ////////////////////////////////////////////////////////////////////////////////
105 /// Free the memory used by a video.
106 ///
107 /// \param video Pointer to the video that will be freed.
108 ///
109 /// This function should be called at the end of the program for
110 /// each video allocated or read by the user.
111 ////////////////////////////////////////////////////////////////////////////////
112 void ts5_free_video(TS5_VIDEO *video)
113 {
114  ts5_check_video("ts5_free_video");
115  ts5_log(TS5_LOGLEVEL_2, "ts5_free_video(%p)\n", video->video);
116 
117  int i;
118  for(i=0; i<video->nbuffers; i++) {
119  al_destroy_bitmap(video->buffer[i]);
120  }
121  al_free(video->buffer);
122 
123  //al_detach_mixer(video->mixer);
124  //al_destroy_mixer(video->mixer);
125  video->mixer = NULL;
126 
127  al_close_video(video->video);
128  al_free(video);
129  video = NULL;
130 }
131 
132 
133 ////////////////////////////////////////////////////////////////////////////////
134 //@}
135 ////////////////////////////////////////////////////////////////////////////////
136 
137 
138 ////////////////////////////////////////////////////////////////////////////////
139 /// @name Playing videos
140 /// Videos can be played using the functions below.
141 ///
142 /// The audio part is played in the background automatically
143 /// so the user doesn't need to do anything special do make
144 /// the audio audible.
145 ///
146 /// The video is not displayed automatically but
147 /// is provided frame by frame as a TS5_BITMAP.
148 ///
149 /// The user will need to draw each frame on the screen
150 /// using the bitmap drawing functions to make the
151 /// video visible.
152 ///
153 /// see <a href="video01_8c-example.html">video01.c</a>
154 /// for an example that shows how this works.
155 //@{
156 ////////////////////////////////////////////////////////////////////////////////
157 
158 
159 ////////////////////////////////////////////////////////////////////////////////
160 /// Start playing a video.
161 ///
162 /// \param video Pointer to the video that will be played.
163 ////////////////////////////////////////////////////////////////////////////////
164 void ts5_play_video(TS5_VIDEO *video)
165 {
166  ts5_check_video("ts5_play_video");
167  ts5_log(TS5_LOGLEVEL_5, "ts5_play_video(%p)\n", video);
168 
169  if (!video) {
170  ts5_fatal("ts5_play_video: video pointer is null\n");
171  }
172 
173  if(!video->ispaused) {
174  al_start_video(video->video, video->mixer);
175  video->isplaying = 1;
176  }
177  else {
178 
179  #if ALLEGRO_WIP_VERSION <= 11
180  al_pause_video(video->video, 0);
181 
182  #else
183  al_set_video_playing(video->video, 1);
184 
185  #endif
186 
187  }
188  video->ispaused = 0;
189 }
190 
191 
192 ////////////////////////////////////////////////////////////////////////////////
193 /// Pause playing a video.
194 ///
195 /// \param video Pointer to the video that will be paused.
196 ////////////////////////////////////////////////////////////////////////////////
197 void ts5_pause_video(TS5_VIDEO *video)
198 {
199  ts5_check_video("ts5_pause_video");
200  ts5_log(TS5_LOGLEVEL_5, "ts5_pause_video(%p)\n", video);
201 
202  if (!video) {
203  ts5_fatal("ts5_pause_video: video pointer is null\n");
204  }
205 
206  if (video->isplaying) {
207 
208  #if ALLEGRO_WIP_VERSION <= 11
209  al_pause_video(video->video, 1);
210 
211  #else
212  al_set_video_playing(video->video, 0);
213 
214  #endif
215 
216  video->ispaused = 1;
217  }
218 }
219 
220 
221 ////////////////////////////////////////////////////////////////////////////////
222 /// Stop playing a video.
223 ///
224 /// \param video Pointer to the video that will be stopped.
225 ////////////////////////////////////////////////////////////////////////////////
226 void ts5_stop_video(TS5_VIDEO *video)
227 {
228  ts5_check_video("ts5_stop_video");
229  ts5_log(TS5_LOGLEVEL_5, "ts5_stop_video(%p)\n", video);
230 
231  if (!video) {
232  ts5_fatal("ts5_stop_video: video pointer is null\n");
233  }
234 
235  if (video->isplaying) {
236 
237  #if ALLEGRO_WIP_VERSION <= 11
238  al_pause_video(video->video, 1);
239 
240  #else
241  al_set_video_playing(video->video, 0);
242 
243  #endif
244 
245  video->ispaused = 1;
246  video->isplaying = 0;
247  }
248 }
249 
250 
251 ////////////////////////////////////////////////////////////////////////////////
252 /// Get the next frame of a video.
253 ///
254 /// \param video Pointer to the video that will be queried.
255 ////////////////////////////////////////////////////////////////////////////////
256 TS5_BITMAP *ts5_get_video_frame(TS5_VIDEO *video)
257 {
258  ts5_check_video("ts5_get_video_frame");
259  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_frame(%p)\n", video);
260 
261  if (!video) {
262  ts5_fatal("ts5_get_video_frame: video pointer is null\n");
263  }
264 
265  // delay some frames
266  static long int num_frames_processed=0;
267  int inbuf = (num_frames_processed + video->nbuffers - 1) % video->nbuffers;
268  int outbuf = num_frames_processed % video->nbuffers;
269 
270  ALLEGRO_BITMAP *frame = al_get_video_frame(video->video);
271 
272  if (frame) {
273  ALLEGRO_BITMAP *screen = al_get_target_bitmap();
274  al_set_target_bitmap(video->buffer[inbuf]);
275  al_draw_bitmap(frame, 0.0, 0.0, 0);
276  al_set_target_bitmap(screen);
277  num_frames_processed++;
278  }
279 
280  return video->buffer[outbuf];
281 }
282 
283 
284 ////////////////////////////////////////////////////////////////////////////////
285 //@}
286 ////////////////////////////////////////////////////////////////////////////////
287 
288 
289 ////////////////////////////////////////////////////////////////////////////////
290 /// @name Video parameters
291 /// For each video the parameters can be queried/set using the functions below:
292 ///
293 /// Video position and video gain can be adjusted
294 /// at any time, even when the video is playing.
295 ///
296 /// There is no function available to query the length of a video.
297 //@{
298 ////////////////////////////////////////////////////////////////////////////////
299 
300 
301 ////////////////////////////////////////////////////////////////////////////////
302 /// Query whether a video is playing.
303 ///
304 /// \param video Pointer to the video that will queried.
305 ///
306 /// \return 1 if the video is playing, 0 if not.
307 ////////////////////////////////////////////////////////////////////////////////
308 int ts5_get_video_status(TS5_VIDEO *video)
309 {
310  ts5_check_video("ts5_get_video_status");
311  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_status(%p)\n", video);
312 
313  if (!video) {
314  ts5_fatal("ts5_get_video_status: video pointer is null\n");
315  }
316 
317  return (video->isplaying && !video->ispaused);
318 }
319 
320 
321 ////////////////////////////////////////////////////////////////////////////////
322 /// Get the aspect ratio of a video.
323 ///
324 /// \param video Pointer to the video that will queried.
325 ///
326 /// \return aspect ratio of the video.
327 ////////////////////////////////////////////////////////////////////////////////
328 double ts5_get_video_aspect_ratio(TS5_VIDEO *video)
329 {
330  ts5_check_video("ts5_get_video_status");
331  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_status(%p)\n", video);
332 
333  if (!video) {
334  ts5_fatal("ts5_get_video_status: video pointer is null\n");
335  }
336 
337  double ratio;
338 
339  #if ALLEGRO_WIP_VERSION <= 11
340  ratio = al_get_video_aspect_ratio(video->video);
341 
342  #else
343  ratio = 1;
344 
345  #endif
346 
347  return ratio;
348 }
349 
350 
351 ////////////////////////////////////////////////////////////////////////////////
352 /// Get the width of a video.
353 ///
354 /// \param video Pointer to the video that will queried.
355 ///
356 /// \return width of the video in pixels.
357 ////////////////////////////////////////////////////////////////////////////////
358 double ts5_get_video_width(TS5_VIDEO *video)
359 {
360  ts5_check_video("ts5_get_video_width");
361  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_width(%p)\n", video);
362 
363  if (!video) {
364  ts5_fatal("ts5_get_video_width: video pointer is null\n");
365  }
366 
367  double w;
368 
369  #if ALLEGRO_WIP_VERSION <= 11
370  w = al_get_video_width(video->video);
371 
372  #else
373  w = al_get_video_scaled_width(video->video);
374 
375  #endif
376 
377  return w;
378 }
379 
380 
381 ////////////////////////////////////////////////////////////////////////////////
382 /// Get the height of a video.
383 ///
384 /// \param video Pointer to the video that will queried.
385 ///
386 /// \return height of the video in pixels.
387 ////////////////////////////////////////////////////////////////////////////////
388 double ts5_get_video_height(TS5_VIDEO *video)
389 {
390  ts5_check_video("ts5_get_video_height");
391  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_height(%p)\n", video);
392 
393  if (!video) {
394  ts5_fatal("ts5_get_video_height: video pointer is null\n");
395  }
396 
397  double h;
398 
399  #if ALLEGRO_WIP_VERSION <= 11
400  h = al_get_video_height(video->video);
401 
402  #else
403  h = al_get_video_scaled_height(video->video);
404 
405  #endif
406 
407 
408  return h;
409 }
410 
411 
412 ////////////////////////////////////////////////////////////////////////////////
413 /// Get the audio samplerate of a video.
414 ///
415 /// \param video Pointer to the video that will queried.
416 ///
417 /// \return audio samplerate of the video.
418 ////////////////////////////////////////////////////////////////////////////////
419 double ts5_get_video_samplerate(TS5_VIDEO *video)
420 {
421  ts5_check_video("ts5_get_video_samplerate");
422  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_samplerate(%p)\n", video);
423 
424  if (!video) {
425  ts5_fatal("ts5_get_video_samplerate: video pointer is null\n");
426  }
427 
428  return al_get_video_audio_rate(video->video);
429 }
430 
431 
432 ////////////////////////////////////////////////////////////////////////////////
433 /// Get the framerate of a video.
434 ///
435 /// \param video Pointer to the video that will queried.
436 ///
437 /// \return frame rate of the video.
438 ////////////////////////////////////////////////////////////////////////////////
439 double ts5_get_video_framerate(TS5_VIDEO *video)
440 {
441  ts5_check_video("ts5_get_video_framerate");
442  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_framerate(%p)\n", video);
443 
444  if (!video) {
445  ts5_fatal("ts5_get_video_framerate: video pointer is null\n");
446  }
447 
448  return al_get_video_fps(video->video);
449 }
450 
451 
452 ////////////////////////////////////////////////////////////////////////////////
453 /// Set the playback position of a video.
454 ///
455 /// \param video Pointer to the video that will be adjusted.
456 /// \param position The new playback position.
457 ///
458 /// \return the old playback position of the video in seconds.
459 ////////////////////////////////////////////////////////////////////////////////
460 double ts5_set_video_position(TS5_VIDEO *video, double position)
461 {
462  ts5_check_video("ts5_set_video_position");
463  ts5_log(TS5_LOGLEVEL_5, "ts5_set_video_position(%p,%f)\n", video, position);
464 
465  if (!video) {
466  ts5_fatal("ts5_set_video_position: video pointer is null\n");
467  }
468 
469  double retval = al_get_video_position(video->video, 0);
470 
471  al_seek_video(video->video, position);
472 
473  return retval;
474 }
475 
476 
477 ////////////////////////////////////////////////////////////////////////////////
478 /// Get the playback position of a video.
479 ///
480 /// \param video Pointer to the video that will be queried.
481 ///
482 /// \return the current playback position of the video in seconds.
483 ////////////////////////////////////////////////////////////////////////////////
484 double ts5_get_video_position(TS5_VIDEO *video)
485 {
486  ts5_check_video("ts5_get_video_position");
487  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_position(%p)\n", video);
488 
489  if (!video) {
490  ts5_fatal("ts5_get_video_position: video pointer is null\n");
491  }
492 
493  return al_get_video_position(video->video, 0);
494 }
495 
496 
497 ////////////////////////////////////////////////////////////////////////////////
498 /// Set the playback gain of a video.
499 ///
500 /// \param video Pointer to the video that will be adjusted.
501 /// \param gain The new playback gain (1.0 is normal gain).
502 ///
503 /// \return The old gain setting.
504 ////////////////////////////////////////////////////////////////////////////////
505 double ts5_set_video_gain(TS5_VIDEO *video, double gain)
506 {
507  ts5_check_video("ts5_set_video_gain");
508  ts5_log(TS5_LOGLEVEL_5, "ts5_set_video_gain(%p,%f)\n", video, gain);
509 
510  if (!video) {
511  ts5_fatal("ts5_set_video_gain: video pointer is null\n");
512  }
513 
514  double retval = al_get_mixer_gain(video->mixer);
515  al_set_mixer_gain(video->mixer, gain);
516 
517  return retval;
518 }
519 
520 
521 ////////////////////////////////////////////////////////////////////////////////
522 /// Get the playback gain of a video.
523 ///
524 /// \param video Pointer to the video that will be queried.
525 ///
526 /// \return the current playback gain.
527 ////////////////////////////////////////////////////////////////////////////////
528 double ts5_get_video_gain(TS5_VIDEO *video)
529 {
530  ts5_check_video("ts5_get_video_gain");
531  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_gain(%p)\n", video);
532 
533  if (!video) {
534  ts5_fatal("ts5_get_video_gain: video pointer is null\n");
535  }
536 
537  return al_get_mixer_gain(video->mixer);;
538 }
539 
540 
541 ////////////////////////////////////////////////////////////////////////////////
542 //@}
543 ////////////////////////////////////////////////////////////////////////////////
544 
void ts5_play_video(TS5_VIDEO *video)
Start playing a video.
Definition: video.c:164
void ts5_free_video(TS5_VIDEO *video)
Free the memory used by a video.
Definition: video.c:112
double ts5_get_video_position(TS5_VIDEO *video)
Get the playback position of a video.
Definition: video.c:484
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:439
double ts5_get_video_height(TS5_VIDEO *video)
Get the height of a video.
Definition: video.c:388
void ts5_pause_video(TS5_VIDEO *video)
Pause playing a video.
Definition: video.c:197
double ts5_set_video_position(TS5_VIDEO *video, double position)
Set the playback position of a video.
Definition: video.c:460
double ts5_set_video_gain(TS5_VIDEO *video, double gain)
Set the playback gain of a video.
Definition: video.c:505
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:256
double ts5_get_video_aspect_ratio(TS5_VIDEO *video)
Get the aspect ratio of a video.
Definition: video.c:328
double ts5_get_video_width(TS5_VIDEO *video)
Get the width of a video.
Definition: video.c:358
void ts5_stop_video(TS5_VIDEO *video)
Stop playing a video.
Definition: video.c:226
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:528
void ts5_fatal(const char *format,...)
Exit safely with an error message.
Definition: system.c:533
double ts5_get_video_samplerate(TS5_VIDEO *video)
Get the audio samplerate of a video.
Definition: video.c:419
int ts5_get_video_status(TS5_VIDEO *video)
Query whether a video is playing.
Definition: video.c:308