[gtk/wip/otte/paintable: 1/8] demos: Add a video playing GdkPaintable
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/otte/paintable: 1/8] demos: Add a video playing GdkPaintable
- Date: Sat, 17 Feb 2018 23:45:55 +0000 (UTC)
commit 11e0f1bbf46dddfacdccbad5512f0f20a887dd3a
Author: Benjamin Otte <otte redhat com>
Date: Sat Feb 17 07:38:11 2018 +0100
demos: Add a video playing GdkPaintable
This is using ffmpeg, so it can't be included in GTK proper (because
FFmpeg is GPL). But it's very useful for feature-testing and
performance-benchmarking to have a video player available.
Also, it might inspire people to actually improve the situation of video
in GTK, seeing as this is just a few 100 lines of C.
The code is very rudimentary and barely good enough to do anything
useful, but it gets the job done.
config.h.meson | 3 +
demos/gtk-demo/gtkdemovideo.c | 569 ++++++++++++++++++++++++++++++++++++++++++
demos/gtk-demo/gtkdemovideo.h | 41 +++
demos/gtk-demo/images.c | 43 +++-
demos/gtk-demo/meson.build | 6 +-
demos/gtk-demo/widgetbowl.c | 11 +
meson.build | 11 +
meson_options.txt | 2 +
8 files changed, 680 insertions(+), 6 deletions(-)
---
diff --git a/config.h.meson b/config.h.meson
index 54dec7fa82..054831bbfa 100644
--- a/config.h.meson
+++ b/config.h.meson
@@ -41,6 +41,9 @@
/* Define to 1 if you have the <dlfcn.h> header file. */
#mesondefine HAVE_DLFCN_H
+/* Have the ffmpeg library */
+#mesondefine HAVE_FFMPEG
+
/* Define to 1 if you have the <ftw.h> header file. */
#mesondefine HAVE_FTW_H
diff --git a/demos/gtk-demo/gtkdemovideo.c b/demos/gtk-demo/gtkdemovideo.c
new file mode 100644
index 0000000000..0d511368f2
--- /dev/null
+++ b/demos/gtk-demo/gtkdemovideo.c
@@ -0,0 +1,569 @@
+/*
+ * Copyright © 2018 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#include "config.h"
+
+#include "gtkdemovideo.h"
+
+#ifdef HAVE_FFMPEG
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include <libswscale/swscale.h>
+#endif
+
+enum {
+ PROP_0,
+ PROP_FILENAME,
+ PROP_PLAYING,
+
+ N_PROPS
+};
+
+struct _GtkDemoVideo {
+ GObject parent_instance;
+
+ char *filename;
+
+#ifdef HAVE_FFMPEG
+ AVFormatContext *format_ctx;
+ AVCodecContext *codec_ctx;
+ int stream_id;
+ struct SwsContext *sws_ctx;
+#endif
+ GdkTexture *current_texture;
+ gint64 current_texture_duration;
+
+ gint64 timestamp; /* monotonic time when we displayed the last frame */
+ guint next_frame_cb; /* Source ID of next frame callback */
+ gboolean playing;
+};
+
+struct _GtkDemoVideoClass {
+ GObjectClass parent_class;
+};
+
+static GParamSpec *properties[N_PROPS];
+
+static void
+gtk_demo_video_paintable_snapshot (GdkPaintable *paintable,
+ GdkSnapshot *snapshot,
+ double width,
+ double height)
+{
+ GtkDemoVideo *video = GTK_DEMO_VIDEO (paintable);
+
+ if (video->current_texture)
+ {
+ gdk_paintable_snapshot (GDK_PAINTABLE (video->current_texture), snapshot, width, height);
+ }
+ else
+ {
+ gtk_snapshot_append_color (snapshot,
+ &(GdkRGBA) { 1.0, 0.1, 0.6, 1.0 },
+ &GRAPHENE_RECT_INIT (0, 0, width, height),
+ "Video Fallback image");
+ }
+}
+
+static GdkPaintable *
+gtk_demo_video_paintable_get_current_image (GdkPaintable *paintable)
+{
+ GtkDemoVideo *video = GTK_DEMO_VIDEO (paintable);
+
+ return GDK_PAINTABLE (g_object_ref (video->current_texture));
+}
+
+static int
+gtk_demo_video_paintable_get_intrinsic_width (GdkPaintable *paintable)
+{
+#ifdef HAVE_FFMPEG
+ GtkDemoVideo *video = GTK_DEMO_VIDEO (paintable);
+
+ if (video->codec_ctx)
+ return video->codec_ctx->width;
+#endif
+
+ return 0;
+}
+
+static int
+gtk_demo_video_paintable_get_intrinsic_height (GdkPaintable *paintable)
+{
+#ifdef HAVE_FFMPEG
+ GtkDemoVideo *video = GTK_DEMO_VIDEO (paintable);
+
+ if (video->codec_ctx)
+ return video->codec_ctx->height;
+#endif
+
+ return 0;
+}
+
+static double gtk_demo_video_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable)
+{
+#ifdef HAVE_FFMPEG
+ GtkDemoVideo *video = GTK_DEMO_VIDEO (paintable);
+
+ if (video->codec_ctx)
+ return (double) video->codec_ctx->width / video->codec_ctx->height;
+#endif
+
+ return 0.0;
+};
+
+static void
+gtk_demo_video_paintable_init (GdkPaintableInterface *iface)
+{
+ iface->snapshot = gtk_demo_video_paintable_snapshot;
+ iface->get_current_image = gtk_demo_video_paintable_get_current_image;
+ iface->get_intrinsic_width = gtk_demo_video_paintable_get_intrinsic_width;
+ iface->get_intrinsic_height = gtk_demo_video_paintable_get_intrinsic_height;
+ iface->get_intrinsic_aspect_ratio = gtk_demo_video_paintable_get_intrinsic_aspect_ratio;
+}
+
+G_DEFINE_TYPE_WITH_CODE (GtkDemoVideo, gtk_demo_video, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
+ gtk_demo_video_paintable_init))
+
+static void
+gtk_demo_video_set_property (GObject *gobject,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkDemoVideo *video = GTK_DEMO_VIDEO (gobject);
+
+ switch (prop_id)
+ {
+ case PROP_FILENAME:
+ gtk_demo_video_set_filename (video, g_value_get_string (value));
+ break;
+
+ case PROP_PLAYING:
+ gtk_demo_video_set_playing (video, g_value_get_boolean (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gtk_demo_video_get_property (GObject *gobject,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkDemoVideo *video = GTK_DEMO_VIDEO (gobject);
+
+ switch (prop_id)
+ {
+ case PROP_FILENAME:
+ g_value_set_string (value, video->filename);
+ break;
+
+ case PROP_PLAYING:
+ g_value_set_boolean (value, video->playing);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gtk_demo_video_stop (GtkDemoVideo *video)
+{
+ if (!video->playing)
+ return;
+
+ if (video->next_frame_cb)
+ {
+ g_source_remove (video->next_frame_cb);
+ video->next_frame_cb = 0;
+ }
+
+ video->timestamp = FALSE;
+ video->playing = FALSE;
+ g_object_notify_by_pspec (G_OBJECT (video), properties[PROP_PLAYING]);
+}
+
+static void
+gtk_demo_video_clear (GtkDemoVideo *video)
+{
+ g_clear_pointer (&video->filename, g_free);
+
+#ifdef HAVE_FFMPEG
+ g_clear_pointer (&video->sws_ctx, sws_freeContext);
+ g_clear_pointer (&video->codec_ctx, avcodec_close);
+ avformat_close_input (&video->format_ctx);
+ video->stream_id = -1;
+#endif
+ g_clear_object (&video->current_texture);
+
+ gdk_paintable_invalidate_size (GDK_PAINTABLE (video));
+ gdk_paintable_invalidate_contents (GDK_PAINTABLE (video));
+}
+
+static void
+gtk_demo_video_dispose (GObject *object)
+{
+ GtkDemoVideo *video = GTK_DEMO_VIDEO (object);
+
+ gtk_demo_video_stop (video);
+ gtk_demo_video_clear (video);
+
+ G_OBJECT_CLASS (gtk_demo_video_parent_class)->dispose (object);
+}
+
+static void
+gtk_demo_video_class_init (GtkDemoVideoClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property = gtk_demo_video_set_property;
+ gobject_class->get_property = gtk_demo_video_get_property;
+ gobject_class->dispose = gtk_demo_video_dispose;
+
+ properties[PROP_FILENAME] =
+ g_param_spec_string ("filename",
+ "Filename",
+ "The file to play",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS |
+ G_PARAM_EXPLICIT_NOTIFY);
+
+ properties[PROP_PLAYING] =
+ g_param_spec_string ("playing",
+ "Playing",
+ "TRUE if the file is playing",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS |
+ G_PARAM_EXPLICIT_NOTIFY);
+
+ g_object_class_install_properties (gobject_class, N_PROPS, properties);
+
+#ifdef HAVE_FFMPEG
+ av_register_all ();
+#endif
+}
+
+static void
+gtk_demo_video_init (GtkDemoVideo *video)
+{
+#ifdef HAVE_FFMPEG
+ video->stream_id = -1;
+#endif
+}
+
+GtkDemoVideo *
+gtk_demo_video_new (void)
+{
+ return g_object_new (GTK_TYPE_DEMO_VIDEO, NULL);
+}
+
+GtkDemoVideo *
+gtk_demo_video_new_for_filename (const char *filename)
+{
+ GtkDemoVideo *video;
+
+ g_return_val_if_fail (filename != NULL, NULL);
+
+ video = gtk_demo_video_new ();
+ gtk_demo_video_set_filename (video, filename);
+ gtk_demo_video_set_playing (video, TRUE);
+
+ return video;
+}
+
+static void
+gtk_demo_video_set_error (GtkDemoVideo *video,
+ const char *error_message)
+{
+}
+
+#ifdef HAVE_FFMPEG
+static void
+gtk_demo_video_set_ffmpeg_error (GtkDemoVideo *video,
+ int av_errnum)
+{
+ char s[AV_ERROR_MAX_STRING_SIZE];
+
+ if (av_strerror (av_errnum, s, sizeof (s) != 0))
+ snprintf (s, sizeof (s), "Unspecified error decoding video");
+
+ gtk_demo_video_set_error (video, s);
+}
+
+static GdkTexture *
+gtk_demo_video_decode_frame (GtkDemoVideo *video,
+ gint64 *duration)
+{
+ GdkTexture *texture;
+ AVPacket packet;
+ AVFrame *frame;
+ int errnum;
+ guchar *data;
+
+ frame = av_frame_alloc ();
+
+ for (errnum = av_read_frame (video->format_ctx, &packet);
+ errnum >= 0;
+ errnum = av_read_frame (video->format_ctx, &packet))
+ {
+ if (packet.stream_index == video->stream_id)
+ {
+ errnum = avcodec_send_packet (video->codec_ctx, &packet);
+ if (errnum >= 0)
+ {
+ errnum = avcodec_receive_frame (video->codec_ctx, frame);
+ if (errnum >= 0)
+ {
+ av_packet_unref (&packet);
+ break;
+ }
+ }
+ }
+
+ av_packet_unref (&packet);
+ }
+
+ if (errnum < 0)
+ {
+ gtk_demo_video_set_ffmpeg_error (video, errnum);
+ av_frame_free (&frame);
+ *duration = 0;
+ return NULL;
+ }
+
+ data = g_try_malloc0 (video->codec_ctx->width * video->codec_ctx->height * 4);
+ if (data == NULL)
+ {
+ gtk_demo_video_set_error (video, "Not enough memory");
+ av_frame_free (&frame);
+ *duration = 0;
+ return NULL;
+ }
+
+ sws_scale(video->sws_ctx,
+ (const uint8_t * const *) frame->data, frame->linesize,
+ 0, video->codec_ctx->height,
+ (uint8_t *[1]) { data }, (int[1]) { video->codec_ctx->width * 4 });
+ texture = gdk_texture_new_for_data (data,
+ video->codec_ctx->width,
+ video->codec_ctx->height,
+ video->codec_ctx->width * 4);
+ g_free (data);
+
+ if (av_frame_get_pkt_duration (frame))
+ *duration = av_rescale_q (av_frame_get_pkt_duration (frame),
+ video->format_ctx->streams[video->stream_id]->time_base,
+ (AVRational) { 1, G_USEC_PER_SEC });
+ else
+ *duration = av_rescale_q (1,
+ video->format_ctx->streams[video->stream_id]->time_base,
+ (AVRational) { 1, G_USEC_PER_SEC });
+ av_frame_free (&frame);
+
+ return texture;
+}
+
+static void
+gtk_demo_video_open_ffmpeg (GtkDemoVideo *video)
+{
+ AVStream *stream;
+ AVCodec *codec;
+ int errnum;
+
+ errnum = avformat_open_input (&video->format_ctx, video->filename, NULL, NULL);
+ if (errnum != 0)
+ {
+ gtk_demo_video_set_ffmpeg_error (video, errnum);
+ return;
+ }
+
+ errnum = avformat_find_stream_info (video->format_ctx, NULL);
+ if (errnum < 0)
+ {
+ gtk_demo_video_set_ffmpeg_error (video, errnum);
+ return;
+ }
+
+ video->stream_id = av_find_best_stream (video->format_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
+ if (video->stream_id < 0)
+ {
+ gtk_demo_video_set_error (video, "File contains no video");
+ return;
+ }
+
+ stream = video->format_ctx->streams[video->stream_id];
+ codec = avcodec_find_decoder (stream->codecpar->codec_id);
+ if (codec == NULL)
+ {
+ gtk_demo_video_set_error (video, "Unsupported video codec");
+ return;
+ }
+
+ video->codec_ctx = avcodec_alloc_context3 (codec);
+ errnum = avcodec_parameters_to_context (video->codec_ctx, stream->codecpar);
+ if (errnum < 0)
+ {
+ gtk_demo_video_set_ffmpeg_error (video, errnum);
+ return;
+ }
+ errnum = avcodec_open2(video->codec_ctx, codec, NULL);
+ if (errnum < 0)
+ {
+ gtk_demo_video_set_ffmpeg_error (video, errnum);
+ return;
+ }
+
+ video->sws_ctx = sws_getContext(video->codec_ctx->width,
+ video->codec_ctx->height,
+ video->codec_ctx->pix_fmt,
+ video->codec_ctx->width,
+ video->codec_ctx->height,
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ AV_PIX_FMT_BGRA,
+#else
+ AV_PIX_FMT_ARGB,
+#endif
+ SWS_BILINEAR,
+ NULL,
+ NULL,
+ NULL);
+
+ gdk_paintable_invalidate_size (GDK_PAINTABLE (video));
+
+ video->current_texture = gtk_demo_video_decode_frame (video, &video->current_texture_duration);
+
+ gdk_paintable_invalidate_contents (GDK_PAINTABLE (video));
+}
+
+#endif /* HAVE_FFMPEG */
+
+static void
+gtk_demo_video_open (GtkDemoVideo *video)
+{
+ if (video->filename == NULL)
+ return;
+
+#ifdef HAVE_FFMPEG
+ gtk_demo_video_open_ffmpeg (video);
+#else
+ gtk_demo_video_set_error (video, "Video support not enabled at build time.");
+#endif
+}
+
+void
+gtk_demo_video_set_filename (GtkDemoVideo *video,
+ const char *filename)
+{
+ gtk_demo_video_clear (video);
+
+ video->filename = g_strdup (filename);
+
+ gtk_demo_video_open (video);
+
+ g_object_notify_by_pspec (G_OBJECT (video), properties[PROP_FILENAME]);
+}
+
+static gboolean
+gtk_demo_video_next_frame_cb (gpointer data);
+static void
+gtk_demo_video_queue_frame (GtkDemoVideo *video)
+{
+ gint64 time, frame_time;
+ guint delay;
+
+ time = g_get_monotonic_time ();
+ frame_time = video->timestamp + video->current_texture_duration;
+ delay = time > frame_time ? 0 : (frame_time - time) / 1000;
+
+ video->next_frame_cb = g_timeout_add (delay, gtk_demo_video_next_frame_cb, video);
+}
+
+static gboolean
+gtk_demo_video_next_frame_cb (gpointer data)
+{
+ GtkDemoVideo *video = data;
+ GdkTexture *next_texture;
+ gint64 next_duration;
+
+ video->next_frame_cb = 0;
+#ifdef HAVE_FFMPEG
+ next_texture = gtk_demo_video_decode_frame (video, &next_duration);
+#else
+ next_texture = NULL;
+ next_duration = 0;
+#endif
+ if (next_texture)
+ {
+ video->timestamp += video->current_texture_duration;
+ g_clear_object (&video->current_texture);
+ gdk_paintable_invalidate_contents (GDK_PAINTABLE (video));
+ video->current_texture_duration = next_duration;
+ video->current_texture = next_texture;
+
+ gtk_demo_video_queue_frame (video);
+ }
+ else
+ {
+ video->current_texture_duration = 0;
+ gtk_demo_video_stop (video);
+ }
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+gtk_demo_video_play (GtkDemoVideo *video)
+{
+ if (video->playing)
+ return;
+
+ if (video->current_texture_duration == 0)
+ return;
+
+ video->timestamp = g_get_monotonic_time ();
+ video->playing = TRUE;
+ g_object_notify_by_pspec (G_OBJECT (video), properties[PROP_PLAYING]);
+
+ gtk_demo_video_queue_frame (video);
+}
+
+void
+gtk_demo_video_set_playing (GtkDemoVideo *video,
+ gboolean playing)
+{
+ if (video->playing == playing)
+ return;
+
+ if (playing)
+ gtk_demo_video_play (video);
+ else
+ gtk_demo_video_stop (video);
+
+ video->playing = playing;
+ g_object_notify_by_pspec (G_OBJECT (video), properties[PROP_PLAYING]);
+}
diff --git a/demos/gtk-demo/gtkdemovideo.h b/demos/gtk-demo/gtkdemovideo.h
new file mode 100644
index 0000000000..62e11ebb61
--- /dev/null
+++ b/demos/gtk-demo/gtkdemovideo.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright © 2018 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#ifndef __GTK_DEMO_VIDEO_H__
+#define __GTK_DEMO_VIDEO_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_DEMO_VIDEO (gtk_demo_video_get_type ())
+
+G_DECLARE_FINAL_TYPE (GtkDemoVideo, gtk_demo_video, GTK, DEMO_VIDEO, GObject)
+
+GtkDemoVideo * gtk_demo_video_new (void);
+GtkDemoVideo * gtk_demo_video_new_for_filename (const char *filename);
+
+void gtk_demo_video_set_filename (GtkDemoVideo *video,
+ const char *filename);
+void gtk_demo_video_set_playing (GtkDemoVideo *video,
+ gboolean playing);
+
+G_END_DECLS
+
+#endif /* __GTK_DEMO_VIDEO_H__ */
diff --git a/demos/gtk-demo/images.c b/demos/gtk-demo/images.c
index c3f0f675f6..b76db7e7cd 100644
--- a/demos/gtk-demo/images.c
+++ b/demos/gtk-demo/images.c
@@ -17,6 +17,8 @@
#include <stdio.h>
#include <errno.h>
+#include "gtkdemovideo.h"
+
static GtkWidget *window = NULL;
static GdkPixbufLoader *pixbuf_loader = NULL;
static guint load_timeout = 0;
@@ -317,12 +319,15 @@ toggle_sensitivity_callback (GtkWidget *togglebutton,
GtkWidget *
do_images (GtkWidget *do_widget)
{
+ GtkDemoVideo *video;
GtkWidget *frame;
GtkWidget *vbox;
+ GtkWidget *hbox;
+ GtkWidget *base_vbox;
GtkWidget *image;
GtkWidget *label;
GtkWidget *button;
- GIcon *gicon;
+ GIcon *gicon;
if (!window)
{
@@ -336,9 +341,15 @@ do_images (GtkWidget *do_widget)
g_signal_connect (window, "destroy",
G_CALLBACK (cleanup_callback), NULL);
+ base_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
+ g_object_set (base_vbox, "margin", 16, NULL);
+ gtk_container_add (GTK_CONTAINER (window), base_vbox);
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 16);
+ gtk_container_add (GTK_CONTAINER (base_vbox), hbox);
+
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
- g_object_set (vbox, "margin", 16, NULL);
- gtk_container_add (GTK_CONTAINER (window), vbox);
+ gtk_container_add (GTK_CONTAINER (hbox), vbox);
label = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (label),
@@ -395,6 +406,8 @@ do_images (GtkWidget *do_widget)
/* Progressive */
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
+ gtk_container_add (GTK_CONTAINER (hbox), vbox);
label = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (label),
@@ -415,13 +428,33 @@ do_images (GtkWidget *do_widget)
start_progressive_loading (image);
+ /* Video */
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
+ gtk_container_add (GTK_CONTAINER (hbox), vbox);
+
+ label = gtk_label_new (NULL);
+ gtk_label_set_markup (GTK_LABEL (label),
+ "<u>Displaying video</u>");
+ gtk_box_pack_start (GTK_BOX (vbox), label);
+
+ frame = gtk_frame_new (NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+ gtk_widget_set_halign (frame, GTK_ALIGN_CENTER);
+ gtk_widget_set_valign (frame, GTK_ALIGN_CENTER);
+ gtk_box_pack_start (GTK_BOX (vbox), frame);
+
+ video = gtk_demo_video_new_for_filename ("/home/lvs/incredibles2.mp4");
+ image = gtk_image_new_from_paintable (GDK_PAINTABLE (video));
+ gtk_container_add (GTK_CONTAINER (frame), image);
+ g_object_unref (video);
+
/* Sensitivity control */
button = gtk_toggle_button_new_with_mnemonic ("_Insensitive");
- gtk_box_pack_start (GTK_BOX (vbox), button);
+ gtk_box_pack_start (GTK_BOX (base_vbox), button);
g_signal_connect (button, "toggled",
G_CALLBACK (toggle_sensitivity_callback),
- vbox);
+ base_vbox);
}
if (!gtk_widget_get_visible (window))
diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build
index 0364c849e3..fc5a034cdb 100644
--- a/demos/gtk-demo/meson.build
+++ b/demos/gtk-demo/meson.build
@@ -77,6 +77,10 @@ if harfbuzz_dep.found() and pangoft_dep.found()
gtkdemo_deps += [ harfbuzz_dep, ]
endif
+if ffmpeg_enabled
+ gtkdemo_deps += ffmpeg_deps
+endif
+
if os_unix
demos += files('pagesetup.c')
endif
@@ -94,7 +98,7 @@ gtkdemo_resources = gnome.compile_resources('gtkdemo_resources',
executable('gtk4-demo',
'main.c', 'gtkfishbowl.c', 'fontplane.c', 'script-names.c', 'language-names.c',
- 'gtkgears.c',
+ 'gtkgears.c', 'gtkdemovideo.c',
demos, demos_h, gtkdemo_resources,
c_args: gtkdemo_args,
dependencies: gtkdemo_deps,
diff --git a/demos/gtk-demo/widgetbowl.c b/demos/gtk-demo/widgetbowl.c
index aadee03610..d1a31c7896 100644
--- a/demos/gtk-demo/widgetbowl.c
+++ b/demos/gtk-demo/widgetbowl.c
@@ -8,6 +8,7 @@
#include <gtk/gtk.h>
#include "gtkfishbowl.h"
+#include "gtkdemovideo.h"
#include "gtkgears.h"
const char *const css =
@@ -81,6 +82,15 @@ create_label (void)
return w;
}
+static GtkWidget *
+create_video (void)
+{
+ GtkDemoVideo *video = gtk_demo_video_new_for_filename ("/home/lvs/incredibles2.mp4");
+ GtkWidget *w = gtk_image_new_from_paintable (GDK_PAINTABLE (video));
+
+ return w;
+}
+
static GtkWidget *
create_gears (void)
{
@@ -102,6 +112,7 @@ static const struct {
{ "Label" , create_label },
{ "Spinner" , create_spinner },
{ "Spinbutton", create_spinbutton },
+ { "Videos", create_video },
{ "Gears", create_gears },
};
diff --git a/meson.build b/meson.build
index b75a085370..9d0c8c5d59 100644
--- a/meson.build
+++ b/meson.build
@@ -596,6 +596,17 @@ if cloudproviders_enabled
endif
endif
+ffmpeg_enabled = get_option('ffmpeg')
+if ffmpeg_enabled
+ libavfilter_dep = dependency('libavfilter', version: '>= 6.47.100', required: true)
+ libavformat_dep = dependency('libavformat', version: '>= 57.41.100', required: true)
+ libavcodec_dep = dependency('libavcodec', version: '>= 57.48.101', required: true)
+ libavutil_dep = dependency('libavutil', version: '>= 55.28.100', required: true)
+ libswscale_dep = dependency('libswscale', version: '>= 4.6.100', required: true)
+ ffmpeg_deps = [libavfilter_dep, libavformat_dep, libavcodec_dep, libavutil_dep, libswscale_dep]
+ cdata.set('HAVE_FFMPEG', 1)
+endif
+
subdir('modules/input')
subdir('gdk')
subdir('gsk')
diff --git a/meson_options.txt b/meson_options.txt
index 896347e10b..6e68c8f786 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -17,6 +17,8 @@ option('xinerama', type: 'combo', choices : ['yes', 'no', 'auto'], value : 'auto
description : 'Enable support for the Xinerama extension')
option('cloudproviders', type: 'boolean', value: false,
description : 'Enable the cloudproviders support')
+option('ffmpeg', type: 'boolean', value: false,
+ description : 'Enable ffmpeg video demos')
# Print backends
option('print-backends', type : 'string', value : 'cups,papi',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]