1 /*****************************************************************
2 * Gmerlin - a general purpose multimedia framework and applications
3 *
4 * Copyright (c) 2001 - 2011 Members of the Gmerlin project
5 * gmerlin-general@lists.sourceforge.net
6 * http://gmerlin.sourceforge.net
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * *****************************************************************/
21
22 #include <string.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <sys/time.h>
26
27 #include <gmerlin/player.h>
28 #include <playerprivate.h>
29
30 #define LOG_DOMAIN "player"
31 #include <gmerlin/log.h>
32
33 /* Input callbacks */
34
35
duration_changed(void * data,gavl_time_t duration)36 static void duration_changed(void * data, gavl_time_t duration)
37 {
38 bg_player_t * p = data;
39 bg_player_set_duration(p, duration, p->can_seek);
40 }
41
name_changed(void * data,const char * name)42 static void name_changed(void * data, const char * name)
43 {
44 bg_player_t * p = data;
45 bg_player_set_track_name(p, name);
46 }
47
metadata_changed(void * data,const gavl_metadata_t * m)48 static void metadata_changed(void * data, const gavl_metadata_t * m)
49 {
50 bg_player_t * p = data;
51 bg_player_set_metadata(p, m);
52 }
53
buffer_notify(void * data,float percentage)54 static void buffer_notify(void * data, float percentage)
55 {
56 bg_player_t * p = data;
57 bg_player_set_state(p, BG_PLAYER_STATE_BUFFERING,
58 &percentage, NULL);
59 }
60
aspect_changed(void * data,int stream,int pixel_width,int pixel_height)61 static void aspect_changed(void * data, int stream, int pixel_width,
62 int pixel_height)
63 {
64 bg_player_t * p = data;
65 bg_log(BG_LOG_INFO, LOG_DOMAIN, "Aspect ratio changed");
66
67 bg_player_ov_update_aspect(&p->video_stream,
68 pixel_width, pixel_height);
69 }
70
71
bg_player_create(bg_plugin_registry_t * plugin_reg)72 bg_player_t * bg_player_create(bg_plugin_registry_t * plugin_reg)
73 {
74 bg_player_t * ret;
75
76 ret = calloc(1, sizeof(*ret));
77
78 /* Callbacks */
79 ret->input_callbacks.data = ret;
80 ret->input_callbacks.name_changed = name_changed;
81 ret->input_callbacks.duration_changed = duration_changed;
82 ret->input_callbacks.metadata_changed = metadata_changed;
83 ret->input_callbacks.buffer_notify = buffer_notify;
84 ret->input_callbacks.aspect_changed = aspect_changed;
85
86 /* Create message queues */
87
88 ret->command_queue = bg_msg_queue_create();
89
90 ret->message_queues = bg_msg_queue_list_create();
91
92 ret->visualizer = bg_visualizer_create(plugin_reg);
93
94 ret->thread_common = bg_player_thread_common_create();
95
96 /* Create contexts */
97
98 bg_player_audio_create(ret, plugin_reg);
99 bg_player_video_create(ret, plugin_reg);
100 bg_player_subtitle_create(ret);
101
102 bg_player_input_create(ret);
103 bg_player_ov_create(ret);
104
105 ret->threads[0] = ret->audio_stream.th;
106 ret->threads[1] = ret->video_stream.th;
107
108 pthread_mutex_init(&ret->state_mutex, NULL);
109 pthread_mutex_init(&ret->config_mutex, NULL);
110
111
112
113
114 /* Subtitles are off by default */
115 ret->current_subtitle_stream = -1;
116 // ret->current_subtitle_stream = 5;
117 ret->state = BG_PLAYER_STATE_INIT;
118
119 ret->wait_time = 10000;
120
121 return ret;
122 }
123
bg_player_destroy(bg_player_t * player)124 void bg_player_destroy(bg_player_t * player)
125 {
126
127 bg_player_input_destroy(player);
128 bg_player_ov_destroy(player);
129 bg_player_audio_destroy(player);
130 bg_player_video_destroy(player);
131 bg_player_subtitle_destroy(player);
132
133 bg_visualizer_destroy(player->visualizer);
134
135 bg_msg_queue_destroy(player->command_queue);
136
137 bg_msg_queue_list_destroy(player->message_queues);
138
139 pthread_mutex_destroy(&player->state_mutex);
140 pthread_mutex_destroy(&player->config_mutex);
141
142 bg_player_thread_common_destroy(player->thread_common);
143
144 free(player);
145 }
146
bg_player_add_message_queue(bg_player_t * player,bg_msg_queue_t * message_queue)147 void bg_player_add_message_queue(bg_player_t * player,
148 bg_msg_queue_t * message_queue)
149 {
150 bg_msg_queue_list_add(player->message_queues, message_queue);
151 }
152
bg_player_delete_message_queue(bg_player_t * player,bg_msg_queue_t * message_queue)153 void bg_player_delete_message_queue(bg_player_t * player,
154 bg_msg_queue_t * message_queue)
155 {
156 bg_msg_queue_list_remove(player->message_queues, message_queue);
157 }
158
159
bg_player_get_state(bg_player_t * player)160 int bg_player_get_state(bg_player_t * player)
161 {
162 int ret;
163 pthread_mutex_lock(&player->state_mutex);
164 ret = player->state;
165 pthread_mutex_unlock(&player->state_mutex);
166 return ret;
167 }
168
169 struct state_struct
170 {
171 int state;
172 float percentage;
173 int want_new;
174 int can_pause;
175 };
176
msg_state(bg_msg_t * msg,const void * data)177 static void msg_state(bg_msg_t * msg,
178 const void * data)
179 {
180 struct state_struct * s;
181 s = (struct state_struct *)data;
182
183
184 bg_msg_set_id(msg, BG_PLAYER_MSG_STATE_CHANGED);
185 bg_msg_set_arg_int(msg, 0, s->state);
186
187 if(s->state == BG_PLAYER_STATE_BUFFERING)
188 {
189 bg_msg_set_arg_float(msg, 1, s->percentage);
190 }
191 else if(s->state == BG_PLAYER_STATE_CHANGING)
192 {
193 bg_msg_set_arg_int(msg, 1, s->want_new);
194 }
195 else if(s->state == BG_PLAYER_STATE_PLAYING)
196 {
197 bg_msg_set_arg_int(msg, 1, s->can_pause);
198 }
199 }
200
bg_player_set_state(bg_player_t * player,int state,const void * arg1,const void * arg2)201 void bg_player_set_state(bg_player_t * player, int state,
202 const void * arg1, const void * arg2)
203 {
204 struct state_struct s;
205 pthread_mutex_lock(&player->state_mutex);
206 player->state = state;
207 pthread_mutex_unlock(&player->state_mutex);
208
209 /* Broadcast this message */
210
211 // memset(&state, 0, sizeof(state));
212
213 s.state = state;
214
215 if(state == BG_PLAYER_STATE_BUFFERING)
216 s.percentage = *((const float*)arg1);
217 else if(state == BG_PLAYER_STATE_CHANGING)
218 s.want_new = *((const int*)arg1);
219 else if(state == BG_PLAYER_STATE_PLAYING)
220 s.can_pause = *((const int*)arg1);
221
222 bg_msg_queue_list_send(player->message_queues,
223 msg_state,
224 &s);
225 }
226
227 const bg_parameter_info_t *
bg_player_get_visualization_parameters(bg_player_t * player)228 bg_player_get_visualization_parameters(bg_player_t * player)
229 {
230 return bg_visualizer_get_parameters(player->visualizer);
231 }
232
233 void
bg_player_set_visualization_parameter(void * data,const char * name,const bg_parameter_value_t * val)234 bg_player_set_visualization_parameter(void*data,
235 const char * name,
236 const bg_parameter_value_t*val)
237 {
238 bg_player_t * p;
239 int do_init;
240
241 p = (bg_player_t*)data;
242 do_init = (bg_player_get_state(p) == BG_PLAYER_STATE_INIT);
243
244 bg_visualizer_set_parameter(p->visualizer, name, val);
245
246 if(!do_init)
247 {
248 if(bg_visualizer_need_restart(p->visualizer))
249 {
250 bg_player_interrupt(p);
251 bg_player_interrupt_resume(p);
252 }
253 }
254 }
255
256 void
bg_player_set_visualization_plugin_parameter(void * data,const char * name,const bg_parameter_value_t * val)257 bg_player_set_visualization_plugin_parameter(void*data,
258 const char * name,
259 const bg_parameter_value_t*val)
260 {
261 bg_player_t * p;
262 p = (bg_player_t*)data;
263 bg_visualizer_set_vis_parameter(p->visualizer, name, val);
264 }
265
266 void
bg_player_set_visualization(bg_player_t * p,int enable)267 bg_player_set_visualization(bg_player_t * p,
268 int enable)
269 {
270 int was_enabled;
271 int do_init;
272 do_init = (bg_player_get_state(p) == BG_PLAYER_STATE_INIT);
273
274 pthread_mutex_lock(&p->config_mutex);
275 was_enabled = p->visualizer_enabled;
276 p->visualizer_enabled = enable;
277 pthread_mutex_unlock(&p->config_mutex);
278
279 if((was_enabled != enable) && !do_init)
280 {
281 bg_player_interrupt(p);
282 bg_player_interrupt_resume(p);
283 }
284 }
285
286 void
bg_player_set_visualization_plugin(bg_player_t * p,const bg_plugin_info_t * plugin_info)287 bg_player_set_visualization_plugin(bg_player_t * p, const bg_plugin_info_t * plugin_info)
288 {
289 int do_init;
290 do_init = (bg_player_get_state(p) == BG_PLAYER_STATE_INIT);
291
292 bg_visualizer_set_vis_plugin(p->visualizer, plugin_info);
293
294 if(!do_init)
295 {
296 if(bg_visualizer_need_restart(p->visualizer))
297 {
298 bg_player_interrupt(p);
299 bg_player_interrupt_resume(p);
300 }
301 }
302
303 }
304
305 static const bg_parameter_info_t parameters[] =
306 {
307 {
308 .name = "message_interval",
309 .long_name = TRS("Control loop interval"),
310 .type = BG_PARAMETER_INT,
311 .val_default = { .val_i = 10 },
312 },
313 {
314 .name = "time_update",
315 .long_name = TRS("Time update interval"),
316 .type = BG_PARAMETER_STRINGLIST,
317 .multi_names = (char const *[]){ "seconds", "frames", NULL },
318 .multi_labels = (char const *[]){ TRS("Seconds"), TRS("frames"), NULL },
319 .val_default = { .val_str = "seconds" },
320 },
321 {
322 .name = "report_peak",
323 .long_name = TRS("Report peak values for audio"),
324 .type = BG_PARAMETER_CHECKBUTTON,
325 },
326 {
327 .name = "finish_mode",
328 .long_name = TRS("Finish mode"),
329 .type = BG_PARAMETER_STRINGLIST,
330 .multi_names = (char const *[]){ "change", "pause", NULL },
331 .multi_labels = (char const *[]){ TRS("Change"), TRS("Pause"), NULL },
332 .val_default = { .val_str = "change" },
333 },
334 { /* End of parameters */ }
335 };
336
bg_player_get_parameters(bg_player_t * player)337 const bg_parameter_info_t * bg_player_get_parameters(bg_player_t * player)
338 {
339 return parameters;
340 }
341
342
bg_player_set_parameter(void * player,const char * name,const bg_parameter_value_t * val)343 void bg_player_set_parameter(void * player, const char * name,
344 const bg_parameter_value_t * val)
345 {
346 bg_player_t * p = player;
347 if(!name)
348 return;
349 else if(!strcmp(name, "message_interval"))
350 {
351 p->wait_time = val->val_i;
352 p->wait_time *= 1000;
353 }
354 else if(!strcmp(name, "time_update"))
355 {
356 if(!strcmp(val->val_str, "second"))
357 {
358 p->time_update_mode = TIME_UPDATE_SECOND;
359 }
360 else if(!strcmp(val->val_str, "frame"))
361 {
362 p->time_update_mode = TIME_UPDATE_FRAME;
363 }
364 }
365 else if(!strcmp(name, "finish_mode"))
366 {
367 if(!strcmp(val->val_str, "change"))
368 {
369 p->finish_mode = BG_PLAYER_FINISH_CHANGE;
370 }
371 else if(!strcmp(val->val_str, "pause"))
372 {
373 p->finish_mode = BG_PLAYER_FINISH_PAUSE;
374 }
375 }
376 else if(!strcmp(name, "report_peak"))
377 {
378 if(val->val_i)
379 p->flags |= PLAYER_DO_REPORT_PEAK;
380 else
381 p->flags &= ~PLAYER_DO_REPORT_PEAK;
382 }
383 }
384