1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3  * gmtk_media_player.c
4  * Copyright (C) Kevin DeKorte 2009 <kdekorte@gmail.com>
5  *
6  * gmtk_media_player.c is free software.
7  *
8  * You may redistribute it and/or modify it under the terms of the
9  * GNU General Public License, as published by the Free Software
10  * Foundation; either version 2 of the License, or (at your option)
11  * any later version.
12  *
13  * gmtk_media_tracker.c 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.
16  * See the GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with playlist.c.  If not, write to:
20  * 	The Free Software Foundation, Inc.,
21  * 	51 Franklin Street, Fifth Floor
22  * 	Boston, MA  02110-1301, USA.
23  */
24 
25 #include "gmtk_media_player.h"
26 #include "gmlib.h"
27 #include "gmtk_common.h"
28 
29 G_DEFINE_TYPE(GmtkMediaPlayer, gmtk_media_player, GTK_TYPE_EVENT_BOX);
30 static GObjectClass *parent_class = NULL;
31 
32 static void gmtk_media_player_dispose(GObject * object);
33 static gboolean gmtk_media_player_draw_event(GtkWidget * widget, cairo_t * cr);
34 static gboolean gmtk_media_player_expose_event(GtkWidget * widget, GdkEventExpose * event);
35 static void gmtk_media_player_size_allocate(GtkWidget * widget, GtkAllocation * allocation);
36 static gboolean player_key_press_event_callback(GtkWidget * widget, GdkEventKey * event, gpointer data);
37 static gboolean player_button_press_event_callback(GtkWidget * widget, GdkEventButton * event, gpointer data);
38 static gboolean player_motion_notify_event_callback(GtkWidget * widget, GdkEventMotion * event, gpointer data);
39 static void gmtk_media_player_restart_complete_callback(GmtkMediaPlayer * player, gpointer data);
40 static void gmtk_media_player_restart_shutdown_complete_callback(GmtkMediaPlayer * player, gpointer data);
41 
42 // monitoring functions
43 gpointer launch_mplayer(gpointer data);
44 gboolean thread_reader_error(GIOChannel * source, GIOCondition condition, gpointer data);
45 gboolean thread_reader(GIOChannel * source, GIOCondition condition, gpointer data);
46 gboolean thread_query(gpointer data);
47 gboolean thread_complete(GIOChannel * source, GIOCondition condition, gpointer data);
48 
49 gboolean write_to_mplayer(GmtkMediaPlayer * player, const gchar * cmd);
50 gboolean detect_mplayer_features(GmtkMediaPlayer * player);
51 
player_realized(GtkWidget * widget,gpointer data)52 static void player_realized(GtkWidget * widget, gpointer data)
53 {
54     GtkStyle *style;
55 
56     style = gtk_widget_get_style(widget);
57     gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, &(style->black));
58     gtk_widget_modify_bg(widget, GTK_STATE_ACTIVE, &(style->black));
59     gtk_widget_modify_bg(widget, GTK_STATE_SELECTED, &(style->black));
60     gtk_widget_modify_bg(widget, GTK_STATE_PRELIGHT, &(style->black));
61     gtk_widget_modify_bg(widget, GTK_STATE_INSENSITIVE, &(style->black));
62 
63 }
64 
alignment_realized(GtkWidget * widget,gpointer data)65 static void alignment_realized(GtkWidget * widget, gpointer data)
66 {
67     GtkStyle *style;
68 
69     style = gtk_widget_get_style(widget);
70     gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, &(style->black));
71     gtk_widget_modify_bg(widget, GTK_STATE_ACTIVE, &(style->black));
72     gtk_widget_modify_bg(widget, GTK_STATE_SELECTED, &(style->black));
73     gtk_widget_modify_bg(widget, GTK_STATE_PRELIGHT, &(style->black));
74     gtk_widget_modify_bg(widget, GTK_STATE_INSENSITIVE, &(style->black));
75 
76 }
77 
vodesc_looks_like_vo(gchar const * const desc,gchar const * const vo)78 static gboolean vodesc_looks_like_vo(gchar const *const desc, gchar const *const vo)
79 {
80     if (g_strcmp0(desc, vo) == 0) {
81         return TRUE;
82     }
83     if (!g_str_has_prefix(desc, vo)) {
84         return FALSE;
85     }
86     /* we know that they are not equal but desc starts with vo, i.e. desc is longer than vo */
87     /* now to check that desc looks like vo: */
88     const size_t vol = strlen(vo);
89     if (desc[vol] == ':') {
90         return TRUE;
91     }
92     return FALSE;
93 }
94 
socket_realized(GtkWidget * widget,gpointer data)95 static void socket_realized(GtkWidget * widget, gpointer data)
96 {
97     GmtkMediaPlayer *player = GMTK_MEDIA_PLAYER(data);
98     GtkStyle *style;
99 
100     player->socket_id = GPOINTER_TO_INT(gtk_socket_get_id(GTK_SOCKET(widget)));
101     style = gtk_widget_get_style(widget);
102     if (player->vo != NULL) {
103         if (!vodesc_looks_like_vo(player->vo, "vdpau")) {
104             gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, &(style->black));
105             gtk_widget_modify_bg(widget, GTK_STATE_ACTIVE, &(style->black));
106             gtk_widget_modify_bg(widget, GTK_STATE_SELECTED, &(style->black));
107             gtk_widget_modify_bg(widget, GTK_STATE_PRELIGHT, &(style->black));
108             gtk_widget_modify_bg(widget, GTK_STATE_INSENSITIVE, &(style->black));
109         } else {
110             gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, NULL);
111             gtk_widget_modify_bg(widget, GTK_STATE_ACTIVE, NULL);
112             gtk_widget_modify_bg(widget, GTK_STATE_SELECTED, NULL);
113             gtk_widget_modify_bg(widget, GTK_STATE_PRELIGHT, NULL);
114             gtk_widget_modify_bg(widget, GTK_STATE_INSENSITIVE, NULL);
115         }
116     } else {
117         gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, &(style->black));
118         gtk_widget_modify_bg(widget, GTK_STATE_ACTIVE, &(style->black));
119         gtk_widget_modify_bg(widget, GTK_STATE_SELECTED, &(style->black));
120         gtk_widget_modify_bg(widget, GTK_STATE_PRELIGHT, &(style->black));
121         gtk_widget_modify_bg(widget, GTK_STATE_INSENSITIVE, &(style->black));
122     }
123 
124 }
125 
126 
127 // use g_idle_add to emit the signals outside of the thread, makes them be emitted in the main loop
128 // this is done so that thread_enter/thread_leave is not needed
signal_event(gpointer data)129 gboolean signal_event(gpointer data)
130 {
131     GmtkMediaPlayerEvent *event = (GmtkMediaPlayerEvent *) data;
132 
133     if (event && event->event_name != NULL
134         && (event->player->restart == FALSE || event->event_data_int == ATTRIBUTE_AF_EXPORT_FILENAME)) {
135 
136         switch (event->type) {
137         case EVENT_TYPE_INT:
138             g_signal_emit_by_name(event->player, event->event_name, event->event_data_int);
139             break;
140 
141         case EVENT_TYPE_DOUBLE:
142             g_signal_emit_by_name(event->player, event->event_name, event->event_data_double);
143             break;
144 
145         case EVENT_TYPE_BOOLEAN:
146             g_signal_emit_by_name(event->player, event->event_name, event->event_data_boolean);
147             break;
148 
149         case EVENT_TYPE_ALLOCATION:
150             if (gtk_widget_get_visible(GTK_WIDGET(event->player))) {
151                 if (!(event->event_allocation->width >= 65535 || event->event_allocation->height >= 65535))
152                     g_signal_emit_by_name(event->player, event->event_name, event->event_allocation);
153             }
154             g_free(event->event_allocation);
155             event->event_allocation = NULL;
156             break;
157 
158         case EVENT_TYPE_STRING:
159             g_signal_emit_by_name(event->player, event->event_name, event->event_data_string);
160             g_free(event->event_data_string);
161             event->event_data_string = NULL;
162             break;
163 
164         default:
165             gm_log(event->player->debug, G_LOG_LEVEL_MESSAGE, "undefined event %s", event->event_name);
166         }
167         g_free(event->event_name);
168         event->event_name = NULL;
169     }
170     if (event)
171         g_free(event);
172 
173     return FALSE;
174 }
175 
176 // build the events we are going to signal
create_event_int(GmtkMediaPlayer * player,const gchar * name,gint value)177 void create_event_int(GmtkMediaPlayer * player, const gchar * name, gint value)
178 {
179     GmtkMediaPlayerEvent *event;
180 
181     event = g_new0(GmtkMediaPlayerEvent, 1);
182     event->player = player;
183     event->type = EVENT_TYPE_INT;
184     event->event_name = g_strdup(name);
185     event->event_data_int = value;
186     g_idle_add(signal_event, event);
187 }
188 
create_event_double(GmtkMediaPlayer * player,const gchar * name,gdouble value)189 void create_event_double(GmtkMediaPlayer * player, const gchar * name, gdouble value)
190 {
191     GmtkMediaPlayerEvent *event;
192 
193     event = g_new0(GmtkMediaPlayerEvent, 1);
194     event->player = player;
195     event->type = EVENT_TYPE_DOUBLE;
196     event->event_name = g_strdup(name);
197     event->event_data_double = value;
198     g_idle_add(signal_event, event);
199 }
200 
create_event_boolean(GmtkMediaPlayer * player,const gchar * name,gboolean value)201 void create_event_boolean(GmtkMediaPlayer * player, const gchar * name, gboolean value)
202 {
203     GmtkMediaPlayerEvent *event;
204 
205     event = g_new0(GmtkMediaPlayerEvent, 1);
206     event->player = player;
207     event->type = EVENT_TYPE_BOOLEAN;
208     event->event_name = g_strdup(name);
209     event->event_data_boolean = value;
210     g_idle_add(signal_event, event);
211 }
212 
create_event_allocation(GmtkMediaPlayer * player,const gchar * name,GtkAllocation * allocation)213 void create_event_allocation(GmtkMediaPlayer * player, const gchar * name, GtkAllocation * allocation)
214 {
215     GmtkMediaPlayerEvent *event;
216 
217     event = g_new0(GmtkMediaPlayerEvent, 1);
218     event->player = player;
219     event->type = EVENT_TYPE_ALLOCATION;
220     event->event_name = g_strdup(name);
221     event->event_allocation = g_new0(GtkAllocation, 1);
222     memcpy(event->event_allocation, allocation, sizeof(GtkAllocation));
223     g_idle_add(signal_event, event);
224 
225 }
226 
create_event_string(GmtkMediaPlayer * player,const gchar * name,gchar * string)227 void create_event_string(GmtkMediaPlayer * player, const gchar * name, gchar * string)
228 {
229     GmtkMediaPlayerEvent *event;
230 
231     event = g_new0(GmtkMediaPlayerEvent, 1);
232     event->player = player;
233     event->type = EVENT_TYPE_STRING;
234     event->event_name = g_strdup(name);
235     event->event_data_string = g_strdup(string);
236     g_idle_add(signal_event, event);
237 
238 }
239 
240 // helper function to assist retry/fallback
gmtk_media_player_switch_protocol(const gchar * uri,gchar * new_protocol)241 gchar *gmtk_media_player_switch_protocol(const gchar * uri, gchar * new_protocol)
242 {
243     gchar *p;
244 
245     p = g_strrstr(uri, "://");
246 
247     if (p != NULL)
248         return g_strdup_printf("%s%s", new_protocol, p);
249     else
250         return NULL;
251 }
252 
gmtk_media_state_to_string(const GmtkMediaPlayerMediaState media_state)253 const gchar *gmtk_media_state_to_string(const GmtkMediaPlayerMediaState media_state)
254 {
255     switch (media_state) {
256     case MEDIA_STATE_UNKNOWN:
257         return "unknown";
258     case MEDIA_STATE_PLAY:
259         return "play";
260     case MEDIA_STATE_PAUSE:
261         return "pause";
262     case MEDIA_STATE_STOP:
263         return "stop";
264     case MEDIA_STATE_QUIT:
265         return "quit";
266     case MEDIA_STATE_BUFFERING:
267         return "buffering";
268     default:
269         return "???";
270     }
271 }
272 
gmtk_media_player_log_state(GmtkMediaPlayer * player,char const * const context)273 static void gmtk_media_player_log_state(GmtkMediaPlayer * player, char const *const context)
274 {
275 // Gmtk_Media_Player_Log_State
276 #define GMPLS_LEN 1024
277     gchar msg[GMPLS_LEN] = "";
278     gchar *tmp;
279 
280     if (context != NULL && (*context) != '\0') {
281         g_strlcat(msg, context, GMPLS_LEN);
282         g_strlcat(msg, ": ", GMPLS_LEN);
283     }
284     tmp = g_strdup_printf("position=%.3f length=%.3f start_time=%.3f run_time=%.3f volume=%.2f", player->position,
285                           player->length, player->start_time, player->run_time, player->volume);
286     g_strlcat(msg, tmp, GMPLS_LEN);
287     g_free(tmp);
288 
289     if (player->muted) {
290         g_strlcat(msg, " muted", GMPLS_LEN);
291     }
292 
293     g_strlcat(msg, " player=", GMPLS_LEN);
294     switch (player->player_state) {
295     case PLAYER_STATE_DEAD:
296         g_strlcat(msg, "dead", GMPLS_LEN);
297         break;
298     case PLAYER_STATE_RUNNING:
299         g_strlcat(msg, "running", GMPLS_LEN);
300         break;
301     default:
302         g_strlcat(msg, "???", GMPLS_LEN);
303     }
304 
305     g_strlcat(msg, " media=", GMPLS_LEN);
306     g_strlcat(msg, gmtk_media_state_to_string(player->media_state), GMPLS_LEN);
307     g_strlcat(msg, " uri=", GMPLS_LEN);
308     if (player->uri != NULL) {
309         g_strlcat(msg, player->uri, GMPLS_LEN);
310     }
311     gm_log(player->debug, G_LOG_LEVEL_INFO, "%s", msg);
312 }
313 
gmtk_media_player_class_init(GmtkMediaPlayerClass * class)314 static void gmtk_media_player_class_init(GmtkMediaPlayerClass * class)
315 {
316     GtkWidgetClass *widget_class;
317     GObjectClass *object_class;
318 
319     object_class = G_OBJECT_CLASS(class);
320     widget_class = GTK_WIDGET_CLASS(class);
321 
322     parent_class = g_type_class_peek_parent(class);
323     G_OBJECT_CLASS(class)->dispose = gmtk_media_player_dispose;
324 #ifdef GTK3_ENABLED
325     widget_class->draw = gmtk_media_player_draw_event;
326 #else
327     widget_class->expose_event = gmtk_media_player_expose_event;
328 #endif
329     widget_class->size_allocate = gmtk_media_player_size_allocate;
330 
331     g_signal_new("position-changed",
332                  G_OBJECT_CLASS_TYPE(object_class),
333                  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
334                  G_STRUCT_OFFSET(GmtkMediaPlayerClass, position_changed),
335                  NULL, NULL, g_cclosure_marshal_VOID__DOUBLE, G_TYPE_NONE, 1, G_TYPE_DOUBLE);
336 
337     g_signal_new("cache-percent-changed",
338                  G_OBJECT_CLASS_TYPE(object_class),
339                  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
340                  G_STRUCT_OFFSET(GmtkMediaPlayerClass, cache_percent_changed),
341                  NULL, NULL, g_cclosure_marshal_VOID__DOUBLE, G_TYPE_NONE, 1, G_TYPE_DOUBLE);
342 
343     g_signal_new("attribute-changed",
344                  G_OBJECT_CLASS_TYPE(object_class),
345                  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
346                  G_STRUCT_OFFSET(GmtkMediaPlayerClass, attribute_changed),
347                  NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
348 
349     g_signal_new("player-state-changed",
350                  G_OBJECT_CLASS_TYPE(object_class),
351                  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
352                  G_STRUCT_OFFSET(GmtkMediaPlayerClass, player_state_changed),
353                  NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
354 
355     g_signal_new("media-state-changed",
356                  G_OBJECT_CLASS_TYPE(object_class),
357                  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
358                  G_STRUCT_OFFSET(GmtkMediaPlayerClass, media_state_changed),
359                  NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
360 
361     g_signal_new("subtitles-changed",
362                  G_OBJECT_CLASS_TYPE(object_class),
363                  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
364                  G_STRUCT_OFFSET(GmtkMediaPlayerClass, subtitles_changed),
365                  NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
366 
367     g_signal_new("audio-tracks-changed",
368                  G_OBJECT_CLASS_TYPE(object_class),
369                  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
370                  G_STRUCT_OFFSET(GmtkMediaPlayerClass, audio_tracks_changed),
371                  NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
372 
373     g_signal_new("restart-shutdown-complete",
374                  G_OBJECT_CLASS_TYPE(object_class),
375                  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
376                  G_STRUCT_OFFSET(GmtkMediaPlayerClass, restart_shutdown_complete),
377                  NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
378 
379     g_signal_new("restart-complete",
380                  G_OBJECT_CLASS_TYPE(object_class),
381                  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
382                  G_STRUCT_OFFSET(GmtkMediaPlayerClass, restart_complete),
383                  NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
384 
385     g_signal_new("error-message",
386                  G_OBJECT_CLASS_TYPE(object_class),
387                  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
388                  G_STRUCT_OFFSET(GmtkMediaPlayerClass, error_message),
389                  NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
390 
391 }
392 
gmtk_media_player_init(GmtkMediaPlayer * player)393 static void gmtk_media_player_init(GmtkMediaPlayer * player)
394 {
395     GtkStyle *style;
396 
397     // player is an GtkEventBox that holds a GtkAlignment that holds a GtkSocket
398     // mplayer uses the xwindow id from the socket to display media
399 
400     gtk_widget_add_events(GTK_WIDGET(player),
401                           GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK |
402                           GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
403                           GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK | GDK_SCROLL_MASK);
404 #ifdef GTK3_ENABLED
405     gtk_widget_set_app_paintable(GTK_WIDGET(player), TRUE);
406 #endif
407 
408     g_signal_connect(player, "key_press_event", G_CALLBACK(player_key_press_event_callback), NULL);
409     g_signal_connect(player, "motion_notify_event", G_CALLBACK(player_motion_notify_event_callback), NULL);
410     g_signal_connect(player, "button_press_event", G_CALLBACK(player_button_press_event_callback), NULL);
411     gtk_widget_push_composite_child();
412 
413     player->alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
414     player->socket = gtk_socket_new();
415     g_signal_connect(G_OBJECT(player), "realize", G_CALLBACK(player_realized), NULL);
416     g_signal_connect(G_OBJECT(player->alignment), "realize", G_CALLBACK(alignment_realized), NULL);
417     g_signal_connect(G_OBJECT(player->socket), "realize", G_CALLBACK(socket_realized), player);
418     gtk_container_add(GTK_CONTAINER(player), player->alignment);
419     gtk_container_add(GTK_CONTAINER(player->alignment), player->socket);
420 #ifdef GTK2_18_ENABLED
421     gtk_widget_set_has_window(GTK_WIDGET(player->socket), TRUE);
422     gtk_widget_set_can_focus(GTK_WIDGET(player->socket), TRUE);
423     gtk_widget_set_can_default(GTK_WIDGET(player->socket), TRUE);
424 #else
425     GTK_WIDGET_SET_FLAGS(GTK_WIDGET(player->socket), GTK_CAN_FOCUS);
426     GTK_WIDGET_SET_FLAGS(GTK_WIDGET(player->socket), GTK_CAN_DEFAULT);
427 #endif
428     gtk_widget_activate(GTK_WIDGET(player->socket));
429 
430     g_signal_connect(player->socket, "key_press_event", G_CALLBACK(player_key_press_event_callback), player);
431 
432     g_signal_connect(player, "restart-shutdown-complete",
433                      G_CALLBACK(gmtk_media_player_restart_shutdown_complete_callback), NULL);
434     g_signal_connect(player, "restart-complete", G_CALLBACK(gmtk_media_player_restart_complete_callback), NULL);
435     gtk_widget_pop_composite_child();
436 
437     gtk_widget_show_all(GTK_WIDGET(player));
438     style = gtk_widget_get_style(GTK_WIDGET(player));
439     player->default_background = gdk_color_copy(&(style->bg[GTK_STATE_NORMAL]));
440     player->player_state = PLAYER_STATE_DEAD;
441     player->media_state = MEDIA_STATE_UNKNOWN;
442     player->uri = NULL;
443     player->message = NULL;
444     player->mplayer_thread = NULL;
445     player->aspect_ratio = ASPECT_DEFAULT;
446     player->mplayer_complete_cond = g_cond_new();
447     player->thread_running = g_mutex_new();
448     player->video_width = 0;
449     player->video_height = 0;
450     player->video_present = FALSE;
451     player->media_device = NULL;
452     player->type = TYPE_FILE;
453     player->title_is_menu = FALSE;
454     player->start_time = 0.0;
455     player->run_time = 0.0;
456     player->vo = NULL;
457     player->ao = NULL;
458     player->cache_size = 0;
459     player->subtitles = NULL;
460     player->audio_tracks = NULL;
461     player->af_export_filename = gm_tempname(NULL, "mplayer-af_exportXXXXXX");
462     player->brightness = 0;
463     player->contrast = 0;
464     player->gamma = 0;
465     player->hue = 0;
466     player->osdlevel = 0;
467     player->saturation = 0;
468     player->restart = FALSE;
469     player->video_format = NULL;
470     player->video_codec = NULL;
471     player->audio_format = NULL;
472     player->audio_codec = NULL;
473     player->disable_upscaling = FALSE;
474     player->mplayer_binary = NULL;
475     player->extra_opts = NULL;
476     player->use_mplayer2 = FALSE;
477     player->features_detected = FALSE;
478     player->zoom = 1.0;
479     player->speed_multiplier = 1.0;
480     player->subtitle_scale = 1.0;
481     player->subtitle_delay = 0.0;
482     player->subtitle_position = 0;
483     player->subtitle_fuzziness = 0;
484     player->audio_delay = 0.0;
485     player->restart = FALSE;
486     player->debug = 1;
487     player->channel_in = NULL;
488     player->channel_out = NULL;
489     player->channel_err = NULL;
490     player->retry_on_full_cache = FALSE;
491     player->profile = NULL;
492     player->alang = NULL;
493     player->slang = NULL;
494     player->artist = NULL;
495     player->title = NULL;
496     player->album = NULL;
497     player->disposed = FALSE;
498     player->player_lock = g_mutex_new();
499     player->name_regex = g_regex_new(".*name\\s*:\\s*(.*)\n", G_REGEX_CASELESS, 0, NULL);
500     player->genre_regex = g_regex_new(".*genre\\s*:\\s*(.*)\n", G_REGEX_CASELESS, 0, NULL);
501     player->title_regex = g_regex_new(".*title\\s*:\\s*(.*)\n", G_REGEX_CASELESS, 0, NULL);
502     player->artist_regex = g_regex_new(".*artist\\s*:\\s*(.*)\n", G_REGEX_CASELESS, 0, NULL);
503     player->album_regex = g_regex_new(".*album\\s*:\\s*(.*)\n", G_REGEX_CASELESS, 0, NULL);
504     player->deintN_regex = g_regex_new("(.*)(:deint=[0-9]+)\\b(.*)", G_REGEX_CASELESS, 0, NULL);
505 
506     gmtk_media_player_log_state(player, "after init");
507 }
508 
gmtk_media_player_dispose(GObject * object)509 static void gmtk_media_player_dispose(GObject * object)
510 {
511 
512     GmtkMediaPlayer *player;
513 
514     if (object == NULL) {
515         return;
516     }
517 
518     player = GMTK_MEDIA_PLAYER(object);
519 
520     if (player->disposed) {
521         return;
522     }
523     player->disposed = TRUE;
524 
525     gm_log(player->debug, G_LOG_LEVEL_DEBUG, "gmtk_media_player_dispose");
526 
527     // cleanup the memory used
528 
529     if (player->uri != NULL) {
530         g_free(player->uri);
531         player->uri = NULL;
532     }
533     if (player->media_device != NULL) {
534         g_free(player->media_device);
535         player->media_device = NULL;
536     }
537     if (player->vo != NULL) {
538         g_free(player->vo);
539         player->vo = NULL;
540     }
541     if (player->ao != NULL) {
542         g_free(player->ao);
543         player->ao = NULL;
544     }
545 
546     if (player->artist != NULL) {
547         g_free(player->artist);
548         player->artist = NULL;
549     }
550 
551     if (player->title != NULL) {
552         g_free(player->title);
553         player->title = NULL;
554     }
555 
556     if (player->message != NULL) {
557         g_free(player->message);
558         player->message = NULL;
559     }
560 
561     if (player->extra_opts != NULL) {
562         g_free(player->extra_opts);
563         player->extra_opts = NULL;
564     }
565 
566     if (player->video_format != NULL) {
567         g_free(player->video_format);
568         player->video_format = NULL;
569     }
570 
571     if (player->video_codec != NULL) {
572         g_free(player->video_codec);
573         player->video_codec = NULL;
574     }
575 
576     if (player->audio_format != NULL) {
577         g_free(player->audio_format);
578         player->audio_format = NULL;
579     }
580 
581     if (player->audio_codec != NULL) {
582         g_free(player->audio_codec);
583         player->audio_codec = NULL;
584     }
585 
586     if (player->af_export_filename != NULL) {
587         g_free(player->af_export_filename);
588         player->af_export_filename = NULL;
589     }
590 
591     if (player->subtitle_font != NULL) {
592         g_free(player->subtitle_font);
593         player->subtitle_font = NULL;
594     }
595 
596     if (player->subtitle_color != NULL) {
597         g_free(player->subtitle_color);
598         player->subtitle_color = NULL;
599     }
600 
601     if (player->profile != NULL) {
602         g_free(player->profile);
603         player->profile = NULL;
604     }
605 
606     if (player->slang != NULL) {
607         g_free(player->slang);
608         player->slang = NULL;
609     }
610 
611     if (player->alang != NULL) {
612         g_free(player->alang);
613         player->alang = NULL;
614     }
615 
616     gdk_color_free(player->default_background);
617 
618     G_OBJECT_CLASS(parent_class)->dispose(object);
619 }
620 
gmtk_media_player_draw_event(GtkWidget * widget,cairo_t * cr)621 static gboolean gmtk_media_player_draw_event(GtkWidget * widget, cairo_t * cr)
622 {
623     GtkStyle *style;
624     GtkAllocation allocation;
625 
626     style = gtk_widget_get_style(widget);
627     gmtk_get_allocation(widget, &allocation);
628 
629     cairo_set_source_rgb(cr, style->black.red / 65535.0, style->black.green / 65535.0, style->black.blue / 65535.0);
630     cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
631     cairo_fill(cr);
632     cairo_stroke(cr);
633 
634     return FALSE;
635 }
636 
gmtk_media_player_expose_event(GtkWidget * widget,GdkEventExpose * event)637 static gboolean gmtk_media_player_expose_event(GtkWidget * widget, GdkEventExpose * event)
638 {
639     return FALSE;
640 }
641 
gmtk_media_player_send_key_press_event(GmtkMediaPlayer * widget,GdkEventKey * event,gpointer data)642 gboolean gmtk_media_player_send_key_press_event(GmtkMediaPlayer * widget, GdkEventKey * event, gpointer data)
643 {
644     return player_key_press_event_callback(GTK_WIDGET(widget), event, data);
645 }
646 
647 /*
648   sub_select [value]
649     Display subtitle with index [value]. Turn subtitle display off if
650     [value] is -1 or greater than the highest available subtitle index.
651     Cycle through the available subtitles if [value] is omitted or less
652     than -1 (forward or backward respectively).
653     Supported subtitle sources are -sub options on the command
654     line, VOBsubs, DVD subtitles, and Ogg and Matroska text streams.
655     This command is mainly for cycling all subtitles, if you want to set
656     a specific subtitle, use sub_file, sub_vob, or sub_demux.
657 
658     GmtkMediaPlayerSubtitle
659 
660     count: (gdouble) g_list_length(player->subtitles)
661 
662     iter = player->subtitles;
663     while (iter) {
664         subtitle = (GmtkMediaPlayerSubtitle *) iter->data;
665         if (subtitle->id == player->subtitle_id && subtitle->is_file == player->subtitle_is_file)
666             value = subtitle->label;
667         iter = iter->next;
668     }
669 
670     sub_visibility [0|1]
671 
672     properties: sub
673        get_property <property>
674        set_property <property> <value>
675 
676 */
gmtk_media_player_cycle_subtitles(GmtkMediaPlayer * player)677 static void gmtk_media_player_cycle_subtitles(GmtkMediaPlayer * player)
678 {
679     write_to_mplayer(player, "sub_select\n");
680 }
681 
player_key_press_event_callback(GtkWidget * widget,GdkEventKey * event,gpointer data)682 static gboolean player_key_press_event_callback(GtkWidget * widget, GdkEventKey * event, gpointer data)
683 {
684     GmtkMediaPlayer *player;
685     GtkAllocation alloc;
686     gchar *cmd;
687 
688     if (data != NULL) {
689         player = GMTK_MEDIA_PLAYER(data);
690     } else {
691         player = GMTK_MEDIA_PLAYER(widget);
692     }
693 
694     if (event->is_modifier)
695         return TRUE;
696 
697     if ((event->state & GDK_CONTROL_MASK) == 0 && (event->state & GDK_MOD1_MASK) == 0) {
698         switch (event->keyval) {
699         case GDK_Right:
700             if (player->title_is_menu) {
701                 write_to_mplayer(player, "dvdnav 4\n");
702             }
703             break;
704         case GDK_Left:
705             if (player->title_is_menu) {
706                 write_to_mplayer(player, "dvdnav 3\n");
707             }
708             break;
709         case GDK_Up:
710             if (player->title_is_menu) {
711                 write_to_mplayer(player, "dvdnav 1\n");
712             }
713             break;
714         case GDK_Down:
715             if (player->title_is_menu) {
716                 write_to_mplayer(player, "dvdnav 2\n");
717             }
718             break;
719         case GDK_Return:
720             if (player->title_is_menu) {
721                 write_to_mplayer(player, "dvdnav 6\n");
722             }
723             return TRUE;
724             break;
725         case GDK_Home:
726             if (!player->title_is_menu) {
727                 write_to_mplayer(player, "dvdnav menu\n");
728             }
729             return TRUE;
730             break;
731         case GDK_space:
732         case GDK_p:
733             switch (player->media_state) {
734             case MEDIA_STATE_PAUSE:
735                 gmtk_media_player_set_state(player, MEDIA_STATE_PLAY);
736                 break;
737             case MEDIA_STATE_PLAY:
738                 gmtk_media_player_set_state(player, MEDIA_STATE_PAUSE);
739                 break;
740             default:
741                 break;
742             }
743             break;
744         case GDK_1:
745             gmtk_media_player_set_attribute_integer_delta(player, ATTRIBUTE_CONTRAST, -5);
746             break;
747         case GDK_2:
748             gmtk_media_player_set_attribute_integer_delta(player, ATTRIBUTE_CONTRAST, 5);
749             break;
750         case GDK_3:
751             gmtk_media_player_set_attribute_integer_delta(player, ATTRIBUTE_BRIGHTNESS, -5);
752             break;
753         case GDK_4:
754             gmtk_media_player_set_attribute_integer_delta(player, ATTRIBUTE_BRIGHTNESS, 5);
755             break;
756         case GDK_5:
757             gmtk_media_player_set_attribute_integer_delta(player, ATTRIBUTE_HUE, -5);
758             break;
759         case GDK_6:
760             gmtk_media_player_set_attribute_integer_delta(player, ATTRIBUTE_HUE, 5);
761             break;
762         case GDK_7:
763             gmtk_media_player_set_attribute_integer_delta(player, ATTRIBUTE_SATURATION, -5);
764             break;
765         case GDK_8:
766             gmtk_media_player_set_attribute_integer_delta(player, ATTRIBUTE_SATURATION, 5);
767             break;
768         case GDK_plus:
769             write_to_mplayer(player, "audio_delay 0.1 0\n");
770             break;
771         case GDK_minus:
772             write_to_mplayer(player, "audio_delay -0.1 0\n");
773             break;
774         case GDK_numbersign:
775             write_to_mplayer(player, "switch_audio -1\n");
776             return TRUE;
777             break;
778         case GDK_period:
779             if (player->media_state == MEDIA_STATE_PAUSE)
780                 write_to_mplayer(player, "frame_step\n");
781             break;
782         case GDK_KP_Add:
783             player->zoom += 0.10;
784             player->zoom = CLAMP(player->zoom, 0.1, 10.0);
785             gmtk_get_allocation(GTK_WIDGET(player), &alloc);
786             gmtk_media_player_size_allocate(GTK_WIDGET(player), &alloc);
787             break;
788         case GDK_KP_Subtract:
789             player->zoom -= 0.10;
790             player->zoom = CLAMP(player->zoom, 0.1, 10.0);
791             gmtk_get_allocation(GTK_WIDGET(player), &alloc);
792             gmtk_media_player_size_allocate(GTK_WIDGET(player), &alloc);
793             break;
794         case GDK_KP_Enter:
795             player->zoom = 1.0;
796             gmtk_get_allocation(GTK_WIDGET(player), &alloc);
797             gmtk_media_player_size_allocate(GTK_WIDGET(player), &alloc);
798             break;
799         case GDK_j:
800             gmtk_media_player_cycle_subtitles(player);
801             break;
802         case GDK_d:
803             write_to_mplayer(player, "frame_drop\n");
804             cmd =
805                 g_strdup_printf("osd_show_property_text \"%s: ${framedropping}\" 1000 1\n",
806                                 g_dgettext(GETTEXT_PACKAGE, "Frame Dropping"));
807             write_to_mplayer(player, cmd);
808             g_free(cmd);
809             break;
810         case GDK_b:
811             write_to_mplayer(player, "sub_pos -1 0\n");
812             break;
813         case GDK_B:
814             write_to_mplayer(player, "sub_pos 1 0\n");
815             break;
816         case GDK_D:
817             write_to_mplayer(player, "step_property deinterlace\n");
818             cmd =
819                 g_strdup_printf("osd_show_property_text \"%s: ${deinterlace}\" 1000 1\n",
820                                 g_dgettext(GETTEXT_PACKAGE, "Deinterlace"));
821             write_to_mplayer(player, cmd);
822             g_free(cmd);
823             break;
824         case GDK_s:
825         case GDK_S:
826             write_to_mplayer(player, "screenshot 0\n");
827             break;
828         case GDK_x:
829             write_to_mplayer(player, "sub_delay 0.1\n");
830             break;
831         case GDK_z:
832             write_to_mplayer(player, "sub_delay -0.1\n");
833             break;
834         case GDK_o:
835             write_to_mplayer(player, "osd\n");
836             break;
837 		case GDK_h:
838 			write_to_mplayer(player, "tv_step_channel -1\n");
839 			break;
840 		case GDK_k:
841 			write_to_mplayer(player, "tv_step_channel 1\n");
842 			break;
843         default:
844             gm_log(player->debug, G_LOG_LEVEL_INFO, "ignoring key %s%s%s%s",
845                    (event->state & GDK_CONTROL_MASK) ? "Control-" : "", (event->state & GDK_MOD1_MASK) ? "Alt-" : "",
846                    (event->state & GDK_SHIFT_MASK) ? "Shift-" : "", gdk_keyval_name(event->keyval));
847         }
848 
849     }
850     return FALSE;
851 }
852 
player_button_press_event_callback(GtkWidget * widget,GdkEventButton * event,gpointer data)853 static gboolean player_button_press_event_callback(GtkWidget * widget, GdkEventButton * event, gpointer data)
854 {
855     GmtkMediaPlayer *player = GMTK_MEDIA_PLAYER(widget);
856     gchar *cmd;
857 
858     if (event->button == 1) {
859         if (player->title_is_menu) {
860             cmd = g_strdup_printf("dvdnav mouse\n");
861             write_to_mplayer(player, cmd);
862             g_free(cmd);
863         }
864     }
865 
866 
867     return FALSE;
868 }
869 
player_motion_notify_event_callback(GtkWidget * widget,GdkEventMotion * event,gpointer data)870 static gboolean player_motion_notify_event_callback(GtkWidget * widget, GdkEventMotion * event, gpointer data)
871 {
872     GmtkMediaPlayer *player = GMTK_MEDIA_PLAYER(widget);
873     gchar *cmd;
874     gint x, y;
875 #if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION >= 4
876     GdkDeviceManager *device_manager;
877     GdkDevice *pointer;
878 #endif
879 
880     if (player->title_is_menu) {
881 #if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION >= 4
882         device_manager = gdk_display_get_device_manager(gtk_widget_get_display(widget));
883         pointer = gdk_device_manager_get_client_pointer(device_manager);
884         gdk_window_get_device_position(gtk_widget_get_window(widget), pointer, &x, &y, NULL);
885 #else
886         gtk_widget_get_pointer(player->socket, &x, &y);
887 #endif
888         cmd = g_strdup_printf("set_mouse_pos %i %i\n", x, y);
889         write_to_mplayer(player, cmd);
890         g_free(cmd);
891     }
892 
893     return FALSE;
894 
895 }
896 
gmtk_media_player_size_allocate(GtkWidget * widget,GtkAllocation * allocation)897 static void gmtk_media_player_size_allocate(GtkWidget * widget, GtkAllocation * allocation)
898 {
899     GmtkMediaPlayer *player = GMTK_MEDIA_PLAYER(widget);
900     gdouble video_aspect;
901     gdouble widget_aspect;
902     gfloat xscale, yscale;
903 
904     if (allocation->width <= 0 || allocation->height <= 0) {
905         gmtk_get_allocation(widget, allocation);
906         gm_log(player->debug, G_LOG_LEVEL_DEBUG, "widget allocation %i x %i", allocation->width, allocation->height);
907     }
908     // protect against possible divide by zero
909     if (allocation->width == 0 || allocation->height == 0) {
910         return;
911     }
912 
913     if (player->video_width == 0 || player->video_height == 0 || !gmtk_widget_get_realized(widget)) {
914         gtk_alignment_set(GTK_ALIGNMENT(player->alignment), 0.0, 0.0, 1.0, 1.0);
915     } else {
916         switch (player->aspect_ratio) {
917         case ASPECT_4X3:
918             video_aspect = 4.0 / 3.0;
919             break;
920         case ASPECT_16X9:
921             video_aspect = 16.0 / 9.0;
922             break;
923         case ASPECT_16X10:
924             video_aspect = 16.0 / 10.0;
925             break;
926         case ASPECT_WINDOW:
927             video_aspect = (gdouble) allocation->width / (gdouble) allocation->height;
928             break;
929         case ASPECT_ANAMORPHIC:
930             video_aspect = 2.39;
931             break;
932         case ASPECT_DEFAULT:
933         default:
934             video_aspect = (gdouble) player->video_width / (gdouble) player->video_height;
935             break;
936         }
937 
938         widget_aspect = (gdouble) allocation->width / (gdouble) allocation->height;
939 
940         if (player->disable_upscaling && allocation->width > player->video_width
941             && allocation->height > player->video_height) {
942 
943             gtk_alignment_set(GTK_ALIGNMENT(player->alignment), 0.5, 0.5,
944                               CLAMP((gdouble) player->video_width / (gdouble) allocation->width, 0.1, 1.0),
945                               CLAMP((gdouble) player->video_height / (gdouble) allocation->height, 0.1, 1.0));
946 
947         } else {
948             if (video_aspect > widget_aspect) {
949                 yscale = ((gdouble) allocation->width / video_aspect) / (gdouble) allocation->height;
950 
951                 gm_log(player->debug, G_LOG_LEVEL_DEBUG, "yscale = %lf", yscale);
952                 if (yscale > 0.0) {
953                     gtk_alignment_set(GTK_ALIGNMENT(player->alignment), 0.0, 0.5, 1.0, CLAMP(yscale, 0.1, 1.0));
954                 } else {
955                     gtk_alignment_set(GTK_ALIGNMENT(player->alignment), 0.0, 0.5, 1.0, 1.0);
956                 }
957             } else {
958                 xscale = ((gdouble) allocation->height * video_aspect) / (gdouble) allocation->width;
959 
960                 gm_log(player->debug, G_LOG_LEVEL_DEBUG, "xscale = %lf", xscale);
961                 if (xscale > 0.0) {
962                     gtk_alignment_set(GTK_ALIGNMENT(player->alignment), 0.5, 0.0, CLAMP(xscale, 0.1, 1.0), 1.0);
963                 } else {
964                     gtk_alignment_set(GTK_ALIGNMENT(player->alignment), 0.5, 0.0, 1.0, 1.0);
965                 }
966             }
967         }
968     }
969 
970 
971     gm_log(player->debug, G_LOG_LEVEL_DEBUG, "gmtk allocation video:%s %ix%i", gm_bool_to_string(player->video_present),
972            allocation->width, allocation->height);
973     GTK_WIDGET_CLASS(parent_class)->size_allocate(widget, allocation);
974 
975 }
976 
gmtk_media_player_new()977 GtkWidget *gmtk_media_player_new()
978 {
979     GtkWidget *player = g_object_new(GMTK_TYPE_MEDIA_PLAYER, NULL);
980 
981     return player;
982 }
983 
gmtk_media_player_restart_complete_callback(GmtkMediaPlayer * player,gpointer data)984 static void gmtk_media_player_restart_complete_callback(GmtkMediaPlayer * player, gpointer data)
985 {
986     gmtk_media_player_seek(player, player->restart_position, SEEK_ABSOLUTE);
987     player->restart = FALSE;
988     gm_log(player->debug, G_LOG_LEVEL_DEBUG, "restart state = %s, current state = %s",
989            gmtk_media_state_to_string(player->restart_state),
990            gmtk_media_state_to_string(gmtk_media_player_get_media_state(player)));
991     if (player->restart_state != gmtk_media_player_get_media_state(player))
992         gmtk_media_player_set_state(GMTK_MEDIA_PLAYER(player), player->restart_state);
993     gm_log(player->debug, G_LOG_LEVEL_INFO, "restart complete");
994 }
995 
gmtk_media_player_restart_shutdown_complete_callback(GmtkMediaPlayer * player,gpointer data)996 static void gmtk_media_player_restart_shutdown_complete_callback(GmtkMediaPlayer * player, gpointer data)
997 {
998     if (player->restart) {
999         if (player->restart_state != MEDIA_STATE_STOP) {
1000             gmtk_media_player_set_state(GMTK_MEDIA_PLAYER(player), MEDIA_STATE_PLAY);
1001         } else {
1002             player->restart = FALSE;
1003         }
1004     }
1005 }
1006 
gmtk_media_player_restart(GmtkMediaPlayer * player)1007 void gmtk_media_player_restart(GmtkMediaPlayer * player)
1008 {
1009     if (player->player_state == PLAYER_STATE_RUNNING) {
1010         player->restart = TRUE;
1011         player->restart_state = gmtk_media_player_get_media_state(player);
1012         gmtk_media_player_set_state(player, MEDIA_STATE_PAUSE);
1013         player->restart_position = player->position;
1014         gmtk_media_player_set_state(GMTK_MEDIA_PLAYER(player), MEDIA_STATE_QUIT);
1015     }
1016 }
1017 
1018 // this will take a new URI, but better to shut it down and start a new instance
gmtk_media_player_set_uri(GmtkMediaPlayer * player,const gchar * uri)1019 void gmtk_media_player_set_uri(GmtkMediaPlayer * player, const gchar * uri)
1020 {
1021     gchar *cmd;
1022     gchar *filename = NULL;
1023 
1024     player->uri = g_strdup(uri);
1025     player->video_width = 0;
1026     player->video_height = 0;
1027     player->length = 0;
1028 
1029     if (player->player_state == PLAYER_STATE_RUNNING) {
1030         if (player->uri != NULL) {
1031             filename = g_filename_from_uri(player->uri, NULL, NULL);
1032         }
1033         cmd = g_strdup_printf("loadfile \"%s\" 0\n", filename);
1034         write_to_mplayer(player, cmd);
1035         g_free(cmd);
1036         if (filename != NULL) {
1037             g_free(filename);
1038             filename = NULL;
1039         }
1040         if (player->media_state == MEDIA_STATE_STOP) {
1041             gmtk_media_player_set_state(player, MEDIA_STATE_PLAY);
1042         }
1043     }
1044 
1045 }
1046 
gmtk_media_player_get_uri(GmtkMediaPlayer * player)1047 const gchar *gmtk_media_player_get_uri(GmtkMediaPlayer * player)
1048 {
1049     return player->uri;
1050 }
1051 
gmtk_media_player_set_state(GmtkMediaPlayer * player,const GmtkMediaPlayerMediaState new_media_state)1052 void gmtk_media_player_set_state(GmtkMediaPlayer * player, const GmtkMediaPlayerMediaState new_media_state)
1053 {
1054     gmtk_media_player_log_state(player, "old");
1055     gm_log(player->debug, G_LOG_LEVEL_DEBUG, "setting media state to %s", gmtk_media_state_to_string(new_media_state));
1056 
1057     if (player->player_state == PLAYER_STATE_DEAD) {
1058 
1059         if (new_media_state == MEDIA_STATE_QUIT) {
1060             player->media_state = MEDIA_STATE_UNKNOWN;
1061         }
1062 
1063         if (new_media_state == MEDIA_STATE_STOP) {
1064             player->media_state = MEDIA_STATE_UNKNOWN;
1065         }
1066 
1067         if (new_media_state == MEDIA_STATE_PAUSE) {
1068             player->media_state = MEDIA_STATE_UNKNOWN;
1069         }
1070 
1071         if (new_media_state == MEDIA_STATE_PLAY) {
1072             // launch player
1073             gm_log(player->debug, G_LOG_LEVEL_DEBUG, "launching launch_mplayer thread");
1074             player->mplayer_thread = g_thread_create(launch_mplayer, player, TRUE, NULL);
1075             if (player->mplayer_thread != NULL) {
1076                 if (player->message != NULL) {
1077                     g_free(player->message);
1078                     player->message = NULL;
1079                 }
1080                 player->message = g_strdup_printf(g_dgettext(GETTEXT_PACKAGE, "Loading..."));
1081                 if (!player->restart)
1082                     g_signal_emit_by_name(player, "attribute-changed", ATTRIBUTE_MESSAGE);
1083                 player->player_state = PLAYER_STATE_RUNNING;
1084                 if (!player->restart)
1085                     g_signal_emit_by_name(player, "player-state-changed", player->player_state);
1086                 gmtk_media_player_log_state(player, "new");
1087                 return;
1088             }
1089         }
1090 
1091     }
1092 
1093     if (player->player_state == PLAYER_STATE_RUNNING) {
1094         if (new_media_state == MEDIA_STATE_STOP) {
1095             if (player->type == TYPE_NETWORK) {
1096                 write_to_mplayer(player, "quit\n");
1097             } else {
1098                 write_to_mplayer(player, "seek 0 2\n");
1099                 if (player->media_state == MEDIA_STATE_PLAY) {
1100                     write_to_mplayer(player, "pause\n");
1101                 }
1102                 player->media_state = MEDIA_STATE_STOP;
1103                 g_signal_emit_by_name(player, "position-changed", 0.0);
1104                 if (!player->restart)
1105                     g_signal_emit_by_name(player, "media-state-changed", player->media_state);
1106             }
1107         }
1108 
1109         if (new_media_state == MEDIA_STATE_PLAY) {
1110             gtk_widget_show(GTK_WIDGET(player->socket));
1111 
1112             if (player->media_state == MEDIA_STATE_PAUSE || player->media_state == MEDIA_STATE_STOP) {
1113                 write_to_mplayer(player, "pause\n");
1114                 player->media_state = MEDIA_STATE_PLAY;
1115                 if (!player->restart)
1116                     g_signal_emit_by_name(player, "media-state-changed", player->media_state);
1117             }
1118             if (player->media_state == MEDIA_STATE_UNKNOWN) {
1119                 player->media_state = MEDIA_STATE_PLAY;
1120                 if (!player->restart)
1121                     g_signal_emit_by_name(player, "media-state-changed", player->media_state);
1122             }
1123         }
1124 
1125         if (new_media_state == MEDIA_STATE_PAUSE) {
1126             if (player->media_state == MEDIA_STATE_PLAY) {
1127                 write_to_mplayer(player, "pause\n");
1128                 player->media_state = MEDIA_STATE_PAUSE;
1129                 if (!player->restart)
1130                     g_signal_emit_by_name(player, "media-state-changed", player->media_state);
1131             }
1132         }
1133 
1134         if (new_media_state == MEDIA_STATE_QUIT) {
1135             write_to_mplayer(player, "quit\n");
1136         }
1137     }
1138 
1139     gmtk_media_player_log_state(player, "new");
1140 }
1141 
gmtk_media_player_get_media_state(GmtkMediaPlayer * player)1142 GmtkMediaPlayerMediaState gmtk_media_player_get_media_state(GmtkMediaPlayer * player)
1143 {
1144     return player->media_state;
1145 }
1146 
gmtk_media_player_send_command(GmtkMediaPlayer * player,GmtkMediaPlayerCommand command)1147 void gmtk_media_player_send_command(GmtkMediaPlayer * player, GmtkMediaPlayerCommand command)
1148 {
1149     gchar *cmd = NULL;
1150 
1151     if (player->player_state == PLAYER_STATE_RUNNING) {
1152         switch (command) {
1153         case COMMAND_SHOW_DVD_MENU:
1154             write_to_mplayer(player, "dvdnav 5\n");
1155             break;
1156 
1157         case COMMAND_TAKE_SCREENSHOT:
1158             write_to_mplayer(player, "screenshot 0\n");
1159             break;
1160 
1161         case COMMAND_SWITCH_ANGLE:
1162             write_to_mplayer(player, "switch_angle\n");
1163             break;
1164 
1165         case COMMAND_SWITCH_AUDIO:
1166             write_to_mplayer(player, "switch_audio\n");
1167             break;
1168 
1169         case COMMAND_FRAME_STEP:
1170             if (player->media_state == MEDIA_STATE_PAUSE)
1171                 write_to_mplayer(player, "frame_step\n");
1172             break;
1173 
1174         case COMMAND_SUBTITLE_SELECT:
1175             gmtk_media_player_cycle_subtitles(player);
1176             break;
1177 
1178         case COMMAND_SUBTITLE_STEP_FORWARD:
1179             write_to_mplayer(player, "sub_step 1\n");
1180             break;
1181 
1182         case COMMAND_SUBTITLE_STEP_BACKWARD:
1183             write_to_mplayer(player, "sub_step -1\n");
1184             break;
1185 
1186         case COMMAND_SWITCH_FRAME_DROP:
1187             write_to_mplayer(player, "frame_drop\n");
1188             cmd =
1189                 g_strdup_printf("osd_show_property_text \"%s ${framedropping}\" 1000 1\n",
1190                                 g_dgettext(GETTEXT_PACKAGE, "Frame Dropping"));
1191             write_to_mplayer(player, cmd);
1192             g_free(cmd);
1193             cmd = NULL;
1194             break;
1195 
1196         default:
1197             gm_log(player->debug, G_LOG_LEVEL_INFO, "Unknown command");
1198         }
1199     }
1200 }
1201 
gmtk_media_player_set_attribute_boolean(GmtkMediaPlayer * player,GmtkMediaPlayerMediaAttributes attribute,gboolean value)1202 void gmtk_media_player_set_attribute_boolean(GmtkMediaPlayer * player,
1203                                              GmtkMediaPlayerMediaAttributes attribute, gboolean value)
1204 {
1205     gchar *cmd = NULL;
1206 
1207     switch (attribute) {
1208     case ATTRIBUTE_SUB_VISIBLE:
1209         player->sub_visible = value;
1210         if (player->player_state == PLAYER_STATE_RUNNING) {
1211             cmd = g_strdup_printf("set_property sub_visibility %i\n", value);
1212             write_to_mplayer(player, cmd);
1213             g_free(cmd);
1214             cmd = NULL;
1215             if (value) {
1216                 cmd =
1217                     g_strdup_printf("osd_show_property_text \"%s\" 1000 1\n",
1218                                     g_dgettext(GETTEXT_PACKAGE, "Subtitles Visible"));
1219             } else {
1220                 cmd =
1221                     g_strdup_printf("osd_show_property_text \"%s\" 1000 1\n",
1222                                     g_dgettext(GETTEXT_PACKAGE, "Subtitles Hidden"));
1223             }
1224             write_to_mplayer(player, cmd);
1225             g_free(cmd);
1226             cmd = NULL;
1227         }
1228         break;
1229 
1230     case ATTRIBUTE_ENABLE_FRAME_DROP:
1231         player->frame_drop = value;
1232         if (player->player_state == PLAYER_STATE_RUNNING) {
1233             cmd = g_strdup_printf("frame_drop %i\n", value);
1234             write_to_mplayer(player, cmd);
1235             g_free(cmd);
1236             cmd = NULL;
1237         }
1238         break;
1239 
1240     case ATTRIBUTE_PLAYLIST:
1241         player->playlist = value;
1242         break;
1243 
1244     case ATTRIBUTE_DISABLE_UPSCALING:
1245         player->disable_upscaling = value;
1246         break;
1247 
1248     case ATTRIBUTE_SOFTVOL:
1249         player->softvol = value;
1250         break;
1251 
1252     case ATTRIBUTE_MUTED:
1253         player->muted = value;
1254         if (player->player_state == PLAYER_STATE_RUNNING) {
1255             cmd = g_strdup_printf("mute %i\n", value);
1256             write_to_mplayer(player, cmd);
1257             g_free(cmd);
1258             cmd = NULL;
1259         }
1260         break;
1261 
1262     case ATTRIBUTE_ENABLE_ADVANCED_SUBTITLES:
1263         player->enable_advanced_subtitles = value;
1264         break;
1265 
1266     case ATTRIBUTE_ENABLE_EMBEDDED_FONTS:
1267         player->enable_embedded_fonts = value;
1268         break;
1269 
1270     case ATTRIBUTE_SUBTITLE_OUTLINE:
1271         player->subtitle_outline = value;
1272         break;
1273 
1274     case ATTRIBUTE_SUBTITLE_SHADOW:
1275         player->subtitle_shadow = value;
1276         break;
1277 
1278     case ATTRIBUTE_DEINTERLACE:
1279         player->deinterlace = value;
1280         break;
1281 
1282     case ATTRIBUTE_ENABLE_DEBUG:
1283         player->debug = value;
1284         break;
1285 
1286     case ATTRIBUTE_HARDWARE_AC3:
1287         player->hardware_ac3 = value;
1288         break;
1289 
1290     case ATTRIBUTE_ENABLE_HARDWARE_CODECS:
1291         player->enable_hardware_codecs = value;
1292         break;
1293 
1294     case ATTRIBUTE_ENABLE_CRYSTALHD_CODECS:
1295         player->enable_crystalhd_codecs = value;
1296         break;
1297 
1298     case ATTRIBUTE_FORCE_CACHE:
1299         player->force_cache = value;
1300         break;
1301 
1302     default:
1303         gm_log(player->debug, G_LOG_LEVEL_INFO, "Unsupported Attribute");
1304     }
1305 
1306     return;
1307 }
1308 
gmtk_media_player_get_attribute_boolean(GmtkMediaPlayer * player,GmtkMediaPlayerMediaAttributes attribute)1309 gboolean gmtk_media_player_get_attribute_boolean(GmtkMediaPlayer * player, GmtkMediaPlayerMediaAttributes attribute)
1310 {
1311     gboolean ret = FALSE;
1312 
1313     switch (attribute) {
1314     case ATTRIBUTE_SUB_VISIBLE:
1315         ret = player->sub_visible;
1316         break;
1317 
1318     case ATTRIBUTE_ENABLE_FRAME_DROP:
1319         ret = player->frame_drop;
1320         break;
1321 
1322     case ATTRIBUTE_SUBS_EXIST:
1323         ret = g_list_length(player->subtitles);
1324         break;
1325 
1326     case ATTRIBUTE_SOFTVOL:
1327         ret = player->softvol;
1328         break;
1329 
1330     case ATTRIBUTE_PLAYLIST:
1331         ret = player->playlist;
1332         break;
1333 
1334     case ATTRIBUTE_SEEKABLE:
1335         ret = player->seekable;
1336         break;
1337 
1338     case ATTRIBUTE_HAS_CHAPTERS:
1339         ret = player->has_chapters;
1340         break;
1341 
1342     case ATTRIBUTE_TITLE_IS_MENU:
1343         ret = player->title_is_menu;
1344         break;
1345 
1346     case ATTRIBUTE_DISABLE_UPSCALING:
1347         ret = player->disable_upscaling;
1348         break;
1349 
1350     case ATTRIBUTE_VIDEO_PRESENT:
1351         ret = player->video_present;
1352         break;
1353 
1354     case ATTRIBUTE_MUTED:
1355         ret = player->muted;
1356         break;
1357 
1358     case ATTRIBUTE_ENABLE_ADVANCED_SUBTITLES:
1359         ret = player->enable_advanced_subtitles;
1360         break;
1361 
1362     case ATTRIBUTE_ENABLE_EMBEDDED_FONTS:
1363         ret = player->enable_embedded_fonts;
1364         break;
1365 
1366     case ATTRIBUTE_SUBTITLE_OUTLINE:
1367         ret = player->subtitle_outline;
1368         break;
1369 
1370     case ATTRIBUTE_SUBTITLE_SHADOW:
1371         ret = player->subtitle_shadow;
1372         break;
1373 
1374     case ATTRIBUTE_DEINTERLACE:
1375         ret = player->deinterlace;
1376         break;
1377 
1378     case ATTRIBUTE_ENABLE_DEBUG:
1379         ret = player->debug;
1380         break;
1381 
1382     case ATTRIBUTE_HARDWARE_AC3:
1383         ret = player->hardware_ac3;
1384         break;
1385 
1386     case ATTRIBUTE_RETRY_ON_FULL_CACHE:
1387         ret = player->retry_on_full_cache;
1388         break;
1389 
1390     case ATTRIBUTE_ENABLE_HARDWARE_CODECS:
1391         ret = player->enable_hardware_codecs;
1392         break;
1393 
1394     case ATTRIBUTE_ENABLE_CRYSTALHD_CODECS:
1395         ret = player->enable_crystalhd_codecs;
1396         break;
1397 
1398     case ATTRIBUTE_FORCE_CACHE:
1399         ret = player->force_cache;
1400         break;
1401 
1402     default:
1403         gm_log(player->debug, G_LOG_LEVEL_INFO, "Unsupported Attribute");
1404     }
1405     return ret;
1406 }
1407 
gmtk_media_player_set_attribute_double(GmtkMediaPlayer * player,GmtkMediaPlayerMediaAttributes attribute,gdouble value)1408 void gmtk_media_player_set_attribute_double(GmtkMediaPlayer * player,
1409                                             GmtkMediaPlayerMediaAttributes attribute, gdouble value)
1410 {
1411     gchar *cmd;
1412     gchar *tmp;
1413 
1414     switch (attribute) {
1415     case ATTRIBUTE_CACHE_SIZE:
1416         player->cache_size = value;
1417         break;
1418 
1419     case ATTRIBUTE_START_TIME:
1420         player->start_time = value;
1421         break;
1422 
1423     case ATTRIBUTE_RUN_TIME:
1424         player->run_time = value;
1425         break;
1426 
1427     case ATTRIBUTE_ZOOM:
1428         player->zoom = CLAMP(value, 0.1, 10.0);
1429         break;
1430 
1431     case ATTRIBUTE_VOLUME_GAIN:
1432         player->volume_gain = CLAMP(value, -200.0, 60.0);
1433         break;
1434 
1435     case ATTRIBUTE_SPEED_MULTIPLIER:
1436         player->speed_multiplier = CLAMP(value, 0.1, 10.0);
1437         if (player->player_state == PLAYER_STATE_RUNNING) {
1438             if (player->speed_multiplier == 1.0) {
1439                 tmp = g_new0(char, G_ASCII_DTOSTR_BUF_SIZE);
1440                 tmp = g_ascii_dtostr(tmp, G_ASCII_DTOSTR_BUF_SIZE, player->speed_multiplier);
1441                 cmd = g_strdup_printf("speed_set %s\n", tmp);
1442                 g_free(tmp);
1443 
1444             } else {
1445                 tmp = g_new0(char, G_ASCII_DTOSTR_BUF_SIZE);
1446                 tmp = g_ascii_dtostr(tmp, G_ASCII_DTOSTR_BUF_SIZE, player->speed_multiplier);
1447                 cmd = g_strdup_printf("speed_mult %s\n", tmp);
1448                 g_free(tmp);
1449             }
1450             write_to_mplayer(player, cmd);
1451             g_free(cmd);
1452             cmd = NULL;
1453             write_to_mplayer(player, "get_property speed\n");
1454         }
1455         break;
1456 
1457     case ATTRIBUTE_SPEED_SET:
1458         player->speed = CLAMP(value, 0.1, 10.0);
1459         if (player->player_state == PLAYER_STATE_RUNNING) {
1460             tmp = g_new0(char, G_ASCII_DTOSTR_BUF_SIZE);
1461             tmp = g_ascii_dtostr(tmp, G_ASCII_DTOSTR_BUF_SIZE, player->speed);
1462             cmd = g_strdup_printf("speed_set %s\n", tmp);
1463             g_free(tmp);
1464             write_to_mplayer(player, cmd);
1465             g_free(cmd);
1466             cmd = NULL;
1467             write_to_mplayer(player, "get_property speed\n");
1468         }
1469         break;
1470 
1471     case ATTRIBUTE_SUBTITLE_SCALE:
1472         player->subtitle_scale = CLAMP(value, 0.2, 100.0);
1473         if (player->player_state == PLAYER_STATE_RUNNING) {
1474             tmp = g_new0(char, G_ASCII_DTOSTR_BUF_SIZE);
1475             tmp = g_ascii_dtostr(tmp, G_ASCII_DTOSTR_BUF_SIZE, player->subtitle_scale);
1476             cmd = g_strdup_printf("sub_scale %s\n", tmp);
1477             g_free(tmp);
1478 
1479             write_to_mplayer(player, cmd);
1480             g_free(cmd);
1481             cmd = NULL;
1482         }
1483         break;
1484 
1485     case ATTRIBUTE_SUBTITLE_DELAY:
1486         player->subtitle_delay = value;
1487         if (player->player_state == PLAYER_STATE_RUNNING) {
1488             tmp = g_new0(char, G_ASCII_DTOSTR_BUF_SIZE);
1489             tmp = g_ascii_dtostr(tmp, G_ASCII_DTOSTR_BUF_SIZE, player->subtitle_delay);
1490             cmd = g_strdup_printf("set_property sub_delay %s\n", tmp);
1491             g_free(tmp);
1492             write_to_mplayer(player, cmd);
1493             g_free(cmd);
1494             cmd = NULL;
1495         }
1496         break;
1497 
1498     case ATTRIBUTE_AUDIO_DELAY:
1499         player->audio_delay = CLAMP(value, -100.0, 100.0);
1500         if (player->player_state == PLAYER_STATE_RUNNING) {
1501             tmp = g_new0(char, G_ASCII_DTOSTR_BUF_SIZE);
1502             tmp = g_ascii_dtostr(tmp, G_ASCII_DTOSTR_BUF_SIZE, player->audio_delay);
1503             cmd = g_strdup_printf("set_property audio_delay %s\n", tmp);
1504             g_free(tmp);
1505             write_to_mplayer(player, cmd);
1506             g_free(cmd);
1507             cmd = NULL;
1508         }
1509         break;
1510 
1511     default:
1512         gm_log(player->debug, G_LOG_LEVEL_INFO, "Unsupported Attribute");
1513     }
1514 
1515     return;
1516 }
1517 
gmtk_media_player_get_attribute_double(GmtkMediaPlayer * player,GmtkMediaPlayerMediaAttributes attribute)1518 gdouble gmtk_media_player_get_attribute_double(GmtkMediaPlayer * player, GmtkMediaPlayerMediaAttributes attribute)
1519 {
1520     gdouble ret = 0.0;
1521 
1522     switch (attribute) {
1523     case ATTRIBUTE_LENGTH:
1524         ret = player->length;
1525         break;
1526 
1527     case ATTRIBUTE_POSITION:
1528         ret = player->position;
1529         break;
1530 
1531     case ATTRIBUTE_POSITION_PERCENT:
1532         if (player->length != 0) {
1533             ret = (player->position - player->start_time) / player->length;
1534         } else {
1535             ret = 0.0;
1536         }
1537         break;
1538 
1539     case ATTRIBUTE_START_TIME:
1540         ret = player->start_time;
1541         break;
1542 
1543     case ATTRIBUTE_WIDTH:
1544         ret = (gdouble) player->video_width;
1545         break;
1546 
1547     case ATTRIBUTE_HEIGHT:
1548         ret = (gdouble) player->video_height;
1549         break;
1550 
1551     case ATTRIBUTE_SUB_COUNT:
1552         ret = (gdouble) g_list_length(player->subtitles);
1553         break;
1554 
1555     case ATTRIBUTE_AUDIO_TRACK_COUNT:
1556         ret = (gdouble) g_list_length(player->audio_tracks);
1557         break;
1558 
1559     case ATTRIBUTE_ZOOM:
1560         ret = player->zoom;
1561         break;
1562 
1563     case ATTRIBUTE_SPEED_MULTIPLIER:
1564         ret = player->speed_multiplier;
1565         break;
1566 
1567     case ATTRIBUTE_SPEED_SET:
1568         ret = player->speed;
1569         break;
1570 
1571     case ATTRIBUTE_SUBTITLE_SCALE:
1572         ret = player->subtitle_scale;
1573         break;
1574 
1575     case ATTRIBUTE_SUBTITLE_DELAY:
1576         ret = player->subtitle_delay;
1577         break;
1578 
1579     case ATTRIBUTE_AUDIO_DELAY:
1580         ret = player->audio_delay;
1581         break;
1582 
1583     case ATTRIBUTE_VIDEO_FPS:
1584         ret = player->video_fps;
1585         break;
1586 
1587     case ATTRIBUTE_VOLUME_GAIN:
1588         ret = player->volume_gain;
1589         break;
1590 
1591     case ATTRIBUTE_CACHE_PERCENT:
1592         ret = player->cache_percent;
1593         break;
1594 
1595     default:
1596         gm_log(player->debug, G_LOG_LEVEL_INFO, "Unsupported Attribute");
1597     }
1598     return ret;
1599 }
1600 
gmtk_media_player_set_attribute_string(GmtkMediaPlayer * player,GmtkMediaPlayerMediaAttributes attribute,const gchar * value)1601 void gmtk_media_player_set_attribute_string(GmtkMediaPlayer * player,
1602                                             GmtkMediaPlayerMediaAttributes attribute, const gchar * value)
1603 {
1604     gchar *cmd;
1605 
1606     switch (attribute) {
1607     case ATTRIBUTE_VO:
1608         if (player->vo != NULL) {
1609             g_free(player->vo);
1610             player->vo = NULL;
1611         }
1612         if (value == NULL || strlen(value) == 0) {
1613             player->vo = NULL;
1614         } else {
1615             player->vo = g_strdup(value);
1616         }
1617         break;
1618 
1619     case ATTRIBUTE_AO:
1620         if (player->ao != NULL) {
1621             g_free(player->ao);
1622             player->ao = NULL;
1623         }
1624         if (value == NULL || strlen(value) == 0) {
1625             player->ao = NULL;
1626         } else {
1627             player->ao = g_strdup(value);
1628         }
1629         break;
1630 
1631     case ATTRIBUTE_MEDIA_DEVICE:
1632         if (player->media_device != NULL) {
1633             g_free(player->media_device);
1634             player->media_device = NULL;
1635         }
1636         if (value == NULL || strlen(value) == 0) {
1637             player->media_device = NULL;
1638         } else {
1639             player->media_device = g_strdup(value);
1640         }
1641         break;
1642 
1643     case ATTRIBUTE_EXTRA_OPTS:
1644         if (player->extra_opts != NULL) {
1645             g_free(player->extra_opts);
1646             player->extra_opts = NULL;
1647         }
1648         if (value == NULL || strlen(value) == 0) {
1649             player->extra_opts = NULL;
1650         } else {
1651             player->extra_opts = g_strdup(value);
1652         }
1653         break;
1654 
1655     case ATTRIBUTE_MPLAYER_BINARY:
1656         if (player->mplayer_binary != NULL) {
1657             g_free(player->mplayer_binary);
1658             player->mplayer_binary = NULL;
1659         }
1660         if (value == NULL || strlen(value) == 0) {
1661             player->mplayer_binary = NULL;
1662         } else {
1663             player->mplayer_binary = g_strdup(value);
1664         }
1665         player->features_detected = FALSE;
1666         break;
1667 
1668     case ATTRIBUTE_AUDIO_TRACK_FILE:
1669         if (player->audio_track_file != NULL) {
1670             g_free(player->audio_track_file);
1671             player->audio_track_file = NULL;
1672         }
1673         if (value == NULL || strlen(value) == 0) {
1674             player->audio_track_file = NULL;
1675         } else {
1676             player->audio_track_file = g_strdup(value);
1677         }
1678         break;
1679 
1680     case ATTRIBUTE_SUBTITLE_FILE:
1681         if (player->subtitle_file != NULL) {
1682             g_free(player->subtitle_file);
1683         }
1684         if (value == NULL || strlen(value) == 0) {
1685             player->subtitle_file = NULL;
1686         } else {
1687             player->subtitle_file = g_strdup(value);
1688             if (player->player_state == PLAYER_STATE_RUNNING) {
1689                 write_to_mplayer(player, "sub_remove\n");
1690                 cmd = g_strdup_printf("sub_load \"%s\" 1\n", player->subtitle_file);
1691                 write_to_mplayer(player, cmd);
1692                 g_free(cmd);
1693                 cmd = g_strdup_printf("sub_file 0\n");
1694                 write_to_mplayer(player, cmd);
1695                 g_free(cmd);
1696             }
1697         }
1698         break;
1699 
1700     case ATTRIBUTE_SUBTITLE_COLOR:
1701         if (player->subtitle_color != NULL) {
1702             g_free(player->subtitle_color);
1703         }
1704         if (value == NULL || strlen(value) == 0) {
1705             player->subtitle_color = NULL;
1706         } else {
1707             player->subtitle_color = g_strdup(value);
1708         }
1709         break;
1710 
1711     case ATTRIBUTE_SUBTITLE_CODEPAGE:
1712         if (player->subtitle_codepage != NULL) {
1713             g_free(player->subtitle_codepage);
1714         }
1715         if (value == NULL || strlen(value) == 0) {
1716             player->subtitle_codepage = NULL;
1717         } else {
1718             player->subtitle_codepage = g_strdup(value);
1719         }
1720         break;
1721 
1722     case ATTRIBUTE_SUBTITLE_FONT:
1723         if (player->subtitle_font != NULL) {
1724             g_free(player->subtitle_font);
1725         }
1726         if (value == NULL || strlen(value) == 0) {
1727             player->subtitle_font = NULL;
1728         } else {
1729             player->subtitle_font = g_strdup(value);
1730         }
1731         break;
1732 
1733     case ATTRIBUTE_PROFILE:
1734         if (player->profile != NULL) {
1735             g_free(player->profile);
1736         }
1737         if (value == NULL || strlen(value) == 0) {
1738             player->profile = NULL;
1739         } else {
1740             player->profile = g_strdup(value);
1741         }
1742         break;
1743 
1744     case ATTRIBUTE_PREFERRED_AUDIO_LANGUAGE:
1745         if (player->alang != NULL) {
1746             g_free(player->alang);
1747         }
1748         if (value == NULL || strlen(value) == 0) {
1749             player->alang = NULL;
1750         } else {
1751             player->alang = g_strdup(value);
1752         }
1753         break;
1754 
1755     case ATTRIBUTE_PREFERRED_SUBTITLE_LANGUAGE:
1756         if (player->slang != NULL) {
1757             g_free(player->slang);
1758         }
1759         if (value == NULL || strlen(value) == 0) {
1760             player->slang = NULL;
1761         } else {
1762             player->slang = g_strdup(value);
1763         }
1764         break;
1765 
1766     default:
1767         gm_log(player->debug, G_LOG_LEVEL_INFO, "Unsupported Attribute");
1768     }
1769 }
1770 
gmtk_media_player_get_attribute_string(GmtkMediaPlayer * player,GmtkMediaPlayerMediaAttributes attribute)1771 const gchar *gmtk_media_player_get_attribute_string(GmtkMediaPlayer * player, GmtkMediaPlayerMediaAttributes attribute)
1772 {
1773     gchar *value = NULL;
1774     GList *iter;
1775     GmtkMediaPlayerAudioTrack *track;
1776     GmtkMediaPlayerSubtitle *subtitle;
1777 
1778     switch (attribute) {
1779     case ATTRIBUTE_AF_EXPORT_FILENAME:
1780         value = player->af_export_filename;
1781         break;
1782 
1783     case ATTRIBUTE_MEDIA_DEVICE:
1784         value = player->media_device;
1785         break;
1786 
1787     case ATTRIBUTE_EXTRA_OPTS:
1788         value = player->extra_opts;
1789         break;
1790 
1791     case ATTRIBUTE_MESSAGE:
1792         value = player->message;
1793         break;
1794 
1795     case ATTRIBUTE_AUDIO_TRACK:
1796         iter = player->audio_tracks;
1797         while (iter) {
1798             track = (GmtkMediaPlayerAudioTrack *) iter->data;
1799             if (track->id == player->audio_track_id)
1800                 value = track->label;
1801             iter = iter->next;
1802         }
1803         break;
1804 
1805     case ATTRIBUTE_SUBTITLE:
1806         iter = player->subtitles;
1807         while (iter) {
1808             subtitle = (GmtkMediaPlayerSubtitle *) iter->data;
1809             if (subtitle->id == player->subtitle_id && subtitle->is_file == player->subtitle_is_file)
1810                 value = subtitle->label;
1811             iter = iter->next;
1812         }
1813         break;
1814 
1815     case ATTRIBUTE_SUBTITLE_COLOR:
1816         value = player->subtitle_color;
1817         break;
1818 
1819     case ATTRIBUTE_SUBTITLE_CODEPAGE:
1820         value = player->subtitle_codepage;
1821         break;
1822 
1823     case ATTRIBUTE_SUBTITLE_FONT:
1824         value = player->subtitle_font;
1825         break;
1826 
1827     case ATTRIBUTE_VIDEO_FORMAT:
1828         value = player->video_format;
1829         break;
1830 
1831     case ATTRIBUTE_VIDEO_CODEC:
1832         value = player->video_codec;
1833         break;
1834 
1835     case ATTRIBUTE_AUDIO_FORMAT:
1836         value = player->audio_format;
1837         break;
1838 
1839     case ATTRIBUTE_AUDIO_CODEC:
1840         value = player->audio_codec;
1841         break;
1842 
1843     case ATTRIBUTE_ARTIST:
1844         if (player->artist == NULL || strlen(player->artist) == 0) {
1845             value = NULL;
1846         } else {
1847             value = player->artist;
1848         }
1849         break;
1850 
1851     case ATTRIBUTE_TITLE:
1852         if (player->title == NULL || strlen(player->title) == 0) {
1853             value = NULL;
1854         } else {
1855             value = player->title;
1856         }
1857         break;
1858 
1859     case ATTRIBUTE_ALBUM:
1860         if (player->album == NULL || strlen(player->album) == 0) {
1861             value = NULL;
1862         } else {
1863             value = player->album;
1864         }
1865         break;
1866 
1867     case ATTRIBUTE_GENRE:
1868         if (player->genre == NULL || strlen(player->genre) == 0) {
1869             value = NULL;
1870         } else {
1871             value = player->genre;
1872         }
1873         break;
1874 
1875     case ATTRIBUTE_PROFILE:
1876         value = player->profile;
1877         break;
1878 
1879     default:
1880         gm_log(player->debug, G_LOG_LEVEL_INFO, "Unsupported Attribute");
1881     }
1882 
1883     return value;
1884 }
1885 
gmtk_media_player_set_attribute_integer(GmtkMediaPlayer * player,GmtkMediaPlayerMediaAttributes attribute,gint value)1886 void gmtk_media_player_set_attribute_integer(GmtkMediaPlayer * player, GmtkMediaPlayerMediaAttributes attribute,
1887                                              gint value)
1888 {
1889     gchar *cmd = NULL;
1890 
1891     switch (attribute) {
1892     case ATTRIBUTE_BRIGHTNESS:
1893         player->brightness = CLAMP(value, -100.0, 100.0);
1894         if (player->player_state == PLAYER_STATE_RUNNING) {
1895             cmd = g_strdup_printf("set_property brightness %i\n", value);
1896             write_to_mplayer(player, cmd);
1897             g_free(cmd);
1898         }
1899         break;
1900 
1901     case ATTRIBUTE_CONTRAST:
1902         player->contrast = CLAMP(value, -100.0, 100.0);
1903         if (player->player_state == PLAYER_STATE_RUNNING) {
1904             cmd = g_strdup_printf("set_property contrast %i\n", value);
1905             write_to_mplayer(player, cmd);
1906             g_free(cmd);
1907         }
1908         break;
1909 
1910     case ATTRIBUTE_GAMMA:
1911         player->gamma = CLAMP(value, -100.0, 100.0);
1912         if (player->player_state == PLAYER_STATE_RUNNING) {
1913             cmd = g_strdup_printf("set_property gamma %i\n", value);
1914             write_to_mplayer(player, cmd);
1915             g_free(cmd);
1916         }
1917         break;
1918 
1919     case ATTRIBUTE_HUE:
1920         player->hue = CLAMP(value, -100.0, 100.0);
1921         if (player->player_state == PLAYER_STATE_RUNNING) {
1922             cmd = g_strdup_printf("set_property hue %i\n", value);
1923             write_to_mplayer(player, cmd);
1924             g_free(cmd);
1925         }
1926         break;
1927 
1928     case ATTRIBUTE_SATURATION:
1929         player->saturation = CLAMP(value, -100.0, 100.0);
1930         if (player->player_state == PLAYER_STATE_RUNNING) {
1931             cmd = g_strdup_printf("set_property saturation %i\n", value);
1932             write_to_mplayer(player, cmd);
1933             g_free(cmd);
1934         }
1935         break;
1936 
1937     case ATTRIBUTE_SUBTITLE_MARGIN:
1938         player->subtitle_margin = CLAMP(value, 0.0, 200.0);
1939         break;
1940 
1941     case ATTRIBUTE_SUBTITLE_POSITION:
1942         player->subtitle_position = CLAMP(value, 0, 100);
1943         if (player->player_state == PLAYER_STATE_RUNNING) {
1944             cmd = g_strdup_printf("set_property sub_pos %i\n", player->subtitle_position);
1945             write_to_mplayer(player, cmd);
1946             g_free(cmd);
1947         }
1948         break;
1949 
1950     case ATTRIBUTE_OSDLEVEL:
1951         player->osdlevel = CLAMP(value, 0, 3);
1952         if (player->player_state == PLAYER_STATE_RUNNING) {
1953             cmd = g_strdup_printf("set_property osdlevel %i\n", player->osdlevel);
1954             write_to_mplayer(player, cmd);
1955             g_free(cmd);
1956         }
1957         break;
1958 
1959     case ATTRIBUTE_POST_PROCESSING_LEVEL:
1960         player->post_processing_level = value;
1961         break;
1962 
1963     case ATTRIBUTE_SUBTITLE_FUZZINESS:
1964         player->subtitle_fuzziness = CLAMP(value, 0, 2);
1965         break;
1966 
1967     case ATTRIBUTE_AUDIO_CHANNELS:
1968         player->audio_channels = CLAMP(value, 0, 3);
1969         break;
1970 
1971     default:
1972         gm_log(player->debug, G_LOG_LEVEL_INFO, "Unsupported Attribute");
1973     }
1974 
1975     return;
1976 
1977 }
1978 
gmtk_media_player_set_attribute_integer_delta(GmtkMediaPlayer * player,GmtkMediaPlayerMediaAttributes attribute,gint delta)1979 void gmtk_media_player_set_attribute_integer_delta(GmtkMediaPlayer * player, GmtkMediaPlayerMediaAttributes attribute,
1980                                                    gint delta)
1981 {
1982     gint value;
1983 
1984     switch (attribute) {
1985     case ATTRIBUTE_BRIGHTNESS:
1986         value = player->brightness + delta;
1987         break;
1988 
1989     case ATTRIBUTE_CONTRAST:
1990         value = player->contrast + delta;
1991         break;
1992 
1993     case ATTRIBUTE_GAMMA:
1994         value = player->gamma + delta;
1995         break;
1996 
1997     case ATTRIBUTE_HUE:
1998         value = player->hue + delta;
1999         break;
2000 
2001     case ATTRIBUTE_SATURATION:
2002         value = player->saturation + delta;
2003         break;
2004 
2005     default:
2006         return;
2007     }
2008 
2009     gmtk_media_player_set_attribute_integer(player, attribute, value);
2010 
2011 }
2012 
gmtk_media_player_get_attribute_integer(GmtkMediaPlayer * player,GmtkMediaPlayerMediaAttributes attribute)2013 gint gmtk_media_player_get_attribute_integer(GmtkMediaPlayer * player, GmtkMediaPlayerMediaAttributes attribute)
2014 {
2015     gint ret;
2016 
2017     switch (attribute) {
2018     case ATTRIBUTE_BRIGHTNESS:
2019         ret = player->brightness;
2020         break;
2021 
2022     case ATTRIBUTE_CONTRAST:
2023         ret = player->contrast;
2024         break;
2025 
2026     case ATTRIBUTE_GAMMA:
2027         ret = player->gamma;
2028         break;
2029 
2030     case ATTRIBUTE_HUE:
2031         ret = player->hue;
2032         break;
2033 
2034     case ATTRIBUTE_SATURATION:
2035         ret = player->saturation;
2036         break;
2037 
2038     case ATTRIBUTE_WIDTH:
2039         ret = player->video_width;
2040         break;
2041 
2042     case ATTRIBUTE_HEIGHT:
2043         ret = player->video_height;
2044         break;
2045 
2046     case ATTRIBUTE_SUBTITLE_MARGIN:
2047         ret = player->subtitle_margin;
2048         break;
2049 
2050     case ATTRIBUTE_SUBTITLE_POSITION:
2051         ret = player->subtitle_position;
2052         break;
2053 
2054     case ATTRIBUTE_CHAPTERS:
2055         ret = player->chapters;
2056         break;
2057 
2058     case ATTRIBUTE_VIDEO_BITRATE:
2059         ret = player->video_bitrate;
2060         break;
2061 
2062     case ATTRIBUTE_AUDIO_BITRATE:
2063         ret = player->audio_bitrate;
2064         break;
2065 
2066     case ATTRIBUTE_AUDIO_RATE:
2067         ret = player->audio_rate;
2068         break;
2069 
2070     case ATTRIBUTE_AUDIO_NCH:
2071         ret = player->audio_nch;
2072         break;
2073 
2074     case ATTRIBUTE_OSDLEVEL:
2075         ret = player->osdlevel;
2076         break;
2077 
2078     case ATTRIBUTE_POST_PROCESSING_LEVEL:
2079         ret = player->post_processing_level;
2080         break;
2081 
2082     case ATTRIBUTE_SUBTITLE_FUZZINESS:
2083         ret = player->subtitle_fuzziness;
2084         break;
2085 
2086     default:
2087         return 0;
2088     }
2089 
2090     return ret;
2091 }
2092 
2093 
gmtk_media_player_seek(GmtkMediaPlayer * player,gdouble value,GmtkMediaPlayerSeekType seek_type)2094 void gmtk_media_player_seek(GmtkMediaPlayer * player, gdouble value, GmtkMediaPlayerSeekType seek_type)
2095 {
2096     gchar *cmd;
2097 
2098     cmd = g_strdup_printf("seek %lf %i\n", value, seek_type);
2099     write_to_mplayer(player, cmd);
2100     g_free(cmd);
2101 }
2102 
gmtk_media_player_seek_chapter(GmtkMediaPlayer * player,gint value,GmtkMediaPlayerSeekType seek_type)2103 void gmtk_media_player_seek_chapter(GmtkMediaPlayer * player, gint value, GmtkMediaPlayerSeekType seek_type)
2104 {
2105     gchar *cmd;
2106     if (seek_type != SEEK_RELATIVE)
2107         seek_type = 1;
2108 
2109     cmd = g_strdup_printf("seek_chapter %i %i\n", value, seek_type);
2110     write_to_mplayer(player, cmd);
2111     g_free(cmd);
2112 }
2113 
gmtk_media_player_set_volume(GmtkMediaPlayer * player,gdouble value)2114 void gmtk_media_player_set_volume(GmtkMediaPlayer * player, gdouble value)
2115 {
2116     gchar *cmd;
2117 
2118     player->volume = value;
2119     if (player->player_state == PLAYER_STATE_RUNNING) {
2120         cmd = g_strdup_printf("volume %i 1\n", (gint) (player->volume * 100.0));
2121         write_to_mplayer(player, cmd);
2122         g_free(cmd);
2123     }
2124 }
2125 
gmtk_media_player_get_volume(GmtkMediaPlayer * player)2126 gdouble gmtk_media_player_get_volume(GmtkMediaPlayer * player)
2127 {
2128     return player->volume;
2129 }
2130 
gmtk_media_player_set_media_device(GmtkMediaPlayer * player,gchar * media_device)2131 void gmtk_media_player_set_media_device(GmtkMediaPlayer * player, gchar * media_device)
2132 {
2133     if (player->media_device != NULL) {
2134         g_free(player->media_device);
2135     }
2136     if (media_device == NULL) {
2137         player->media_device = NULL;
2138     } else {
2139         player->media_device = g_strdup(media_device);
2140     }
2141 }
2142 
gmtk_media_player_set_aspect(GmtkMediaPlayer * player,GmtkMediaPlayerAspectRatio aspect)2143 void gmtk_media_player_set_aspect(GmtkMediaPlayer * player, GmtkMediaPlayerAspectRatio aspect)
2144 {
2145     GtkAllocation alloc;
2146 
2147     player->aspect_ratio = aspect;
2148     gmtk_get_allocation(GTK_WIDGET(player), &alloc);
2149     gmtk_media_player_size_allocate(GTK_WIDGET(player), &alloc);
2150 }
2151 
gmtk_media_player_get_aspect(GmtkMediaPlayer * player)2152 GmtkMediaPlayerAspectRatio gmtk_media_player_get_aspect(GmtkMediaPlayer * player)
2153 {
2154     return player->aspect_ratio;
2155 }
2156 
gmtk_media_player_set_media_type(GmtkMediaPlayer * player,GmtkMediaPlayerMediaType type)2157 void gmtk_media_player_set_media_type(GmtkMediaPlayer * player, GmtkMediaPlayerMediaType type)
2158 {
2159     player->type = type;
2160 }
2161 
gmtk_media_player_get_media_type(GmtkMediaPlayer * player)2162 GmtkMediaPlayerMediaType gmtk_media_player_get_media_type(GmtkMediaPlayer * player)
2163 {
2164     return player->type;
2165 }
2166 
gmtk_media_player_select_subtitle(GmtkMediaPlayer * player,const gchar * label)2167 void gmtk_media_player_select_subtitle(GmtkMediaPlayer * player, const gchar * label)
2168 {
2169     GList *list;
2170     GmtkMediaPlayerSubtitle *subtitle;
2171     gchar *cmd;
2172 
2173     list = player->subtitles;
2174     subtitle = NULL;
2175 
2176     while (list != NULL) {
2177         subtitle = (GmtkMediaPlayerSubtitle *) list->data;
2178         if (g_ascii_strcasecmp(subtitle->label, label) == 0) {
2179             break;
2180         }
2181         list = list->next;
2182     }
2183 
2184     if (list != NULL && subtitle != NULL && player->player_state == PLAYER_STATE_RUNNING) {
2185         if (subtitle->is_file) {
2186             cmd = g_strdup_printf("sub_file %i \n", subtitle->id);
2187         } else {
2188             cmd = g_strdup_printf("sub_demux %i \n", subtitle->id);
2189         }
2190         player->subtitle_id = subtitle->id;
2191         player->subtitle_is_file = subtitle->is_file;
2192         write_to_mplayer(player, cmd);
2193         g_free(cmd);
2194     }
2195 }
2196 
gmtk_media_player_select_audio_track(GmtkMediaPlayer * player,const gchar * label)2197 void gmtk_media_player_select_audio_track(GmtkMediaPlayer * player, const gchar * label)
2198 {
2199     GList *list;
2200     GmtkMediaPlayerAudioTrack *track;
2201     gchar *cmd;
2202 
2203     list = player->audio_tracks;
2204     track = NULL;
2205 
2206     while (list != NULL) {
2207         track = (GmtkMediaPlayerAudioTrack *) list->data;
2208         if (g_ascii_strcasecmp(track->label, label) == 0) {
2209             break;
2210         }
2211         list = list->next;
2212     }
2213 
2214     if (list != NULL && track != NULL && player->player_state == PLAYER_STATE_RUNNING) {
2215         cmd = g_strdup_printf("switch_audio %i \n", track->id);
2216         player->audio_track_id = track->id;
2217         write_to_mplayer(player, cmd);
2218         g_free(cmd);
2219     }
2220 }
2221 
gmtk_media_player_select_subtitle_by_id(GmtkMediaPlayer * player,gint id)2222 void gmtk_media_player_select_subtitle_by_id(GmtkMediaPlayer * player, gint id)
2223 {
2224     GList *list;
2225     GmtkMediaPlayerSubtitle *subtitle;
2226     gchar *cmd;
2227 
2228     list = player->subtitles;
2229     subtitle = NULL;
2230 
2231     while (list != NULL) {
2232         subtitle = (GmtkMediaPlayerSubtitle *) list->data;
2233         if (subtitle->id == id) {
2234             break;
2235         }
2236         list = list->next;
2237     }
2238 
2239     if (list != NULL && subtitle != NULL && player->player_state == PLAYER_STATE_RUNNING) {
2240         if (subtitle->is_file) {
2241             cmd = g_strdup_printf("sub_file %i \n", subtitle->id);
2242         } else {
2243             cmd = g_strdup_printf("sub_demux %i \n", subtitle->id);
2244         }
2245         player->subtitle_id = subtitle->id;
2246         player->subtitle_is_file = subtitle->is_file;
2247         write_to_mplayer(player, cmd);
2248         g_free(cmd);
2249     }
2250 }
2251 
gmtk_media_player_select_audio_track_by_id(GmtkMediaPlayer * player,gint id)2252 void gmtk_media_player_select_audio_track_by_id(GmtkMediaPlayer * player, gint id)
2253 {
2254     GList *list;
2255     GmtkMediaPlayerAudioTrack *track;
2256     gchar *cmd;
2257 
2258     list = player->audio_tracks;
2259     track = NULL;
2260 
2261     while (list != NULL) {
2262         track = (GmtkMediaPlayerAudioTrack *) list->data;
2263         if (track->id == id) {
2264             break;
2265         }
2266         list = list->next;
2267     }
2268 
2269     if (list != NULL && track != NULL && player->player_state == PLAYER_STATE_RUNNING) {
2270         cmd = g_strdup_printf("switch_audio %i \n", track->id);
2271         player->audio_track_id = track->id;
2272         write_to_mplayer(player, cmd);
2273         g_free(cmd);
2274     }
2275 }
2276 
playback_error_to_string(const GmtkMediaPlayerPlaybackError playback_error)2277 static const gchar *playback_error_to_string(const GmtkMediaPlayerPlaybackError playback_error)
2278 {
2279     switch (playback_error) {
2280     case NO_ERROR:
2281         return "NO_ERROR";
2282     case ERROR_RETRY_WITH_PLAYLIST:
2283         return "RETRY_WITH_PLAYLIST";
2284     case ERROR_RETRY_WITH_HTTP:
2285         return "RETRY_WITH_HTTP";
2286     case ERROR_RETRY_WITH_HTTP_AND_PLAYLIST:
2287         return "RETRY_WITH_HTTP_AND_PLAYLIST";
2288     case ERROR_RETRY_WITH_MMSHTTP:
2289         return "RETRY_WITH_MMSHTTP";
2290     case ERROR_RETRY_WITHOUT_DIVX_VDPAU:
2291         return "RETRY_WITHOUT_DIVX_VDPAU";
2292     case ERROR_RETRY_WITHOUT_XVMC:
2293         return "RETRY_WITHOUT_XVMC";
2294     case ERROR_RETRY_ALSA_BUSY:
2295         return "RETRY_ALSA_BUSY";
2296     case ERROR_RETRY_VDPAU:
2297         return "RETRY_VDPAU";
2298     case ERROR_RETRY_WITHOUT_HARDWARE_CODECS:
2299         return "RETRY_WITHOUT_HARDWARE_CODECS";
2300     case ERROR_RETRY:
2301         return "RETRY";
2302     default:
2303         return "???";
2304     }
2305 
2306 }
2307 
2308 /* if it contains a deint=N leave as is, otherwise add deint=2
2309    returns newly-allocated string, passing ownership to caller */
vdpau_compute_vo_with_deint(GmtkMediaPlayer * player,gchar const * const vodesc)2310 static gchar *vdpau_compute_vo_with_deint(GmtkMediaPlayer * player, gchar const *const vodesc)
2311 {
2312     gchar *ret;
2313     if (g_regex_match(player->deintN_regex, vodesc, 0, NULL)) {
2314         ret = g_strdup(vodesc);
2315     } else {
2316         ret = g_strdup_printf("%s:deint=2", vodesc);
2317     }
2318     return ret;
2319 }
2320 
2321 /* if it contains a deint=N  remove that, otherwise leave as is
2322    returns newly-allocated string, passing ownership to caller */
vdpau_compute_vo_without_deint(GmtkMediaPlayer * player,gchar const * const vodesc)2323 static gchar *vdpau_compute_vo_without_deint(GmtkMediaPlayer * player, gchar const *const vodesc)
2324 {
2325     GMatchInfo *match_info = NULL;
2326     gchar *ret;
2327     if (g_regex_match(player->deintN_regex, vodesc, 0, &match_info)) {
2328         gchar *before = g_match_info_fetch(match_info, 1);
2329         gchar *after = g_match_info_fetch(match_info, 3);
2330         ret = g_strdup_printf("%s%s", before, after);
2331         g_free(before);
2332         g_free(after);
2333     } else {
2334         ret = g_strdup(vodesc);
2335     }
2336     g_match_info_free(match_info);
2337     return ret;
2338 }
2339 
2340 /* replace the vo part with "gl_nosw"
2341    returns newly-allocated string, passing ownership to caller */
vodesc_replace_gl_with_gl_nosw(GmtkMediaPlayer * player,gchar const * const vodesc)2342 static gchar *vodesc_replace_gl_with_gl_nosw(GmtkMediaPlayer * player, gchar const *const vodesc)
2343 {
2344     /* find the first colon : and replace the part before that with gl_nosw */
2345     char *colonptr = strchr(vodesc, ':');
2346     gchar *ret;
2347     if (colonptr == NULL) {
2348         ret = g_strdup("gl_nosw");
2349     } else {
2350         ret = g_strdup_printf("gl_nosw%s", colonptr);
2351     }
2352     return ret;
2353 }
2354 
launch_mplayer(gpointer data)2355 gpointer launch_mplayer(gpointer data)
2356 {
2357     GmtkMediaPlayer *player = GMTK_MEDIA_PLAYER(data);
2358     gchar *argv[255];
2359     gchar *filename = NULL;
2360     gint argn;
2361     GPid pid;
2362     GError *error;
2363     gint i;
2364     gboolean spawn;
2365     gchar *fontname;
2366     gchar *size;
2367     gchar *tmp;
2368     GList *list;
2369     GmtkMediaPlayerSubtitle *subtitle;
2370     GmtkMediaPlayerAudioTrack *track;
2371     gchar *codecs_vdpau = NULL;
2372     gchar *codecs_crystalhd = NULL;
2373     gchar *codecs = NULL;
2374     GmtkMediaPlayerPlaybackError last_error = NO_ERROR;
2375 #ifdef GIO_ENABLED
2376     GFile *file;
2377 #endif
2378 
2379     gm_log_name_this_thread("lm");
2380     gm_log(player->debug, G_LOG_LEVEL_DEBUG, "within launch_mplayer()");
2381 
2382     player->seekable = FALSE;
2383     player->has_chapters = FALSE;
2384     //player->video_present = FALSE;
2385     player->position = 0.0;
2386     player->cache_percent = -1.0;
2387     player->title_is_menu = FALSE;
2388     player->enable_divx = TRUE;
2389     player->disable_xvmc = FALSE;
2390     player->retry_on_full_cache = FALSE;
2391     player->speed = 1.0;
2392     player->hardware_ac3 = FALSE;
2393 
2394     gm_log(player->debug, G_LOG_LEVEL_DEBUG, "locking thread_running");
2395     g_mutex_lock(player->thread_running);
2396 
2397     do {
2398         gm_log(player->debug, G_LOG_LEVEL_INFO, "setting up mplayer");
2399 
2400         list = player->subtitles;
2401         while (list) {
2402             subtitle = (GmtkMediaPlayerSubtitle *) list->data;
2403             g_free(subtitle->lang);
2404             g_free(subtitle->name);
2405             g_free(subtitle->label);
2406             list = g_list_remove(list, subtitle);
2407         }
2408         player->subtitles = NULL;
2409 
2410         list = player->audio_tracks;
2411         while (list) {
2412             track = (GmtkMediaPlayerAudioTrack *) list->data;
2413             g_free(track->lang);
2414             g_free(track->name);
2415             g_free(track->label);
2416             list = g_list_remove(list, track);
2417         }
2418         player->audio_tracks = NULL;
2419         player->has_metadata = FALSE;
2420         if (player->artist) {
2421             g_free(player->artist);
2422             player->artist = NULL;
2423         }
2424         if (player->title) {
2425             g_free(player->title);
2426             player->title = NULL;
2427         }
2428         if (player->album) {
2429             g_free(player->album);
2430             player->album = NULL;
2431         }
2432 
2433         argn = 0;
2434         player->playback_error = NO_ERROR;
2435         if (player->uri != NULL) {
2436 #ifdef GIO_ENABLED
2437             file = g_file_new_for_uri(player->uri);
2438             if (file != NULL) {
2439                 filename = g_file_get_path(file);
2440                 g_object_unref(file);
2441             }
2442 #else
2443             filename = g_filename_from_uri(player->uri, NULL, NULL);
2444 #endif
2445             if (filename != NULL)
2446                 player->type = TYPE_FILE;
2447         }
2448 
2449         player->minimum_mplayer = detect_mplayer_features(player);
2450 
2451         if (player->mplayer_binary == NULL || !g_file_test(player->mplayer_binary, G_FILE_TEST_EXISTS)) {
2452             argv[argn++] = g_strdup_printf("mplayer");
2453         } else {
2454             argv[argn++] = g_strdup_printf("%s", player->mplayer_binary);
2455         }
2456 
2457         // use the profile to set up some default values
2458         if (player->profile != NULL) {
2459             argv[argn++] = g_strdup_printf("-profile");
2460             argv[argn++] = g_strdup(player->profile);
2461         }
2462 
2463         if (player->vo != NULL) {
2464             argv[argn++] = g_strdup_printf("-vo");
2465 
2466             if (vodesc_looks_like_vo(player->vo, "vdpau")) {
2467 
2468                 if (player->deinterlace) {
2469                     /* if it contains a deint=N leave as is, otherwise add deint=2 */
2470                     gchar *vo_with_deint = vdpau_compute_vo_with_deint(player, player->vo);
2471                     argv[argn++] = g_strdup_printf("%s,gl,x11,", player->vo);
2472                     g_free(vo_with_deint);
2473                 } else {
2474                     /* if it contains a deint=N remove that, otherwise leave as is */
2475                     gchar *vo_without_deint = vdpau_compute_vo_without_deint(player, player->vo);
2476                     argv[argn++] = g_strdup_printf("%s,gl,x11,", player->vo);
2477                     g_free(vo_without_deint);
2478                 }
2479 
2480                 // told by uau that vdpau without hardware decoding is often what you want
2481                 if (player->enable_hardware_codecs) {
2482                     if (player->enable_divx) {
2483                         codecs_vdpau =
2484                             g_strdup_printf("ffmpeg12vdpau,ffh264vdpau,ffwmv3vdpau,ffvc1vdpau,ffodivxvdpau,");
2485                     } else {
2486                         codecs_vdpau = g_strdup_printf("ffmpeg12vdpau,ffh264vdpau,ffwmv3vdpau,ffvc1vdpau,");
2487                     }
2488                 }
2489 
2490             } else if (vodesc_looks_like_vo(player->vo, "vaapi")) {
2491                 argv[argn++] = g_strdup_printf("%s,", player->vo);
2492                 argv[argn++] = g_strdup_printf("-va");
2493                 argv[argn++] = g_strdup_printf("vaapi");
2494 
2495             } else if (vodesc_looks_like_vo(player->vo, "xvmc")) {
2496 
2497                 if (player->disable_xvmc) {
2498                     argv[argn++] = g_strdup_printf("xv,");
2499                 } else {
2500                     argv[argn++] = g_strdup_printf("%s,xv,", player->vo);
2501                 }
2502 
2503             } else {
2504 
2505                 if (vodesc_looks_like_vo(player->vo, "gl") && player->enable_hardware_codecs) {
2506                     gchar *vodesc = vodesc_replace_gl_with_gl_nosw(player, player->vo);
2507                     argv[argn++] = vodesc;
2508                 } else if (vodesc_looks_like_vo(player->vo, "gl2") && player->enable_hardware_codecs) {
2509                     gchar *vodesc = vodesc_replace_gl_with_gl_nosw(player, player->vo);
2510                     argv[argn++] = vodesc;
2511                 } else {
2512                     argv[argn++] = g_strdup_printf("%s", player->vo);
2513                     if (vodesc_looks_like_vo(player->vo, "x11")) {
2514                         argv[argn++] = g_strdup_printf("-zoom");
2515                     }
2516                 }
2517 
2518                 if (player->deinterlace) {
2519                     argv[argn++] = g_strdup_printf("-vf-pre");
2520                     argv[argn++] = g_strdup_printf("yadif,softskip,scale");
2521                 }
2522 
2523                 if (player->post_processing_level > 0) {
2524                     argv[argn++] = g_strdup_printf("-vf-add");
2525                     argv[argn++] = g_strdup_printf("pp=ac/tn:a");
2526                     argv[argn++] = g_strdup_printf("-autoq");
2527                     argv[argn++] = g_strdup_printf("%d", player->post_processing_level);
2528                 }
2529 
2530                 argv[argn++] = g_strdup_printf("-vf-add");
2531                 argv[argn++] = g_strdup_printf("screenshot");
2532 
2533             }
2534         }
2535 
2536         if (player->enable_crystalhd_codecs) {
2537             codecs_crystalhd = g_strdup_printf
2538                 ("ffmpeg2crystalhd,ffdivxcrystalhd,ffwmv3crystalhd,ffvc1crystalhd,ffh264crystalhd,ffodivxcrystalhd,");
2539         }
2540 
2541         if (codecs_vdpau && codecs_crystalhd) {
2542             codecs = g_strconcat(codecs_vdpau, codecs_crystalhd, NULL);
2543             g_free(codecs_vdpau);
2544             g_free(codecs_crystalhd);
2545             codecs_vdpau = NULL;
2546             codecs_crystalhd = NULL;
2547         } else if (codecs_vdpau) {
2548             codecs = g_strdup(codecs_vdpau);
2549             g_free(codecs_vdpau);
2550             codecs_vdpau = NULL;
2551         } else if (codecs_crystalhd) {
2552             codecs = g_strdup(codecs_crystalhd);
2553             g_free(codecs_crystalhd);
2554             codecs_crystalhd = NULL;
2555         }
2556 
2557         if (codecs != NULL) {
2558             argv[argn++] = g_strdup_printf("-vc");
2559             argv[argn++] = g_strdup_printf("%s", codecs);
2560             g_free(codecs);
2561             codecs = NULL;
2562         }
2563 
2564         if (player->ao != NULL) {
2565 
2566             argv[argn++] = g_strdup_printf("-ao");
2567             argv[argn++] = g_strdup_printf("%s", player->ao);
2568 
2569             if (player->alsa_mixer != NULL) {
2570                 argv[argn++] = g_strdup_printf("-mixer-channel");
2571                 argv[argn++] = g_strdup_printf("%s", player->alsa_mixer);
2572             }
2573         }
2574 
2575         argv[argn++] = g_strdup_printf("-channels");
2576         switch (player->audio_channels) {
2577         case 1:
2578             argv[argn++] = g_strdup_printf("4");
2579             break;
2580         case 2:
2581             argv[argn++] = g_strdup_printf("6");
2582             break;
2583         case 3:
2584             argv[argn++] = g_strdup_printf("8");
2585             break;
2586         default:
2587             argv[argn++] = g_strdup_printf("2");
2588             break;
2589         }
2590 
2591         if (player->hardware_ac3) {
2592             argv[argn++] = g_strdup_printf("-afm");
2593             argv[argn++] = g_strdup_printf("hwac3,");
2594         } else {
2595             argv[argn++] = g_strdup_printf("-af-add");
2596             argv[argn++] = g_strdup_printf("export=%s:512", player->af_export_filename);
2597         }
2598 
2599         argv[argn++] = g_strdup_printf("-quiet");
2600         argv[argn++] = g_strdup_printf("-slave");
2601         argv[argn++] = g_strdup_printf("-noidle");
2602         argv[argn++] = g_strdup_printf("-noconsolecontrols");
2603         argv[argn++] = g_strdup_printf("-nostop-xscreensaver");
2604         argv[argn++] = g_strdup_printf("-identify");
2605         if (player->softvol) {
2606             if ((gint) (player->volume * 100) != 0) {
2607                 argv[argn++] = g_strdup_printf("-volume");
2608                 argv[argn++] = g_strdup_printf("%i", (gint) (player->volume * 100));
2609             }
2610 
2611             if ((gint) (player->volume_gain) != 0) {
2612                 argv[argn++] = g_strdup_printf("-af-add");
2613                 argv[argn++] = g_strdup_printf("volume=%lf:0", player->volume_gain);
2614             }
2615 
2616             argv[argn++] = g_strdup_printf("-softvol");
2617         }
2618 
2619         if ((gint) (player->start_time) > 0) {
2620             argv[argn++] = g_strdup_printf("-ss");
2621             tmp = g_new0(char, G_ASCII_DTOSTR_BUF_SIZE);
2622             tmp = g_ascii_dtostr(tmp, G_ASCII_DTOSTR_BUF_SIZE, player->start_time);
2623             argv[argn++] = g_strdup(tmp);
2624             g_free(tmp);
2625         }
2626 
2627         if ((gint) (player->run_time) > 0) {
2628             argv[argn++] = g_strdup_printf("-endpos");
2629             tmp = g_new0(char, G_ASCII_DTOSTR_BUF_SIZE);
2630             tmp = g_ascii_dtostr(tmp, G_ASCII_DTOSTR_BUF_SIZE, player->run_time);
2631             argv[argn++] = g_strdup(tmp);
2632             g_free(tmp);
2633         }
2634 
2635         if (player->frame_drop)
2636             argv[argn++] = g_strdup_printf("-framedrop");
2637 
2638         argv[argn++] = g_strdup_printf("-msglevel");
2639         argv[argn++] = g_strdup_printf("all=5");
2640 
2641         argv[argn++] = g_strdup_printf("-osdlevel");
2642         argv[argn++] = g_strdup_printf("%i", player->osdlevel);
2643 
2644         argv[argn++] = g_strdup_printf("-delay");
2645         tmp = g_new0(char, G_ASCII_DTOSTR_BUF_SIZE);
2646         tmp = g_ascii_dtostr(tmp, G_ASCII_DTOSTR_BUF_SIZE, player->audio_delay);
2647         argv[argn++] = g_strdup(tmp);
2648         g_free(tmp);
2649 
2650         argv[argn++] = g_strdup_printf("-subdelay");
2651         tmp = g_new0(char, G_ASCII_DTOSTR_BUF_SIZE);
2652         tmp = g_ascii_dtostr(tmp, G_ASCII_DTOSTR_BUF_SIZE, player->subtitle_delay);
2653         argv[argn++] = g_strdup(tmp);
2654         g_free(tmp);
2655 
2656         argv[argn++] = g_strdup_printf("-subpos");
2657         argv[argn++] = g_strdup_printf("%i", player->subtitle_position);
2658 
2659         argv[argn++] = g_strdup_printf("-sub-fuzziness");
2660         argv[argn++] = g_strdup_printf("%i", player->subtitle_fuzziness);
2661 
2662         // wait upto 1 second for the socket_id to be valid, but in plugin mode it may not so timeout
2663         i = 0;
2664         while (player->socket_id == 0 && (i++ < 100)) {
2665             g_usleep(1000);
2666         }
2667 
2668         argv[argn++] = g_strdup_printf("-wid");
2669         argv[argn++] = g_strdup_printf("0x%x", player->socket_id);
2670 
2671         argv[argn++] = g_strdup_printf("-brightness");
2672         argv[argn++] = g_strdup_printf("%i", player->brightness);
2673         argv[argn++] = g_strdup_printf("-contrast");
2674         argv[argn++] = g_strdup_printf("%i", player->contrast);
2675         //argv[argn++] = g_strdup_printf("-gamma");
2676         //argv[argn++] = g_strdup_printf("%i", player->gamma);
2677         argv[argn++] = g_strdup_printf("-hue");
2678         argv[argn++] = g_strdup_printf("%i", player->hue);
2679         argv[argn++] = g_strdup_printf("-saturation");
2680         argv[argn++] = g_strdup_printf("%i", player->saturation);
2681 
2682         if (player->alang) {
2683             argv[argn++] = g_strdup_printf("-alang");
2684             argv[argn++] = g_strdup_printf("%s", player->alang);
2685         }
2686 
2687         if (player->slang) {
2688             argv[argn++] = g_strdup_printf("-slang");
2689             argv[argn++] = g_strdup_printf("%s", player->slang);
2690         }
2691 
2692         /* disable msg stuff to make sure extra console characters don't mess around */
2693         argv[argn++] = g_strdup_printf("-nomsgcolor");
2694         argv[argn++] = g_strdup_printf("-nomsgmodule");
2695 
2696         // mplayer says that nokeepaspect isn't supported by all vo's but it seems to work
2697         //if (player->use_mplayer2)
2698         argv[argn++] = g_strdup_printf("-nokeepaspect");
2699 
2700         if (player->audio_track_file != NULL && strlen(player->audio_track_file) > 0) {
2701             argv[argn++] = g_strdup_printf("-audiofile");
2702             argv[argn++] = g_strdup_printf("%s", player->audio_track_file);
2703         }
2704 
2705         if (player->subtitle_file != NULL && strlen(player->subtitle_file) > 0) {
2706             argv[argn++] = g_strdup_printf("-sub");
2707             argv[argn++] = g_strdup_printf("%s", player->subtitle_file);
2708         }
2709         // subtitle stuff
2710         if (player->enable_advanced_subtitles) {
2711             argv[argn++] = g_strdup_printf("-ass");
2712 
2713             if (player->subtitle_margin > 0) {
2714                 argv[argn++] = g_strdup_printf("-ass-bottom-margin");
2715                 argv[argn++] = g_strdup_printf("%i", player->subtitle_margin);
2716                 argv[argn++] = g_strdup_printf("-ass-use-margins");
2717             }
2718 
2719             if (player->enable_embedded_fonts) {
2720                 argv[argn++] = g_strdup_printf("-embeddedfonts");
2721             } else {
2722                 argv[argn++] = g_strdup_printf("-noembeddedfonts");
2723 
2724                 if (player->subtitle_font != NULL && strlen(player->subtitle_font) > 0) {
2725                     fontname = g_strdup(player->subtitle_font);
2726                     size = g_strrstr(fontname, " ");
2727                     if (size)
2728                         size[0] = '\0';
2729                     size = g_strrstr(fontname, " Bold");
2730                     if (size)
2731                         size[0] = '\0';
2732                     size = g_strrstr(fontname, " Italic");
2733                     if (size)
2734                         size[0] = '\0';
2735                     argv[argn++] = g_strdup_printf("-ass-force-style");
2736                     argv[argn++] = g_strconcat("FontName=", fontname,
2737                                                ((g_strrstr(player->subtitle_font, "Italic") !=
2738                                                  NULL) ? ",Italic=1" : ",Italic=0"),
2739                                                ((g_strrstr(player->subtitle_font, "Bold") !=
2740                                                  NULL) ? ",Bold=1" : ",Bold=0"),
2741                                                (player->subtitle_outline ? ",Outline=1" : ",Outline=0"),
2742                                                (player->subtitle_shadow ? ",Shadow=2" : ",Shadow=0"), NULL);
2743                     g_free(fontname);
2744                 }
2745             }
2746 
2747             argv[argn++] = g_strdup_printf("-ass-font-scale");
2748             tmp = g_new0(char, G_ASCII_DTOSTR_BUF_SIZE);
2749             tmp = g_ascii_dtostr(tmp, G_ASCII_DTOSTR_BUF_SIZE, player->subtitle_scale);
2750             argv[argn++] = g_strdup(tmp);
2751             g_free(tmp);
2752 
2753             if (player->subtitle_color != NULL && strlen(player->subtitle_color) > 0) {
2754                 argv[argn++] = g_strdup_printf("-ass-color");
2755                 argv[argn++] = g_strdup_printf("%s", player->subtitle_color);
2756             }
2757 
2758         } else {
2759             if (player->subtitle_scale != 0) {
2760                 argv[argn++] = g_strdup_printf("-subfont-text-scale");
2761                 argv[argn++] = g_strdup_printf("%d", (int) (player->subtitle_scale * 5));       // 5 is the default
2762             }
2763 
2764             if (player->subtitle_font != NULL && strlen(player->subtitle_font) > 0) {
2765                 fontname = g_strdup(player->subtitle_font);
2766                 size = g_strrstr(fontname, " ");
2767                 if (size)
2768                     size[0] = '\0';
2769                 argv[argn++] = g_strdup_printf("-subfont");
2770                 argv[argn++] = g_strdup_printf("%s", fontname);
2771                 g_free(fontname);
2772             }
2773         }
2774 
2775         if (player->subtitle_codepage != NULL && strlen(player->subtitle_codepage) > 0) {
2776             argv[argn++] = g_strdup_printf("-subcp");
2777             argv[argn++] = g_strdup_printf("%s", player->subtitle_codepage);
2778         }
2779 
2780         if (player->extra_opts != NULL) {
2781             char **opts = g_strsplit(player->extra_opts, " ", -1);
2782             int i;
2783             for (i = 0; opts[i] != NULL; i++)
2784                 argv[argn++] = g_strdup(opts[i]);
2785             g_strfreev(opts);
2786         }
2787 
2788         switch (player->type) {
2789         case TYPE_FILE:
2790             if (filename != NULL) {
2791                 if (player->force_cache && player->cache_size >= 32) {
2792                     argv[argn++] = g_strdup_printf("-cache");
2793                     argv[argn++] = g_strdup_printf("%i", (gint) player->cache_size);
2794                 }
2795                 if (player->playlist) {
2796                     argv[argn++] = g_strdup_printf("-playlist");
2797                 }
2798                 argv[argn++] = g_strdup_printf("%s", filename);
2799                 break;
2800             }
2801         case TYPE_CD:
2802             argv[argn++] = g_strdup_printf("-cache");
2803             argv[argn++] = g_strdup_printf("%i", (gint) player->cache_size);
2804             argv[argn++] = g_strdup_printf("%s", player->uri);
2805             if (player->media_device != NULL) {
2806                 argv[argn++] = g_strdup_printf("-dvd-device");
2807                 argv[argn++] = g_strdup_printf("%s", player->media_device);
2808             }
2809             break;
2810 
2811         case TYPE_DVD:
2812             argv[argn++] = g_strdup_printf("-mouse-movements");
2813             argv[argn++] = g_strdup_printf("-nocache");
2814             argv[argn++] = g_strdup_printf("dvdnav://");
2815             if (player->media_device != NULL) {
2816                 argv[argn++] = g_strdup_printf("-dvd-device");
2817                 argv[argn++] = g_strdup_printf("%s", player->media_device);
2818             }
2819             break;
2820 
2821         case TYPE_VCD:
2822             argv[argn++] = g_strdup_printf("-nocache");
2823             argv[argn++] = g_strdup_printf("%s", player->uri);
2824             if (player->media_device != NULL) {
2825                 argv[argn++] = g_strdup_printf("-dvd-device");
2826                 argv[argn++] = g_strdup_printf("%s", player->media_device);
2827             }
2828             break;
2829 
2830         case TYPE_NETWORK:
2831             if (g_strrstr(player->uri, "apple.com")) {
2832                 argv[argn++] = g_strdup_printf("-user-agent");
2833                 argv[argn++] = g_strdup_printf("QuickTime/7.6.9");
2834             }
2835             if (player->cache_size >= 32) {
2836                 argv[argn++] = g_strdup_printf("-cache");
2837                 argv[argn++] = g_strdup_printf("%i", (gint) player->cache_size);
2838             }
2839             if (player->playlist) {
2840                 argv[argn++] = g_strdup_printf("-playlist");
2841             }
2842             argv[argn++] = g_strdup_printf("%s", player->uri);
2843             break;
2844 
2845         case TYPE_DVB:
2846         case TYPE_TV:
2847             if (player->tv_device != NULL) {
2848                 argv[argn++] = g_strdup_printf("-tv:device");
2849                 argv[argn++] = g_strdup_printf("%s", player->tv_device);
2850             }
2851             if (player->tv_driver != NULL) {
2852                 argv[argn++] = g_strdup_printf("-tv:driver");
2853                 argv[argn++] = g_strdup_printf("%s", player->tv_driver);
2854             }
2855             if (player->tv_input != NULL) {
2856                 argv[argn++] = g_strdup_printf("-tv:input");
2857                 argv[argn++] = g_strdup_printf("%s", player->tv_input);
2858             }
2859             if (player->tv_width > 0) {
2860                 argv[argn++] = g_strdup_printf("-tv:width");
2861                 argv[argn++] = g_strdup_printf("%i", player->tv_width);
2862             }
2863             if (player->tv_height > 0) {
2864                 argv[argn++] = g_strdup_printf("-tv:height");
2865                 argv[argn++] = g_strdup_printf("%i", player->tv_height);
2866             }
2867             if (player->tv_fps > 0) {
2868                 argv[argn++] = g_strdup_printf("-tv:fps");
2869                 argv[argn++] = g_strdup_printf("%i", player->tv_fps);
2870             }
2871             argv[argn++] = g_strdup_printf("-nocache");
2872             argv[argn++] = g_strdup_printf("%s", player->uri);
2873 
2874 
2875         default:
2876             break;
2877         }
2878         argv[argn] = NULL;
2879 
2880         gchar *allargs = g_strjoinv(" ", argv);
2881         gm_log(player->debug, G_LOG_LEVEL_INFO, "%s", allargs);
2882         g_free(allargs);
2883 
2884         error = NULL;
2885         player->std_in = -1;
2886         player->std_out = -1;
2887         player->std_err = -1;
2888         spawn =
2889             g_spawn_async_with_pipes(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &pid,
2890                                      &(player->std_in), &(player->std_out), &(player->std_err), &error);
2891 
2892         gm_log(player->debug, G_LOG_LEVEL_DEBUG, "spawn = %s files in %i out %i err %i", gm_bool_to_string(spawn),
2893                player->std_in, player->std_out, player->std_err);
2894 
2895         if (error != NULL) {
2896             gm_log(player->debug, G_LOG_LEVEL_INFO, "error code = %i - %s", error->code, error->message);
2897             g_error_free(error);
2898             error = NULL;
2899         }
2900 
2901         argn = 0;
2902         while (argv[argn] != NULL) {
2903             g_free(argv[argn]);
2904             argv[argn] = NULL;
2905             argn++;
2906         }
2907 
2908         if (spawn) {
2909             gmtk_media_player_log_state(player, "launched");
2910             gm_log(player->debug, G_LOG_LEVEL_DEBUG, "spawn succeeded, setup up channels");
2911 
2912             player->player_state = PLAYER_STATE_RUNNING;
2913             player->media_state = MEDIA_STATE_BUFFERING;
2914             if (player->channel_in != NULL) {
2915                 g_io_channel_unref(player->channel_in);
2916                 player->channel_in = NULL;
2917             }
2918 
2919             if (player->channel_out != NULL) {
2920                 g_io_channel_unref(player->channel_out);
2921                 player->channel_out = NULL;
2922             }
2923 
2924             if (player->channel_err != NULL) {
2925                 g_io_channel_unref(player->channel_err);
2926                 player->channel_err = NULL;
2927             }
2928 
2929             player->channel_in = g_io_channel_unix_new(player->std_in);
2930             g_io_channel_set_encoding(player->channel_in, NULL, NULL);
2931             player->channel_out = g_io_channel_unix_new(player->std_out);
2932             g_io_channel_set_encoding(player->channel_out, NULL, NULL);
2933             player->channel_err = g_io_channel_unix_new(player->std_err);
2934             g_io_channel_set_encoding(player->channel_err, NULL, NULL);
2935 
2936             g_io_channel_set_close_on_unref(player->channel_in, TRUE);
2937             g_io_channel_set_close_on_unref(player->channel_out, TRUE);
2938             g_io_channel_set_close_on_unref(player->channel_err, TRUE);
2939 
2940             player->watch_in_id =
2941                 g_io_add_watch_full(player->channel_out, G_PRIORITY_LOW, G_IO_IN, thread_reader, player, NULL);
2942             player->watch_err_id =
2943                 g_io_add_watch_full(player->channel_err, G_PRIORITY_LOW, G_IO_IN, thread_reader_error, player, NULL);
2944             player->watch_in_hup_id =
2945                 g_io_add_watch_full(player->channel_out, G_PRIORITY_LOW, G_IO_HUP, thread_complete, player, NULL);
2946 
2947 #ifdef GLIB2_14_ENABLED
2948             g_timeout_add_seconds(1, thread_query, player);
2949 #else
2950             g_timeout_add(1000, thread_query, player);
2951 #endif
2952 
2953             // /////////////////////////////////////////////////////////////////////
2954             // Now this thread waits till somebody signals player->mplayer_complete_cond
2955 
2956             gm_log(player->debug, G_LOG_LEVEL_DEBUG, "waiting for mplayer_complete_cond");
2957             g_cond_wait(player->mplayer_complete_cond, player->thread_running);
2958             gm_log(player->debug, G_LOG_LEVEL_DEBUG, "mplayer_complete_cond was signalled");
2959 
2960             g_source_remove(player->watch_in_id);
2961             g_source_remove(player->watch_err_id);
2962             g_source_remove(player->watch_in_hup_id);
2963             if (player->channel_in != NULL) {
2964                 g_io_channel_shutdown(player->channel_in, FALSE, NULL);
2965                 g_io_channel_unref(player->channel_in);
2966                 player->channel_in = NULL;
2967             }
2968 
2969             if (player->channel_out != NULL) {
2970                 g_io_channel_shutdown(player->channel_out, FALSE, NULL);
2971                 g_io_channel_unref(player->channel_out);
2972                 player->channel_out = NULL;
2973             }
2974 
2975             if (player->channel_err != NULL) {
2976                 g_io_channel_shutdown(player->channel_err, FALSE, NULL);
2977                 g_io_channel_unref(player->channel_err);
2978                 player->channel_err = NULL;
2979             }
2980             close(player->std_in);
2981             player->std_in = -1;
2982             g_spawn_close_pid(pid);
2983 
2984         }
2985 
2986         if (player->cache_percent < 0.0 && g_str_has_prefix(player->uri, "mms"))
2987             player->playback_error = ERROR_RETRY_WITH_MMSHTTP;
2988 
2989         if (player->cache_percent < 0.0 && g_str_has_prefix(player->uri, "mmshttp"))
2990             player->playback_error = ERROR_RETRY_WITH_HTTP;
2991 
2992         switch (player->playback_error) {
2993         case ERROR_RETRY_WITH_PLAYLIST:
2994             player->playlist = TRUE;
2995             break;
2996 
2997         case ERROR_RETRY_WITH_HTTP:
2998             tmp = gmtk_media_player_switch_protocol(player->uri, "http");
2999             g_free(player->uri);
3000             player->uri = tmp;
3001             break;
3002 
3003         case ERROR_RETRY_WITH_HTTP_AND_PLAYLIST:
3004             tmp = gmtk_media_player_switch_protocol(player->uri, "http");
3005             g_free(player->uri);
3006             player->uri = tmp;
3007             player->playlist = TRUE;
3008             break;
3009 
3010         case ERROR_RETRY_WITH_MMSHTTP:
3011             tmp = gmtk_media_player_switch_protocol(player->uri, "mmsh");
3012             g_free(player->uri);
3013             player->uri = tmp;
3014             break;
3015 
3016         case ERROR_RETRY_WITHOUT_DIVX_VDPAU:
3017             player->enable_divx = FALSE;
3018             break;
3019 
3020         case ERROR_RETRY_WITHOUT_XVMC:
3021             player->disable_xvmc = TRUE;
3022             break;
3023 
3024         case ERROR_RETRY_ALSA_BUSY:
3025         case ERROR_RETRY_VDPAU:
3026             break;
3027         case ERROR_RETRY:
3028             if (last_error == NO_ERROR) {
3029                 last_error = ERROR_RETRY;
3030             } else {
3031                 last_error = NO_ERROR;
3032                 player->playback_error = NO_ERROR;
3033             }
3034             break;
3035 
3036         case ERROR_RETRY_WITHOUT_HARDWARE_CODECS:
3037             player->enable_hardware_codecs = FALSE;
3038             break;
3039 
3040         case ERROR_RETRY_WITHOUT_AF_EXPORT:
3041             player->hardware_ac3 = TRUE;
3042             break;
3043 
3044         default:
3045             break;
3046         }
3047 
3048         gm_log(player->debug, G_LOG_LEVEL_DEBUG, "playback error code is %s",
3049                playback_error_to_string(player->playback_error));
3050 
3051     } while (player->playback_error != NO_ERROR);
3052 
3053     gm_log(player->debug, G_LOG_LEVEL_DEBUG, "marking playback complete");
3054     player->player_state = PLAYER_STATE_DEAD;
3055     player->media_state = MEDIA_STATE_UNKNOWN;
3056     player->mplayer_thread = NULL;
3057     player->start_time = 0.0;
3058     player->run_time = 0.0;
3059     if (player->artist) {
3060         g_free(player->artist);
3061         player->artist = NULL;
3062     }
3063     if (player->title) {
3064         g_free(player->title);
3065         player->title = NULL;
3066     }
3067     if (player->album) {
3068         g_free(player->album);
3069         player->album = NULL;
3070     }
3071 
3072     gmtk_media_player_log_state(player, "finished");
3073 
3074     gm_log(player->debug, G_LOG_LEVEL_DEBUG, "unlocking thread_running");
3075     g_mutex_unlock(player->thread_running);
3076 
3077     if (player->restart) {
3078         g_signal_emit_by_name(player, "restart-shutdown-complete", NULL);
3079     } else {
3080         create_event_double(player, "position-changed", 0.0);
3081         create_event_int(player, "player-state-changed", player->player_state);
3082         create_event_int(player, "media-state-changed", player->media_state);
3083     }
3084 
3085     return NULL;
3086 }
3087 
finalize_mplayer(GmtkMediaPlayer * player)3088 static void finalize_mplayer(GmtkMediaPlayer * player)
3089 {
3090     g_source_remove(player->watch_in_id);
3091     g_source_remove(player->watch_in_hup_id);
3092     g_source_remove(player->watch_err_id);
3093     g_unlink(player->af_export_filename);
3094     gmtk_media_player_log_state(player, "completed");
3095     gm_log(player->debug, G_LOG_LEVEL_DEBUG, "signaling mplayer_complete_cond");
3096     g_cond_signal(player->mplayer_complete_cond);
3097 }
3098 
3099 // this executes in the main thread
thread_complete(GIOChannel * source,GIOCondition condition,gpointer data)3100 gboolean thread_complete(GIOChannel * source, GIOCondition condition, gpointer data)
3101 {
3102     GmtkMediaPlayer *player = GMTK_MEDIA_PLAYER(data);
3103 
3104     gm_log(player->debug, G_LOG_LEVEL_DEBUG, "thread_complete()");
3105     player->player_state = PLAYER_STATE_DEAD;
3106     player->media_state = MEDIA_STATE_UNKNOWN;
3107     finalize_mplayer(player);
3108 
3109     return FALSE;
3110 }
3111 
3112 // this executes in the main thread
thread_reader_error(GIOChannel * source,GIOCondition condition,gpointer data)3113 gboolean thread_reader_error(GIOChannel * source, GIOCondition condition, gpointer data)
3114 {
3115     GmtkMediaPlayer *player = GMTK_MEDIA_PLAYER(data);
3116     GString *mplayer_output;
3117     GIOStatus status;
3118     gchar *error_msg = NULL;
3119     //GtkWidget *dialog;
3120     gchar *buf;
3121 
3122     if (player == NULL) {
3123         gm_log(player->debug, G_LOG_LEVEL_DEBUG, "player is NULL");
3124         finalize_mplayer(player);
3125         return FALSE;
3126     }
3127 
3128     if (source == NULL) {
3129         gm_log(player->debug, G_LOG_LEVEL_DEBUG, "source is null");
3130         finalize_mplayer(player);
3131         return FALSE;
3132     }
3133 
3134     if (player->player_state == PLAYER_STATE_DEAD) {
3135         gm_log(player->debug, G_LOG_LEVEL_DEBUG, "player is dead");
3136         finalize_mplayer(player);
3137         return FALSE;
3138     }
3139 
3140     mplayer_output = g_string_new("");
3141     status = g_io_channel_read_line_string(source, mplayer_output, NULL, NULL);
3142     if (status == G_IO_STATUS_ERROR) {
3143         gm_logsp(player->debug, G_LOG_LEVEL_INFO, "GIO IO Error:", mplayer_output->str);
3144         return TRUE;
3145     } else {
3146         if (g_strrstr(mplayer_output->str, "ANS") == NULL) {
3147             gm_logsp(player->debug, G_LOG_LEVEL_INFO, "< ERROR:", mplayer_output->str);
3148         }
3149 
3150         if (strstr(mplayer_output->str, "Couldn't open DVD device") != 0) {
3151             error_msg = g_strdup(mplayer_output->str);
3152         }
3153 
3154         if (strstr(mplayer_output->str, "X11 error") != 0) {
3155             create_event_int(player, "attribute-changed", ATTRIBUTE_SIZE);
3156         }
3157 
3158         if (strstr(mplayer_output->str, "signal") != NULL) {
3159             if (strstr(mplayer_output->str, "decode") != NULL) {
3160                 create_event_int(player, "attribute-changed", ATTRIBUTE_SIZE);
3161                 if (player->position == 0) {
3162                     player->playback_error = ERROR_RETRY;
3163                 }
3164             } else if (strstr(mplayer_output->str, "filter video") != NULL) {
3165                 player->playback_error = ERROR_RETRY;
3166             } else {
3167                 error_msg = g_strdup(mplayer_output->str);
3168             }
3169         }
3170         if (strstr(mplayer_output->str, "Error when calling vdp_output_surface_create") != NULL) {
3171             create_event_int(player, "attribute-changed", ATTRIBUTE_SIZE);
3172             if (player->position == 0) {
3173                 player->playback_error = ERROR_RETRY;
3174             }
3175         }
3176 
3177         if (strstr(mplayer_output->str, "Failed creating VDPAU decoder") != NULL) {
3178             if (player->enable_divx && vodesc_looks_like_vo(player->vo, "vdpau"))
3179                 player->playback_error = ERROR_RETRY_WITHOUT_DIVX_VDPAU;
3180         }
3181 
3182         if (strstr(mplayer_output->str, "decoding to PIX_FMT_NONE is not supported") != NULL) {
3183             if (player->enable_divx)
3184                 player->playback_error = ERROR_RETRY_WITHOUT_HARDWARE_CODECS;
3185         }
3186 
3187         if (strstr(mplayer_output->str, "The selected video_out device is incompatible with this codec") != NULL) {
3188             if (!player->disable_xvmc && vodesc_looks_like_vo(player->vo, "xvmc"))
3189                 player->playback_error = ERROR_RETRY_WITHOUT_XVMC;
3190         }
3191 
3192         if (strstr(mplayer_output->str, "[AO_ALSA] Playback open error: Device or resource busy") != NULL) {
3193             player->playback_error = ERROR_RETRY_ALSA_BUSY;
3194         }
3195 
3196         if (strstr(mplayer_output->str, "Sample format big-endian AC3 not yet supported") != NULL) {
3197             player->playback_error = ERROR_RETRY_WITHOUT_AF_EXPORT;
3198         }
3199 
3200         /*
3201            if (strstr(mplayer_output->str, "Error when calling vdp_output_surface_create") != NULL) {
3202            create_event_int(player, "attribute-changed", ATTRIBUTE_SIZE);
3203            player->playback_error = ERROR_RETRY_VDPAU;
3204            write_to_mplayer(player, "quit\n");
3205            }
3206          */
3207 
3208         if (strstr(mplayer_output->str, "Failed to open") != NULL) {
3209             if (strstr(mplayer_output->str, "LIRC") == NULL &&
3210                 strstr(mplayer_output->str, "input.conf") == NULL &&
3211                 strstr(mplayer_output->str, "/dev/rtc") == NULL &&
3212                 strstr(mplayer_output->str, "VDPAU") == NULL && strstr(mplayer_output->str, "registry file") == NULL) {
3213                 if (strstr(mplayer_output->str, "<") == NULL && strstr(mplayer_output->str, ">") == NULL
3214                     && player->type == TYPE_FILE) {
3215                     error_msg =
3216                         g_strdup_printf(g_dgettext(GETTEXT_PACKAGE, "Failed to open %s"),
3217                                         mplayer_output->str + strlen("Failed to open "));
3218                 }
3219 
3220                 if (strstr(mplayer_output->str, "mms://") != NULL && player->type == TYPE_NETWORK) {
3221                     player->playback_error = ERROR_RETRY_WITH_MMSHTTP;
3222                 }
3223             }
3224         }
3225 
3226         if (strstr(mplayer_output->str, "MPlayer interrupted by signal 13 in module: open_stream") != NULL
3227             && g_strrstr(player->uri, "mms://") != NULL) {
3228             player->playback_error = ERROR_RETRY_WITH_MMSHTTP;
3229         }
3230 
3231         if (strstr(mplayer_output->str, "No stream found to handle url mmshttp://") != NULL) {
3232             player->playback_error = ERROR_RETRY_WITH_HTTP;
3233         }
3234 
3235         if (strstr(mplayer_output->str, "Server returned 404:File Not Found") != NULL
3236             && g_strrstr(player->uri, "mmshttp://") != NULL) {
3237             player->playback_error = ERROR_RETRY_WITH_HTTP;
3238         }
3239 
3240         if (strstr(mplayer_output->str, "unknown ASF streaming type") != NULL
3241             && g_strrstr(player->uri, "mmshttp://") != NULL) {
3242             player->playback_error = ERROR_RETRY_WITH_HTTP;
3243         }
3244 
3245         if (strstr(mplayer_output->str, "Error while parsing chunk header") != NULL) {
3246             player->playback_error = ERROR_RETRY_WITH_HTTP_AND_PLAYLIST;
3247         }
3248 
3249         if (strstr(mplayer_output->str, "Failed to initiate \"video/X-ASF-PF\" RTP subsession") != NULL) {
3250             player->playback_error = ERROR_RETRY_WITH_PLAYLIST;
3251         }
3252 
3253         if (strstr(mplayer_output->str, "playlist support will not be used") != NULL) {
3254             player->playback_error = ERROR_RETRY_WITH_PLAYLIST;
3255         }
3256 
3257         if (strstr(mplayer_output->str, "Compressed SWF format not supported") != NULL) {
3258             error_msg = g_strdup_printf(g_dgettext(GETTEXT_PACKAGE, "Compressed SWF format not supported"));
3259         }
3260 
3261         if (strstr(mplayer_output->str, "moov atom not found") != NULL) {
3262             player->retry_on_full_cache = TRUE;
3263             create_event_boolean(player, "attribute-changed", ATTRIBUTE_RETRY_ON_FULL_CACHE);
3264         }
3265 
3266         if (strstr(mplayer_output->str, "MOV: missing header (moov/cmov) chunk") != NULL) {
3267             player->retry_on_full_cache = TRUE;
3268             create_event_boolean(player, "attribute-changed", ATTRIBUTE_RETRY_ON_FULL_CACHE);
3269         }
3270 
3271         if (strstr(mplayer_output->str, "Seek failed") != NULL) {
3272             write_to_mplayer(player, "quit\n");
3273             player->retry_on_full_cache = TRUE;
3274             create_event_boolean(player, "attribute-changed", ATTRIBUTE_RETRY_ON_FULL_CACHE);
3275         }
3276 
3277         if (strstr(mplayer_output->str, "Title: ") != 0) {
3278             buf = strstr(mplayer_output->str, "Title:");
3279             buf = strstr(mplayer_output->str, "Title: ") + strlen("Title: ");
3280             buf = g_strchomp(buf);
3281             if (player->title != NULL) {
3282                 g_free(player->title);
3283                 player->title = NULL;
3284             }
3285 
3286             player->title = g_locale_to_utf8(buf, -1, NULL, NULL, NULL);
3287             if (player->title == NULL) {
3288                 player->title = g_strdup(buf);
3289                 gm_str_strip_unicode(player->title, strlen(player->title));
3290             }
3291             create_event_int(player, "attribute-changed", ATTRIBUTE_TITLE);
3292         }
3293 
3294         if (error_msg != NULL && player->playback_error == NO_ERROR) {
3295             create_event_string(player, "error-message", error_msg);
3296             /*
3297                dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,
3298                GTK_BUTTONS_CLOSE, "%s", error_msg);
3299                gtk_window_set_title(GTK_WINDOW(dialog), g_dgettext(GETTEXT_PACKAGE, "GNOME MPlayer Error"));
3300                gtk_dialog_run(GTK_DIALOG(dialog));
3301                gtk_widget_destroy(dialog);
3302              */
3303             g_free(error_msg);
3304             error_msg = NULL;
3305         }
3306 
3307     }
3308     g_string_free(mplayer_output, TRUE);
3309 
3310     return TRUE;
3311 }
3312 
3313 // this executes in the main thread
thread_reader(GIOChannel * source,GIOCondition condition,gpointer data)3314 gboolean thread_reader(GIOChannel * source, GIOCondition condition, gpointer data)
3315 {
3316     GmtkMediaPlayer *player = GMTK_MEDIA_PLAYER(data);
3317     GString *mplayer_output;
3318     GIOStatus status;
3319     GError *error = NULL;
3320     gchar *buf, *title, *message = NULL, *icy = NULL;
3321     gint w, h, i;
3322     gfloat percent, oldposition;
3323     gchar vm[10];
3324     gint id;
3325     GtkAllocation allocation = { 0 };
3326     GmtkMediaPlayerSubtitle *subtitle = NULL;
3327     GmtkMediaPlayerAudioTrack *audio_track = NULL;
3328     GList *iter;
3329     GtkWidget *dialog;
3330     gchar **split;
3331     gint index;
3332 
3333     if (player == NULL) {
3334         gm_log(player->debug, G_LOG_LEVEL_MESSAGE, "player is NULL");
3335         finalize_mplayer(player);
3336         return FALSE;
3337     }
3338 
3339     if (source == NULL) {
3340         gm_log(player->debug, G_LOG_LEVEL_INFO, "source is null");
3341         finalize_mplayer(player);
3342         return FALSE;
3343     }
3344 
3345     if (player->player_state == PLAYER_STATE_DEAD) {
3346         gm_log(player->debug, G_LOG_LEVEL_INFO, "player is dead");
3347         finalize_mplayer(player);
3348         return FALSE;
3349     }
3350 
3351     mplayer_output = g_string_new("");
3352 
3353     status = g_io_channel_read_line_string(source, mplayer_output, NULL, &error);
3354     if (status == G_IO_STATUS_ERROR) {
3355         gm_logsp(player->debug, G_LOG_LEVEL_INFO, "GIO IO Error:", mplayer_output->str);
3356         return TRUE;
3357     } else {
3358         if (g_strrstr(mplayer_output->str, "ANS") == NULL) {
3359             gm_logsp(player->debug, G_LOG_LEVEL_INFO, "<", mplayer_output->str);
3360         } else {
3361             gm_logsp(player->debug, G_LOG_LEVEL_DEBUG, "<", mplayer_output->str);
3362         }
3363 
3364         if (strstr(mplayer_output->str, "Cache fill") != 0) {
3365             buf = strstr(mplayer_output->str, "Cache fill");
3366             sscanf(buf, "Cache fill: %f%%", &percent);
3367             buf = g_strdup_printf(g_dgettext(GETTEXT_PACKAGE, "Cache fill: %2.2f%%"), percent);
3368             player->cache_percent = percent / 100.0;
3369             create_event_double(player, "cache-percent-changed", player->cache_percent);
3370         }
3371 
3372         if (strstr(mplayer_output->str, "AO:") != NULL) {
3373             write_to_mplayer(player, "get_property switch_audio\n");
3374         }
3375 
3376         if (strstr(mplayer_output->str, "VO:") != NULL) {
3377             buf = strstr(mplayer_output->str, "VO:");
3378             sscanf(buf, "VO: [%[^]]] %ix%i => %ix%i", vm, &w, &h, &(player->video_width), &(player->video_height));
3379             gm_log(player->debug, G_LOG_LEVEL_DEBUG, "%ix%i => %ix%i", w, h, player->video_width, player->video_height);
3380             gmtk_get_allocation(GTK_WIDGET(player), &allocation);
3381             player->media_state = MEDIA_STATE_PLAY;
3382             if (player->restart) {
3383                 g_signal_emit_by_name(player, "restart-complete", NULL);
3384             } else {
3385                 create_event_int(player, "media-state-changed", player->media_state);
3386                 allocation.width = player->video_width;
3387                 allocation.height = player->video_height;
3388 				if (player->video_present == FALSE) {
3389             		create_event_allocation(player, "size_allocate", &allocation);
3390 				}
3391                 player->video_present = TRUE;
3392                 buf = g_strdup_printf("set_property sub_visibility %i\n", player->sub_visible);
3393                 write_to_mplayer(player, buf);
3394                 g_free(buf);
3395                 write_to_mplayer(player, "get_property sub_source\n");
3396                 write_to_mplayer(player, "get_property sub_visibility\n");
3397                 create_event_int(player, "attribute-changed", ATTRIBUTE_SIZE);
3398                 create_event_int(player, "attribute-changed", ATTRIBUTE_VIDEO_PRESENT);
3399                 create_event_int(player, "subtitles-changed", g_list_length(player->subtitles));
3400                 create_event_int(player, "audio-tracks-changed", g_list_length(player->audio_tracks));
3401                 create_event_double(player, "cache-percent-changed", 0.0);
3402             }
3403             create_event_int(player, "attribute-changed", ATTRIBUTE_AF_EXPORT_FILENAME);
3404             create_event_int(player, "attribute-changed", ATTRIBUTE_AUDIO_TRACK);
3405             create_event_int(player, "attribute-changed", ATTRIBUTE_SUBTITLE);
3406             gmtk_media_player_log_state(player, "media_loaded");
3407         }
3408 
3409         if (strstr(mplayer_output->str, "Video: no video") != NULL) {
3410             gm_log(player->debug, G_LOG_LEVEL_MESSAGE, "Running in audio only mode");
3411             player->video_width = 0;
3412             player->video_height = 0;
3413             gmtk_get_allocation(GTK_WIDGET(player), &allocation);
3414             player->media_state = MEDIA_STATE_PLAY;
3415             if (player->restart) {
3416                 g_signal_emit_by_name(player, "restart-complete", NULL);
3417             } else {
3418                 create_event_int(player, "media-state-changed", player->media_state);
3419                 player->video_present = FALSE;
3420                 create_event_int(player, "attribute-changed", ATTRIBUTE_SIZE);
3421                 create_event_int(player, "attribute-changed", ATTRIBUTE_VIDEO_PRESENT);
3422                 create_event_int(player, "subtitles-changed", g_list_length(player->subtitles));
3423                 create_event_int(player, "audio-tracks-changed", g_list_length(player->audio_tracks));
3424                 create_event_double(player, "cache-percent-changed", 0.0);
3425             }
3426             create_event_int(player, "attribute-changed", ATTRIBUTE_AF_EXPORT_FILENAME);
3427             create_event_int(player, "attribute-changed", ATTRIBUTE_AUDIO_TRACK);
3428             create_event_int(player, "attribute-changed", ATTRIBUTE_SUBTITLE);
3429             gmtk_media_player_log_state(player, "media_loaded");
3430         }
3431 
3432         if (strstr(mplayer_output->str, "ANS_TIME_POSITION") != 0) {
3433             buf = strstr(mplayer_output->str, "ANS_TIME_POSITION");
3434             oldposition = player->position;
3435             sscanf(buf, "ANS_TIME_POSITION=%lf", &player->position);
3436             if (oldposition != player->position)
3437                 create_event_double(player, "position-changed", player->position);
3438             if (player->position > player->length)
3439                 write_to_mplayer(player, "get_time_length\n");
3440         }
3441 
3442         if (strstr(mplayer_output->str, "ID_START_TIME") != 0) {
3443             buf = strstr(mplayer_output->str, "ID_START_TIME");
3444             sscanf(buf, "ID_START_TIME=%lf", &player->start_time);
3445             create_event_int(player, "attribute-changed", ATTRIBUTE_START_TIME);
3446         }
3447 
3448         if (strstr(mplayer_output->str, "ID_LENGTH") != 0) {
3449             buf = strstr(mplayer_output->str, "ID_LENGTH");
3450             sscanf(buf, "ID_LENGTH=%lf", &player->length);
3451             create_event_int(player, "attribute-changed", ATTRIBUTE_LENGTH);
3452         }
3453 
3454         if (strstr(mplayer_output->str, "ANS_LENGTH") != 0) {
3455             buf = strstr(mplayer_output->str, "ANS_LENGTH");
3456             sscanf(buf, "ANS_LENGTH=%lf", &player->length);
3457             create_event_int(player, "attribute-changed", ATTRIBUTE_LENGTH);
3458         }
3459 
3460         if (strstr(mplayer_output->str, "ID_AUDIO_TRACK") != 0) {
3461             buf = strstr(mplayer_output->str, "ID_AUDIO_TRACK");
3462             id = player->audio_track_id;
3463             sscanf(buf, "ID_AUDIO_TRACK=%i", &player->audio_track_id);
3464             if (id != player->audio_track_id)
3465                 create_event_int(player, "attribute-changed", ATTRIBUTE_AUDIO_TRACK);
3466         }
3467 
3468         if (strstr(mplayer_output->str, "ANS_switch_audio") != 0) {
3469             buf = strstr(mplayer_output->str, "ANS_switch_audio");
3470             id = player->audio_track_id;
3471             sscanf(buf, "ANS_switch_audio=%i", &player->audio_track_id);
3472             if (id != player->audio_track_id)
3473                 create_event_int(player, "attribute-changed", ATTRIBUTE_AUDIO_TRACK);
3474         }
3475 
3476         if (strstr(mplayer_output->str, "ANS_sub_source") != 0) {
3477             buf = strstr(mplayer_output->str, "ANS_sub_source");
3478             sscanf(buf, "ANS_sub_source=%i", &player->subtitle_source);
3479             switch (player->subtitle_source) {
3480             case 0:
3481                 player->subtitle_is_file = TRUE;
3482                 write_to_mplayer(player, "get_property sub_file\n");
3483                 break;
3484             case 1:
3485                 player->subtitle_is_file = FALSE;
3486                 write_to_mplayer(player, "get_property sub_vob\n");
3487                 break;
3488             case 2:
3489                 player->subtitle_is_file = FALSE;
3490                 write_to_mplayer(player, "get_property sub_demux\n");
3491                 break;
3492             }
3493         }
3494 
3495         if (strstr(mplayer_output->str, "ANS_sub_file") != 0) {
3496             buf = strstr(mplayer_output->str, "ANS_sub_file");
3497             sscanf(buf, "ANS_sub_file=%i", &player->subtitle_id);
3498             create_event_int(player, "attribute-changed", ATTRIBUTE_SUBTITLE);
3499         }
3500 
3501         if (strstr(mplayer_output->str, "ANS_sub_demux") != 0) {
3502             buf = strstr(mplayer_output->str, "ANS_sub_demux");
3503             sscanf(buf, "ANS_sub_demux=%i", &player->subtitle_id);
3504             create_event_int(player, "attribute-changed", ATTRIBUTE_SUBTITLE);
3505         }
3506 
3507         if (strstr(mplayer_output->str, "ANS_sub_visibility") != 0) {
3508             if (strstr(mplayer_output->str, "ANS_sub_visibility=yes") != 0) {
3509                 player->sub_visible = TRUE;
3510             } else {
3511                 player->sub_visible = FALSE;
3512             }
3513             create_event_int(player, "attribute-changed", ATTRIBUTE_SUB_VISIBLE);
3514         }
3515 
3516         if (strstr(mplayer_output->str, "ANS_speed") != 0) {
3517             buf = strstr(mplayer_output->str, "ANS_speed");
3518             sscanf(buf, "ANS_speed=%lf", &player->speed);
3519             gm_log(player->debug, G_LOG_LEVEL_MESSAGE, "new speed is %lf", player->speed);
3520             create_event_int(player, "attribute-changed", ATTRIBUTE_SPEED_SET);
3521         }
3522 
3523         if (strstr(mplayer_output->str, "DVDNAV_TITLE_IS_MENU") != 0) {
3524             player->title_is_menu = TRUE;
3525             write_to_mplayer(player, "get_time_length\n");
3526         }
3527 
3528         if (strstr(mplayer_output->str, "DVDNAV_TITLE_IS_MOVIE") != 0) {
3529             player->title_is_menu = FALSE;
3530             write_to_mplayer(player, "get_time_length\n");
3531         }
3532 
3533         if (strstr(mplayer_output->str, "ID_SUBTITLE_ID=") != 0) {
3534             buf = strstr(mplayer_output->str, "ID_SUBTITLE_ID");
3535             sscanf(buf, "ID_SUBTITLE_ID=%i", &id);
3536             subtitle = g_new0(GmtkMediaPlayerSubtitle, 1);
3537             subtitle->id = id;
3538             subtitle->lang = g_strdup_printf(g_dgettext(GETTEXT_PACKAGE, "Unknown"));
3539             subtitle->name = g_strdup_printf(g_dgettext(GETTEXT_PACKAGE, "Unknown"));
3540             subtitle->label = g_strdup_printf("%s (%s) - %i", subtitle->name, subtitle->lang, subtitle->id);
3541             player->subtitles = g_list_append(player->subtitles, subtitle);
3542 
3543         }
3544 
3545         if (strstr(mplayer_output->str, "ID_SID_") != 0) {
3546             buf = strstr(mplayer_output->str, "ID_SID_");
3547             sscanf(buf, "ID_SID_%i_", &id);
3548             g_string_truncate(mplayer_output, mplayer_output->len - 1);
3549             buf = strstr(mplayer_output->str, "_LANG=");
3550             if (buf != NULL) {
3551                 buf += strlen("_LANG=");
3552                 iter = player->subtitles;
3553                 while (iter) {
3554                     subtitle = ((GmtkMediaPlayerSubtitle *) (iter->data));
3555                     if (subtitle->id == id && subtitle->is_file == FALSE) {
3556                         if (subtitle->lang != NULL) {
3557                             g_free(subtitle->lang);
3558                             subtitle->lang = NULL;
3559                         }
3560                         subtitle->lang = g_strdup(buf);
3561                     }
3562                     iter = iter->next;
3563                 }
3564             }
3565             buf = strstr(mplayer_output->str, "_NAME=");
3566             if (buf != NULL) {
3567                 buf += strlen("_NAME=");
3568                 iter = player->subtitles;
3569                 while (iter) {
3570                     subtitle = ((GmtkMediaPlayerSubtitle *) (iter->data));
3571                     if (subtitle->id == id && subtitle->is_file == FALSE) {
3572                         if (subtitle->name != NULL) {
3573                             g_free(subtitle->name);
3574                             subtitle->name = NULL;
3575                         }
3576                         subtitle->name = g_strdup(buf);
3577                     }
3578                     iter = iter->next;
3579                 }
3580             }
3581             if (subtitle) {
3582                 if (subtitle->label != NULL) {
3583                     g_free(subtitle->label);
3584                     subtitle->label = NULL;
3585                 }
3586                 subtitle->label =
3587                     g_strdup_printf("%s (%s) - %i",
3588                                     (subtitle->name) ? subtitle->name : g_dgettext(GETTEXT_PACKAGE, "Unknown"),
3589                                     subtitle->lang, subtitle->id);
3590             }
3591         }
3592 
3593         if (strstr(mplayer_output->str, "ID_FILE_SUB_ID=") != 0) {
3594             buf = strstr(mplayer_output->str, "ID_FILE_SUB_ID");
3595             sscanf(buf, "ID_FILE_SUB_ID=%i", &id);
3596             subtitle = g_new0(GmtkMediaPlayerSubtitle, 1);
3597             subtitle->id = id;
3598             subtitle->is_file = TRUE;
3599             subtitle->label = g_strdup_printf(g_dgettext(GETTEXT_PACKAGE, "External Subtitle #%i"), id + 1);
3600             player->subtitles = g_list_append(player->subtitles, subtitle);
3601             create_event_int(player, "subtitles-changed", g_list_length(player->subtitles));
3602         }
3603 
3604         if (strstr(mplayer_output->str, "ID_AUDIO_ID=") != 0) {
3605             buf = strstr(mplayer_output->str, "ID_AUDIO_ID");
3606             sscanf(buf, "ID_AUDIO_ID=%i", &id);
3607             iter = player->audio_tracks;
3608             gboolean found = FALSE;
3609             while (iter) {
3610                 audio_track = ((GmtkMediaPlayerAudioTrack *) (iter->data));
3611                 if (audio_track->id == id) {
3612                     found = TRUE;
3613                 }
3614                 iter = iter->next;
3615             }
3616 
3617             if (!found) {
3618                 audio_track = g_new0(GmtkMediaPlayerAudioTrack, 1);
3619                 audio_track->id = id;
3620                 audio_track->lang = g_strdup_printf(g_dgettext(GETTEXT_PACKAGE, "Unknown"));
3621                 audio_track->name = g_strdup_printf(g_dgettext(GETTEXT_PACKAGE, "Unknown"));
3622                 audio_track->label = g_strdup_printf("%s (%s) - %i", audio_track->name, audio_track->lang,
3623                                                      audio_track->id);
3624                 player->audio_tracks = g_list_append(player->audio_tracks, audio_track);
3625             }
3626         }
3627 
3628         if (strstr(mplayer_output->str, "ID_AID_") != 0) {
3629             buf = strstr(mplayer_output->str, "ID_AID_");
3630             sscanf(buf, "ID_AID_%i_", &id);
3631             g_string_truncate(mplayer_output, mplayer_output->len - 1);
3632             buf = strstr(mplayer_output->str, "_LANG=");
3633             if (buf != NULL) {
3634                 buf += strlen("_LANG=");
3635                 iter = player->audio_tracks;
3636                 gboolean updated = FALSE;
3637                 while (iter) {
3638                     audio_track = ((GmtkMediaPlayerAudioTrack *) (iter->data));
3639                     if (audio_track->id == id) {
3640                         updated = TRUE;
3641                         if (audio_track->lang != NULL) {
3642                             g_free(audio_track->lang);
3643                             audio_track->lang = NULL;
3644                         }
3645                         audio_track->lang = g_strdup(buf);
3646                     }
3647                     iter = iter->next;
3648                 }
3649                 if (updated == FALSE) {
3650                     audio_track = g_new0(GmtkMediaPlayerAudioTrack, 1);
3651                     audio_track->id = id;
3652                     audio_track->lang = g_strdup_printf("%s", buf);
3653                     audio_track->name = g_strdup_printf(g_dgettext(GETTEXT_PACKAGE, "Unknown"));
3654                     audio_track->label = g_strdup_printf("%s (%s) - %i", audio_track->name, audio_track->lang,
3655                                                          audio_track->id);
3656                     player->audio_tracks = g_list_append(player->audio_tracks, audio_track);
3657                     create_event_int(player, "audio-tracks-changed", g_list_length(player->audio_tracks));
3658                 }
3659             }
3660             buf = strstr(mplayer_output->str, "_NAME=");
3661             if (buf != NULL) {
3662                 buf += strlen("_NAME=");
3663                 iter = player->audio_tracks;
3664                 while (iter) {
3665                     audio_track = ((GmtkMediaPlayerAudioTrack *) (iter->data));
3666                     if (audio_track->id == id) {
3667                         if (audio_track->name != NULL) {
3668                             g_free(audio_track->name);
3669                             audio_track->name = NULL;
3670                         }
3671                         audio_track->name = g_strdup(buf);
3672                     }
3673                     iter = iter->next;
3674                 }
3675             }
3676 
3677             if (audio_track) {
3678                 if (audio_track->label != NULL) {
3679                     g_free(audio_track->label);
3680                     audio_track->label = NULL;
3681                 }
3682 
3683                 audio_track->label =
3684                     g_strdup_printf("%s (%s) - %i",
3685                                     (audio_track->name) ? audio_track->name : g_dgettext(GETTEXT_PACKAGE, "Unknown"),
3686                                     audio_track->lang, audio_track->id);
3687             }
3688         }
3689 
3690         if ((strstr(mplayer_output->str, "ID_CHAPTERS=") != NULL)) {
3691             buf = strstr(mplayer_output->str, "ID_CHAPTERS");
3692             sscanf(buf, "ID_CHAPTERS=%i", &player->chapters);
3693             if (player->chapters > 1) {
3694                 player->has_chapters = TRUE;
3695             } else {
3696                 player->has_chapters = FALSE;
3697             }
3698             create_event_int(player, "attribute-changed", ATTRIBUTE_HAS_CHAPTERS);
3699             create_event_int(player, "attribute-changed", ATTRIBUTE_CHAPTERS);
3700         }
3701 
3702         if ((strstr(mplayer_output->str, "ID_SEEKABLE=") != NULL)
3703             && !(strstr(mplayer_output->str, "ID_SEEKABLE=0") != NULL)) {
3704             player->seekable = TRUE;
3705             create_event_int(player, "attribute-changed", ATTRIBUTE_SEEKABLE);
3706         }
3707 
3708         if (strstr(mplayer_output->str, "ID_VIDEO_FORMAT") != 0) {
3709             g_string_truncate(mplayer_output, mplayer_output->len - 1);
3710             buf = strstr(mplayer_output->str, "ID_VIDEO_FORMAT") + strlen("ID_VIDEO_FORMAT=");
3711             if (player->video_format != NULL) {
3712                 g_free(player->video_format);
3713                 player->video_format = NULL;
3714             }
3715             player->video_format = g_strdup(buf);
3716             create_event_int(player, "attribute-changed", ATTRIBUTE_VIDEO_FORMAT);
3717             if (player->video_width == 0 && player->video_height == 0) {
3718                 gm_log(player->debug, G_LOG_LEVEL_INFO,
3719                        "Setting to minimum size so that mplayer has something to draw to");
3720                 allocation.width = 32;
3721                 allocation.height = 16;
3722                 create_event_allocation(player, "size_allocate", &allocation);
3723             }
3724         }
3725 
3726         if (strstr(mplayer_output->str, "ID_VIDEO_CODEC") != 0) {
3727             g_string_truncate(mplayer_output, mplayer_output->len - 1);
3728             buf = strstr(mplayer_output->str, "ID_VIDEO_CODEC") + strlen("ID_VIDEO_CODEC=");
3729             if (player->video_codec != NULL) {
3730                 g_free(player->video_codec);
3731                 player->video_codec = NULL;
3732             }
3733             player->video_codec = g_strdup(buf);
3734             create_event_int(player, "attribute-changed", ATTRIBUTE_VIDEO_CODEC);
3735         }
3736 
3737         if (strstr(mplayer_output->str, "ID_VIDEO_FPS") != 0) {
3738             buf = strstr(mplayer_output->str, "ID_VIDEO_FPS");
3739             sscanf(buf, "ID_VIDEO_FPS=%lf", &player->video_fps);
3740             create_event_int(player, "attribute-changed", ATTRIBUTE_VIDEO_FPS);
3741         }
3742 
3743         if (strstr(mplayer_output->str, "ID_VIDEO_BITRATE") != 0) {
3744             buf = strstr(mplayer_output->str, "ID_VIDEO_BITRATE");
3745             sscanf(buf, "ID_VIDEO_BITRATE=%i", &player->video_bitrate);
3746             create_event_int(player, "attribute-changed", ATTRIBUTE_VIDEO_BITRATE);
3747         }
3748 
3749         if (strstr(mplayer_output->str, "ID_AUDIO_FORMAT") != 0) {
3750             g_string_truncate(mplayer_output, mplayer_output->len - 1);
3751             buf = strstr(mplayer_output->str, "ID_AUDIO_FORMAT") + strlen("ID_AUDIO_FORMAT=");
3752             if (player->audio_format != NULL) {
3753                 g_free(player->audio_format);
3754                 player->audio_format = NULL;
3755             }
3756             player->audio_format = g_strdup(buf);
3757             create_event_int(player, "attribute-changed", ATTRIBUTE_AUDIO_FORMAT);
3758         }
3759 
3760         if (strstr(mplayer_output->str, "ID_AUDIO_CODEC") != 0) {
3761             g_string_truncate(mplayer_output, mplayer_output->len - 1);
3762             buf = strstr(mplayer_output->str, "ID_AUDIO_CODEC") + strlen("ID_AUDIO_CODEC=");
3763             if (player->audio_codec != NULL) {
3764                 g_free(player->audio_codec);
3765                 player->audio_codec = NULL;
3766             }
3767             player->audio_codec = g_strdup(buf);
3768             create_event_int(player, "attribute-changed", ATTRIBUTE_AUDIO_CODEC);
3769         }
3770 
3771         if (strstr(mplayer_output->str, "ID_AUDIO_BITRATE") != 0) {
3772             buf = strstr(mplayer_output->str, "ID_AUDIO_BITRATE");
3773             sscanf(buf, "ID_AUDIO_BITRATE=%i", &player->audio_bitrate);
3774             create_event_int(player, "attribute-changed", ATTRIBUTE_AUDIO_BITRATE);
3775         }
3776 
3777         if (strstr(mplayer_output->str, "ID_AUDIO_RATE") != 0) {
3778             buf = strstr(mplayer_output->str, "ID_AUDIO_RATE");
3779             sscanf(buf, "ID_AUDIO_RATE=%i", &player->audio_rate);
3780             g_signal_emit_by_name(player, "attribute-changed", ATTRIBUTE_AUDIO_RATE);
3781         }
3782 
3783         if (strstr(mplayer_output->str, "ID_AUDIO_NCH") != 0) {
3784             buf = strstr(mplayer_output->str, "ID_AUDIO_NCH");
3785             sscanf(buf, "ID_AUDIO_NCH=%i", &player->audio_nch);
3786             create_event_int(player, "attribute-changed", ATTRIBUTE_AUDIO_NCH);
3787         }
3788 
3789         if (strstr(mplayer_output->str, "*** screenshot") != 0) {
3790             buf = strstr(mplayer_output->str, "'") + 1;
3791             buf[12] = '\0';
3792             message = g_strdup_printf(g_dgettext(GETTEXT_PACKAGE, "Screenshot saved to '%s'"), buf);
3793             dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO,
3794                                             GTK_BUTTONS_OK, "%s", message);
3795             gtk_window_set_title(GTK_WINDOW(dialog), g_dgettext(GETTEXT_PACKAGE, "GNOME MPlayer Notification"));
3796             gtk_dialog_run(GTK_DIALOG(dialog));
3797             gtk_widget_destroy(dialog);
3798             g_free(message);
3799             message = NULL;
3800         }
3801 
3802         if (strstr(mplayer_output->str, "failed (forgot -vf screenshot?)") != 0) {
3803             dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,
3804                                             GTK_BUTTONS_OK, g_dgettext(GETTEXT_PACKAGE, "Failed to take screenshot"));
3805             gtk_window_set_title(GTK_WINDOW(dialog), g_dgettext(GETTEXT_PACKAGE, "GNOME MPlayer Notification"));
3806             gtk_dialog_run(GTK_DIALOG(dialog));
3807             gtk_widget_destroy(dialog);
3808         }
3809 
3810         if (g_regex_match(player->name_regex, mplayer_output->str, 0, NULL)
3811             && (g_strrstr(mplayer_output->str, "CPU vendor name:") == NULL)) {
3812             gm_logs(player->debug, G_LOG_LEVEL_DEBUG, "recognized movie name - updating UI etc");
3813             split = g_regex_split(player->name_regex, mplayer_output->str, 0);
3814             index = 0;
3815             while (split[index]) {
3816                 if (strlen(split[index]) > 0) {
3817                     if (player->title != NULL) {
3818                         g_free(player->title);
3819                         player->title = NULL;
3820                     }
3821 
3822                     player->title = g_locale_to_utf8(split[index], -1, NULL, NULL, NULL);
3823                     if (player->title == NULL) {
3824                         player->title = g_strdup(split[index]);
3825                         gm_str_strip_unicode(player->title, strlen(player->title));
3826                     }
3827                     player->has_metadata = TRUE;
3828                     create_event_int(player, "attribute-changed", ATTRIBUTE_TITLE);
3829                 }
3830                 index++;
3831             }
3832             g_strfreev(split);
3833         }
3834 
3835         if (g_regex_match(player->genre_regex, mplayer_output->str, 0, NULL)) {
3836             gm_logs(player->debug, G_LOG_LEVEL_DEBUG, "recognized genre - updating UI etc");
3837             split = g_regex_split(player->genre_regex, mplayer_output->str, 0);
3838             index = 0;
3839             while (split[index]) {
3840                 if (strlen(split[index]) > 0) {
3841                     if (player->genre != NULL) {
3842                         g_free(player->genre);
3843                         player->genre = NULL;
3844                     }
3845 
3846                     player->genre = g_locale_to_utf8(split[index], -1, NULL, NULL, NULL);
3847                     if (player->genre == NULL) {
3848                         player->genre = g_strdup(split[index]);
3849                         gm_str_strip_unicode(player->genre, strlen(player->genre));
3850                     }
3851                     player->has_metadata = TRUE;
3852                     create_event_int(player, "attribute-changed", ATTRIBUTE_GENRE);
3853                 }
3854                 index++;
3855             }
3856             g_strfreev(split);
3857         }
3858 
3859         if (g_regex_match(player->title_regex, mplayer_output->str, 0, NULL)) {
3860             gm_logs(player->debug, G_LOG_LEVEL_DEBUG, "recognized title - updating UI etc");
3861             split = g_regex_split(player->title_regex, mplayer_output->str, 0);
3862             index = 0;
3863             while (split[index]) {
3864                 if (strlen(split[index]) > 0) {
3865                     if (player->title != NULL) {
3866                         g_free(player->title);
3867                         player->title = NULL;
3868                     }
3869 
3870                     player->title = g_locale_to_utf8(split[index], -1, NULL, NULL, NULL);
3871                     if (player->title == NULL) {
3872                         player->title = g_strdup(split[index]);
3873                         gm_str_strip_unicode(player->title, strlen(player->title));
3874                     }
3875                     player->has_metadata = TRUE;
3876                     create_event_int(player, "attribute-changed", ATTRIBUTE_TITLE);
3877                 }
3878                 index++;
3879             }
3880             g_strfreev(split);
3881         }
3882 
3883         if (g_regex_match(player->artist_regex, mplayer_output->str, 0, NULL)) {
3884             gm_logs(player->debug, G_LOG_LEVEL_DEBUG, "recognized artist - updating UI etc");
3885             split = g_regex_split(player->artist_regex, mplayer_output->str, 0);
3886             index = 0;
3887             while (split[index]) {
3888                 if (strlen(split[index]) > 0) {
3889                     if (player->artist != NULL) {
3890                         g_free(player->artist);
3891                         player->artist = NULL;
3892                     }
3893 
3894                     player->artist = g_locale_to_utf8(split[index], -1, NULL, NULL, NULL);
3895                     if (player->artist == NULL) {
3896                         player->artist = g_strdup(split[index]);
3897                         gm_str_strip_unicode(player->artist, strlen(player->artist));
3898                     }
3899                     player->has_metadata = TRUE;
3900                     create_event_int(player, "attribute-changed", ATTRIBUTE_ARTIST);
3901                 }
3902                 index++;
3903             }
3904             g_strfreev(split);
3905         }
3906 
3907         if (g_regex_match(player->album_regex, mplayer_output->str, 0, NULL)) {
3908             gm_logs(player->debug, G_LOG_LEVEL_DEBUG, "recognized album - updating UI etc");
3909             split = g_regex_split(player->album_regex, mplayer_output->str, 0);
3910             index = 0;
3911             while (split[index]) {
3912                 if (strlen(split[index]) > 0) {
3913                     if (player->album != NULL) {
3914                         g_free(player->album);
3915                         player->album = NULL;
3916                     }
3917 
3918                     player->album = g_locale_to_utf8(split[index], -1, NULL, NULL, NULL);
3919                     if (player->album == NULL) {
3920                         player->album = g_strdup(split[index]);
3921                         gm_str_strip_unicode(player->album, strlen(player->album));
3922                     }
3923                     player->has_metadata = TRUE;
3924                     create_event_int(player, "attribute-changed", ATTRIBUTE_ALBUM);
3925                 }
3926                 index++;
3927             }
3928             g_strfreev(split);
3929         }
3930 
3931         if (player->minimum_mplayer == FALSE) {
3932             message = g_strdup_printf(g_dgettext(GETTEXT_PACKAGE, "MPlayer should be Upgraded to a Newer Version"));
3933             dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO,
3934                                             GTK_BUTTONS_OK, "%s", message);
3935             gtk_window_set_title(GTK_WINDOW(dialog), g_dgettext(GETTEXT_PACKAGE, "GNOME MPlayer Notification"));
3936             gtk_dialog_run(GTK_DIALOG(dialog));
3937             gtk_widget_destroy(dialog);
3938             g_free(message);
3939             message = NULL;
3940             player->minimum_mplayer = TRUE;
3941         }
3942 
3943         if (strstr(mplayer_output->str, "ICY Info") != NULL) {
3944             buf = strstr(mplayer_output->str, "'");
3945             if (message) {
3946                 g_free(message);
3947                 message = NULL;
3948             }
3949             if (buf != NULL) {
3950                 for (i = 1; i < (int) strlen(buf) - 1; i++) {
3951                     if (!strncmp(&buf[i], "\';", 2)) {
3952                         buf[i] = '\0';
3953                         break;
3954                     }
3955                 }
3956                 if (g_ascii_strcasecmp(buf + 1, " - ") != 0) {
3957                     if (g_utf8_validate(buf + 1, strlen(buf + 1), 0))
3958                         message = g_markup_printf_escaped("<small>\n\t<big><b>%s</b></big>\n</small>", buf + 1);
3959                 }
3960             }
3961             if (message) {
3962                 // reset max values in audio meter
3963                 g_free(message);
3964                 message = g_markup_printf_escaped("\n\t<b>%s</b>\n", buf + 1);
3965                 icy = g_strdup(buf + 1);
3966                 buf = strstr(icy, " - ");
3967                 title = buf + 3;
3968 
3969                 if (buf == NULL) {
3970                     buf = strstr(icy, ":");
3971                     title = buf + 1;
3972                 }
3973 
3974                 if (buf != NULL) {
3975 
3976                     if (player->title)
3977                         g_free(player->title);
3978                     player->title = g_strdup(title);
3979                     create_event_int(player, "attribute-changed", ATTRIBUTE_TITLE);
3980                     buf[0] = '\0';
3981                     if (player->artist)
3982                         g_free(player->artist);
3983                     player->artist = g_strdup(icy);
3984                     create_event_int(player, "attribute-changed", ATTRIBUTE_ARTIST);
3985                     if (player->album)
3986                         g_free(player->album);
3987                     player->album = NULL;
3988                     create_event_int(player, "attribute-changed", ATTRIBUTE_ALBUM);
3989 
3990                 }
3991                 g_free(icy);
3992                 icy = NULL;
3993                 g_free(message);
3994                 message = NULL;
3995             }
3996         }
3997 
3998         if (strstr(mplayer_output->str, "ID_FILENAME") != NULL && player->has_metadata == FALSE) {
3999             buf = g_strrstr(mplayer_output->str, ".");
4000             if (buf)
4001                 buf[0] = '\0';
4002 
4003             buf = g_strrstr(mplayer_output->str, "/");
4004             icy = g_strdup(buf + 1);
4005             buf = strstr(icy, " - ");
4006             title = buf + 3;
4007 
4008             if (buf == NULL) {
4009                 buf = strstr(icy, ":");
4010                 title = buf + 1;
4011             }
4012 
4013             if (buf != NULL) {
4014 
4015                 if (player->title)
4016                     g_free(player->title);
4017                 player->title = g_strdup(title);
4018                 create_event_int(player, "attribute-changed", ATTRIBUTE_TITLE);
4019                 buf[0] = '\0';
4020                 if (player->artist)
4021                     g_free(player->artist);
4022                 player->artist = g_strdup(icy);
4023                 create_event_int(player, "attribute-changed", ATTRIBUTE_ARTIST);
4024                 if (player->album)
4025                     g_free(player->album);
4026                 player->album = NULL;
4027                 create_event_int(player, "attribute-changed", ATTRIBUTE_ALBUM);
4028 
4029             }
4030             g_free(icy);
4031             icy = NULL;
4032             g_free(message);
4033             message = NULL;
4034         }
4035 
4036         if (strstr(mplayer_output->str, "ID_SIGNAL") != 0) {
4037             if (player->position == 0) {
4038                 player->playback_error = ERROR_RETRY;
4039             }
4040         }
4041 
4042     }
4043 
4044     g_string_free(mplayer_output, TRUE);
4045     return TRUE;
4046 }
4047 
4048 // this executes in the main thread
thread_query(gpointer data)4049 gboolean thread_query(gpointer data)
4050 {
4051     GmtkMediaPlayer *player = GMTK_MEDIA_PLAYER(data);
4052     gint written;
4053 
4054     // gm_log(player->debug, G_LOG_LEVEL_DEBUG, "in thread_query, data = %p", data);
4055     if (player == NULL) {
4056         gm_log(player->debug, G_LOG_LEVEL_DEBUG, "thread_query called with player == NULL");
4057         finalize_mplayer(player);
4058         return FALSE;
4059     }
4060 
4061     if (player->player_state == PLAYER_STATE_RUNNING) {
4062         if (player->media_state == MEDIA_STATE_PLAY) {
4063             // gm_log(player->debug, G_LOG_LEVEL_DEBUG, "writing");
4064             if (player->use_mplayer2) {
4065                 written = write(player->std_in, "get_time_pos\n", strlen("get_time_pos\n"));
4066             } else {
4067                 written =
4068                     write(player->std_in, "pausing_keep_force get_time_pos\n",
4069                           strlen("pausing_keep_force get_time_pos\n"));
4070             }
4071             // gm_log(player->debug, G_LOG_LEVEL_DEBUG, "written = %i", written);
4072             if (written == -1) {
4073                 //return TRUE;
4074                 gm_log(player->debug, G_LOG_LEVEL_INFO, "thread_query, write failed");
4075                 return FALSE;
4076             } else {
4077                 return TRUE;
4078             }
4079         } else {
4080             return TRUE;
4081         }
4082     } else {
4083         gm_log(player->debug, G_LOG_LEVEL_DEBUG, "thread_query, player is dead");
4084         finalize_mplayer(player);
4085         return FALSE;
4086     }
4087 }
4088 
write_to_mplayer(GmtkMediaPlayer * player,const gchar * cmd)4089 gboolean write_to_mplayer(GmtkMediaPlayer * player, const gchar * cmd)
4090 {
4091     GIOStatus result;
4092     gsize bytes_written;
4093     gchar *pkf_cmd;
4094 
4095     /* ending \n is part of cmd */
4096     gm_logsp(player->debug, G_LOG_LEVEL_DEBUG, ">", cmd);
4097 
4098     if (player->channel_in) {
4099         if (player->use_mplayer2) {
4100             pkf_cmd = g_strdup(cmd);
4101         } else {
4102             /* if cmd starts with "pause" (non case sensitive) */
4103             if (g_ascii_strncasecmp(cmd, "pause", strlen("pause")) == 0) {
4104                 pkf_cmd = g_strdup(cmd);
4105             } else {
4106                 pkf_cmd = g_strdup_printf("pausing_keep_force %s", cmd);
4107             }
4108         }
4109         result = g_io_channel_write_chars(player->channel_in, pkf_cmd, -1, &bytes_written, NULL);
4110         g_free(pkf_cmd);
4111         if (result != G_IO_STATUS_ERROR && bytes_written > 0) {
4112             result = g_io_channel_flush(player->channel_in, NULL);
4113             return TRUE;
4114         } else {
4115             return FALSE;
4116         }
4117     } else {
4118         return FALSE;
4119     }
4120 
4121 }
4122 
detect_mplayer_features(GmtkMediaPlayer * player)4123 gboolean detect_mplayer_features(GmtkMediaPlayer * player)
4124 {
4125     gchar *av[255];
4126     gint ac = 0, i;
4127     gchar **output;
4128     GError *error;
4129     gint exit_status;
4130     gchar *out = NULL;
4131     gchar *err = NULL;
4132     gboolean ret = TRUE;
4133 
4134     if (player->features_detected)
4135         return ret;
4136 
4137     if (player->mplayer_binary == NULL || !g_file_test(player->mplayer_binary, G_FILE_TEST_EXISTS)) {
4138         av[ac++] = g_strdup_printf("mplayer");
4139     } else {
4140         av[ac++] = g_strdup_printf("%s", player->mplayer_binary);
4141     }
4142     av[ac++] = g_strdup_printf("-noidle");
4143     av[ac++] = g_strdup_printf("-softvol");
4144     av[ac++] = g_strdup_printf("-volume");
4145     av[ac++] = g_strdup_printf("100");
4146     av[ac++] = g_strdup_printf("-nostop-xscreensaver");
4147 
4148     // enable these lines to force newer mplayer
4149     //av[ac++] = g_strdup_printf("-gamma");
4150     //av[ac++] = g_strdup_printf("0");
4151 
4152     av[ac] = NULL;
4153 
4154     error = NULL;
4155 
4156     g_spawn_sync(NULL, av, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &out, &err, &exit_status, &error);
4157 
4158     for (i = 0; i < ac; i++) {
4159         g_free(av[i]);
4160     }
4161 
4162     if (error != NULL) {
4163         gm_log(player->debug, G_LOG_LEVEL_MESSAGE, "Error when running: %s", error->message);
4164         g_error_free(error);
4165         error = NULL;
4166         if (out != NULL) {
4167             g_free(out);
4168             out = NULL;
4169         }
4170         if (err != NULL) {
4171             g_free(err);
4172             err = NULL;
4173         }
4174         return FALSE;
4175     }
4176     output = g_strsplit(out, "\n", 0);
4177     ac = 0;
4178     while (output[ac] != NULL) {
4179         /* if output[ac] starts with "Unknown option" (non case sensitive) */
4180         if (g_ascii_strncasecmp(output[ac], "Unknown option", strlen("Unknown option")) == 0) {
4181             ret = FALSE;
4182         }
4183         /* if output[ac] starts with "MPlayer2" (non case sensitive) */
4184         if (g_ascii_strncasecmp(output[ac], "MPlayer2", strlen("MPlayer2")) == 0) {
4185             player->use_mplayer2 = TRUE;
4186         }
4187         ac++;
4188     }
4189     g_strfreev(output);
4190     g_free(out);
4191     out = NULL;
4192     g_free(err);
4193     err = NULL;
4194 
4195     player->features_detected = TRUE;
4196     if (!ret) {
4197         gm_log(player->debug, G_LOG_LEVEL_MESSAGE,
4198                g_dgettext(GETTEXT_PACKAGE, "You might want to consider upgrading mplayer to a newer version"));
4199     }
4200     return ret;
4201 }
4202