1#include "video_player.h"
2
3static void *loader_thread
(void *data
)
4{
5 Video_Player::Thread_Data
*thread_data
= (Video_Player::Thread_Data
*)data
;
6
7 General::set_physfs_file_interface
();
8 al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP
);
9
10 while (!thread_data->end_thread
) {
11 al_lock_mutex(thread_data->mutex
);
12 if (thread_data->num_frames_to_load
> 0) {
13 thread_data->bitmaps
= new ALLEGRO_BITMAP *[thread_data->num_frames_to_load
];
14 for (int i
= 0; i
< thread_data->num_frames_to_load
; i
++) {
15 char buf
[1000];
16 snprintf(buf,
1000,
"%s/%06d.png", thread_data->dirname.c_str
(), thread_data->start_frame
+i
);
17 thread_data->bitmaps
[i
] = al_load_bitmap(buf
);
18 }
19 thread_data->num_frames_to_load
= 0;
20 thread_data->done
= true;
21 al_broadcast_cond(thread_data->loaded
);
22 }
23 al_unlock_mutex(thread_data->mutex
);
24 al_rest(0.
001);
25 }
26
27 return NULL
;
28}
29
30void Video_Player::start
()
31{
32 start_time
= al_get_time();
33}
34
35// returns true when video is done
36bool Video_Player::draw
()
37{
38 double now
= al_get_time();
39 double elapsed
= now
- start_time
;
40 double total_len
= total_frames
* (1.
0/FPS
);
41 int frame
;
42
43 if (elapsed
>= total_len
) {
44 frame
= total_frames-1
;
45 }
46 else {
47 frame
= total_frames
* (elapsed
/ total_len
);
48 }
49
50 // Drop passed frames
51 while (frames.size
() > 0 && frames
[0].frame_num
< frame
) {
52 frames.erase
(frames.begin
());
53 }
54
55 if (frames.size
() == 0) {
56 // This might mean something bad happened
57 return true;
58 }
59
60 al_draw_bitmap(frames
[frames.size
()-1].bitmap->bitmap, offset.x, offset.y,
0);
61
62 if (elapsed
>= total_len
) {
63 return true;
64 }
65
66 return false;
67}
68
69void Video_Player::update
()
70{
71 if (total_frames_loaded
>= total_frames
) {
72 return;
73 }
74
75 int needed
= MIN
(total_frames-total_frames_loaded, buffer_size_in_frames
- (int)frames.size
());
76 if (needed
> 0) {
77 get_frames
(needed
);
78 }
79}
80
81void Video_Player::set_offset
(General::Point
<float> offset
)
82{
83 this->offset
= offset
;
84}
85
86void Video_Player::get_frames
(int num
)
87{
88 // Make the request
89 al_lock_mutex(thread_data.mutex
);
90 thread_data.start_frame
= total_frames_loaded
;
91 thread_data.num_frames_to_load
= num
;
92 thread_data.done
= false;
93 al_unlock_mutex(thread_data.mutex
);
94
95 // Wait for it
96 General::log_message
("VIDEO: Waiting on condition...");
97 al_lock_mutex(thread_data.mutex
);
98 while (!thread_data.done
) {
99 al_wait_cond(thread_data.loaded, thread_data.mutex
);
100 }
101 al_unlock_mutex(thread_data.mutex
);
102 General::log_message
("VIDEO: Thread loaded frames!");
103
104 // Convert to video bitmaps
105 for (int i
= 0; i
< num
; i
++) {
106 printf("i=%d\n", i
);
107 printf("bitmaps[%d]=%p\n", i, thread_data.bitmaps
[i
]);
108 ALLEGRO_BITMAP *bmp
= al_clone_bitmap(thread_data.bitmaps
[i
]);
109 printf("bmp=%p\n", bmp
);
110 Wrap::Bitmap
*b
= new Wrap::Bitmap
(bmp,
"");
111 Video_Frame frame
;
112 frame.bitmap
= b
;
113 frame.frame_num
= total_frames_loaded
+ i
;
114 frames.push_back
(frame
);
115 al_destroy_bitmap(thread_data.bitmaps
[i
]);
116 }
117 delete[] thread_data.bitmaps
;
118
119 total_frames_loaded
+= num
;
120 if (total_frames_loaded
>= total_frames
) {
121 thread_data.end_thread
= true;
122 }
123 printf("total_frames_loaded=%d\n", total_frames_loaded
);
124}
125
126Video_Player::Video_Player
(std::string
dirname,
int buffer_size_in_frames
) :
127 buffer_size_in_frames
(buffer_size_in_frames
),
128 offset
(0,
0)
129{
130 thread_data.dirname
= dirname;
131
132 // Count frames
133 total_frames
= 0;
134 for (; total_frames
< 0xffff /* RANDOM */; total_frames
++) {
135 char filename
[1000];
136 snprintf(filename,
1000,
"%s/%06d.png", thread_data.dirname.c_str
(), total_frames
);
137 if (!General::exists
(filename
)) {
138 break;
139 }
140 }
141 total_frames_loaded
= 0;
142 General::log_message
("Video frame count=" + General::itos
(total_frames
));
143
144 // Setup threading
145 thread_data.mutex
= al_create_mutex();
146 thread_data.loaded
= al_create_cond();
147
148 // Start the loading thread
149 al_run_detached_thread(loader_thread,
(void *)&thread_data
);
150
151 // Request a full buffer of frames to start
152 get_frames
(MIN
(buffer_size_in_frames, total_frames
));
153}
154
155Video_Player::~Video_Player
()
156{
157 al_destroy_mutex(thread_data.mutex
);
158 al_destroy_cond(thread_data.loaded
);
159
160 // Cleanup potentially unused frames (due to skipping/lag)
161 for (size_t i
= 0; i
< frames.size
(); i
++) {
162 Wrap::destroy_bitmap
(frames
[i
].bitmap
);
163 }
164}