diff options
author | TheJackiMonster <thejackimonster@gmail.com> | 2022-12-04 18:40:40 +0100 |
---|---|---|
committer | TheJackiMonster <thejackimonster@gmail.com> | 2022-12-04 18:40:40 +0100 |
commit | 90aeae98ca55fffcfbd598255d62fd258d287e1d (patch) | |
tree | ec07af02efb42721f60fa96424423c162b2fee03 | |
parent | 056af2fb44379238609a2a28ede614ee3c5defed (diff) | |
download | messenger-gtk-90aeae98ca55fffcfbd598255d62fd258d287e1d.tar.gz messenger-gtk-90aeae98ca55fffcfbd598255d62fd258d287e1d.zip |
Implement video playback from local file
Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>
-rw-r--r-- | resources/ui/play_media.ui | 64 | ||||
-rw-r--r-- | src/ui/new_contact.c | 9 | ||||
-rw-r--r-- | src/ui/new_contact.h | 2 | ||||
-rw-r--r-- | src/ui/play_media.c | 354 | ||||
-rw-r--r-- | src/ui/play_media.h | 18 |
5 files changed, 433 insertions, 14 deletions
diff --git a/resources/ui/play_media.ui b/resources/ui/play_media.ui index 9e485df..ca1a1cf 100644 --- a/resources/ui/play_media.ui +++ b/resources/ui/play_media.ui | |||
@@ -25,7 +25,7 @@ Author: Tobias Frisch | |||
25 | <requires lib="libhandy" version="1.2"/> | 25 | <requires lib="libhandy" version="1.2"/> |
26 | <object class="HdyWindow" id="play_media_window"> | 26 | <object class="HdyWindow" id="play_media_window"> |
27 | <property name="width-request">250</property> | 27 | <property name="width-request">250</property> |
28 | <property name="height-request">180</property> | 28 | <property name="height-request">250</property> |
29 | <property name="can-focus">False</property> | 29 | <property name="can-focus">False</property> |
30 | <property name="modal">True</property> | 30 | <property name="modal">True</property> |
31 | <property name="window-position">center-on-parent</property> | 31 | <property name="window-position">center-on-parent</property> |
@@ -82,11 +82,64 @@ Author: Tobias Frisch | |||
82 | <property name="flap-position">end</property> | 82 | <property name="flap-position">end</property> |
83 | <property name="modal">False</property> | 83 | <property name="modal">False</property> |
84 | <child type="content"> | 84 | <child type="content"> |
85 | <object class="GtkImage"> | 85 | <object class="GtkStack" id="preview_stack"> |
86 | <property name="visible">True</property> | 86 | <property name="visible">True</property> |
87 | <property name="can-focus">False</property> | 87 | <property name="can-focus">False</property> |
88 | <property name="icon-name">folder-videos-symbolic</property> | 88 | <child> |
89 | <property name="icon_size">6</property> | 89 | <object class="GtkBox" id="video_box"> |
90 | <property name="visible">True</property> | ||
91 | <property name="can-focus">False</property> | ||
92 | <property name="orientation">vertical</property> | ||
93 | <child> | ||
94 | <placeholder/> | ||
95 | </child> | ||
96 | </object> | ||
97 | <packing> | ||
98 | <property name="name">page0</property> | ||
99 | <property name="title" translatable="yes">page0</property> | ||
100 | </packing> | ||
101 | </child> | ||
102 | <child> | ||
103 | <object class="GtkBox" id="fail_box"> | ||
104 | <property name="visible">True</property> | ||
105 | <property name="can-focus">False</property> | ||
106 | <property name="halign">center</property> | ||
107 | <property name="valign">center</property> | ||
108 | <property name="orientation">vertical</property> | ||
109 | <property name="spacing">8</property> | ||
110 | <child> | ||
111 | <object class="GtkImage"> | ||
112 | <property name="visible">True</property> | ||
113 | <property name="can-focus">False</property> | ||
114 | <property name="pixel-size">64</property> | ||
115 | <property name="icon-name">action-unavailable-symbolic</property> | ||
116 | <property name="icon_size">3</property> | ||
117 | </object> | ||
118 | <packing> | ||
119 | <property name="expand">False</property> | ||
120 | <property name="fill">True</property> | ||
121 | <property name="position">0</property> | ||
122 | </packing> | ||
123 | </child> | ||
124 | <child> | ||
125 | <object class="GtkLabel"> | ||
126 | <property name="visible">True</property> | ||
127 | <property name="can-focus">False</property> | ||
128 | <property name="label" translatable="yes">Video source invalid!</property> | ||
129 | </object> | ||
130 | <packing> | ||
131 | <property name="expand">False</property> | ||
132 | <property name="fill">True</property> | ||
133 | <property name="position">1</property> | ||
134 | </packing> | ||
135 | </child> | ||
136 | </object> | ||
137 | <packing> | ||
138 | <property name="name">page1</property> | ||
139 | <property name="title" translatable="yes">page1</property> | ||
140 | <property name="position">1</property> | ||
141 | </packing> | ||
142 | </child> | ||
90 | </object> | 143 | </object> |
91 | </child> | 144 | </child> |
92 | <child type="separator"> | 145 | <child type="separator"> |
@@ -109,6 +162,7 @@ Author: Tobias Frisch | |||
109 | <child> | 162 | <child> |
110 | <object class="GtkButton" id="play_pause_button"> | 163 | <object class="GtkButton" id="play_pause_button"> |
111 | <property name="visible">True</property> | 164 | <property name="visible">True</property> |
165 | <property name="sensitive">False</property> | ||
112 | <property name="can-focus">True</property> | 166 | <property name="can-focus">True</property> |
113 | <property name="receives-default">True</property> | 167 | <property name="receives-default">True</property> |
114 | <property name="relief">none</property> | 168 | <property name="relief">none</property> |
@@ -119,6 +173,7 @@ Author: Tobias Frisch | |||
119 | <child> | 173 | <child> |
120 | <object class="GtkImage"> | 174 | <object class="GtkImage"> |
121 | <property name="visible">True</property> | 175 | <property name="visible">True</property> |
176 | <property name="sensitive">False</property> | ||
122 | <property name="can-focus">False</property> | 177 | <property name="can-focus">False</property> |
123 | <property name="icon-name">media-playback-start-symbolic</property> | 178 | <property name="icon-name">media-playback-start-symbolic</property> |
124 | </object> | 179 | </object> |
@@ -149,6 +204,7 @@ Author: Tobias Frisch | |||
149 | <child> | 204 | <child> |
150 | <object class="GtkVolumeButton" id="volume_button"> | 205 | <object class="GtkVolumeButton" id="volume_button"> |
151 | <property name="visible">True</property> | 206 | <property name="visible">True</property> |
207 | <property name="sensitive">False</property> | ||
152 | <property name="can-focus">True</property> | 208 | <property name="can-focus">True</property> |
153 | <property name="focus-on-click">False</property> | 209 | <property name="focus-on-click">False</property> |
154 | <property name="receives-default">True</property> | 210 | <property name="receives-default">True</property> |
diff --git a/src/ui/new_contact.c b/src/ui/new_contact.c index 562219e..90bb4b6 100644 --- a/src/ui/new_contact.c +++ b/src/ui/new_contact.c | |||
@@ -76,7 +76,10 @@ static void | |||
76 | _disable_video_processing(UI_NEW_CONTACT_Handle *handle, | 76 | _disable_video_processing(UI_NEW_CONTACT_Handle *handle, |
77 | gboolean drop_pipeline) | 77 | gboolean drop_pipeline) |
78 | { | 78 | { |
79 | gtk_stack_set_visible_child(handle->preview_stack, handle->fail_box); | 79 | GNUNET_assert(handle); |
80 | |||
81 | if (handle->preview_stack) | ||
82 | gtk_stack_set_visible_child(handle->preview_stack, handle->fail_box); | ||
80 | 83 | ||
81 | if ((!(handle->pipeline)) || (!drop_pipeline)) | 84 | if ((!(handle->pipeline)) || (!drop_pipeline)) |
82 | return; | 85 | return; |
@@ -252,6 +255,8 @@ void | |||
252 | ui_new_contact_dialog_init(MESSENGER_Application *app, | 255 | ui_new_contact_dialog_init(MESSENGER_Application *app, |
253 | UI_NEW_CONTACT_Handle *handle) | 256 | UI_NEW_CONTACT_Handle *handle) |
254 | { | 257 | { |
258 | GNUNET_assert((app) && (handle)); | ||
259 | |||
255 | _setup_gst_pipeline(handle); | 260 | _setup_gst_pipeline(handle); |
256 | 261 | ||
257 | pthread_create( | 262 | pthread_create( |
@@ -345,6 +350,8 @@ ui_new_contact_dialog_init(MESSENGER_Application *app, | |||
345 | void | 350 | void |
346 | ui_new_contact_dialog_cleanup(UI_NEW_CONTACT_Handle *handle) | 351 | ui_new_contact_dialog_cleanup(UI_NEW_CONTACT_Handle *handle) |
347 | { | 352 | { |
353 | GNUNET_assert(handle); | ||
354 | |||
348 | pthread_join(handle->video_tid, NULL); | 355 | pthread_join(handle->video_tid, NULL); |
349 | 356 | ||
350 | g_object_unref(handle->builder); | 357 | g_object_unref(handle->builder); |
diff --git a/src/ui/new_contact.h b/src/ui/new_contact.h index 74c2ff4..f9d2a64 100644 --- a/src/ui/new_contact.h +++ b/src/ui/new_contact.h | |||
@@ -39,8 +39,6 @@ typedef struct UI_NEW_CONTACT_Handle | |||
39 | GstElement *scanner; | 39 | GstElement *scanner; |
40 | GstElement *sink; | 40 | GstElement *sink; |
41 | 41 | ||
42 | guint bus_watch; | ||
43 | |||
44 | GtkBuilder *builder; | 42 | GtkBuilder *builder; |
45 | GtkDialog *dialog; | 43 | GtkDialog *dialog; |
46 | 44 | ||
diff --git a/src/ui/play_media.c b/src/ui/play_media.c index dc41a3e..5dbfdec 100644 --- a/src/ui/play_media.c +++ b/src/ui/play_media.c | |||
@@ -27,6 +27,8 @@ | |||
27 | #include "../application.h" | 27 | #include "../application.h" |
28 | #include "../ui.h" | 28 | #include "../ui.h" |
29 | 29 | ||
30 | #include <gst/gst.h> | ||
31 | |||
30 | static void | 32 | static void |
31 | handle_back_button_click(GtkButton *button, | 33 | handle_back_button_click(GtkButton *button, |
32 | gpointer user_data) | 34 | gpointer user_data) |
@@ -36,19 +38,131 @@ handle_back_button_click(GtkButton *button, | |||
36 | } | 38 | } |
37 | 39 | ||
38 | static void | 40 | static void |
41 | _disable_video_processing(UI_PLAY_MEDIA_Handle *handle, | ||
42 | gboolean drop_pipeline) | ||
43 | { | ||
44 | GNUNET_assert(handle); | ||
45 | |||
46 | if (handle->preview_stack) | ||
47 | gtk_stack_set_visible_child(handle->preview_stack, handle->fail_box); | ||
48 | |||
49 | if ((!(handle->pipeline)) || (!drop_pipeline)) | ||
50 | return; | ||
51 | |||
52 | gst_element_set_state(handle->pipeline, GST_STATE_NULL); | ||
53 | } | ||
54 | |||
55 | static gboolean | ||
56 | _adjust_playing_media_position(UI_PLAY_MEDIA_Handle *handle) | ||
57 | { | ||
58 | gint64 pos, len; | ||
59 | |||
60 | if (!(handle->pipeline)) | ||
61 | return FALSE; | ||
62 | |||
63 | if (!gst_element_query_position(handle->pipeline, GST_FORMAT_TIME, &pos)) | ||
64 | return FALSE; | ||
65 | |||
66 | if (!gst_element_query_duration(handle->pipeline, GST_FORMAT_TIME, &len)) | ||
67 | return FALSE; | ||
68 | |||
69 | if (handle->timeline_label) | ||
70 | { | ||
71 | GString *str = g_string_new(NULL); | ||
72 | |||
73 | guint pos_seconds = GST_TIME_AS_SECONDS(pos); | ||
74 | guint len_seconds = GST_TIME_AS_SECONDS(len); | ||
75 | |||
76 | g_string_append_printf( | ||
77 | str, | ||
78 | "%u:%02u / %u:%02u", | ||
79 | pos_seconds / 60, | ||
80 | pos_seconds % 60, | ||
81 | len_seconds / 60, | ||
82 | len_seconds % 60 | ||
83 | ); | ||
84 | |||
85 | ui_label_set_text(handle->timeline_label, str->str); | ||
86 | g_string_free(str, TRUE); | ||
87 | } | ||
88 | |||
89 | if (handle->timeline_progress_bar) | ||
90 | gtk_progress_bar_set_fraction( | ||
91 | handle->timeline_progress_bar, | ||
92 | 1.0 * pos / len | ||
93 | ); | ||
94 | |||
95 | return TRUE; | ||
96 | } | ||
97 | |||
98 | static void | ||
99 | _adjust_playing_media_state(UI_PLAY_MEDIA_Handle *handle, | ||
100 | gboolean playing) | ||
101 | { | ||
102 | handle->playing = playing; | ||
103 | |||
104 | if (!(handle->play_symbol_stack)) | ||
105 | return; | ||
106 | |||
107 | gtk_stack_set_visible_child_name( | ||
108 | handle->play_symbol_stack, | ||
109 | handle->playing? "pause_page" : "play_page" | ||
110 | ); | ||
111 | |||
112 | if (handle->timeline) | ||
113 | g_source_remove(handle->timeline); | ||
114 | |||
115 | if (handle->playing) | ||
116 | handle->timeline = g_timeout_add( | ||
117 | 1000, | ||
118 | G_SOURCE_FUNC(_adjust_playing_media_position), | ||
119 | handle | ||
120 | ); | ||
121 | else | ||
122 | handle->timeline = 0; | ||
123 | |||
124 | gtk_widget_set_sensitive(GTK_WIDGET(handle->play_pause_button), TRUE); | ||
125 | |||
126 | gtk_stack_set_visible_child( | ||
127 | handle->preview_stack, | ||
128 | handle->video_box | ||
129 | ); | ||
130 | } | ||
131 | |||
132 | static void | ||
39 | _pause_playing_media(UI_PLAY_MEDIA_Handle *handle) | 133 | _pause_playing_media(UI_PLAY_MEDIA_Handle *handle) |
40 | { | 134 | { |
41 | // | 135 | if (!(handle->pipeline)) |
136 | _adjust_playing_media_state(handle, FALSE); | ||
42 | 137 | ||
43 | handle->playing = FALSE; | 138 | GstStateChangeReturn ret = gst_element_set_state( |
139 | handle->pipeline, | ||
140 | GST_STATE_PAUSED | ||
141 | ); | ||
142 | |||
143 | if (GST_STATE_CHANGE_FAILURE == ret) | ||
144 | { | ||
145 | _disable_video_processing(handle, TRUE); | ||
146 | return; | ||
147 | } | ||
44 | } | 148 | } |
45 | 149 | ||
46 | static void | 150 | static void |
47 | _continue_playing_media(UI_PLAY_MEDIA_Handle *handle) | 151 | _continue_playing_media(UI_PLAY_MEDIA_Handle *handle) |
48 | { | 152 | { |
49 | // | 153 | if (!(handle->pipeline)) |
154 | _adjust_playing_media_state(handle, TRUE); | ||
50 | 155 | ||
51 | handle->playing = TRUE; | 156 | GstStateChangeReturn ret = gst_element_set_state( |
157 | handle->pipeline, | ||
158 | GST_STATE_PLAYING | ||
159 | ); | ||
160 | |||
161 | if (GST_STATE_CHANGE_FAILURE == ret) | ||
162 | { | ||
163 | _disable_video_processing(handle, TRUE); | ||
164 | return; | ||
165 | } | ||
52 | } | 166 | } |
53 | 167 | ||
54 | static void | 168 | static void |
@@ -57,14 +171,36 @@ handle_play_pause_button_click(GtkButton *button, | |||
57 | { | 171 | { |
58 | UI_PLAY_MEDIA_Handle *handle = (UI_PLAY_MEDIA_Handle*) user_data; | 172 | UI_PLAY_MEDIA_Handle *handle = (UI_PLAY_MEDIA_Handle*) user_data; |
59 | 173 | ||
174 | gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE); | ||
175 | |||
60 | if (handle->playing) | 176 | if (handle->playing) |
61 | _pause_playing_media(handle); | 177 | _pause_playing_media(handle); |
62 | else | 178 | else |
63 | _continue_playing_media(handle); | 179 | _continue_playing_media(handle); |
180 | } | ||
64 | 181 | ||
65 | gtk_stack_set_visible_child_name( | 182 | static void |
66 | handle->play_symbol_stack, | 183 | handle_volume_button_value_changed(GtkScaleButton *button, |
67 | handle->playing? "pause_page" : "play_page" | 184 | double value, |
185 | gpointer user_data) | ||
186 | { | ||
187 | UI_PLAY_MEDIA_Handle *handle = (UI_PLAY_MEDIA_Handle*) user_data; | ||
188 | |||
189 | if (!(handle->vol)) | ||
190 | return; | ||
191 | |||
192 | g_object_set( | ||
193 | G_OBJECT(handle->vol), | ||
194 | "volume", | ||
195 | value, | ||
196 | NULL | ||
197 | ); | ||
198 | |||
199 | g_object_set( | ||
200 | G_OBJECT(handle->vol), | ||
201 | "mute", | ||
202 | (value <= 0.0), | ||
203 | NULL | ||
68 | ); | 204 | ); |
69 | } | 205 | } |
70 | 206 | ||
@@ -157,12 +293,155 @@ handle_window_destroy(UNUSED GtkWidget *window, | |||
157 | ui_play_media_window_cleanup((UI_PLAY_MEDIA_Handle*) user_data); | 293 | ui_play_media_window_cleanup((UI_PLAY_MEDIA_Handle*) user_data); |
158 | } | 294 | } |
159 | 295 | ||
296 | static void | ||
297 | msg_error_cb(UNUSED GstBus *bus, | ||
298 | GstMessage *msg, | ||
299 | gpointer *data) | ||
300 | { | ||
301 | UI_PLAY_MEDIA_Handle *handle = (UI_PLAY_MEDIA_Handle*) data; | ||
302 | |||
303 | GError* error; | ||
304 | gst_message_parse_error(msg, &error, NULL); | ||
305 | |||
306 | if (!error) | ||
307 | fprintf(stderr, "ERROR: Unknown error\n"); | ||
308 | else if (error->message) | ||
309 | fprintf(stderr, "ERROR: %s (%d)\n", error->message, error->code); | ||
310 | else | ||
311 | fprintf(stderr, "ERROR: Unknown error (%d)\n", error->code); | ||
312 | |||
313 | _disable_video_processing(handle, TRUE); | ||
314 | } | ||
315 | |||
316 | static void | ||
317 | msg_eos_cb(UNUSED GstBus *bus, | ||
318 | UNUSED GstMessage *msg, | ||
319 | gpointer *data) | ||
320 | { | ||
321 | UI_PLAY_MEDIA_Handle *handle = (UI_PLAY_MEDIA_Handle*) data; | ||
322 | |||
323 | if (GST_MESSAGE_SRC(msg) == GST_OBJECT(handle->pipeline)) | ||
324 | _adjust_playing_media_state(handle, FALSE); | ||
325 | } | ||
326 | |||
327 | static void | ||
328 | msg_state_changed_cb(UNUSED GstBus *bus, | ||
329 | GstMessage *msg, | ||
330 | gpointer *data) | ||
331 | { | ||
332 | UI_PLAY_MEDIA_Handle *handle = (UI_PLAY_MEDIA_Handle*) data; | ||
333 | |||
334 | GstState old_state, new_state, pending_state; | ||
335 | gst_message_parse_state_changed(msg, &old_state, &new_state, &pending_state); | ||
336 | |||
337 | if ((GST_MESSAGE_SRC(msg) != GST_OBJECT(handle->pipeline)) || | ||
338 | (new_state == old_state) || (!(handle->preview_stack))) | ||
339 | return; | ||
340 | |||
341 | if (!(handle->sink)) | ||
342 | _disable_video_processing(handle, FALSE); | ||
343 | else if (GST_STATE_PLAYING == new_state) | ||
344 | _adjust_playing_media_state(handle, TRUE); | ||
345 | else if (GST_STATE_PAUSED == new_state) | ||
346 | _adjust_playing_media_state(handle, FALSE); | ||
347 | } | ||
348 | |||
349 | static void | ||
350 | _setup_gst_pipeline(UI_PLAY_MEDIA_Handle *handle) | ||
351 | { | ||
352 | handle->pipeline = gst_parse_launch( | ||
353 | "filesrc name=source" | ||
354 | " ! decodebin name=decode" | ||
355 | " ! videoconvert ! video/x-raw,format=RGB" | ||
356 | " ! videoconvert ! gtksink name=vsink decode." | ||
357 | " ! audioconvert ! audioresample" | ||
358 | " ! volume name=vol ! autoaudiosink", | ||
359 | NULL | ||
360 | ); | ||
361 | |||
362 | if (!(handle->pipeline)) | ||
363 | return; | ||
364 | |||
365 | handle->source = gst_bin_get_by_name( | ||
366 | GST_BIN(handle->pipeline), "source" | ||
367 | ); | ||
368 | |||
369 | g_object_set( | ||
370 | G_OBJECT(handle->source), | ||
371 | "location", | ||
372 | "", // absolute path to video file | ||
373 | NULL | ||
374 | ); | ||
375 | |||
376 | handle->decode = gst_bin_get_by_name( | ||
377 | GST_BIN(handle->pipeline), "decode" | ||
378 | ); | ||
379 | |||
380 | handle->sink = gst_bin_get_by_name( | ||
381 | GST_BIN(handle->pipeline), "vsink" | ||
382 | ); | ||
383 | |||
384 | handle->vol = gst_bin_get_by_name( | ||
385 | GST_BIN(handle->pipeline), "vol" | ||
386 | ); | ||
387 | |||
388 | GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(handle->pipeline)); | ||
389 | |||
390 | if (!bus) | ||
391 | return; | ||
392 | |||
393 | gst_bus_add_signal_watch(bus); | ||
394 | |||
395 | g_signal_connect( | ||
396 | G_OBJECT(bus), | ||
397 | "message::error", | ||
398 | (GCallback) msg_error_cb, | ||
399 | handle | ||
400 | ); | ||
401 | |||
402 | g_signal_connect( | ||
403 | G_OBJECT(bus), | ||
404 | "message::eos", | ||
405 | (GCallback) msg_eos_cb, | ||
406 | handle | ||
407 | ); | ||
408 | |||
409 | g_signal_connect( | ||
410 | G_OBJECT(bus), | ||
411 | "message::state-changed", | ||
412 | (GCallback) msg_state_changed_cb, | ||
413 | handle | ||
414 | ); | ||
415 | |||
416 | gst_object_unref(bus); | ||
417 | } | ||
418 | |||
419 | static void* | ||
420 | _ui_play_media_video_thread(void *args) | ||
421 | { | ||
422 | UI_PLAY_MEDIA_Handle *handle = (UI_PLAY_MEDIA_Handle*) args; | ||
423 | |||
424 | if (!handle->playing) | ||
425 | _continue_playing_media(handle); | ||
426 | |||
427 | return NULL; | ||
428 | } | ||
429 | |||
160 | void | 430 | void |
161 | ui_play_media_window_init(MESSENGER_Application *app, | 431 | ui_play_media_window_init(MESSENGER_Application *app, |
162 | UI_PLAY_MEDIA_Handle *handle) | 432 | UI_PLAY_MEDIA_Handle *handle) |
163 | { | 433 | { |
164 | GNUNET_assert((app) && (handle)); | 434 | GNUNET_assert((app) && (handle)); |
165 | 435 | ||
436 | _setup_gst_pipeline(handle); | ||
437 | |||
438 | pthread_create( | ||
439 | &(handle->video_tid), | ||
440 | NULL, | ||
441 | _ui_play_media_video_thread, | ||
442 | handle | ||
443 | ); | ||
444 | |||
166 | handle->parent = GTK_WINDOW(app->ui.messenger.main_window); | 445 | handle->parent = GTK_WINDOW(app->ui.messenger.main_window); |
167 | 446 | ||
168 | handle->builder = gtk_builder_new_from_resource( | 447 | handle->builder = gtk_builder_new_from_resource( |
@@ -208,6 +487,40 @@ ui_play_media_window_init(MESSENGER_Application *app, | |||
208 | gtk_builder_get_object(handle->builder, "controls_flap") | 487 | gtk_builder_get_object(handle->builder, "controls_flap") |
209 | ); | 488 | ); |
210 | 489 | ||
490 | handle->preview_stack = GTK_STACK( | ||
491 | gtk_builder_get_object(handle->builder, "preview_stack") | ||
492 | ); | ||
493 | |||
494 | handle->fail_box = GTK_WIDGET( | ||
495 | gtk_builder_get_object(handle->builder, "fail_box") | ||
496 | ); | ||
497 | |||
498 | handle->video_box = GTK_WIDGET( | ||
499 | gtk_builder_get_object(handle->builder, "video_box") | ||
500 | ); | ||
501 | |||
502 | GtkWidget *widget; | ||
503 | if (handle->sink) | ||
504 | g_object_get(handle->sink, "widget", &widget, NULL); | ||
505 | else | ||
506 | widget = NULL; | ||
507 | |||
508 | if (widget) | ||
509 | { | ||
510 | gtk_box_pack_start( | ||
511 | GTK_BOX(handle->video_box), | ||
512 | widget, | ||
513 | true, | ||
514 | true, | ||
515 | 0 | ||
516 | ); | ||
517 | |||
518 | g_object_unref(widget); | ||
519 | gtk_widget_realize(widget); | ||
520 | |||
521 | gtk_widget_show_all(handle->video_box); | ||
522 | } | ||
523 | |||
211 | handle->play_pause_button = GTK_BUTTON( | 524 | handle->play_pause_button = GTK_BUTTON( |
212 | gtk_builder_get_object(handle->builder, "play_pause_button") | 525 | gtk_builder_get_object(handle->builder, "play_pause_button") |
213 | ); | 526 | ); |
@@ -227,10 +540,21 @@ ui_play_media_window_init(MESSENGER_Application *app, | |||
227 | gtk_builder_get_object(handle->builder, "volume_button") | 540 | gtk_builder_get_object(handle->builder, "volume_button") |
228 | ); | 541 | ); |
229 | 542 | ||
543 | g_signal_connect( | ||
544 | handle->volume_button, | ||
545 | "value-changed", | ||
546 | G_CALLBACK(handle_volume_button_value_changed), | ||
547 | handle | ||
548 | ); | ||
549 | |||
230 | handle->timeline_label = GTK_LABEL( | 550 | handle->timeline_label = GTK_LABEL( |
231 | gtk_builder_get_object(handle->builder, "timeline_label") | 551 | gtk_builder_get_object(handle->builder, "timeline_label") |
232 | ); | 552 | ); |
233 | 553 | ||
554 | handle->timeline_progress_bar = GTK_PROGRESS_BAR( | ||
555 | gtk_builder_get_object(handle->builder, "timeline_progress_bar") | ||
556 | ); | ||
557 | |||
234 | handle->settings_button = GTK_BUTTON( | 558 | handle->settings_button = GTK_BUTTON( |
235 | gtk_builder_get_object(handle->builder, "settings_button") | 559 | gtk_builder_get_object(handle->builder, "settings_button") |
236 | ); | 560 | ); |
@@ -270,6 +594,11 @@ ui_play_media_window_init(MESSENGER_Application *app, | |||
270 | handle | 594 | handle |
271 | ); | 595 | ); |
272 | 596 | ||
597 | gtk_scale_button_set_value( | ||
598 | GTK_SCALE_BUTTON(handle->volume_button), | ||
599 | 1.0 | ||
600 | ); | ||
601 | |||
273 | gtk_widget_show_all(GTK_WIDGET(handle->window)); | 602 | gtk_widget_show_all(GTK_WIDGET(handle->window)); |
274 | } | 603 | } |
275 | 604 | ||
@@ -278,10 +607,21 @@ ui_play_media_window_cleanup(UI_PLAY_MEDIA_Handle *handle) | |||
278 | { | 607 | { |
279 | GNUNET_assert(handle); | 608 | GNUNET_assert(handle); |
280 | 609 | ||
610 | pthread_join(handle->video_tid, NULL); | ||
611 | |||
281 | g_object_unref(handle->builder); | 612 | g_object_unref(handle->builder); |
282 | 613 | ||
614 | if (handle->timeline) | ||
615 | g_source_remove(handle->timeline); | ||
616 | |||
283 | if (handle->motion_lost) | 617 | if (handle->motion_lost) |
284 | g_source_remove(handle->motion_lost); | 618 | g_source_remove(handle->motion_lost); |
285 | 619 | ||
620 | if (handle->pipeline) | ||
621 | { | ||
622 | gst_element_set_state(handle->pipeline, GST_STATE_NULL); | ||
623 | gst_object_unref(GST_OBJECT(handle->pipeline)); | ||
624 | } | ||
625 | |||
286 | memset(handle, 0, sizeof(*handle)); | 626 | memset(handle, 0, sizeof(*handle)); |
287 | } | 627 | } |
diff --git a/src/ui/play_media.h b/src/ui/play_media.h index 29f8d1a..597bf7c 100644 --- a/src/ui/play_media.h +++ b/src/ui/play_media.h | |||
@@ -27,11 +27,20 @@ | |||
27 | 27 | ||
28 | #include "messenger.h" | 28 | #include "messenger.h" |
29 | 29 | ||
30 | #include <gstreamer-1.0/gst/gst.h> | ||
31 | #include <pthread.h> | ||
32 | |||
30 | typedef struct UI_PLAY_MEDIA_Handle | 33 | typedef struct UI_PLAY_MEDIA_Handle |
31 | { | 34 | { |
32 | gboolean playing; | 35 | gboolean playing; |
33 | gboolean fullscreen; | 36 | gboolean fullscreen; |
34 | 37 | ||
38 | GstElement *pipeline; | ||
39 | GstElement *source; | ||
40 | GstElement *decode; | ||
41 | GstElement *sink; | ||
42 | GstElement *vol; | ||
43 | |||
35 | GtkWindow *parent; | 44 | GtkWindow *parent; |
36 | 45 | ||
37 | GtkBuilder *builder; | 46 | GtkBuilder *builder; |
@@ -42,18 +51,27 @@ typedef struct UI_PLAY_MEDIA_Handle | |||
42 | GtkButton *back_button; | 51 | GtkButton *back_button; |
43 | 52 | ||
44 | HdyFlap *controls_flap; | 53 | HdyFlap *controls_flap; |
54 | |||
55 | GtkStack *preview_stack; | ||
56 | GtkWidget *fail_box; | ||
57 | GtkWidget *video_box; | ||
58 | |||
45 | GtkButton *play_pause_button; | 59 | GtkButton *play_pause_button; |
46 | GtkStack *play_symbol_stack; | 60 | GtkStack *play_symbol_stack; |
47 | 61 | ||
48 | GtkVolumeButton *volume_button; | 62 | GtkVolumeButton *volume_button; |
49 | GtkLabel *timeline_label; | 63 | GtkLabel *timeline_label; |
64 | GtkProgressBar *timeline_progress_bar; | ||
50 | 65 | ||
51 | GtkButton *settings_button; | 66 | GtkButton *settings_button; |
52 | 67 | ||
53 | GtkButton *fullscreen_button; | 68 | GtkButton *fullscreen_button; |
54 | GtkStack *fullscreen_symbol_stack; | 69 | GtkStack *fullscreen_symbol_stack; |
55 | 70 | ||
71 | guint timeline; | ||
56 | guint motion_lost; | 72 | guint motion_lost; |
73 | |||
74 | pthread_t video_tid; | ||
57 | } UI_PLAY_MEDIA_Handle; | 75 | } UI_PLAY_MEDIA_Handle; |
58 | 76 | ||
59 | /** | 77 | /** |