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 <a href="video01_8c-example.html">video01.c</a>
143 /// for an example that shows how this works.
144 //@{
145 ////////////////////////////////////////////////////////////////////////////////
146 
147 
148 ////////////////////////////////////////////////////////////////////////////////
149 /// Start playing a video.
150 ///
151 /// \param video Pointer to the video that will be played.
152 ////////////////////////////////////////////////////////////////////////////////
153 void ts5_play_video(TS5_VIDEO *video)
154 {
155  ts5_check_video("ts5_play_video");
156  ts5_log(TS5_LOGLEVEL_5, "ts5_play_video(%p)\n", video);
157 
158  if (!video) {
159  ts5_fatal("ts5_play_video: video pointer is null\n");
160  }
161 
162  if(!video->ispaused) {
163  al_start_video(video->video, video->mixer);
164  video->isplaying = 1;
165  }
166  else {
167  al_pause_video(video->video, 0);
168  }
169  video->ispaused = 0;
170 }
171 
172 
173 ////////////////////////////////////////////////////////////////////////////////
174 /// Pause playing a video.
175 ///
176 /// \param video Pointer to the video that will be paused.
177 ////////////////////////////////////////////////////////////////////////////////
178 void ts5_pause_video(TS5_VIDEO *video)
179 {
180  ts5_check_video("ts5_pause_video");
181  ts5_log(TS5_LOGLEVEL_5, "ts5_pause_video(%p)\n", video);
182 
183  if (!video) {
184  ts5_fatal("ts5_pause_video: video pointer is null\n");
185  }
186 
187  if (video->isplaying) {
188  al_pause_video(video->video, 1);
189  video->ispaused = 1;
190  }
191 }
192 
193 
194 ////////////////////////////////////////////////////////////////////////////////
195 /// Stop playing a video.
196 ///
197 /// \param video Pointer to the video that will be stopped.
198 ////////////////////////////////////////////////////////////////////////////////
199 void ts5_stop_video(TS5_VIDEO *video)
200 {
201  ts5_check_video("ts5_stop_video");
202  ts5_log(TS5_LOGLEVEL_5, "ts5_stop_video(%p)\n", video);
203 
204  if (!video) {
205  ts5_fatal("ts5_stop_video: video pointer is null\n");
206  }
207 
208  if (video->isplaying) {
209  al_pause_video(video->video, 1);
210  video->ispaused = 1;
211  video->isplaying = 0;
212  }
213 }
214 
215 
216 ////////////////////////////////////////////////////////////////////////////////
217 /// Get the next frame of a video.
218 ///
219 /// \param video Pointer to the video that will be queried.
220 ////////////////////////////////////////////////////////////////////////////////
221 TS5_BITMAP *ts5_get_video_frame(TS5_VIDEO *video)
222 {
223  ts5_check_video("ts5_get_video_frame");
224  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_frame(%p)\n", video);
225 
226  if (!video) {
227  ts5_fatal("ts5_get_video_frame: video pointer is null\n");
228  }
229 
230  // delay some frames
231  static long int num_frames_processed=0;
232  int inbuf = (num_frames_processed + video->nbuffers - 1) % video->nbuffers;
233  int outbuf = num_frames_processed % video->nbuffers;
234 
235  ALLEGRO_BITMAP *frame = al_get_video_frame(video->video);
236 
237  if (frame) {
238  ALLEGRO_BITMAP *screen = al_get_target_bitmap();
239  al_set_target_bitmap(video->buffer[inbuf]);
240  al_draw_bitmap(frame, 0.0, 0.0, 0);
241  al_set_target_bitmap(screen);
242  num_frames_processed++;
243  }
244 
245  return video->buffer[outbuf];
246 }
247 
248 
249 ////////////////////////////////////////////////////////////////////////////////
250 //@}
251 ////////////////////////////////////////////////////////////////////////////////
252 
253 
254 ////////////////////////////////////////////////////////////////////////////////
255 /// @name Video parameters
256 /// For each video the parameters can be queried/set using the functions below:
257 ///
258 /// Video position and video gain can be adjusted
259 /// at any time, even when the video is playing.
260 ///
261 /// There is no function available to query the length of a video.
262 //@{
263 ////////////////////////////////////////////////////////////////////////////////
264 
265 
266 ////////////////////////////////////////////////////////////////////////////////
267 /// Query whether a video is playing.
268 ///
269 /// \param video Pointer to the video that will queried.
270 ///
271 /// \return 1 if the video is playing, 0 if not.
272 ////////////////////////////////////////////////////////////////////////////////
273 int ts5_get_video_status(TS5_VIDEO *video)
274 {
275  ts5_check_video("ts5_get_video_status");
276  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_status(%p)\n", video);
277 
278  if (!video) {
279  ts5_fatal("ts5_get_video_status: video pointer is null\n");
280  }
281 
282  return (video->isplaying && !video->ispaused);
283 }
284 
285 
286 ////////////////////////////////////////////////////////////////////////////////
287 /// Get the aspect ratio of a video.
288 ///
289 /// \param video Pointer to the video that will queried.
290 ///
291 /// \return aspect ratio of the video.
292 ////////////////////////////////////////////////////////////////////////////////
293 double ts5_get_video_aspect_ratio(TS5_VIDEO *video)
294 {
295  ts5_check_video("ts5_get_video_status");
296  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_status(%p)\n", video);
297 
298  if (!video) {
299  ts5_fatal("ts5_get_video_status: video pointer is null\n");
300  }
301 
302  return al_get_video_aspect_ratio(video->video);
303 }
304 
305 
306 ////////////////////////////////////////////////////////////////////////////////
307 /// Get the width of a video.
308 ///
309 /// \param video Pointer to the video that will queried.
310 ///
311 /// \return width of the video in pixels.
312 ////////////////////////////////////////////////////////////////////////////////
313 double ts5_get_video_width(TS5_VIDEO *video)
314 {
315  ts5_check_video("ts5_get_video_width");
316  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_width(%p)\n", video);
317 
318  if (!video) {
319  ts5_fatal("ts5_get_video_width: video pointer is null\n");
320  }
321 
322  return al_get_video_width(video->video);
323 }
324 
325 
326 ////////////////////////////////////////////////////////////////////////////////
327 /// Get the height of a video.
328 ///
329 /// \param video Pointer to the video that will queried.
330 ///
331 /// \return height of the video in pixels.
332 ////////////////////////////////////////////////////////////////////////////////
333 double ts5_get_video_height(TS5_VIDEO *video)
334 {
335  ts5_check_video("ts5_get_video_height");
336  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_height(%p)\n", video);
337 
338  if (!video) {
339  ts5_fatal("ts5_get_video_height: video pointer is null\n");
340  }
341 
342  return al_get_video_height(video->video);
343 }
344 
345 
346 ////////////////////////////////////////////////////////////////////////////////
347 /// Get the audio samplerate of a video.
348 ///
349 /// \param video Pointer to the video that will queried.
350 ///
351 /// \return audio samplerate of the video.
352 ////////////////////////////////////////////////////////////////////////////////
353 double ts5_get_video_samplerate(TS5_VIDEO *video)
354 {
355  ts5_check_video("ts5_get_video_samplerate");
356  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_samplerate(%p)\n", video);
357 
358  if (!video) {
359  ts5_fatal("ts5_get_video_samplerate: video pointer is null\n");
360  }
361 
362  return al_get_video_audio_rate(video->video);
363 }
364 
365 
366 ////////////////////////////////////////////////////////////////////////////////
367 /// Get the framerate of a video.
368 ///
369 /// \param video Pointer to the video that will queried.
370 ///
371 /// \return frame rate of the video.
372 ////////////////////////////////////////////////////////////////////////////////
373 double ts5_get_video_framerate(TS5_VIDEO *video)
374 {
375  ts5_check_video("ts5_get_video_framerate");
376  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_framerate(%p)\n", video);
377 
378  if (!video) {
379  ts5_fatal("ts5_get_video_framerate: video pointer is null\n");
380  }
381 
382  return al_get_video_fps(video->video);
383 }
384 
385 
386 ////////////////////////////////////////////////////////////////////////////////
387 /// Set the playback position of a video.
388 ///
389 /// \param video Pointer to the video that will be adjusted.
390 /// \param position The new playback position.
391 ///
392 /// \return the old playback position of the video in seconds.
393 ////////////////////////////////////////////////////////////////////////////////
394 double ts5_set_video_position(TS5_VIDEO *video, double position)
395 {
396  ts5_check_video("ts5_set_video_position");
397  ts5_log(TS5_LOGLEVEL_5, "ts5_set_video_position(%p,%f)\n", video, position);
398 
399  if (!video) {
400  ts5_fatal("ts5_set_video_position: video pointer is null\n");
401  }
402 
403  double retval = al_get_video_position(video->video, 0);
404 
405  al_seek_video(video->video, position);
406 
407  return retval;
408 }
409 
410 
411 ////////////////////////////////////////////////////////////////////////////////
412 /// Get the playback position of a video.
413 ///
414 /// \param video Pointer to the video that will be queried.
415 ///
416 /// \return the current playback position of the video in seconds.
417 ////////////////////////////////////////////////////////////////////////////////
418 double ts5_get_video_position(TS5_VIDEO *video)
419 {
420  ts5_check_video("ts5_get_video_position");
421  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_position(%p)\n", video);
422 
423  if (!video) {
424  ts5_fatal("ts5_get_video_position: video pointer is null\n");
425  }
426 
427  return al_get_video_position(video->video, 0);
428 }
429 
430 
431 ////////////////////////////////////////////////////////////////////////////////
432 /// Set the playback gain of a video.
433 ///
434 /// \param video Pointer to the video that will be adjusted.
435 /// \param gain The new playback gain (1.0 is normal gain).
436 ///
437 /// \return The old gain setting.
438 ////////////////////////////////////////////////////////////////////////////////
439 double ts5_set_video_gain(TS5_VIDEO *video, double gain)
440 {
441  ts5_check_video("ts5_set_video_gain");
442  ts5_log(TS5_LOGLEVEL_5, "ts5_set_video_gain(%p,%f)\n", video, gain);
443 
444  if (!video) {
445  ts5_fatal("ts5_set_video_gain: video pointer is null\n");
446  }
447 
448  double retval = al_get_mixer_gain(video->mixer);
449  al_set_mixer_gain(video->mixer, gain);
450 
451  return retval;
452 }
453 
454 
455 ////////////////////////////////////////////////////////////////////////////////
456 /// Get the playback gain of a video.
457 ///
458 /// \param video Pointer to the video that will be queried.
459 ///
460 /// \return the current playback gain.
461 ////////////////////////////////////////////////////////////////////////////////
462 double ts5_get_video_gain(TS5_VIDEO *video)
463 {
464  ts5_check_video("ts5_get_video_gain");
465  ts5_log(TS5_LOGLEVEL_5, "ts5_get_video_gain(%p)\n", video);
466 
467  if (!video) {
468  ts5_fatal("ts5_get_video_gain: video pointer is null\n");
469  }
470 
471  return al_get_mixer_gain(video->mixer);;
472 }
473 
474 
475 ////////////////////////////////////////////////////////////////////////////////
476 //@}
477 ////////////////////////////////////////////////////////////////////////////////
478 
void ts5_play_video(TS5_VIDEO *video)
Start playing a video.
Definition: video.c:153
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:418
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:373
double ts5_get_video_height(TS5_VIDEO *video)
Get the height of a video.
Definition: video.c:333
void ts5_pause_video(TS5_VIDEO *video)
Pause playing a video.
Definition: video.c:178
double ts5_set_video_position(TS5_VIDEO *video, double position)
Set the playback position of a video.
Definition: video.c:394
double ts5_set_video_gain(TS5_VIDEO *video, double gain)
Set the playback gain of a video.
Definition: video.c:439
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:221
double ts5_get_video_aspect_ratio(TS5_VIDEO *video)
Get the aspect ratio of a video.
Definition: video.c:293
double ts5_get_video_width(TS5_VIDEO *video)
Get the width of a video.
Definition: video.c:313
void ts5_stop_video(TS5_VIDEO *video)
Stop playing a video.
Definition: video.c:199
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:462
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:353
int ts5_get_video_status(TS5_VIDEO *video)
Query whether a video is playing.
Definition: video.c:273