summaryrefslogtreecommitdiff
path: root/audio-video-properties/totem-properties-view.c
diff options
context:
space:
mode:
authorrbuj <[email protected]>2022-07-31 20:58:57 +0200
committerLuke from DC <[email protected]>2022-08-04 19:26:40 +0000
commite9d03be8a4a23c411df1a5a2c6fb2284dd5df22f (patch)
treeb039f264e84588f6117874aa704eb7862e9cf3b2 /audio-video-properties/totem-properties-view.c
parentf3f8f9615ef9e2a4e255e4eac7e481a7253be54f (diff)
downloadcaja-extensions-e9d03be8a4a23c411df1a5a2c6fb2284dd5df22f.tar.bz2
caja-extensions-e9d03be8a4a23c411df1a5a2c6fb2284dd5df22f.tar.xz
add audio-video-properties plugin
Diffstat (limited to 'audio-video-properties/totem-properties-view.c')
-rw-r--r--audio-video-properties/totem-properties-view.c389
1 files changed, 389 insertions, 0 deletions
diff --git a/audio-video-properties/totem-properties-view.c b/audio-video-properties/totem-properties-view.c
new file mode 100644
index 0000000..8bae081
--- /dev/null
+++ b/audio-video-properties/totem-properties-view.c
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) 2003 Andrew Sobala <[email protected]>
+ * Copyright (C) 2004 Bastien Nocera <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <config.h>
+
+#include <gtk/gtk.h>
+#include <glib/gi18n-lib.h>
+
+#define GST_USE_UNSTABLE_API 1
+#include <gst/tag/tag.h>
+#include <gst/pbutils/pbutils.h>
+
+#include "totem-properties-view.h"
+#include "bacon-video-widget-properties.h"
+
+struct TotemPropertiesViewPriv {
+ GtkWidget *label;
+ GtkWidget *vbox;
+ BaconVideoWidgetProperties *props;
+ GstDiscoverer *disco;
+};
+
+static GObjectClass *parent_class = NULL;
+static void totem_properties_view_finalize (GObject *object);
+
+G_DEFINE_TYPE (TotemPropertiesView, totem_properties_view, GTK_TYPE_GRID)
+
+void
+totem_properties_view_register_type (GTypeModule *module)
+{
+ totem_properties_view_get_type ();
+}
+
+static void
+totem_properties_view_class_init (TotemPropertiesViewClass *class)
+{
+ parent_class = g_type_class_peek_parent (class);
+ G_OBJECT_CLASS (class)->finalize = totem_properties_view_finalize;
+}
+
+static void
+update_general (TotemPropertiesView *props,
+ const GstTagList *list)
+{
+ struct {
+ const char *tag_name;
+ const char *widget;
+ } items[] = {
+ { GST_TAG_TITLE, "title" },
+ { GST_TAG_ARTIST, "artist" },
+ { GST_TAG_ALBUM, "album" },
+ };
+ guint i;
+ GDate *date;
+ GstDateTime *datetime;
+ gchar *comment;
+
+ for (i = 0; i < G_N_ELEMENTS(items); i++) {
+ char *string;
+
+ if (gst_tag_list_get_string_index (list, items[i].tag_name, 0, &string) != FALSE) {
+ bacon_video_widget_properties_set_label (props->priv->props,
+ items[i].widget,
+ string);
+ g_free (string);
+ }
+ }
+
+ /* Comment else use Description defined by:
+ * http://xiph.org/vorbis/doc/v-comment.html */
+ if (gst_tag_list_get_string (list, GST_TAG_COMMENT, &comment) ||
+ gst_tag_list_get_string (list, GST_TAG_DESCRIPTION, &comment)) {
+
+ bacon_video_widget_properties_set_label (props->priv->props,
+ "comment",
+ comment);
+ g_free (comment);
+ }
+
+ /* Date */
+ if (gst_tag_list_get_date (list, GST_TAG_DATE, &date)) {
+ char *string;
+
+ string = g_strdup_printf ("%d", g_date_get_year (date));
+ g_date_free (date);
+ bacon_video_widget_properties_set_label (props->priv->props,
+ "year",
+ string);
+ g_free (string);
+ } else if (gst_tag_list_get_date_time (list, GST_TAG_DATE_TIME, &datetime)) {
+ char *string;
+
+ string = g_strdup_printf ("%d", gst_date_time_get_year (datetime));
+ gst_date_time_unref (datetime);
+ bacon_video_widget_properties_set_label (props->priv->props,
+ "year",
+ string);
+ g_free (string);
+ }
+}
+
+static void
+set_codec (TotemPropertiesView *props,
+ GstDiscovererStreamInfo *info,
+ const char *widget)
+{
+ GstCaps *caps;
+ const char *nick;
+
+ nick = gst_discoverer_stream_info_get_stream_type_nick (info);
+ if (g_str_equal (nick, "audio") == FALSE &&
+ g_str_equal (nick, "video") == FALSE &&
+ g_str_equal (nick, "container") == FALSE) {
+ bacon_video_widget_properties_set_label (props->priv->props,
+ widget,
+ _("N/A"));
+ return;
+ }
+
+ caps = gst_discoverer_stream_info_get_caps (info);
+ if (caps) {
+ if (gst_caps_is_fixed (caps)) {
+ char *string;
+
+ string = gst_pb_utils_get_codec_description (caps);
+ bacon_video_widget_properties_set_label (props->priv->props,
+ widget,
+ string);
+ g_free (string);
+ }
+ gst_caps_unref (caps);
+ }
+}
+
+static void
+set_bitrate (TotemPropertiesView *props,
+ guint bitrate,
+ const char *widget)
+{
+ char *string;
+
+ if (!bitrate) {
+ bacon_video_widget_properties_set_label (props->priv->props,
+ widget,
+ C_("Stream bit rate", "N/A"));
+ return;
+ }
+ string = g_strdup_printf (_("%d kbps"), bitrate / 1000);
+ bacon_video_widget_properties_set_label (props->priv->props,
+ widget,
+ string);
+ g_free (string);
+}
+
+static void
+update_video (TotemPropertiesView *props,
+ GstDiscovererVideoInfo *info)
+{
+ guint width, height;
+ guint fps_n, fps_d;
+ char *string;
+
+ width = gst_discoverer_video_info_get_width (info);
+ height = gst_discoverer_video_info_get_height (info);
+ string = g_strdup_printf (N_("%d × %d"), width, height);
+ bacon_video_widget_properties_set_label (props->priv->props,
+ "dimensions",
+ string);
+ g_free (string);
+
+ set_codec (props, (GstDiscovererStreamInfo *) info, "vcodec");
+ set_bitrate (props, gst_discoverer_video_info_get_bitrate (info), "video_bitrate");
+
+ /* Round up/down to the nearest integer framerate */
+ fps_n = gst_discoverer_video_info_get_framerate_num (info);
+ fps_d = gst_discoverer_video_info_get_framerate_denom (info);
+ if (fps_d > 0.0)
+ bacon_video_widget_properties_set_framerate (props->priv->props,
+ (float) fps_n / (float) fps_d);
+ else
+ bacon_video_widget_properties_set_framerate (props->priv->props, 0.0);
+}
+
+static void
+update_audio (TotemPropertiesView *props,
+ GstDiscovererAudioInfo *info)
+{
+ guint samplerate, channels;
+
+ set_codec (props, (GstDiscovererStreamInfo *) info, "acodec");
+
+ set_bitrate (props, gst_discoverer_audio_info_get_bitrate (info), "audio_bitrate");
+
+ samplerate = gst_discoverer_audio_info_get_sample_rate (info);
+ if (samplerate) {
+ char *string;
+ string = g_strdup_printf (_("%d Hz"), samplerate);
+ bacon_video_widget_properties_set_label (props->priv->props,
+ "samplerate",
+ string);
+ g_free (string);
+ } else {
+ bacon_video_widget_properties_set_label (props->priv->props,
+ "samplerate",
+ C_("Sample rate", "N/A"));
+ }
+
+ channels = gst_discoverer_audio_info_get_channels (info);
+ if (channels) {
+ char *string;
+
+ if (channels > 2) {
+ string = g_strdup_printf ("%s %d.1", _("Surround"), channels - 1);
+ } else if (channels == 1) {
+ string = g_strdup (_("Mono"));
+ } else if (channels == 2) {
+ string = g_strdup (_("Stereo"));
+ } else {
+ string = g_strdup (""); //Should not happen
+ }
+ bacon_video_widget_properties_set_label (props->priv->props,
+ "channels",
+ string);
+ g_free (string);
+ } else {
+ bacon_video_widget_properties_set_label (props->priv->props,
+ "channels",
+ C_("Number of audio channels", "N/A"));
+ }
+}
+
+static void
+discovered_cb (GstDiscoverer *discoverer,
+ GstDiscovererInfo *info,
+ GError *error,
+ TotemPropertiesView *props)
+{
+ GList *video_streams, *audio_streams;
+ const GstTagList *taglist;
+ gboolean has_audio, has_video;
+ const char *label;
+ GstClockTime duration;
+ GstDiscovererStreamInfo *sinfo;
+
+ if (error) {
+ g_warning ("Couldn't get information about '%s': %s",
+ gst_discoverer_info_get_uri (info),
+ error->message);
+ return;
+ }
+
+ video_streams = gst_discoverer_info_get_video_streams (info);
+ has_video = (video_streams != NULL);
+ audio_streams = gst_discoverer_info_get_audio_streams (info);
+ has_audio = (audio_streams != NULL);
+
+ if (has_audio == has_video)
+ label = N_("Audio/Video");
+ else if (has_audio)
+ label = N_("Audio");
+ else
+ label = N_("Video");
+
+ gtk_label_set_text (GTK_LABEL (props->priv->label), _(label));
+
+ /* Widgets */
+ bacon_video_widget_properties_set_has_type (props->priv->props,
+ has_video,
+ has_audio);
+
+ /* General */
+ duration = gst_discoverer_info_get_duration (info);
+ bacon_video_widget_properties_set_duration (props->priv->props, duration / GST_SECOND * 1000);
+
+ sinfo = gst_discoverer_info_get_stream_info (info);
+ if (sinfo) {
+ set_codec (props, sinfo, "container");
+ gst_discoverer_stream_info_unref (sinfo);
+ }
+
+ taglist = gst_discoverer_info_get_tags (info);
+ update_general (props, taglist);
+
+ /* Video and Audio */
+ if (video_streams)
+ update_video (props, video_streams->data);
+ if (audio_streams)
+ update_audio (props, audio_streams->data);
+
+ gst_discoverer_stream_info_list_free (video_streams);
+ gst_discoverer_stream_info_list_free (audio_streams);
+}
+
+static void
+totem_properties_view_init (TotemPropertiesView *props)
+{
+ GError *err = NULL;
+
+ props->priv = g_new0 (TotemPropertiesViewPriv, 1);
+
+ props->priv->vbox = bacon_video_widget_properties_new ();
+ gtk_grid_attach (GTK_GRID (props), props->priv->vbox, 0, 0, 1, 1);
+ gtk_widget_show (GTK_WIDGET (props));
+
+ props->priv->props = BACON_VIDEO_WIDGET_PROPERTIES (props->priv->vbox);
+
+ props->priv->disco = gst_discoverer_new (GST_SECOND * 60, &err);
+ if (props->priv->disco == NULL) {
+ g_warning ("Could not create discoverer object: %s", err->message);
+ g_error_free (err);
+ return;
+ }
+ g_signal_connect (props->priv->disco, "discovered",
+ G_CALLBACK (discovered_cb), props);
+}
+
+static void
+totem_properties_view_finalize (GObject *object)
+{
+ TotemPropertiesView *props;
+
+ props = TOTEM_PROPERTIES_VIEW (object);
+
+ if (props->priv != NULL) {
+ if (props->priv->disco) {
+ g_signal_handlers_disconnect_by_func (props->priv->disco,
+ discovered_cb,
+ props);
+ gst_discoverer_stop (props->priv->disco);
+ g_clear_object (&props->priv->disco);
+ }
+ g_clear_object (&props->priv->label);
+ g_free (props->priv);
+ }
+ props->priv = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+totem_properties_view_set_location (TotemPropertiesView *props,
+ const char *location)
+{
+ g_assert (TOTEM_IS_PROPERTIES_VIEW (props));
+
+ if (props->priv->disco)
+ gst_discoverer_stop (props->priv->disco);
+
+ bacon_video_widget_properties_reset (props->priv->props);
+
+ if (location != NULL && props->priv->disco != NULL) {
+ gst_discoverer_start (props->priv->disco);
+
+ if (gst_discoverer_discover_uri_async (props->priv->disco, location) == FALSE) {
+ g_warning ("Couldn't add %s to list", location);
+ return;
+ }
+ }
+}
+
+GtkWidget *
+totem_properties_view_new (const char *location, GtkWidget *label)
+{
+ TotemPropertiesView *self;
+
+ self = g_object_new (TOTEM_TYPE_PROPERTIES_VIEW, NULL);
+ g_object_ref (label);
+ self->priv->label = label;
+ totem_properties_view_set_location (self, location);
+
+ return GTK_WIDGET (self);
+}