Package: release.debian.org Severity: normal X-Debbugs-Cc: to...@packages.debian.org Control: affects -1 + src:totem User: release.debian....@packages.debian.org Usertags: unblock
[ Reason ] New upstream bugfix release, in particular fixing #986432 [ Impact ] If not accepted, various bugs would be unfixed, notably: - #986432 which makes totem unusable on 32-bit; - totem#614 which can leak a lot of disk space in ~/.cache/totem/stream-buffer if I'm reading correctly If the release team is unhappy with the size of this upstream bugfix release, then I think we should cherry-pick the fixes for at least those two bugs instead. But following upstream and getting the benefit of other distros' testing seems safer than doing our own thing. [ Tests ] Manually tested by watching some videos with and without TOTEM_USE_GST_GTKSINK=1 environment variable. I tried streaming some videos over smb:// and http, but was unable to reproduce large temporary files appearing in ~/.cache/totem/stream-buffer, so I cannot confirm that totem#614 is fixed. Other distros are also shipping this version, e.g. it has been in Fedora 41 and 42 for 20 days. [ Risks ] Key package, installed by our default desktop environment. Adding support for falling back to gtksink is a larger change than I would normally expect in a stable-branch update, but it could be the difference between totem being usable or unusable on weaker hardware, and the code is not too complicated. Similarly using GStreamer's convert-sample instead of open-coding it is a larger change than I would have expected, but it's a code deletion rather than addition, and I trust GStreamer to get this right more than I trust Totem. We can revert any of these changes if they prove to be a problem. [ Checklist ] [x] all changes are documented in the d/changelog [x] I reviewed all changes and I approve them [x] attach debdiff against the package in testing - debdiff is testing vs. experimental, what I'm proposing to upload to unstable is this plus a changelog entry. I filtered out translation updates, upstream CI changes, and the content of the patches that were dropped.
debdiff *.dsc | filterdiff -p1 -x.gitlab-ci.yml -x'debian/patches/*.patch' -x'po/*.po' NEWS | 16 + data/appdata/org.gnome.Totem.appdata.xml.in.in | 22 + data/mime-functions.sh | 2 debian/changelog | 62 ++++ debian/control | 3 debian/patches/series | 9 meson.build | 23 - po/LINGUAS | 1 src/backend/bacon-video-widget.c | 134 ++++++++-- src/backend/bacon-video-widget.h | 2 src/backend/meson.build | 4 src/gst/totem-gst-pixbuf-helpers.c | 289 ---------------------- src/icon-helpers.c | 2 src/plugins/open-directory/totem-open-directory.c | 8 src/plugins/pythonconsole/console.py | 3 src/plugins/recent/totem-recent.c | 2 src/plugins/rotation/totem-rotation.c | 7 src/plugins/save-file/totem-save-file.c | 2 src/plugins/screenshot/totem-screenshot-plugin.c | 47 --- src/totem-object.c | 9 src/totem-playlist.c | 2 src/totem-resources.c | 10 src/totem-resources.h | 3 src/totem-video-thumbnailer.c | 15 - src/totem.c | 2 25 files changed, 277 insertions(+), 402 deletions(-) diff -Nru totem-43.1/data/appdata/org.gnome.Totem.appdata.xml.in.in totem-43.2/data/appdata/org.gnome.Totem.appdata.xml.in.in --- totem-43.1/data/appdata/org.gnome.Totem.appdata.xml.in.in 2024-10-22 17:04:07.000000000 +0100 +++ totem-43.2/data/appdata/org.gnome.Totem.appdata.xml.in.in 2025-05-21 14:08:29.000000000 +0100 @@ -20,17 +20,18 @@ and support for recording DVDs. </p> </description> - <url type="homepage">https://wiki.gnome.org/Apps/Videos</url> + <url type="homepage">https://apps.gnome.org/Totem/</url> <url type="bugtracker">https://gitlab.gnome.org/GNOME/totem/issues</url> - <url type="donation">https://www.gnome.org/friends/</url> + <url type="donation">https://www.gnome.org/donate/</url> <url type="translate">https://l10n.gnome.org/module/totem/</url> <url type="help">https://help.gnome.org/users/totem/stable/</url> + <url type="vcs-browser">https://gitlab.gnome.org/GNOME/totem</url> <screenshots> <screenshot type="default"> - <image>https://gitlab.gnome.org/GNOME/totem/raw/HEAD/data/appdata/ss-player.png</image> + <image>https://gitlab.gnome.org/GNOME/totem/raw/gnome-43/data/appdata/ss-player.png</image> </screenshot> <screenshot> - <image>https://gitlab.gnome.org/GNOME/totem/raw/HEAD/data/appdata/ss-videos.png</image> + <image>https://gitlab.gnome.org/GNOME/totem/raw/gnome-43/data/appdata/ss-videos.png</image> </screenshot> </screenshots> <update_contact>had...@hadess.net</update_contact> @@ -39,6 +40,15 @@ <translation type="gettext">totem</translation> <launchable type="desktop-id">@APPLICATION_ID@.desktop</launchable> <releases> + <release version="43.2" date="2025-05-21"> + <description> + <p> + This new 43.2 version includes the use of gtksink as a video output + when native OpenGL support is not available, as well as many thumbnailer + related bug fixes, and translation updates. + </p> + </description> + </release> <release version="43.1" date="2024-10-22"> <description> <p> @@ -113,4 +123,8 @@ <kudo>UserDocs</kudo> </kudos> <content_rating type="oars-1.1" /> + <branding> + <color type="primary" scheme_preference="light">#f8e45c</color> + <color type="primary" scheme_preference="dark">#613583</color> + </branding> </component> diff -Nru totem-43.1/data/mime-functions.sh totem-43.2/data/mime-functions.sh --- totem-43.1/data/mime-functions.sh 2024-10-22 17:04:07.000000000 +0100 +++ totem-43.2/data/mime-functions.sh 2025-05-21 14:08:29.000000000 +0100 @@ -8,7 +8,7 @@ get_video_mimetypes () { - MIMETYPES=`grep -v '^#' $1 | grep -v x-content/ | grep -v audio | grep -v "application/x-flac" | grep -v "text/google-video-pointer" | grep -v "application/x-quicktime-media-link" | grep -v "application/smil" | grep -v "application/smil+xml" | grep -v "application/x-smil" | grep -v "application/xspf+xml" | grep -v -E 'application/[a-z-]*ogg'` + MIMETYPES=`grep -v '^#' $1 | grep -v x-content/ | grep -v audio | grep -v "application/x-flac" | grep -v "text/google-video-pointer" | grep -v "application/x-quicktime-media-link" | grep -v -E 'application/.*smil.*' | grep -v "application/xspf+xml" | grep -v "mpegurl" | grep -v -E 'application/[a-z-]*ogg'` MIMETYPES="$MIMETYPES audio/x-pn-realaudio" } diff -Nru totem-43.1/debian/changelog totem-43.2/debian/changelog --- totem-43.1/debian/changelog 2025-05-05 20:28:32.000000000 +0100 +++ totem-43.2/debian/changelog 2025-06-11 11:01:40.000000000 +0100 @@ -1,3 +1,65 @@ +totem (43.2-2) experimental; urgency=medium + + * Team upload + * Summarize upstream changes in previous changelog entry + * d/control: Increase libportal build-dependency to 0.7, now required + upstream due to totem!390. + This version is already present in trixie, but not in bookworm. + * d/control: Explicitly build-depend on libepoxy-dev, required by the + GL check in totem!379 + + -- Simon McVittie <s...@debian.org> Wed, 11 Jun 2025 11:01:40 +0100 + +totem (43.2-1) experimental; urgency=medium + + * New upstream release + - Fix a crash on startup on 32-bit architectures + (Closes: #986432, totem!393 upstream) + - Fix memory leaks, one of which could have the side-effect of leaking + large amounts of disk space in ~/.cache/totem/stream-buffer + (totem#614, totem!409 upstream) + - Make the main video widget take keyboard focus when playback starts, + so that keyboard shortcuts like spacebar to pause work as expected + (totem!420 upstream) + - Don't crash the whole application if libportal fails to initialize: + use xdp_portal_initable_new() instead, which has error reporting + (totem!390 upstream) + - Match the window to the application ID so that Wayland compositors + will show the correct icon + (totem!391 upstream) + - Automatically fall back to plain GTK video sink if environment + variable TOTEM_USE_GST_GTKSINK=1 is set, if the GL driver is too old + to work, or if the GL driver name indicates software rendering + (totem!379 upstream) + - Use GStreamer playbin's convert-sample feature instead of + reimplementing equivalent functionality locally + (totem!261 upstream) + - Exclude m3u playlists from thumbnailing: they are not a video format, + and loading them from a sandbox with no network access will usually + fail anyway + (totem#626 upstream) + - Avoid a duplicate MIME-type registration for application/x-smil, etc. + (totem#635 upstream) + - Allow one thumbnailing process per CPU + (totem!399 upstream) + - Fix a deprecation warning in the pythonconsole plugin + (totem!400 upstream) + - Stop using a private gnome-shell API to show a "camera flash" effect + when taking screenshots: unprivileged apps are no longer allowed to + call into this API, so it had no practical effect + (totem!371 upstream) + - AppStream metadata improvements + + update URLs + + pin screenshots to the gnome-43 branch so they will not become + misleading if the UI changes in the main branch + + add branding colours + - Fix build system warnings + - Translation updates + * Remove all patches except d/p/Mark-lint-checks-as-part-of-a-suite.patch, + applied in new release + + -- Jeremy BĂcha <jbi...@ubuntu.com> Fri, 06 Jun 2025 13:20:12 -0400 + totem (43.1-6) unstable; urgency=medium * Team upload diff -Nru totem-43.1/debian/control totem-43.2/debian/control --- totem-43.1/debian/control 2025-05-05 20:28:32.000000000 +0100 +++ totem-43.2/debian/control 2025-06-11 11:01:40.000000000 +0100 @@ -19,6 +19,7 @@ libatk1.0-dev, libbluetooth-dev [linux-any], libcairo2-dev, + libepoxy-dev, libgdk-pixbuf-2.0-dev, libgirepository1.0-dev, libglib2.0-dev (>= 2.72.0), @@ -29,7 +30,7 @@ libgtk-3-dev, libhandy-1-dev (>= 1.5.90), libpeas-dev, - libportal-gtk3-dev, + libportal-gtk3-dev (>= 0.7), librsvg2-dev, libtotem-plparser-dev, libx11-dev (>= 2:1.8), diff -Nru totem-43.1/debian/patches/series totem-43.2/debian/patches/series --- totem-43.1/debian/patches/series 2025-05-05 20:28:32.000000000 +0100 +++ totem-43.2/debian/patches/series 2025-06-11 11:01:40.000000000 +0100 @@ -1,10 +1 @@ Mark-lint-checks-as-part-of-a-suite.patch -plugins-remove-apple-trailers-plugin.patch -plugins-Remove-vimeo-plug-in.patch -Update-POTFILES.in.patch -Update-POTFILES.in-1.patch -data-Add-new-canonical-mime-type-for-AVI-files.patch -Fix-totem-thumbnailer-fail-due-to-OpenBLAS-pthread-e.patch -thumbnailer-Bump-memory-usage-limit.patch -use-appstreamcli.patch -Fix-Thumbnailer-Gstreamer-threading.patch diff -Nru totem-43.1/meson.build totem-43.2/meson.build --- totem-43.1/meson.build 2024-10-22 17:04:07.000000000 +0100 +++ totem-43.2/meson.build 2025-05-21 14:08:29.000000000 +0100 @@ -1,6 +1,6 @@ project( 'totem', 'c', - version: '43.1', + version: '43.2', license: 'GPL2+ with exception', default_options: 'buildtype=debugoptimized', meson_version: '>= 0.57.0' @@ -126,17 +126,18 @@ glib_req_version = '>= 2.72.0' gtk_req_version = '>= 3.22.0' hdy_req_version = '>= 1.5.0' -gst_req_version = '>= 1.6.0' +gst_req_version = '>= 1.21.1' grilo_req_version = '>= 0.3.0' peas_req_version = '>= 1.1.0' totem_plparser_req_version = '>= 3.26.5' +libportal_req_version = '>= 0.7' glib_dep = dependency('glib-2.0', version: glib_req_version) gobject_dep = dependency('gobject-2.0', version: glib_req_version) gmodule_dep = dependency('gmodule-2.0', version: glib_req_version) gio_dep = dependency('gio-2.0', version: '>= 2.43.4') gtk_dep = dependency('gtk+-3.0', version: gtk_req_version) -targets = gtk_dep.get_pkgconfig_variable('targets') +targets = gtk_dep.get_variable(pkgconfig : 'targets') if targets.split(' ').contains('x11') x11_dep = dependency('x11', version: '>= 1.8') else @@ -144,9 +145,9 @@ endif hdy_dep = dependency('libhandy-1', version: hdy_req_version) gst_dep = dependency('gstreamer-1.0', version: gst_req_version) -gst_tag_dep = dependency('gstreamer-tag-1.0', version: '>= 0.11.93') -gst_video_dep = dependency('gstreamer-video-1.0') -gst_pbutils_dep = dependency('gstreamer-pbutils-1.0') +gst_tag_dep = dependency('gstreamer-tag-1.0', version: gst_req_version) +gst_video_dep = dependency('gstreamer-video-1.0', version: gst_req_version) +gst_pbutils_dep = dependency('gstreamer-pbutils-1.0', version: gst_req_version) peas_dep = dependency('libpeas-1.0', version: peas_req_version) peas_gtk_dep = dependency('libpeas-gtk-1.0', version: peas_req_version) totem_plparser_dep = dependency('totem-plparser', version: totem_plparser_req_version) @@ -208,7 +209,7 @@ endif # libportal support -libportal_dep = dependency('libportal-gtk3', required: get_option('libportal')) +libportal_dep = dependency('libportal-gtk3', version: libportal_req_version, required: get_option('libportal')) have_libportal = libportal_dep.found() configure_file( @@ -220,7 +221,7 @@ i18n = import('i18n') pkg = import('pkgconfig') -po_dir = join_paths(meson.source_root(), 'po') +po_dir = join_paths(meson.project_source_root(), 'po') top_inc = include_directories('.') @@ -245,21 +246,21 @@ totem_minor_version != 'rc') if is_stable meson.add_dist_script( - find_program('check-news.sh').path(), + find_program('check-news.sh').full_path(), '@0@'.format(meson.project_version()), 'NEWS', 'data/appdata/org.gnome.Totem.appdata.xml.in.in' ) else meson.add_dist_script( - find_program('check-news.sh').path(), + find_program('check-news.sh').full_path(), '@0@'.format(meson.project_version()), 'NEWS', ) endif meson.add_dist_script( - find_program('remove-flatpak-dist.sh').path() + find_program('remove-flatpak-dist.sh').full_path() ) message('Totem was configured with the following options:') diff -Nru totem-43.1/NEWS totem-43.2/NEWS --- totem-43.1/NEWS 2024-10-22 17:04:07.000000000 +0100 +++ totem-43.2/NEWS 2025-05-21 14:08:29.000000000 +0100 @@ -1,5 +1,21 @@ New features and significant updates in version... +Major changes in 43.2: +- Implement a gtksink video output fallback if native OpenGL support is + not available. +- Fix a lot of thumbnailing failures caused by memory hungry video decoders +- Hide the rotate menu items if rotation is not supported +- Fix some AVI files not being associated correctly +- Fix widget focus when starting video playback +- Fix left-over files when streaming a video and the player is closed +- Fix window not being matched to the application under Wayland +- Stop using gnome-shell to flash the screenshot area, that stopped + working a long time ago +- Stop thumbnailing m3u playlists +- Remove obsolete plugins (apple-trailers, vimeo) +- Fix a number of possible crashers +- Translation updates + Major changes in 43.1: - Fix scroll-by-page GTK setting breaking slider - Fix a number of MPRIS playback controls not working correctly diff -Nru totem-43.1/po/LINGUAS totem-43.2/po/LINGUAS --- totem-43.1/po/LINGUAS 2024-10-22 17:04:07.000000000 +0100 +++ totem-43.2/po/LINGUAS 2025-05-21 14:08:29.000000000 +0100 @@ -90,6 +90,7 @@ tr ug uk +uz vi wa xh diff -Nru totem-43.1/src/backend/bacon-video-widget.c totem-43.2/src/backend/bacon-video-widget.c --- totem-43.1/src/backend/bacon-video-widget.c 2024-10-22 17:04:07.000000000 +0100 +++ totem-43.2/src/backend/bacon-video-widget.c 2025-05-21 14:08:29.000000000 +0100 @@ -63,6 +63,9 @@ /* for the cover metadata info */ #include <gst/tag/tag.h> +/* for detecting GL vendor/renderer */ +#include <epoxy/gl.h> + /* system */ #include <unistd.h> #include <time.h> @@ -192,6 +195,7 @@ gint64 current_time; gdouble current_position; gboolean is_live; + gboolean use_gl; GstTagList *tagcache; GstTagList *audiotags; @@ -282,6 +286,7 @@ static void bacon_video_widget_finalize (GObject * object); +static void bvw_init_video_sink (BaconVideoWidget *bvw); static void bvw_reconfigure_fill_timeout (BaconVideoWidget *bvw, guint msecs); static void bvw_stop_play_pipeline (BaconVideoWidget * bvw); static GError* bvw_error_from_gst_error (BaconVideoWidget *bvw, GstMessage *m); @@ -433,6 +438,8 @@ GTK_WIDGET_CLASS (parent_class)->realize (widget); + bvw_init_video_sink (bvw); + window = gtk_widget_get_window (widget); display = gdk_window_get_display (window); bvw->hand_cursor = gdk_cursor_new_for_display (display, GDK_HAND2); @@ -3882,9 +3889,12 @@ bvw->buffering_left = -1; bvw_reconfigure_fill_timeout (bvw, 0); g_signal_emit (bvw, bvw_signals[SIGNAL_BUFFERING], 0, 100.0); - g_object_set (bvw->video_sink, - "rotate-method", GST_VIDEO_ORIENTATION_AUTO, - NULL); + + if (bvw->use_gl) + g_object_set (bvw->video_sink, + "rotate-method", GST_VIDEO_ORIENTATION_AUTO, + NULL); + GST_DEBUG ("stopped"); } @@ -4493,6 +4503,9 @@ { g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw)); + if (!bvw->use_gl) + return; + GST_DEBUG ("Rotating to %s (%f degrees) from %s", g_enum_to_string (BVW_TYPE_ROTATION, rotation), rotation * 90.0, @@ -4518,6 +4531,22 @@ return bvw->rotation; } +/** + * bacon_video_widget_use_gl: + * @bvw: a #BaconVideoWidget + * + * Returns whether gl is used. + * + * Return value: %TRUE if gl is used, %FALSE otherwise + **/ +gboolean +bacon_video_widget_use_gl (BaconVideoWidget *bvw) +{ + g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE); + + return bvw->use_gl; +} + /* Search for the color balance channel corresponding to type and return it. */ static GstColorBalanceChannel * bvw_get_color_balance_channel (GstColorBalance * color_balance, @@ -5492,12 +5521,7 @@ static void bacon_video_widget_init (BaconVideoWidget *bvw) { - GstElement *audio_sink = NULL; gchar *version_str; - GstPlayFlags flags; - GstElement *glsinkbin, *audio_bin; - GstPad *audio_pad; - char *template; gtk_widget_set_can_focus (GTK_WIDGET (bvw), TRUE); @@ -5538,19 +5562,84 @@ GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK); gtk_widget_init_template (GTK_WIDGET (bvw)); +} + +static inline gboolean +bvw_gl_check (GtkWidget *widget) +{ + static gsize gl_works = 0; + + if (is_feature_enabled ("TOTEM_USE_GST_GTKSINK")) { + return FALSE; + } + + if (g_once_init_enter (&gl_works)) { + GError *error = NULL; + gsize works = 1; + GdkGLContext *context; + GdkWindow *window; + + if ((window = gtk_widget_get_window (widget)) && + (context = gdk_window_create_gl_context (window, &error))) { + const gchar *vendor, *renderer; + + gdk_gl_context_make_current (context); + + vendor = (const gchar *) glGetString (GL_VENDOR); + renderer = (const gchar *) glGetString (GL_RENDERER); + + GST_INFO ("GL Vendor: %s, renderer: %s", vendor, renderer); + + if (g_str_has_prefix (renderer, "llvmpipe") || + g_str_has_prefix (renderer, "softpipe")) + GST_INFO ("Detected software GL rasterizer, falling back to gtksink"); + else + works = 2; + + gdk_gl_context_clear_current (); + } + + if (error) { + GST_WARNING ("Could not window to create GL context, %s", error->message); + g_error_free (error); + } + + g_once_init_leave (&gl_works, works); + } + + return (gl_works > 1); +} + +static void +bvw_init_video_sink (BaconVideoWidget *bvw) +{ + GstElement *audio_sink = NULL; + GstPlayFlags flags; + GstElement *glsinkbin = NULL; + GstElement *audio_bin; + GstPad *audio_pad; + char *template; + + bvw->use_gl = bvw_gl_check (GTK_WIDGET (bvw)); /* Instantiate all the fallible plugins */ bvw->play = element_make_or_warn ("playbin", "play"); bvw->audio_pitchcontrol = element_make_or_warn ("scaletempo", "scaletempo"); - bvw->video_sink = element_make_or_warn ("gtkglsink", "video-sink"); - glsinkbin = element_make_or_warn ("glsinkbin", "glsinkbin"); + + if (bvw->use_gl) { + bvw->video_sink = element_make_or_warn ("gtkglsink", "video-sink"); + glsinkbin = element_make_or_warn ("glsinkbin", "glsinkbin"); + } else { + bvw->video_sink = element_make_or_warn ("gtksink", "video-sink"); + } + audio_sink = element_make_or_warn ("autoaudiosink", "audio-sink"); if (!bvw->play || !bvw->audio_pitchcontrol || !bvw->video_sink || !audio_sink || - !glsinkbin) { + (bvw->use_gl && !glsinkbin)) { if (bvw->video_sink) g_object_ref_sink (bvw->video_sink); if (audio_sink) @@ -5595,23 +5684,34 @@ if (is_feature_enabled ("FPS_DISPLAY")) { GstElement *fps; fps = gst_element_factory_make ("fpsdisplaysink", "fpsdisplaysink"); - g_object_set (glsinkbin, "sink", fps, NULL); + + if (bvw->use_gl) + g_object_set (glsinkbin, "sink", fps, NULL); + else + g_object_set (bvw->play, "video-sink", fps, NULL); + g_object_set (fps, "video-sink", bvw->video_sink, NULL); } else { - g_object_set (glsinkbin, "sink", bvw->video_sink, NULL); + if (bvw->use_gl) + g_object_set (glsinkbin, "sink", bvw->video_sink, NULL); + else + g_object_set (bvw->play, "video-sink", bvw->video_sink, NULL); } + g_object_get (bvw->video_sink, "widget", &bvw->video_widget, NULL); gtk_widget_show (bvw->video_widget); gtk_stack_add_named (GTK_STACK (bvw->stack), bvw->video_widget, "video"); g_object_unref (bvw->video_widget); gtk_stack_set_visible_child_name (GTK_STACK (bvw->stack), "video"); - g_object_set (bvw->video_sink, - "rotate-method", GST_VIDEO_ORIENTATION_AUTO, - NULL); + if (bvw->use_gl) + g_object_set (bvw->video_sink, + "rotate-method", GST_VIDEO_ORIENTATION_AUTO, + NULL); /* And tell playbin */ - g_object_set (bvw->play, "video-sink", glsinkbin, NULL); + if (bvw->use_gl) + g_object_set (bvw->play, "video-sink", glsinkbin, NULL); /* Link the audiopitch element */ bvw->audio_capsfilter = diff -Nru totem-43.1/src/backend/bacon-video-widget.h totem-43.2/src/backend/bacon-video-widget.h --- totem-43.1/src/backend/bacon-video-widget.h 2024-10-22 17:04:07.000000000 +0100 +++ totem-43.2/src/backend/bacon-video-widget.h 2025-05-21 14:08:29.000000000 +0100 @@ -282,6 +282,8 @@ void bacon_video_widget_set_rotation (BaconVideoWidget *bvw, BvwRotation rotation); BvwRotation bacon_video_widget_get_rotation (BaconVideoWidget *bvw); +gboolean bacon_video_widget_use_gl (BaconVideoWidget *bvw); + int bacon_video_widget_get_video_property (BaconVideoWidget *bvw, BvwVideoProperty type); diff -Nru totem-43.1/src/backend/meson.build totem-43.2/src/backend/meson.build --- totem-43.1/src/backend/meson.build 2024-10-22 17:04:07.000000000 +0100 +++ totem-43.2/src/backend/meson.build 2025-05-21 14:08:29.000000000 +0100 @@ -2,7 +2,7 @@ gst_inspect = find_program( 'gst-inspect-1.0', - join_paths(gst_dep.get_pkgconfig_variable('toolsdir'), 'gst-inspect-1.0'), + join_paths(gst_dep.get_variable(pkgconfig : 'toolsdir'), 'gst-inspect-1.0'), required: false ) @@ -23,6 +23,7 @@ gst_good_plugins = [ 'autoaudiosink', 'scaletempo', + 'gtksink', 'gtkglsink', 'glsinkbin' ] @@ -73,6 +74,7 @@ libtotem_time_helpers_dep, gtk_dep, gmodule_dep, + dependency('epoxy'), ] libbacon_video_widget_cflags = common_flags + warn_flags + [ diff -Nru totem-43.1/src/gst/totem-gst-pixbuf-helpers.c totem-43.2/src/gst/totem-gst-pixbuf-helpers.c --- totem-43.1/src/gst/totem-gst-pixbuf-helpers.c 2024-10-22 17:04:07.000000000 +0100 +++ totem-43.2/src/gst/totem-gst-pixbuf-helpers.c 2025-05-21 14:08:29.000000000 +0100 @@ -47,290 +47,12 @@ gst_sample_unref (GST_SAMPLE (data)); } -static gboolean -caps_are_raw (const GstCaps * caps) -{ - guint i, len; - - len = gst_caps_get_size (caps); - - for (i = 0; i < len; i++) { - GstStructure *st = gst_caps_get_structure (caps, i); - if (gst_structure_has_name (st, "video/x-raw")) - return TRUE; - } - - return FALSE; -} - -static gboolean -create_element (const gchar * factory_name, GstElement ** element, - GError ** err) -{ - *element = gst_element_factory_make (factory_name, NULL); - if (*element) - return TRUE; - - if (err && *err == NULL) { - *err = g_error_new (GST_CORE_ERROR, GST_CORE_ERROR_MISSING_PLUGIN, - "cannot create element '%s' - please check your GStreamer installation", - factory_name); - } - - return FALSE; -} - -static GstElement * -build_convert_frame_pipeline (FrameCaptureType capture_type, - GstElement ** src_element, - GstElement ** sink_element, const GstCaps * from_caps, - const GstCaps * to_caps, GError ** err) -{ - GstElement *csp = NULL, *vscale = NULL; - GstElement *src = NULL, *sink = NULL, *dl = NULL, *pipeline; - GError *error = NULL; - gboolean ret; - - if (!caps_are_raw (to_caps)) - goto no_pipeline; - - /* videoscale is here to correct for the pixel-aspect-ratio for us */ - GST_DEBUG ("creating elements"); - if (!create_element ("appsrc", &src, &error) || - !create_element ("appsink", &sink, &error)) - goto no_elements; - if (capture_type == FRAME_CAPTURE_TYPE_RAW) { - if (!create_element ("videoconvert", &csp, &error) || - !create_element ("videoscale", &vscale, &error)) - goto no_elements; - } else { - if (!create_element ("glcolorconvert", &csp, &error) || - !create_element ("glcolorscale", &vscale, &error) || - !create_element ("gldownload", &dl, &error)) - goto no_elements; - } - - pipeline = gst_pipeline_new ("videoconvert-pipeline"); - if (pipeline == NULL) - goto no_pipeline; - - /* Add black borders if necessary to keep the DAR */ - if (g_object_class_find_property (G_OBJECT_GET_CLASS (vscale), "add-borders")) - g_object_set (vscale, "add-borders", TRUE, NULL); - - GST_DEBUG ("adding elements"); - gst_bin_add_many (GST_BIN (pipeline), src, csp, vscale, sink, dl, NULL); - - /* set caps */ - g_object_set (src, "caps", from_caps, NULL); - g_object_set (sink, "caps", to_caps, NULL); - - if (dl) - ret = gst_element_link_many (src, csp, vscale, dl, sink, NULL); - else - ret = gst_element_link_many (src, csp, vscale, sink, NULL); - if (!ret) - goto link_failed; - - g_object_set (src, "emit-signals", TRUE, NULL); - g_object_set (sink, "emit-signals", TRUE, NULL); - - *src_element = src; - *sink_element = sink; - - return pipeline; - /* ERRORS */ -no_elements: - { - if (src) - gst_object_unref (src); - if (csp) - gst_object_unref (csp); - if (vscale) - gst_object_unref (vscale); - if (dl) - gst_object_unref (dl); - if (sink) - gst_object_unref (sink); - GST_ERROR ("Could not convert video frame: %s", error->message); - if (err) - *err = error; - else - g_error_free (error); - return NULL; - } -no_pipeline: - { - gst_object_unref (src); - gst_object_unref (csp); - gst_object_unref (vscale); - g_clear_pointer (&dl, gst_object_unref); - gst_object_unref (sink); - - GST_ERROR ("Could not convert video frame: no pipeline (unknown error)"); - if (err) - *err = g_error_new (GST_CORE_ERROR, GST_CORE_ERROR_FAILED, - "Could not convert video frame: no pipeline (unknown error)"); - return NULL; - } -link_failed: - { - gst_object_unref (pipeline); - - GST_ERROR ("Could not convert video frame: failed to link elements"); - if (err) - *err = g_error_new (GST_CORE_ERROR, GST_CORE_ERROR_NEGOTIATION, - "Could not convert video frame: failed to link elements"); - return NULL; - } -} - -/** - * totem_gst_video_convert_sample: - * @capture_type: capture type - * @sample: a #GstSample - * @to_caps: the #GstCaps to convert to - * @timeout: the maximum amount of time allowed for the processing. - * @error: pointer to a #GError. Can be %NULL. - * - * Converts a raw video buffer into the specified output caps. - * - * The output caps can be any raw video formats or any image formats (jpeg, png, ...). - * - * The width, height and pixel-aspect-ratio can also be specified in the output caps. - * - * Returns: The converted #GstSample, or %NULL if an error happened (in which case @err - * will point to the #GError). - */ -static GstSample * -totem_gst_video_convert_sample (FrameCaptureType capture_type, - GstSample * sample, const GstCaps * to_caps, - GstClockTime timeout, GError ** error) -{ - GstMessage *msg; - GstBuffer *buf; - GstSample *result = NULL; - GError *err = NULL; - GstBus *bus; - GstCaps *from_caps, *to_caps_copy = NULL; - GstFlowReturn ret; - GstElement *pipeline, *src, *sink; - guint i, n; - - g_return_val_if_fail (sample != NULL, NULL); - g_return_val_if_fail (to_caps != NULL, NULL); - - buf = gst_sample_get_buffer (sample); - g_return_val_if_fail (buf != NULL, NULL); - - from_caps = gst_sample_get_caps (sample); - g_return_val_if_fail (from_caps != NULL, NULL); - - to_caps_copy = gst_caps_new_empty (); - n = gst_caps_get_size (to_caps); - for (i = 0; i < n; i++) { - GstStructure *s = gst_caps_get_structure (to_caps, i); - - s = gst_structure_copy (s); - gst_structure_remove_field (s, "framerate"); - gst_caps_append_structure (to_caps_copy, s); - } - - pipeline = - build_convert_frame_pipeline (capture_type, &src, &sink, from_caps, - to_caps_copy, &err); - if (!pipeline) - goto no_pipeline; - - /* now set the pipeline to the paused state, after we push the buffer into - * appsrc, this should preroll the converted buffer in appsink */ - GST_DEBUG ("running conversion pipeline to caps %" GST_PTR_FORMAT, - to_caps_copy); - if (gst_element_set_state (pipeline, - GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) - goto state_change_failed; - - /* feed buffer in appsrc */ - GST_DEBUG ("feeding buffer %p, size %" G_GSIZE_FORMAT ", caps %" - GST_PTR_FORMAT, buf, gst_buffer_get_size (buf), from_caps); - g_signal_emit_by_name (src, "push-buffer", buf, &ret); - - /* now see what happens. We either got an error somewhere or the pipeline - * prerolled */ - bus = gst_element_get_bus (pipeline); - msg = gst_bus_timed_pop_filtered (bus, - timeout, GST_MESSAGE_ERROR | GST_MESSAGE_ASYNC_DONE); - - if (msg) { - switch (GST_MESSAGE_TYPE (msg)) { - case GST_MESSAGE_ASYNC_DONE: - { - /* we're prerolled, get the frame from appsink */ - g_signal_emit_by_name (sink, "pull-preroll", &result); - - if (result) { - GST_DEBUG ("conversion successful: result = %p", result); - } else { - GST_ERROR ("prerolled but no result frame?!"); - } - break; - } - case GST_MESSAGE_ERROR:{ - gchar *dbg = NULL; - - gst_message_parse_error (msg, &err, &dbg); - if (err) { - GST_ERROR ("Could not convert video frame: %s", err->message); - GST_DEBUG ("%s [debug: %s]", err->message, GST_STR_NULL (dbg)); - if (error) - *error = err; - else - g_error_free (err); - } - g_free (dbg); - break; - } - default:{ - g_return_val_if_reached (NULL); - } - } - gst_message_unref (msg); - } else { - GST_ERROR ("Could not convert video frame: timeout during conversion"); - if (error) - *error = g_error_new (GST_CORE_ERROR, GST_CORE_ERROR_FAILED, - "Could not convert video frame: timeout during conversion"); - } - - gst_element_set_state (pipeline, GST_STATE_NULL); - gst_object_unref (bus); - gst_object_unref (pipeline); - gst_caps_unref (to_caps_copy); - - return result; - - /* ERRORS */ -no_pipeline: -state_change_failed: - { - gst_caps_unref (to_caps_copy); - - if (error) - *error = err; - else - g_error_free (err); - - return NULL; - } -} - GdkPixbuf * totem_gst_playbin_get_frame (GstElement *play, GError **error) { FrameCaptureType capture_type; GstStructure *s; GstSample *sample = NULL; - GstSample *last_sample = NULL; guint bpp; GdkPixbuf *pixbuf = NULL; GstCaps *to_caps, *sample_caps; @@ -359,19 +81,12 @@ NULL); /* get frame */ - g_object_get (G_OBJECT (play), "sample", &last_sample, NULL); - if (!last_sample) { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Failed to retrieve video frame"); - return NULL; - } - sample = totem_gst_video_convert_sample (capture_type, last_sample, to_caps, 25 * GST_SECOND, error); - gst_sample_unref (last_sample); + g_signal_emit_by_name (play, "convert-sample", to_caps, &sample); gst_caps_unref (to_caps); if (!sample) { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Failed to convert video frame"); + "Failed to retrieve or convert video frame"); return NULL; } diff -Nru totem-43.1/src/icon-helpers.c totem-43.2/src/icon-helpers.c --- totem-43.1/src/icon-helpers.c 2024-10-22 17:04:07.000000000 +0100 +++ totem-43.2/src/icon-helpers.c 2025-05-21 14:08:29.000000000 +0100 @@ -30,7 +30,7 @@ #define GNOME_DESKTOP_USE_UNSTABLE_API 1 #include <libgnome-desktop/gnome-desktop-thumbnail.h> -#define DEFAULT_MAX_THREADS 1 +#define DEFAULT_MAX_THREADS g_get_num_processors () #define THUMB_SEARCH_SIZE 256 #define THUMB_SEARCH_HEIGHT THUMB_SEARCH_SIZE #define SOURCES_MAX_HEIGHT 64 diff -Nru totem-43.1/src/plugins/open-directory/totem-open-directory.c totem-43.2/src/plugins/open-directory/totem-open-directory.c --- totem-43.1/src/plugins/open-directory/totem-open-directory.c 2024-10-22 17:04:07.000000000 +0100 +++ totem-43.2/src/plugins/open-directory/totem-open-directory.c 2025-05-21 14:08:29.000000000 +0100 @@ -135,11 +135,17 @@ GMenu *menu; GMenuItem *item; char *mrl; + g_autoptr(GError) error = NULL; pi->totem = g_object_get_data (G_OBJECT (plugin), "object"); - pi->portal = xdp_portal_new (); + pi->portal = xdp_portal_initable_new (&error); pi->cancellable = g_cancellable_new (); + if (error) { + g_warning ("Failed to create XdpPortal instance: %s", error->message); + return; + } + g_signal_connect (pi->totem, "file-opened", G_CALLBACK (totem_open_directory_file_opened), diff -Nru totem-43.1/src/plugins/pythonconsole/console.py totem-43.2/src/plugins/pythonconsole/console.py --- totem-43.1/src/plugins/pythonconsole/console.py 2024-10-22 17:04:07.000000000 +0100 +++ totem-43.2/src/plugins/pythonconsole/console.py 2025-05-21 14:08:29.000000000 +0100 @@ -291,7 +291,8 @@ except SyntaxError: exec(command, self.namespace) # pylint: disable=W0122 except: # pylint: disable=W0702 - if hasattr(sys, 'last_type') and sys.last_type == SystemExit: # pylint: disable=E1101 + last_type, = sys.exc_info() + if last_type == SystemExit: self.destroy() else: traceback.print_exc() diff -Nru totem-43.1/src/plugins/recent/totem-recent.c totem-43.2/src/plugins/recent/totem-recent.c --- totem-43.1/src/plugins/recent/totem-recent.c 2024-10-22 17:04:07.000000000 +0100 +++ totem-43.2/src/plugins/recent/totem-recent.c 2025-05-21 14:08:29.000000000 +0100 @@ -80,7 +80,7 @@ } data.app_name = g_strdup (g_get_application_name ()); - data.app_exec = g_strjoin (" ", g_get_prgname (), "%u", NULL); + data.app_exec = g_strdup ("totem %u"); data.groups = groups; if (gtk_recent_manager_add_full (pi->recent_manager, uri, &data) == FALSE) { diff -Nru totem-43.1/src/plugins/rotation/totem-rotation.c totem-43.2/src/plugins/rotation/totem-rotation.c --- totem-43.1/src/plugins/rotation/totem-rotation.c 2024-10-22 17:04:07.000000000 +0100 +++ totem-43.2/src/plugins/rotation/totem-rotation.c 2025-05-21 14:08:29.000000000 +0100 @@ -219,6 +219,11 @@ pi->totem = g_object_get_data (G_OBJECT (plugin), "object"); pi->bvw = totem_object_get_video_widget (pi->totem); + + /* rotate-method is not supported by gtksink */ + if (!bacon_video_widget_use_gl (BACON_VIDEO_WIDGET (pi->bvw))) + return; + pi->cancellable = g_cancellable_new (); g_signal_connect (pi->totem, @@ -290,5 +295,5 @@ g_action_map_remove_action (G_ACTION_MAP (pi->totem), "rotate-right"); pi->totem = NULL; - pi->bvw = NULL; + g_clear_object (&pi->bvw); } diff -Nru totem-43.1/src/plugins/save-file/totem-save-file.c totem-43.2/src/plugins/save-file/totem-save-file.c --- totem-43.1/src/plugins/save-file/totem-save-file.c 2024-10-22 17:04:07.000000000 +0100 +++ totem-43.2/src/plugins/save-file/totem-save-file.c 2025-05-21 14:08:29.000000000 +0100 @@ -477,7 +477,7 @@ } pi->totem = NULL; - pi->bvw = NULL; + g_clear_object (&pi->bvw); g_clear_pointer (&pi->mrl, g_free); g_clear_pointer (&pi->cache_mrl, g_free); diff -Nru totem-43.1/src/plugins/screenshot/totem-screenshot-plugin.c totem-43.2/src/plugins/screenshot/totem-screenshot-plugin.c --- totem-43.1/src/plugins/screenshot/totem-screenshot-plugin.c 2024-10-22 17:04:07.000000000 +0100 +++ totem-43.2/src/plugins/screenshot/totem-screenshot-plugin.c 2025-05-21 14:08:29.000000000 +0100 @@ -152,51 +152,6 @@ g_object_unref (save_file); } -static void -flash_area_done_cb (GObject *source_object, - GAsyncResult *res, - gpointer user_data) -{ - GVariant *variant; - - variant = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, NULL); - if (variant != NULL) - g_variant_unref (variant); -} - -static void -flash_area (GtkWidget *widget) -{ - GDBusProxy *proxy; - GdkWindow *window; - int x, y, w, h; - - window = gtk_widget_get_window (widget); - gdk_window_get_origin (window, &x, &y); - w = gdk_window_get_width (window); - h = gdk_window_get_height (window); - - proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | - G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | - G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, - "org.gnome.Shell", - "/org/gnome/Shell/Screenshot", - "org.gnome.Shell.Screenshot", - NULL, NULL); - if (proxy == NULL) - g_warning ("no proxy"); - - g_dbus_proxy_call (proxy, "org.gnome.Shell.Screenshot.FlashArea", - g_variant_new ("(iiii)", x, y, w, h), - G_DBUS_CALL_FLAGS_NO_AUTO_START, - -1, - NULL, - flash_area_done_cb, - NULL); -} - static char * escape_video_name (const char *orig) { @@ -224,8 +179,6 @@ return; } - flash_area (GTK_WIDGET (pi->bvw)); - pixbuf = bacon_video_widget_get_current_frame (pi->bvw); if (pixbuf == NULL) { totem_object_show_error (pi->totem, _("Videos could not get a screenshot of the video."), _("This is not supposed to happen; please file a bug report.")); diff -Nru totem-43.1/src/totem.c totem-43.2/src/totem.c --- totem-43.1/src/totem.c 2024-10-22 17:04:07.000000000 +0100 +++ totem-43.2/src/totem.c 2025-05-21 14:08:29.000000000 +0100 @@ -47,7 +47,7 @@ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); - g_set_prgname ("totem"); + g_set_prgname (APPLICATION_ID); #if DEVELOPMENT_VERSION g_set_application_name (_("Videos Preview")); #else diff -Nru totem-43.1/src/totem-object.c totem-43.2/src/totem-object.c --- totem-43.1/src/totem-object.c 2024-10-22 17:04:07.000000000 +0100 +++ totem-43.2/src/totem-object.c 2025-05-21 14:08:29.000000000 +0100 @@ -268,8 +268,6 @@ totem_callback_connect (totem); - gtk_widget_grab_focus (GTK_WIDGET (totem->bvw)); - /* The prefs after the video widget is connected */ totem->prefs = totem_preferences_dialog_new (totem); gtk_window_set_transient_for (GTK_WINDOW (totem->prefs), GTK_WINDOW(totem->win)); @@ -1077,6 +1075,8 @@ gtk_widget_show (totem->subtitles_button); gtk_widget_hide (totem->add_button); gtk_widget_hide (totem->main_menu_button); + + gtk_widget_grab_focus (GTK_WIDGET (totem->bvw)); show_popup (totem); } else if (g_strcmp0 (page_id, "grilo") == 0) { totem_grilo_start (TOTEM_GRILO (totem->grilo)); @@ -1379,8 +1379,11 @@ if (totem == NULL) exit (0); - if (totem->bvw) + if (totem->bvw) { totem_object_save_size (totem); + bacon_video_widget_close (totem->bvw); + g_clear_object (&totem->bvw); + } if (totem->win != NULL) { gtk_widget_hide (totem->win); diff -Nru totem-43.1/src/totem-playlist.c totem-43.2/src/totem-playlist.c --- totem-43.1/src/totem-playlist.c 2024-10-22 17:04:07.000000000 +0100 +++ totem-43.2/src/totem-playlist.c 2025-05-21 14:08:29.000000000 +0100 @@ -1744,7 +1744,7 @@ * hence the "steal" in the API name */ gtk_list_store_set (GTK_LIST_STORE (playlist->model), &iter, - STARTTIME_COL, 0, + STARTTIME_COL, (gint64) 0, -1); return starttime; diff -Nru totem-43.1/src/totem-resources.c totem-43.2/src/totem-resources.c --- totem-43.1/src/totem-resources.c 2025-06-11 11:27:22.000000000 +0100 +++ totem-43.2/src/totem-resources.c 2025-05-21 14:08:29.000000000 +0100 @@ -49,7 +49,7 @@ static gboolean finished = TRUE; static void -set_resource_limits (const char *input) +set_resource_limits (const char *input, gboolean verbose) { #ifdef G_OS_UNIX struct rlimit limit; @@ -81,6 +81,10 @@ limit.rlim_cur = MAX_HELPER_SECONDS; limit.rlim_max = MAX_HELPER_SECONDS; setrlimit (RLIMIT_CPU, &limit); + + if (verbose) + g_message ("Setting limit to %lu MB RAM usage and %d seconds CPU time", + max / 1024 / 1024, MAX_HELPER_SECONDS); #else #warning unimplemented #endif @@ -108,9 +112,9 @@ } void -totem_resources_monitor_start (const char *input, gint wall_clock_time) +totem_resources_monitor_start (const char *input, gint wall_clock_time, gboolean verbose) { - set_resource_limits (input); + set_resource_limits (input, verbose); if (wall_clock_time < 0) return; diff -Nru totem-43.1/src/totem-resources.h totem-43.2/src/totem-resources.h --- totem-43.1/src/totem-resources.h 2024-10-22 17:04:07.000000000 +0100 +++ totem-43.2/src/totem-resources.h 2025-05-21 14:08:29.000000000 +0100 @@ -28,6 +28,7 @@ #include <glib.h> void totem_resources_monitor_start (const char *input, - gint wall_clock_time); + gint wall_clock_time, + gboolean verbose); void totem_resources_monitor_stop (void); diff -Nru totem-43.1/src/totem-video-thumbnailer.c totem-43.2/src/totem-video-thumbnailer.c --- totem-43.1/src/totem-video-thumbnailer.c 2025-06-11 11:27:22.000000000 +0100 +++ totem-43.2/src/totem-video-thumbnailer.c 2025-05-21 14:08:29.000000000 +0100 @@ -377,6 +377,9 @@ return async_received; } +/* Manually set number of worker threads for decoders in order to reduce memory + * usage on setups with many cores, see + * https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/4423 */ static void element_setup_cb (GstElement * playbin, GstElement * element, gpointer udata) { @@ -637,14 +640,8 @@ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); - /* Limit the number of BLAS threads to avoid reaching our RLIMIT_DATA - * address space max size safeguard for the thumbnailer. - * This as GStreamer plugins call into OpenBLAS for linear algebra - * which automatically spawns as many threads as there are CPU cores - * and allocates static buffers for each of them. - * Thus our 512MB address space limit is too short for the video - * file size plus the currently 128 MB per OpenBLAS thread - * when we reach 4 CPU cores. */ + /* Limit the number of OpenBLAS threads to avoid reaching our RLIMIT_DATA + * address space max size safeguard for the thumbnailer. */ g_setenv("OMP_NUM_THREADS", "1", TRUE); /* Call before the global thread pool is setup */ @@ -695,7 +692,7 @@ PRINT_PROGRESS (6.0); if (time_limit != FALSE) - totem_resources_monitor_start (input, 0); + totem_resources_monitor_start (input, 0, verbose); PROGRESS_DEBUG("About to open video file");