diff --git a/data/icons/region-symbolic.svg b/data/icons/region-symbolic.svg new file mode 100644 index 0000000000000000000000000000000000000000..11ac471a53b3f74c80811533635e35b87c0f0ccb --- /dev/null +++ b/data/icons/region-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/livi-controls.c b/src/livi-controls.c index 98aa994afa0427fe088365dcf8df7c2aaf4c6e0a..470593e7de36c6b845c5b7b58d481eaccae9c194 100644 --- a/src/livi-controls.c +++ b/src/livi-controls.c @@ -35,6 +35,7 @@ struct _LiviControls { /* wide layout */ GtkAdjustment *adj_duration; GtkMenuButton *btn_menu; + GtkMenuButton *btn_lang_menu; GtkButton *btn_play; GtkImage *img_play; GtkButton *btn_mute; @@ -42,11 +43,13 @@ struct _LiviControls { GtkLabel *lbl_time; /* narrow layout */ GtkMenuButton *nrw_btn_menu; + GtkMenuButton *nrw_btn_lang_menu; guint64 duration; guint64 position; GtkPopover *playback_menu; + GtkPopoverMenu *lang_menu; gboolean narrow; }; @@ -66,11 +69,16 @@ set_narrow (LiviControls *self, gboolean narrow) if (narrow) { gtk_menu_button_set_popover (self->btn_menu, NULL); gtk_menu_button_set_popover (self->nrw_btn_menu, GTK_WIDGET (self->playback_menu)); + + gtk_menu_button_set_popover (self->btn_lang_menu, NULL); + gtk_menu_button_set_popover (self->nrw_btn_lang_menu, GTK_WIDGET (self->lang_menu)); } else { gtk_menu_button_set_popover (self->nrw_btn_menu, NULL); gtk_menu_button_set_popover (self->btn_menu, GTK_WIDGET (self->playback_menu)); - } + gtk_menu_button_set_popover (self->nrw_btn_lang_menu, NULL); + gtk_menu_button_set_popover (self->btn_lang_menu, GTK_WIDGET (self->lang_menu)); + } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_NARROW]); } @@ -167,11 +175,14 @@ livi_controls_class_init (LiviControlsClass *klass) gtk_widget_class_bind_template_child (widget_class, LiviControls, adj_duration); gtk_widget_class_bind_template_child (widget_class, LiviControls, btn_menu); gtk_widget_class_bind_template_child (widget_class, LiviControls, btn_mute); + gtk_widget_class_bind_template_child (widget_class, LiviControls, btn_lang_menu); gtk_widget_class_bind_template_child (widget_class, LiviControls, btn_play); gtk_widget_class_bind_template_child (widget_class, LiviControls, img_mute); gtk_widget_class_bind_template_child (widget_class, LiviControls, img_play); + gtk_widget_class_bind_template_child (widget_class, LiviControls, lang_menu); gtk_widget_class_bind_template_child (widget_class, LiviControls, lbl_time); gtk_widget_class_bind_template_child (widget_class, LiviControls, nrw_btn_menu); + gtk_widget_class_bind_template_child (widget_class, LiviControls, nrw_btn_lang_menu); gtk_widget_class_bind_template_child (widget_class, LiviControls, playback_menu); gtk_widget_class_bind_template_child (widget_class, LiviControls, stack); gtk_widget_class_bind_template_callback (widget_class, on_slider_value_changed); @@ -238,3 +249,14 @@ livi_controls_set_play_icon (LiviControls *self, const char *icon_name) g_object_set (self->img_play, "icon-name", icon_name, NULL); } + + +void +livi_controls_set_langs (LiviControls *self, GMenuModel *lang) +{ + g_assert (LIVI_IS_CONTROLS (self)); + g_assert (lang == NULL || G_IS_MENU_MODEL (lang)); + + gtk_popover_menu_set_menu_model (self->lang_menu, lang); + gtk_widget_set_visible (GTK_WIDGET (self->btn_lang_menu), !!lang); +} diff --git a/src/livi-controls.h b/src/livi-controls.h index a985a310b7b2b42a136c52801d55cd7713df53dc..0e56a86110fb88979d9c46b83801447bca599c73 100644 --- a/src/livi-controls.h +++ b/src/livi-controls.h @@ -20,5 +20,6 @@ void livi_controls_set_position (LiviControls *self, guint64 position_n void livi_controls_show_mute_button (LiviControls *self, gboolean show); void livi_controls_set_mute_icon (LiviControls *self, const char *icon_name); void livi_controls_set_play_icon (LiviControls *self, const char *icon_name); +void livi_controls_set_langs (LiviControls *self, GMenuModel *lang); G_END_DECLS diff --git a/src/livi-controls.ui b/src/livi-controls.ui index a62e8e78ee0696c55850f17843fe49eaff7efce2..c8815bd9399c6aa58bcc8cf02b4aa1d7b298bba8 100644 --- a/src/livi-controls.ui +++ b/src/livi-controls.ui @@ -115,18 +115,38 @@ - - up - 64 + - - emblem-system-symbolic - 24 + + + up + 64 + + + region-symbolic + 24 + + + + + + + + up + 64 + + + emblem-system-symbolic + 24 + + + - @@ -149,129 +169,148 @@ 1000 - - horizontal - True - end - 64 - + + horizontal + True + end + 64 + - - horizontal - - - Skip backwards - False - 64 - win.rev - -10000 - - - skip-backwards-10-symbolic - 24 - - - - - - + + horizontal + + + Skip backwards + False + 64 + win.rev + -10000 + + + skip-backwards-10-symbolic + 24 + + + + + + - - Play/Pause - False - 64 - win.toggle-play - - - media-playback-pause-symbolic - 24 - - - - + + Play/Pause + False + 64 + win.toggle-play + + + media-playback-pause-symbolic + 24 + + + + - - - - Skip forward - True - 64 - win.ff - 30000 - - - skip-forward-30-symbolic - 24 - - - - - - - - - - 6 - 6 - True - adj_duration - True - - - - - - 24 - True - False - start - center - 6 - - - - - - Mute - win.mute - 64 - - - audio-volume-muted-symbolic - 24 - - - - - - - - up - 64 - - - emblem-system-symbolic - 24 - - - - - - - + + + + Skip forward + True + 64 + win.ff + 30000 + + + skip-forward-30-symbolic + 24 + + + + + + + + + + 6 + 6 + True + adj_duration + True + + + + + + 24 + True + False + start + center + 6 + + + + + + Mute + win.mute + 64 + + + audio-volume-muted-symbolic + 24 + + + + + + + + + + up + 64 + + + region-symbolic + 24 + + + + + + + + up + 64 + + + emblem-system-symbolic + 24 + + + + + + + + + @@ -290,7 +329,12 @@ 10 + + + vertical @@ -299,6 +343,10 @@ start Speed + diff --git a/src/livi-window.c b/src/livi-window.c index a15f6967067d275db2101df5d9a54586f95a4e99..3e369ed1f3439ad23ede98872952daa764f8eff5 100644 --- a/src/livi-window.c +++ b/src/livi-window.c @@ -65,8 +65,12 @@ struct _LiviWindow GstPlayState state; guint cookie; - gboolean muted; - int playback_speed; + struct { + gboolean muted; + int playback_speed; + guint num_audio_streams; + guint num_subtitle_streams; + } stream; GtkFileFilter *video_filter; char *last_local_uri; @@ -75,18 +79,26 @@ struct _LiviWindow G_DEFINE_TYPE (LiviWindow, livi_window, ADW_TYPE_APPLICATION_WINDOW) +static void +reset_stream (LiviWindow *self) +{ + memset (&self->stream, 0, sizeof (self->stream)); + self->stream.playback_speed = 100; +} + + static void livi_window_set_playback_speed (LiviWindow *self, int percent) { g_debug ("Setting Rate to : %f", percent / 100.0); - if (percent == self->playback_speed) + if (percent == self->stream.playback_speed) return; if (self->player) gst_play_set_rate (self->player, percent / 100.0); - self->playback_speed = percent; + self->stream.playback_speed = percent; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PLAYBACK_SPEED]); } @@ -106,7 +118,7 @@ livi_window_set_property (GObject *object, if (self->player) gst_play_set_mute (self->player, muted); else - self->muted = muted; + self->stream.muted = muted; break; case PROP_PLAYBACK_SPEED: livi_window_set_playback_speed (self, g_value_get_int (value)); @@ -128,10 +140,10 @@ livi_window_get_property (GObject *object, switch (property_id) { case PROP_MUTED: - g_value_set_boolean (value, self->muted); + g_value_set_boolean (value, self->stream.muted); break; case PROP_PLAYBACK_SPEED: - g_value_set_int (value, self->playback_speed); + g_value_set_int (value, self->stream.playback_speed); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -236,6 +248,18 @@ on_toggle_play_activated (GtkWidget *widget, const char *action_name, GVariant } +static void +on_audio_stream_activated (GtkWidget *widget, const char *action_name, GVariant *param) +{ + LiviWindow *self = LIVI_WINDOW (widget); + gint index; + + index = g_variant_get_int32 (param); + + gst_play_set_audio_track (self->player, index); +} + + static void on_file_chooser_done (GObject *object, GAsyncResult *response, gpointer user_data) { @@ -441,10 +465,10 @@ on_player_mute_changed (GstPlaySignalAdapter *adapter, gboolean muted, gpointer g_assert (LIVI_IS_WINDOW (self)); - if (self->muted == muted) + if (self->stream.muted == muted) return; - self->muted = muted; + self->stream.muted = muted; g_debug ("Muted %d", muted); icon = muted ? "audio-volume-medium-symbolic" : "audio-volume-muted-symbolic"; livi_controls_set_mute_icon (self->controls, icon); @@ -475,6 +499,81 @@ on_player_position_updated (GstPlaySignalAdapter *adapter, guint64 position, gpo } +static void +update_audio_streams (LiviWindow *self, GstPlayMediaInfo *info) +{ + g_autoptr (GMenu) menu = NULL; + g_autoptr (GMenu) lang_section = NULL; + g_autoptr (GMenu) subtitles_section = NULL; + guint num_audio_streams, num_subtitle_streams; + GList *streams; + + num_audio_streams = gst_play_media_info_get_number_of_audio_streams (info); + num_subtitle_streams = gst_play_media_info_get_number_of_subtitle_streams (info); + + if (num_audio_streams == self->stream.num_audio_streams && + num_subtitle_streams == self->stream.num_subtitle_streams) { + return; + } + + self->stream.num_audio_streams = num_audio_streams; + self->stream.num_subtitle_streams = num_subtitle_streams; + + if (num_audio_streams >= 2) { + streams = gst_play_media_info_get_audio_streams (info); + lang_section = g_menu_new (); + + for (GList *l = streams; l; l = l->next) { + GstPlayAudioInfo *ai = GST_PLAY_AUDIO_INFO (l->data); + g_autofree char *action = NULL; + const char *lang; + gint index; + + index = gst_play_stream_info_get_index (GST_PLAY_STREAM_INFO (ai)); + if (index < 0) + continue; + + lang = gst_play_audio_info_get_language (ai); + action = g_strdup_printf ("win.audio-stream(%d)", index); + g_menu_insert (lang_section, -1, lang, action); + } + } + + if (num_subtitle_streams) { + streams = gst_play_media_info_get_subtitle_streams (info); + subtitles_section = g_menu_new (); + + for (GList *l = streams; l; l = l->next) { + GstPlaySubtitleInfo *si = GST_PLAY_SUBTITLE_INFO (l->data); + g_autofree char *action = NULL; + const char *lang; + gint index; + + index = gst_play_stream_info_get_index (GST_PLAY_STREAM_INFO (si)); + if (index < 0) + continue; + + lang = gst_play_subtitle_info_get_language (si); + action = g_strdup_printf ("win.subtitle-stream(%d)", index); + g_menu_insert (subtitles_section, -1, lang, action); + } + } + + if (!lang_section && !subtitles_section) { + livi_controls_set_langs (self->controls, NULL); + return; + } + + menu = g_menu_new (); + if (lang_section) + g_menu_insert_section (menu, -1, _("Languages"), G_MENU_MODEL (lang_section)); + if (subtitles_section) + g_menu_insert_section (menu, -1, _("Subtitles"), G_MENU_MODEL (subtitles_section)); + + livi_controls_set_langs (self->controls, G_MENU_MODEL (menu)); +} + + static void on_media_info_updated (GstPlaySignalAdapter *adapter, GstPlayMediaInfo *info, gpointer user_data) { @@ -483,6 +582,7 @@ on_media_info_updated (GstPlaySignalAdapter *adapter, GstPlayMediaInfo *info, gp show = gst_play_media_info_get_number_of_audio_streams (info); + update_audio_streams (self, info); livi_controls_show_mute_button (self->controls, !!show); } @@ -599,6 +699,7 @@ livi_window_class_init (LiviWindowClass *klass) gtk_widget_class_install_action (widget_class, "win.ff", "i", on_ff_rev_activated); gtk_widget_class_install_action (widget_class, "win.rev", "i", on_ff_rev_activated); gtk_widget_class_install_action (widget_class, "win.seek", "i", on_seek_activated); + gtk_widget_class_install_action (widget_class, "win.audio-stream", "i", on_audio_stream_activated); gtk_widget_class_install_action (widget_class, "win.toggle-play", NULL, on_toggle_play_activated); gtk_widget_class_install_action (widget_class, "win.open-file", NULL, on_open_file_activated); @@ -626,7 +727,7 @@ add_controls_toggle (LiviWindow *self, GtkWidget *widget) static void livi_window_init (LiviWindow *self) { - self->playback_speed = 100; + reset_stream (self); gtk_widget_init_template (GTK_WIDGET (self)); @@ -641,6 +742,7 @@ livi_window_init (LiviWindow *self) void livi_window_set_uri (LiviWindow *self, const char *uri) { + reset_stream (self); gtk_stack_set_visible_child (self->stack_content, GTK_WIDGET (self->box_content)); gst_play_set_uri (self->player, uri); } diff --git a/src/livi.gresource.xml b/src/livi.gresource.xml index b4d3e14766aea8b2af592881afc11e1906acf81b..287181d4341bdc3056dec3b72c437b795f87ebaa 100644 --- a/src/livi.gresource.xml +++ b/src/livi.gresource.xml @@ -6,10 +6,11 @@ style.css gtk/help-overlay.ui ../data/org.sigxcpu.Livi.metainfo.xml - ../data/icons/view-restore-symbolic.svg ../data/icons/play-large-symbolic.svg - ../data/icons/speedometer4-symbolic.svg + ../data/icons/view-restore-symbolic.svg ../data/icons/skip-backwards-10-symbolic.svg ../data/icons/skip-forward-30-symbolic.svg + ../data/icons/speedometer4-symbolic.svg + ../data/icons/region-symbolic.svg