93 Commits

Author SHA1 Message Date
Rafał Dzięgiel
23b57cd326 Use new "clappersink" element
Use brand new clapper video sink for video output. Also add "CLAPPER_USE_LEGACY_SINK" env
to still allow the usage of old video sink if any problems arise.
2022-04-12 11:48:45 +02:00
Rafał Dzięgiel
9a19e10542 plugin: Add "clapperglimport" element
A Clapper import element that imports GStreamer `GLMemory` into `GdkTexture` for improved performance where OpenGL is available
2022-04-12 09:47:27 +02:00
Rafał Dzięgiel
0061e133f9 plugin: Add clapper GStreamer plugin
Add new GStreamer plugin that consists of multiple elements for Clapper video player.

The main difference is that unlike the old one, this does not operate using `GtkGLArea`
anymore, but processes and displays `GdkTextures` directly through `GtkPicture` widget.
Also this one is installed like any other GStreamer plugin, thus can be used via
`gst-launch-1.0` binary or even used by other GTK4 apps if they wish to integrate it.

This commit adds new video sink that uses a new kind of memory as input, called
`ClapperGdkMemory`. With it comes a simple dedicated memory allocator, buffer pool
and a `clapperimport` element that converts system mapped memory frames into
`GdkTextures` that are later passed in our `ClapperGdkMemory` for the sink to display.
2022-04-12 09:43:20 +02:00
Rafał Dzięgiel
f771e0320c Merge pull request #240 from Rafostar/pkgs
Update Flatpak, remove RPM specfiles
2022-04-01 11:05:22 +02:00
Rafał Dzięgiel
72a64a41d9 Update README.md 2022-04-01 09:42:06 +02:00
Rafał Dzięgiel
2818d3c91b flatpak: Enable network access for CI GTK4 builds
Make sure CI can satisfy latest GTK4 dependency requirements by allowing it to download libs it needs as fallback projects
2022-04-01 09:27:13 +02:00
Rafał Dzięgiel
ffb481b52b pkgs: Remove RPM build files from git
Clapper is now available in official repos on both Fedora and openSUSE. Considering that, I will not have time to properly maintain them here, so they go away.
2022-04-01 09:27:10 +02:00
Rafał Dzięgiel
c5c289d466 flatpak: Do not build libsoup3 anymore
It is now included in GNOME 42 runtime
2022-04-01 09:27:07 +02:00
Rafał Dzięgiel
3074051b3d flatpak: Build recent GTK 4.6.2 version
We are gonna move into depending on at least 4.6.0, build it for CI to pass
2022-04-01 09:26:58 +02:00
Rafał Dzięgiel
980e1d9e1a flatpak: Update git actions runtime to 42 2022-03-31 16:28:30 +02:00
Rafał Dzięgiel
045e4fc2c4 flatpak: Sync with Flathub 2022-03-31 16:20:47 +02:00
Rafał Dzięgiel
52aa7710dc Update README.md 2022-03-30 11:21:01 +02:00
Rafał Dzięgiel
5101fce5a7 Merge pull request #228 from Rafostar/nightly-fix
Flatpak nightly fixes
2022-03-11 00:30:05 +01:00
Rafał Dzięgiel
e0daf8435a flatpak-nightly: Use "--wrap-mode=nodownload" for GStreamer build
We do not have net access during build of GStreamer, nor we want to pull anything, so disable downloads so it will not try
2022-03-10 22:55:31 +01:00
Rafał Dzięgiel
9f18295728 flatpak-nightly: Do not disable GStreamer asserts and checks
We may disable them for stable releases, but should be left to default on nightly
2022-03-10 22:55:27 +01:00
Rafał Dzięgiel
8ce977505e actions: nightly: Manually install SDK extensions via workflow
The github actions Flatpak action only allows to specify single source
for installing missing dependencies. This makes impossible to build
some things from "gnome-nightly" while others from "flathub" repo.

Work around this limitation by manually installing missing SDK
extensions from Flathub prior to using this git action.
2022-03-10 22:55:24 +01:00
Rafał Dzięgiel
8ac839c9aa flatpak-nightly: Disable cloning GStreamer submodules
It seems that now GStreamer ships its testsuite (which we do not need) as a submodule. Do not try to clone it.
2022-03-10 22:55:09 +01:00
Rafał Dzięgiel
8fa2036265 actions: Allow runs on workflow_dispatch 2022-03-10 09:32:11 +01:00
Rafał Dzięgiel
1d5bb1e6aa Merge pull request #227 from Rafostar/nightly-rust
flatpak-nightly: Build dav1d decoder from gst-plugins-rs
2022-03-09 22:09:22 +01:00
Rafał Dzięgiel
9ec87c1b58 flatpak-nightly: Build dav1d decoder from gst-plugins-rs 2022-03-09 20:53:18 +01:00
Rafał Dzięgiel
16c0f8baae Merge pull request #226 from Rafostar/speed-fix
Fix end time calculation with with non-1x speed
2022-03-06 16:52:40 +01:00
Rafał Dzięgiel
c94d21fc53 Fix end time calculation with with non-1x speed 2022-03-06 15:51:06 +01:00
Rafał Dzięgiel
159f96c984 Merge pull request #214 from Rafostar/libsoup3
libsoup3
2022-02-28 16:58:29 +01:00
Rafał Dzięgiel
96ad4fa3db RPM: Require libsoup3 2022-02-17 15:44:45 +01:00
Rafał Dzięgiel
b2e7bef8d4 flatpak: Update git actions runtime to 41
We need to update, so we can build libsoup3. Flathub ver will likely remain as 40 ver to avoid some problems and will be updated directly to 42 later.
2022-02-14 17:37:15 +01:00
Rafał Dzięgiel
40a1dc6960 flatpak: Build libsoup3
Now both Clapper and Gtuber lib require libsoup3, so build it until it will be available in runtime
2022-02-14 17:37:15 +01:00
Rafał Dzięgiel
c4bd604e17 Port to libsoup3
With all apps and modules/plugins porting itself to libsoup3 we also need to do so.

It would appear as a good idea to conditionally import "3.0" and fallback to "2.4"
bindings here, but its not as loaded GStreamer plugins might use libsoup3 already
and we cannot have both libsoup2 and libsoup3 in a single process.
2022-02-14 17:37:15 +01:00
Rafał Dzięgiel
83c0e3b598 Remove unfinished web application
It used Broadway as an easy "reuse the same code into web application" way for me, but Broadway
is not very good for this. This feature should be made using some better dedicated framework for
building websites (so it can work better and support different screen sizes).

All the WebSocket functionality needed for this will remain (and be documented at a later point
when expanded and stable), so if anyone would like to make such remote controlling app, will be
free to do so (outside of Clapper code).
2022-02-14 17:37:15 +01:00
Rafał Dzięgiel
54715023c0 flatpak: Update git actions manifest 2022-02-14 16:36:29 +01:00
Rafał Dzięgiel
95046ceba8 flatpak: Sync with Flathub 2022-02-14 16:06:36 +01:00
Rafał Dzięgiel
b189e24b5e Merge pull request #209 from simonsextras/swdeish-tranlation-nbfreygff
Full Swedish Translation
2022-01-21 12:14:22 +01:00
sastofficial
cb9e2ac979 Update sv.po 2022-01-21 09:35:17 +01:00
sastofficial
545d8826e0 Update sv.po 2022-01-19 13:46:08 +01:00
Rafał Dzięgiel
c2160198b9 Update LINGUAS file 2022-01-19 10:07:09 +01:00
Rafał Dzięgiel
aa7eae2417 New translations com.github.rafostar.Clapper.pot (French) (#208) 2022-01-19 10:00:56 +01:00
Rafał Dzięgiel
3192a32845 Merge pull request #206 from Rafostar/unicode
Use more unicode characters
2022-01-18 18:46:06 +01:00
Rafał Dzięgiel
706c783498 Use unicode U+2215 for division 2022-01-17 22:28:17 +01:00
Rafał Dzięgiel
8ba3ca4af6 Use unicode U+00D7 for multiplication 2022-01-17 21:01:23 +01:00
Rafał Dzięgiel
38efa7ab9f Use unicode U+2236 for time 2022-01-17 20:27:13 +01:00
Rafał Dzięgiel
d19ddbcaca Merge pull request #204 from Rafostar/devel
Misc gstclapper fixes
2022-01-17 11:00:28 +01:00
Rafał Dzięgiel
615f1553fb flatpak: Sync with Flathub 2022-01-17 10:19:29 +01:00
Rafał Dzięgiel
09c9e7560b New Crowdin updates (#201)
* New translations com.github.rafostar.Clapper.pot (Swedish)

* New translations com.github.rafostar.Clapper.pot (Russian)

* New translations com.github.rafostar.Clapper.pot (Chinese Simplified)

* New translations com.github.rafostar.Clapper.pot (Spanish)

* New translations com.github.rafostar.Clapper.pot (Spanish)

* New translations com.github.rafostar.Clapper.pot (Basque)
2022-01-17 08:56:59 +01:00
Rafał Dzięgiel
f40ce756ad Merge pull request #199 from majjejjam/master
change three dots to ellipsis
2022-01-16 14:10:49 +01:00
majjejjam
23d51be185 changed to ellipses in ui/clapper.ui 2022-01-15 18:20:13 +01:00
Rafał Dzięgiel
0db2a4a045 gstclapper: Fix plugin feature leak 2022-01-14 09:28:26 +01:00
Rafostar
469c06d22b gstclapper: Go into NULL state directly when stopped
Instead of waiting another 60 seconds for user, go into NULL state ASAP to free all resources and open devices.
2022-01-09 13:31:37 +01:00
Rafostar
3feaf225b5 gstclapper: Make tags writable before insert
Someone might be holding a copied media info in which case tag
list ref count is not 1. Use gst_tag_list_make_writable to
assure that ref count is 1, so we can insert more tags into the list.
2022-01-09 13:31:29 +01:00
majjejjam
fc8d881efd change three dots to ellipsis 2022-01-08 16:28:07 +01:00
Rafał Dzięgiel
ac76836fd7 Merge pull request #192 from Rafostar/yt-removal
YouTube code removal
2022-01-05 14:27:59 +01:00
Rafał Dzięgiel
f6a1aaf1dc Remove all YouTube code
It has been broken for quite some time. From now on this is gonna be left to handle for GStreamer plugins.
2021-12-22 08:12:55 +01:00
Rafał Dzięgiel
000dca82d9 flatpak: Sync with Flathub 2021-12-20 21:23:31 +01:00
Rafał Dzięgiel
7a508fef39 0.4.1 2021-12-20 11:33:19 +01:00
Rafał Dzięgiel
d465d9f150 Make floating window update its title earlier
Instead of waiting till animation finishes, update the window title right away when changing modes
2021-12-15 16:58:54 +01:00
Rafał Dzięgiel
5e4dfb322c Append "PiP" suffix to window title when in floating mode
We are gonna take advantage of this simple change elsewhere
2021-12-15 12:44:23 +01:00
Rafał Dzięgiel
0c561ab4b3 Also allow enabling gtuber code path via env
Having to use "gtuber" URI scheme might be inconvenient, so also allow to
whitelist it with "GST_PLUGIN_FEATURE_RANK=gtubersrc:300" env
2021-12-10 11:05:00 +01:00
Rafał Dzięgiel
46ce261524 widget: Make sure we have caps before logging them 2021-12-10 11:03:06 +01:00
Rafał Dzięgiel
50aac8cdd8 gstclapper: Merge global tags instead replacing them
There is no guarantee that received later tags also contain values from
earlier ones, as they might come from different element.
Combine them instead while replacing old values with newer ones.
2021-12-02 08:52:35 +01:00
Rafał Dzięgiel
810aea476f Use gtuber lib for URIs with "gtuber" scheme
Take a different code path when URI uses "gtuber" scheme.
This allows testing new WIP lib as an opt-in.
2021-11-29 22:33:53 +01:00
Rafał Dzięgiel
24905f1d60 flatpak: Build gtuber 2021-11-29 22:30:21 +01:00
Rafał Dzięgiel
82e3c9a52f prefs: Add can-swipe-back compat with latest libadwaita
Recent libadwaita has renamed "can-swipe-back" into "can-navigate-back".
Set both in JS code instead of UI file in order to support all libadwaita versions.

Fixes #185
2021-11-29 10:13:06 +01:00
Rafał Dzięgiel
654b8aaf60 prefs: Fix expander rows compat with latest libadwaita 2021-11-19 18:43:01 +01:00
Rafał Dzięgiel
3c0e33e4a4 css: Few override fixes for latest libadwaita 2021-11-19 18:40:34 +01:00
Rafał Dzięgiel
d2df1c3bd8 app: Use Adw.StyleManager to enable dark-theme
Latest libadwaita (for reasons unknown to me) totally ignores/breaks dark theme usage with gtk_application_prefer_dark_theme property. Lets just try using the new Adw.StyleManager without asking questions why.
2021-11-18 22:42:05 +01:00
Rafał Dzięgiel
af24073590 Update LINGUAS file 2021-11-18 15:37:48 +01:00
Rafał Dzięgiel
44cee14eb2 New translations com.github.rafostar.Clapper.pot (Portuguese) (#175) 2021-11-18 15:34:16 +01:00
Rafał Dzięgiel
b853685dd4 gstclapper: Fix decoder stream ID string leak 2021-10-22 13:11:42 +02:00
Rafał Dzięgiel
15461dd38a gstclapper: Fix video/audio decoder change detection
The video/audio decoder changed signal was not working correctly in case of
multiple streams with multiple decoders in single file.

We need to listen to the current-(video/audio) signal, when it changes find
corresponding "input-selector", get stream ID from its active pad and then
find the decoder in the pipeline that handles this stream ID. Similarly for
playbin3, but use stream ID from the "streams-selected" signal.
2021-10-22 11:05:08 +02:00
Rafał Dzięgiel
1c1989bc32 gstclapper: Fix GST_PLUGIN_FEATURE_RANK env usage
We change few default plugin ranks during init to whitelist them, but we do not update
their values from GST_PLUGIN_FEATURE_RANK env afterwards, so do that.
The ENV should be preferred over default config.
2021-10-21 11:21:07 +02:00
Rafał Dzięgiel
e9c9ae073f flatpak-nightly: Enable GPL gstreamer plugins 2021-10-19 10:23:41 +02:00
Rafał Dzięgiel
22d2c40b0f flatpak-nightly: Build from gstreamer mono repo 2021-10-18 11:13:44 +02:00
Rafał Dzięgiel
5301c8b368 flatpak: Sync with Flathub 2021-10-14 20:35:53 +02:00
Rafał Dzięgiel
e910978590 Update LINGUAS file
Install Portuguese-Brazilian translation
2021-10-14 20:30:18 +02:00
Rafał Dzięgiel
3b99f0ee0c New Crowdin updates (#172)
* New translations com.github.rafostar.Clapper.pot (Portuguese, Brazilian)
2021-10-12 08:44:14 +02:00
Rafał Dzięgiel
f93a0fed98 Update LINGUAS file 2021-10-04 16:06:45 +02:00
Rafał Dzięgiel
6b8c35b16e Merge pull request #166 from GNUuser/patch-1
Update es.po
2021-10-04 15:59:21 +02:00
Rafał Dzięgiel
5fdb6e64be New Crowdin updates (#164)
* New translations com.github.rafostar.Clapper.pot (Chinese Simplified)

* New translations com.github.rafostar.Clapper.pot (Italian)
2021-10-04 15:14:51 +02:00
Rafał Dzięgiel
60d4b5aec1 widget: Do gestures in capture phase
Capture phase runs from the toplevel down to the event widget and is meant to be used
in containers that might possibly handle events before their children, like our OSD layer.

This avoids an issue where pressing an OSD button does not emit cancelled signal,
accidentally triggering long press gesture signal handler.

Fixes #170
2021-10-04 10:11:53 +02:00
carlosgonz
f5258889cf Update es.po 2021-10-02 10:08:14 -04:00
carlosgonz
31eddf5dd2 Update es.po 2021-10-02 10:07:15 -04:00
carlosgonz
89f7304e0e Update es.po
initial Spanish file
2021-10-01 18:59:03 -04:00
Rafał Dzięgiel
3c918bda73 New Crowdin updates (#163)
* New translations com.github.rafostar.Clapper.pot (Hungarian)
2021-09-22 10:15:35 +02:00
Rafał Dzięgiel
2a8ef2559f New Crowdin updates (#162)
* New translations com.github.rafostar.Clapper.pot (Czech)
2021-09-20 08:34:28 +02:00
Rafał Dzięgiel
7676e18eee New translations com.github.rafostar.Clapper.pot (Russian) (#161) 2021-09-17 11:03:54 +02:00
Rafał Dzięgiel
00b05b460d Merge pull request #158 from igor-dyatlov/master
Added Russian translate
2021-09-17 10:58:05 +02:00
Igor Dyatlov
62f02cf2a3 Added Russian translate 2021-09-16 12:31:19 +03:00
Rafał Dzięgiel
9fc1d9b8c4 sink: Do not leak pool when set config fails 2021-09-15 16:28:23 +02:00
Rafał Dzięgiel
45a5ebb4b6 New Crowdin updates (#157)
* New translations com.github.rafostar.Clapper.pot (Romanian)

* New translations com.github.rafostar.Clapper.pot (Korean)

* New translations com.github.rafostar.Clapper.pot (Vietnamese)

* New translations com.github.rafostar.Clapper.pot (Chinese Traditional)

* New translations com.github.rafostar.Clapper.pot (Chinese Simplified)

* New translations com.github.rafostar.Clapper.pot (Ukrainian)

* New translations com.github.rafostar.Clapper.pot (Turkish)

* New translations com.github.rafostar.Clapper.pot (Swedish)

* New translations com.github.rafostar.Clapper.pot (Serbian (Cyrillic))

* New translations com.github.rafostar.Clapper.pot (Russian)

* New translations com.github.rafostar.Clapper.pot (Portuguese)

* New translations com.github.rafostar.Clapper.pot (Polish)

* New translations com.github.rafostar.Clapper.pot (Norwegian)

* New translations com.github.rafostar.Clapper.pot (Dutch)

* New translations com.github.rafostar.Clapper.pot (Japanese)

* New translations com.github.rafostar.Clapper.pot (French)

* New translations com.github.rafostar.Clapper.pot (Italian)

* New translations com.github.rafostar.Clapper.pot (Hungarian)

* New translations com.github.rafostar.Clapper.pot (Hebrew)

* New translations com.github.rafostar.Clapper.pot (Finnish)

* New translations com.github.rafostar.Clapper.pot (Greek)

* New translations com.github.rafostar.Clapper.pot (German)

* New translations com.github.rafostar.Clapper.pot (Danish)

* New translations com.github.rafostar.Clapper.pot (Czech)

* New translations com.github.rafostar.Clapper.pot (Catalan)

* New translations com.github.rafostar.Clapper.pot (Arabic)

* New translations com.github.rafostar.Clapper.pot (Afrikaans)

* New translations com.github.rafostar.Clapper.pot (Spanish)

* New translations com.github.rafostar.Clapper.pot (Portuguese, Brazilian)

* New translations com.github.rafostar.Clapper.pot (Catalan)

* New translations com.github.rafostar.Clapper.pot (Dutch)

* New translations com.github.rafostar.Clapper.pot (Polish)
2021-09-15 10:54:52 +02:00
Rafał Dzięgiel
2500a42286 Fix missing gio-unix-2.0 dep
Our autogenerated MPRIS code needs it. On some packaging systems this might be included outside of glib, so depend on it explicitly.
2021-09-14 17:54:03 +02:00
Rafał Dzięgiel
bafffa59b9 Fix missing translator-credits 2021-09-14 16:40:09 +02:00
Rafał Dzięgiel
201cb6f64c actions: Also allow mute with "M" key alone
For faster access
2021-09-14 13:09:23 +02:00
Rafał Dzięgiel
636098182b actions: Keep consistent letters case 2021-09-14 13:06:44 +02:00
Rafał Dzięgiel
5442b0b70a uri-dialog: Catch errors when reading from clipboard
The clipboard.read_text_finish method might throw an error when something goes wrong. Catch it and print in debug message. There is no alternative clipboard reading, so simply ignore.
2021-09-14 13:00:14 +02:00
Rafał Dzięgiel
67d1b9f5bc flatpak: Sync with Flathub 2021-09-13 14:06:48 +02:00
116 changed files with 6325 additions and 3930 deletions

View File

@@ -1,4 +1,5 @@
on:
workflow_dispatch:
schedule:
- cron: "0 0 * * *"
name: "Flatpak Nightly"
@@ -25,8 +26,12 @@ jobs:
uses: docker/setup-qemu-action@v1
with:
platforms: arm64
- name: Prepare Runtime
run: |
flatpak --system install -y --noninteractive flathub org.freedesktop.Sdk.Extension.rust-nightly/${{ matrix.arch }}/21.08
flatpak --system install -y --noninteractive flathub org.freedesktop.Sdk.Extension.llvm13/${{ matrix.arch }}/21.08
- uses: bilelmoussaoui/flatpak-github-actions/flatpak-builder@v4
name: "Build"
name: Build
with:
bundle: com.github.rafostar.Clapper.flatpak
manifest-path: pkgs/flatpak/com.github.rafostar.Clapper-nightly.json

View File

@@ -1,4 +1,5 @@
on:
workflow_dispatch:
push:
branches:
- master
@@ -11,7 +12,7 @@ jobs:
name: "Flatpak"
runs-on: ubuntu-latest
container:
image: bilelmoussaoui/flatpak-github-actions:gnome-40
image: bilelmoussaoui/flatpak-github-actions:gnome-42
options: --privileged
strategy:
matrix:

View File

@@ -2,6 +2,8 @@
[![Flatpak](https://github.com/Rafostar/clapper/actions/workflows/flatpak.yml/badge.svg?event=push)](https://github.com/Rafostar/clapper/actions/workflows/flatpak.yml)
[![Flatpak Nightly](https://github.com/Rafostar/clapper/actions/workflows/flatpak-nightly.yml/badge.svg?event=schedule)](https://github.com/Rafostar/clapper/actions/workflows/flatpak-nightly.yml)
[![Crowdin](https://badges.crowdin.net/clapper/localized.svg)](https://crowdin.com/project/clapper)
[![Matrix](https://img.shields.io/matrix/clapper-player:matrix.org?label=matrix)](https://matrix.to/#/#clapper-player:matrix.org)
[![Donate](https://img.shields.io/liberapay/receives/Clapper.svg?logo=liberapay)](https://liberapay.com/Clapper)
A GNOME media player built using [GJS](https://gitlab.gnome.org/GNOME/gjs) with [GTK4](https://www.gtk.org) toolkit.
The media player uses [GStreamer](https://gstreamer.freedesktop.org/) as a media backend and renders everything via [OpenGL](https://www.opengl.org).
@@ -38,17 +40,13 @@ List of patches used in this version can be found [here](https://github.com/Rafo
<img width='240' alt='Download on Flathub' src='https://flathub.org/assets/badges/flathub-badge-en.png'/>
</a>
## Packages
#### Fedora & openSUSE
Pre-built packages are available in [my repo](https://software.opensuse.org//download.html?project=home%3ARafostar&package=clapper) ([see status](https://build.opensuse.org/package/show/home:Rafostar/clapper)).<br>
Those are automatically built on each git commit, and are thus considered unstable.
## Packages in Linux Distributions
[![Packaging status](https://repology.org/badge/vertical-allrepos/clapper.svg)](https://repology.org/project/clapper/versions)
#### Arch Linux
You can get Clapper from the AUR:
* [clapper](https://aur.archlinux.org/packages/clapper) (stable version)
* [clapper-git](https://aur.archlinux.org/packages/clapper-git)
Pre-built RPM packages are also available in [my repo](https://software.opensuse.org//download.html?project=home%3ARafostar&package=clapper) ([see status](https://build.opensuse.org/package/show/home:Rafostar/clapper)).<br>
Those are automatically built on each git commit, thus are considered unstable.
## Installation from source code
## Installation from Source Code
```sh
meson builddir --prefix=/usr/local
sudo meson install -C builddir

View File

@@ -6,4 +6,4 @@ imports.package.init({
prefix: '@prefix@',
libdir: '@libdir@',
});
imports.package.run(imports.src.main@ID_POSTFIX@);
imports.package.run(imports.src.main);

View File

@@ -1,25 +1,19 @@
clapper_apps = ['', 'Remote', 'Daemon']
bin_conf = configuration_data()
foreach id_postfix : clapper_apps
app_postfix = (id_postfix != '') ? '.' + id_postfix : ''
bin_conf.set('GJS', find_program('gjs').path())
bin_conf.set('PACKAGE_NAME', meson.project_name())
bin_conf.set('PACKAGE_VERSION', meson.project_version())
bin_conf.set('prefix', get_option('prefix'))
bin_conf.set('libdir', libdir)
bin_conf = configuration_data()
bin_conf.set('GJS', find_program('gjs').path())
bin_conf.set('PACKAGE_NAME', meson.project_name())
bin_conf.set('PACKAGE_VERSION', meson.project_version())
bin_conf.set('ID_POSTFIX', id_postfix)
bin_conf.set('prefix', get_option('prefix'))
bin_conf.set('libdir', libdir)
configure_file(
input: 'com.github.rafostar.Clapper.in',
output: 'com.github.rafostar.Clapper' + app_postfix,
configuration: bin_conf,
install: true,
install_dir: bindir,
install_mode: 'rwxr-xr-x'
)
endforeach
configure_file(
input: 'com.github.rafostar.Clapper.in',
output: 'com.github.rafostar.Clapper',
configuration: bin_conf,
install: true,
install_dir: bindir,
install_mode: 'rwxr-xr-x'
)
clapper_symlink_cmd = 'ln -fs @0@ $DESTDIR@1@'.format(
'com.github.rafostar.Clapper',

View File

@@ -10,6 +10,9 @@ scrolledwindow scrollbar.vertical slider {
}
/* Adwaita is missing osd ListBox */
.clapperplaylist {
background: none;
}
.clapperplaylist row {
border-radius: 5px;
}
@@ -28,9 +31,6 @@ scrolledwindow scrollbar.vertical slider {
margin-left: 2px;
margin-right: 2px;
}
.osd .clapperplaylist {
background: none;
}
.osd .clapperplaylist row image {
-gtk-icon-shadow: none;
}
@@ -223,6 +223,9 @@ scale trough slider {
.fullscreen.tvmode .positionscale marks.bottom {
margin-top: 2px;
}
.fullscreen.tvmode .positionscale trough {
border-radius: 3px;
}
.fullscreen.tvmode .positionscale trough highlight {
border-radius: 3px;
min-height: 20px;

View File

@@ -103,16 +103,6 @@
<summary>Set PlayFlags for playbin</summary>
</key>
<!-- YouTube -->
<key name="yt-adaptive-enabled" type="b">
<default>false</default>
<summary>Enable to use adaptive streaming for YouTube</summary>
</key>
<key name="yt-quality-type" type="i">
<default>1</default>
<summary>Max YouTube video quality type</summary>
</key>
<!-- Other -->
<key name="window-size" type="s">
<default>'[800, 490]'</default>

View File

@@ -48,6 +48,34 @@
</screenshot>
</screenshots>
<releases>
<release version="0.4.1" date="2021-12-20">
<description>
<p>Fixes:</p>
<ul>
<li>Compatibility with more recent libadwaita versions</li>
<li>Toggle mute with M button alone</li>
<li>Allow handling YouTube with external GStreamer plugins</li>
<li>Fix catching errors when reading clipboard</li>
<li>Fix missing translator-credits</li>
<li>Fix missing gio-unix-2.0 dep</li>
<li>Fix playback pausing when entering fullscreen with touchscreen</li>
<li>Fix GST_PLUGIN_FEATURE_RANK env usage</li>
<li>Fix video/audio decoder change detection</li>
<li>Merge global video tags instead replacing them</li>
<li>Few other misc bug fixes</li>
</ul>
<p>New translations:</p>
<ul>
<li>Chinese Simplified</li>
<li>Czech</li>
<li>Hungarian</li>
<li>Portuguese</li>
<li>Portuguese, Brazilian</li>
<li>Russian</li>
<li>Spanish</li>
</ul>
</description>
</release>
<release version="0.4.0" date="2021-09-12">
<description>
<p>Changes:</p>

View File

@@ -152,7 +152,7 @@ struct _GstClapper
GstBus *bus;
GstState target_state, current_state;
gboolean is_live;
GSource *tick_source, *ready_timeout_source;
GSource *tick_source;
GstClockTime cached_duration;
gdouble rate;
@@ -253,6 +253,9 @@ static void gst_clapper_audio_info_update (GstClapper * self,
static void gst_clapper_subtitle_info_update (GstClapper * self,
GstClapperStreamInfo * stream_info);
static gboolean find_active_decoder_with_stream_id (GstClapper * self,
GstElementFactoryListType type, const gchar * stream_id);
/* For playbin3 */
static void gst_clapper_streams_info_create_from_collection (GstClapper * self,
GstClapperMediaInfo * media_info, GstStreamCollection * collection);
@@ -1135,44 +1138,6 @@ remove_tick_source (GstClapper * self)
self->tick_source = NULL;
}
static gboolean
ready_timeout_cb (gpointer user_data)
{
GstClapper *self = user_data;
if (self->target_state <= GST_STATE_READY) {
GST_DEBUG_OBJECT (self, "Setting pipeline to NULL state");
self->target_state = GST_STATE_NULL;
self->current_state = GST_STATE_NULL;
gst_element_set_state (self->playbin, GST_STATE_NULL);
}
return G_SOURCE_REMOVE;
}
static void
add_ready_timeout_source (GstClapper * self)
{
if (self->ready_timeout_source)
return;
self->ready_timeout_source = g_timeout_source_new_seconds (60);
g_source_set_callback (self->ready_timeout_source,
(GSourceFunc) ready_timeout_cb, self, NULL);
g_source_attach (self->ready_timeout_source, self->context);
}
static void
remove_ready_timeout_source (GstClapper * self)
{
if (!self->ready_timeout_source)
return;
g_source_destroy (self->ready_timeout_source);
g_source_unref (self->ready_timeout_source);
self->ready_timeout_source = NULL;
}
typedef struct
{
GstClapper *clapper;
@@ -1217,7 +1182,6 @@ emit_error (GstClapper * self, GError * err)
g_error_free (err);
remove_tick_source (self);
remove_ready_timeout_source (self);
self->target_state = GST_STATE_NULL;
self->current_state = GST_STATE_NULL;
@@ -1862,6 +1826,17 @@ media_info_update (GstClapper * self, GstClapperMediaInfo * info)
"image_sample: %p", info->title, info->container, info->image_sample);
}
static void
merge_tags (GstTagList **my_tags, GstTagList *tags)
{
if (*my_tags) {
*my_tags = gst_tag_list_make_writable (*my_tags);
gst_tag_list_insert (*my_tags, tags, GST_TAG_MERGE_REPLACE);
} else {
*my_tags = gst_tag_list_ref (tags);
}
}
static void
tags_cb (G_GNUC_UNUSED GstBus * bus, GstMessage * msg, gpointer user_data)
{
@@ -1877,17 +1852,12 @@ tags_cb (G_GNUC_UNUSED GstBus * bus, GstMessage * msg, gpointer user_data)
if (gst_tag_list_get_scope (tags) == GST_TAG_SCOPE_GLOBAL) {
g_mutex_lock (&self->lock);
if (self->media_info) {
if (self->media_info->tags)
gst_tag_list_unref (self->media_info->tags);
self->media_info->tags = gst_tag_list_ref (tags);
merge_tags (&self->media_info->tags, tags);
media_info_update (self, self->media_info);
g_mutex_unlock (&self->lock);
} else {
if (self->global_tags)
gst_tag_list_unref (self->global_tags);
self->global_tags = gst_tag_list_ref (tags);
g_mutex_unlock (&self->lock);
merge_tags (&self->global_tags, tags);
}
g_mutex_unlock (&self->lock);
}
gst_tag_list_unref (tags);
@@ -2050,6 +2020,7 @@ streams_selected_cb (G_GNUC_UNUSED GstBus * bus, GstMessage * msg,
{
GstClapper *self = GST_CLAPPER (user_data);
GstStreamCollection *collection = NULL;
gchar *video_sid, *audio_sid;
guint i, len;
gst_message_parse_streams_selected (msg, &collection);
@@ -2098,7 +2069,22 @@ streams_selected_cb (G_GNUC_UNUSED GstBus * bus, GstMessage * msg,
*current_sid = g_strdup (stream_id);
}
video_sid = g_strdup (self->video_sid);
audio_sid = g_strdup (self->audio_sid);
g_mutex_unlock (&self->lock);
if (video_sid) {
find_active_decoder_with_stream_id (self, GST_ELEMENT_FACTORY_TYPE_DECODER
| GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO, video_sid);
g_free (video_sid);
}
if (audio_sid) {
find_active_decoder_with_stream_id (self, GST_ELEMENT_FACTORY_TYPE_DECODER
| GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO, audio_sid);
g_free (audio_sid);
}
}
static gboolean
@@ -3009,11 +2995,12 @@ decoder_changed_signal_data_free (DecoderChangedSignalData * data)
static void
emit_decoder_changed (GstClapper * self, gchar * decoder_name,
gboolean is_video)
GstElementFactoryListType type)
{
GstClapperSignalDispatcherFunc func = NULL;
if (is_video) {
if ((type & GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO) ==
GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO) {
if (g_signal_handler_find (self, G_SIGNAL_MATCH_ID,
signals[SIGNAL_VIDEO_DECODER_CHANGED], 0, NULL, NULL, NULL) != 0 &&
g_strcmp0 (self->last_vdecoder, decoder_name) != 0) {
@@ -3021,7 +3008,8 @@ emit_decoder_changed (GstClapper * self, gchar * decoder_name,
g_free (self->last_vdecoder);
self->last_vdecoder = g_strdup (decoder_name);
}
} else {
} else if ((type & GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO) ==
GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO) {
if (g_signal_handler_find (self, G_SIGNAL_MATCH_ID,
signals[SIGNAL_AUDIO_DECODER_CHANGED], 0, NULL, NULL, NULL) != 0 &&
g_strcmp0 (self->last_adecoder, decoder_name) != 0) {
@@ -3042,6 +3030,138 @@ emit_decoder_changed (GstClapper * self, gchar * decoder_name,
}
}
static gboolean
iterate_decoder_pads (GstClapper * self, GstElement * element,
const gchar * stream_id, GstElementFactoryListType type)
{
GstIterator *iter;
GValue value = { 0, };
gboolean found = FALSE;
iter = gst_element_iterate_src_pads (element);
while (gst_iterator_next (iter, &value) == GST_ITERATOR_OK) {
GstPad *decoder_pad = g_value_get_object (&value);
gchar *decoder_stream_id = gst_pad_get_stream_id (decoder_pad);
GST_DEBUG_OBJECT (self, "Decoder stream: %s", decoder_stream_id);
/* In case of playbin3, pad may not be active yet */
if ((found = (g_strcmp0 (decoder_stream_id, stream_id) == 0
|| (!decoder_stream_id && self->use_playbin3)))) {
GstElementFactory *factory;
gchar *plugin_name;
factory = gst_element_get_factory (element);
plugin_name = gst_object_get_name (GST_OBJECT_CAST (factory));
if (plugin_name) {
GST_DEBUG_OBJECT (self, "Found decoder: %s", plugin_name);
emit_decoder_changed (self, plugin_name, type);
g_free (plugin_name);
}
}
g_free (decoder_stream_id);
g_value_unset (&value);
if (found)
break;
}
gst_iterator_free (iter);
return found;
}
static gboolean
find_active_decoder_with_stream_id (GstClapper * self, GstElementFactoryListType type,
const gchar * stream_id)
{
GstIterator *iter;
GValue value = { 0, };
gboolean found = FALSE;
GST_DEBUG_OBJECT (self, "Searching for decoder with stream: %s", stream_id);
iter = gst_bin_iterate_recurse (GST_BIN (self->playbin));
while (gst_iterator_next (iter, &value) == GST_ITERATOR_OK) {
GstElement *element = g_value_get_object (&value);
GstElementFactory *factory = gst_element_get_factory (element);
if (factory && gst_element_factory_list_is_type (factory, type))
found = iterate_decoder_pads (self, element, stream_id, type);
g_value_unset (&value);
if (found)
break;
}
gst_iterator_free (iter);
return found;
}
static void
update_current_decoder (GstClapper *self, GstElementFactoryListType type)
{
GstIterator *iter;
GValue value = { 0, };
iter = gst_bin_iterate_all_by_element_factory_name (
GST_BIN (self->playbin), "input-selector");
while (gst_iterator_next (iter, &value) == GST_ITERATOR_OK) {
GstElement *element = g_value_get_object (&value);
GstPad *active_pad;
gboolean found = FALSE;
g_object_get (G_OBJECT (element), "active-pad", &active_pad, NULL);
if (active_pad) {
gchar *stream_id;
stream_id = gst_pad_get_stream_id (active_pad);
gst_object_unref (active_pad);
if (stream_id) {
found = find_active_decoder_with_stream_id (self, type, stream_id);
g_free (stream_id);
}
}
g_value_unset (&value);
if (found)
break;
}
gst_iterator_free (iter);
}
static void
current_video_notify_cb (G_GNUC_UNUSED GObject * obj, G_GNUC_UNUSED GParamSpec * pspec,
GstClapper * self)
{
GstElementFactoryListType type = GST_ELEMENT_FACTORY_TYPE_DECODER
| GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO;
update_current_decoder (self, type);
}
static void
current_audio_notify_cb (G_GNUC_UNUSED GObject * obj, G_GNUC_UNUSED GParamSpec * pspec,
GstClapper * self)
{
GstElementFactoryListType type = GST_ELEMENT_FACTORY_TYPE_DECODER
| GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO;
update_current_decoder (self, type);
}
static void
element_setup_cb (GstElement * playbin, GstElement * element, GstClapper * self)
{
@@ -3054,13 +3174,6 @@ element_setup_cb (GstElement * playbin, GstElement * element, GstClapper * self)
if (plugin_name) {
GST_INFO_OBJECT (self, "Plugin setup: %s", plugin_name);
if (gst_element_factory_list_is_type (factory,
GST_ELEMENT_FACTORY_TYPE_DECODER | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO))
emit_decoder_changed (self, plugin_name, TRUE);
else if (gst_element_factory_list_is_type (factory,
GST_ELEMENT_FACTORY_TYPE_DECODER | GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO))
emit_decoder_changed (self, plugin_name, FALSE);
/* TODO: Set plugin props */
}
g_free (plugin_name);
@@ -3229,6 +3342,11 @@ gst_clapper_main (gpointer data)
G_CALLBACK (audio_tags_changed_cb), self);
g_signal_connect (self->playbin, "text-tags-changed",
G_CALLBACK (subtitle_tags_changed_cb), self);
g_signal_connect (self->playbin, "notify::current-video",
G_CALLBACK (current_video_notify_cb), self);
g_signal_connect (self->playbin, "notify::current-audio",
G_CALLBACK (current_audio_notify_cb), self);
}
g_signal_connect (self->playbin, "notify::volume",
@@ -3255,7 +3373,6 @@ gst_clapper_main (gpointer data)
gst_object_unref (bus);
remove_tick_source (self);
remove_ready_timeout_source (self);
g_mutex_lock (&self->lock);
if (self->media_info) {
@@ -3324,6 +3441,104 @@ gst_clapper_has_plugin_with_features (const gchar * name)
return ret;
}
static gboolean
parse_feature_name (gchar * str, const gchar ** feature)
{
if (!str)
return FALSE;
g_strstrip (str);
if (str[0] != '\0') {
*feature = str;
return TRUE;
}
return FALSE;
}
static gboolean
parse_feature_rank (gchar * str, GstRank * rank)
{
if (!str)
return FALSE;
g_strstrip (str);
if (g_ascii_isdigit (str[0])) {
unsigned long l;
char *endptr;
l = strtoul (str, &endptr, 10);
if (endptr > str && endptr[0] == 0) {
*rank = (GstRank) l;
} else {
return FALSE;
}
} else if (g_ascii_strcasecmp (str, "NONE") == 0) {
*rank = GST_RANK_NONE;
} else if (g_ascii_strcasecmp (str, "MARGINAL") == 0) {
*rank = GST_RANK_MARGINAL;
} else if (g_ascii_strcasecmp (str, "SECONDARY") == 0) {
*rank = GST_RANK_SECONDARY;
} else if (g_ascii_strcasecmp (str, "PRIMARY") == 0) {
*rank = GST_RANK_PRIMARY;
} else if (g_ascii_strcasecmp (str, "MAX") == 0) {
*rank = (GstRank) G_MAXINT;
} else {
return FALSE;
}
return TRUE;
}
static void
_env_feature_rank_update (void)
{
const gchar *env;
gchar **split, **walk;
env = g_getenv ("GST_PLUGIN_FEATURE_RANK");
if (!env)
return;
split = g_strsplit (env, ",", 0);
for (walk = split; *walk; walk++) {
if (strchr (*walk, ':')) {
gchar **values;
values = g_strsplit (*walk, ":", 2);
if (values[0] && values[1]) {
GstRank rank;
const gchar *name;
if (parse_feature_name (values[0], &name)
&& parse_feature_rank (values[1], &rank)) {
GstPluginFeature *feature;
feature = gst_registry_find_feature (gst_registry_get (), name,
GST_TYPE_ELEMENT_FACTORY);
if (feature) {
GstRank old_rank;
old_rank = gst_plugin_feature_get_rank (feature);
if (old_rank != rank) {
gst_plugin_feature_set_rank (feature, rank);
GST_DEBUG ("Updated rank from env: %i -> %i for %s", old_rank, rank, name);
}
gst_object_unref (feature);
}
}
}
g_strfreev (values);
}
}
g_strfreev (split);
}
static void
gst_clapper_prepare_gstreamer (void)
{
@@ -3346,6 +3561,9 @@ gst_clapper_prepare_gstreamer (void)
gst_clapper_set_feature_rank ("v4l2slvp8dec", GST_RANK_NONE);
}
/* After setting defaults, update them from ENV */
_env_feature_rank_update ();
gst_clapper_gstreamer_prepared = TRUE;
GST_DEBUG ("GStreamer plugins prepared");
}
@@ -3422,7 +3640,6 @@ gst_clapper_play_internal (gpointer user_data)
}
g_mutex_unlock (&self->lock);
remove_ready_timeout_source (self);
self->target_state = GST_STATE_PLAYING;
if (self->current_state < GST_STATE_PAUSED)
@@ -3490,7 +3707,6 @@ gst_clapper_pause_internal (gpointer user_data)
tick_cb (self);
remove_tick_source (self);
remove_ready_timeout_source (self);
self->target_state = GST_STATE_PAUSED;
@@ -3570,13 +3786,11 @@ gst_clapper_stop_internal (GstClapper * self, gboolean transient)
tick_cb (self);
remove_tick_source (self);
add_ready_timeout_source (self);
self->target_state = GST_STATE_NULL;
self->current_state = GST_STATE_READY;
self->current_state = GST_STATE_NULL;
self->is_live = FALSE;
gst_bus_set_flushing (self->bus, TRUE);
gst_element_set_state (self->playbin, GST_STATE_READY);
gst_element_set_state (self->playbin, GST_STATE_NULL);
gst_bus_set_flushing (self->bus, FALSE);
change_state (self, transient && self->app_state != GST_CLAPPER_STATE_STOPPED
? GST_CLAPPER_STATE_BUFFERING : GST_CLAPPER_STATE_STOPPED);

View File

@@ -372,8 +372,10 @@ gst_clapper_gl_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
gst_buffer_pool_config_add_option (config,
GST_BUFFER_POOL_OPTION_GL_SYNC_META);
if (!gst_buffer_pool_set_config (pool, config))
if (!gst_buffer_pool_set_config (pool, config)) {
gst_object_unref (pool);
goto config_failed;
}
}
/* we need at least 2 buffer because we hold on to the last one */

View File

@@ -34,36 +34,13 @@ gstclapper_defines = [
'-DGST_USE_UNSTABLE_API',
'-DHAVE_GTK_GL',
]
gtk_deps = [gstgl_dep, gstglproto_dep]
have_gtk_gl_windowing = false
gtk4_dep = dependency('gtk4', required: true)
if not gtk4_dep.version().version_compare('>=4.0.0')
error('GTK4 version on this system is too old')
if not get_option('lib')
subdir_done()
endif
if gst_gl_have_window_x11 and (gst_gl_have_platform_egl or gst_gl_have_platform_glx)
gtk_x11_dep = dependency('gtk4-x11', required: false)
if gtk_x11_dep.found()
gtk_deps += gtk_x11_dep
if gst_gl_have_platform_glx
gtk_deps += gstglx11_dep
endif
have_gtk_gl_windowing = true
endif
endif
if gst_gl_have_window_wayland and gst_gl_have_platform_egl
gtk_wayland_dep = dependency('gtk4-wayland', required: false)
if gtk_wayland_dep.found()
gtk_deps += [gtk_wayland_dep, gstglwayland_dep]
have_gtk_gl_windowing = true
endif
endif
if gst_gl_have_platform_egl
gtk_deps += gstglegl_dep
if not gir.found()
error('Clapper lib requires GI bindings to be compiled')
endif
if not have_gtk_gl_windowing
@@ -84,7 +61,7 @@ gstclapper = library('gstclapper-' + api_version,
version: libversion,
install: true,
install_dir: pkglibdir,
dependencies: [gtk4_dep, glib_dep, gio_dep,
dependencies: [gtk4_dep, glib_dep, gio_dep, giounix_dep,
gstbase_dep, gstvideo_dep, gstaudio_dep,
gsttag_dep, gstpbutils_dep, libm] + gtk_deps,
)

1
lib/gst/meson.build vendored
View File

@@ -1 +1,2 @@
subdir('clapper')
subdir('plugin')

374
lib/gst/plugin/gstclapperbaseimport.c vendored Normal file
View File

@@ -0,0 +1,374 @@
/*
* Copyright (C) 2022 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstclapperbaseimport.h"
#include "gstclappergdkmemory.h"
#include "gstclappergdkbufferpool.h"
#define GST_CAT_DEFAULT gst_clapper_base_import_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define parent_class gst_clapper_base_import_parent_class
G_DEFINE_TYPE (GstClapperBaseImport, gst_clapper_base_import, GST_TYPE_BASE_TRANSFORM);
static void
gst_clapper_base_import_init (GstClapperBaseImport *self)
{
g_mutex_init (&self->lock);
gst_video_info_init (&self->in_info);
gst_video_info_init (&self->out_info);
}
static void
gst_clapper_base_import_finalize (GObject *object)
{
GstClapperBaseImport *self = GST_CLAPPER_BASE_IMPORT_CAST (object);
GST_TRACE ("Finalize");
g_mutex_clear (&self->lock);
GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
}
static GstStateChangeReturn
gst_clapper_base_import_change_state (GstElement *element, GstStateChange transition)
{
GST_DEBUG_OBJECT (element, "Changing state: %s => %s",
gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
}
static gboolean
gst_clapper_base_import_start (GstBaseTransform *bt)
{
GST_INFO_OBJECT (bt, "Start");
return TRUE;
}
static gboolean
gst_clapper_base_import_stop (GstBaseTransform *bt)
{
GST_INFO_OBJECT (bt, "Stop");
return TRUE;
}
static GstCaps *
gst_clapper_base_import_transform_caps (GstBaseTransform *bt,
GstPadDirection direction, GstCaps *caps, GstCaps *filter)
{
GstCaps *result, *tmp;
tmp = (direction == GST_PAD_SINK)
? gst_pad_get_pad_template_caps (GST_BASE_TRANSFORM_SRC_PAD (bt))
: gst_pad_get_pad_template_caps (GST_BASE_TRANSFORM_SINK_PAD (bt));
if (filter) {
GST_DEBUG ("Intersecting with filter caps: %" GST_PTR_FORMAT, filter);
result = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (tmp);
} else {
result = tmp;
}
GST_DEBUG ("Returning %s caps: %" GST_PTR_FORMAT,
(direction == GST_PAD_SINK) ? "src" : "sink", result);
return result;
}
static gboolean
_structure_filter_cb (GQuark field_id, GValue *value,
G_GNUC_UNUSED gpointer user_data)
{
const gchar *str = g_quark_to_string (field_id);
if (!strcmp (str, "format")
|| !strcmp (str, "width")
|| !strcmp (str, "height")
|| !strcmp (str, "pixel-aspect-ratio")
|| !strcmp (str, "framerate"))
return TRUE;
return FALSE;
}
static GstCaps *
gst_clapper_base_import_fixate_caps (GstBaseTransform *bt,
GstPadDirection direction, GstCaps *caps, GstCaps *othercaps)
{
GstCaps *fixated;
fixated = (!gst_caps_is_any (caps))
? gst_caps_fixate (gst_caps_ref (caps))
: gst_caps_copy (caps);
if (direction == GST_PAD_SINK) {
guint i, n = gst_caps_get_size (fixated);
for (i = 0; i < n; i++) {
GstCapsFeatures *features;
GstStructure *structure;
gboolean had_overlay_comp;
features = gst_caps_get_features (fixated, i);
had_overlay_comp = gst_caps_features_contains (features,
GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION);
features = gst_caps_features_new (GST_CAPS_FEATURE_CLAPPER_GDK_MEMORY, NULL);
if (had_overlay_comp)
gst_caps_features_add (features, GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION);
gst_caps_set_features (fixated, i, features);
/* Remove fields that do not apply to our memory */
if ((structure = gst_caps_get_structure (fixated, i))) {
gst_structure_filter_and_map_in_place (structure,
(GstStructureFilterMapFunc) _structure_filter_cb, NULL);
}
}
}
GST_DEBUG ("Fixated %s caps: %" GST_PTR_FORMAT,
(direction == GST_PAD_SRC) ? "sink" : "src", fixated);
return fixated;
}
static gboolean
gst_clapper_base_import_set_caps (GstBaseTransform *bt,
GstCaps *incaps, GstCaps *outcaps)
{
GstClapperBaseImport *self = GST_CLAPPER_BASE_IMPORT_CAST (bt);
gboolean has_sink_info, has_src_info;
if ((has_sink_info = gst_video_info_from_caps (&self->in_info, incaps)))
GST_INFO_OBJECT (self, "Set sink caps: %" GST_PTR_FORMAT, incaps);
if ((has_src_info = gst_video_info_from_caps (&self->out_info, outcaps)))
GST_INFO_OBJECT (self, "Set src caps: %" GST_PTR_FORMAT, outcaps);
return (has_sink_info && has_src_info);
}
static gboolean
gst_clapper_base_import_import_propose_allocation (GstBaseTransform *bt,
GstQuery *decide_query, GstQuery *query)
{
GstClapperBaseImport *self = GST_CLAPPER_BASE_IMPORT_CAST (bt);
GstClapperBaseImportClass *bi_class = GST_CLAPPER_BASE_IMPORT_GET_CLASS (self);
GstBufferPool *pool = NULL;
GstCaps *caps;
GstVideoInfo info;
guint size;
gboolean need_pool;
if (!GST_BASE_TRANSFORM_CLASS (parent_class)->propose_allocation (bt,
decide_query, query))
return FALSE;
/* Passthrough, nothing to do */
if (!decide_query)
return TRUE;
gst_query_parse_allocation (query, &caps, &need_pool);
if (!caps) {
GST_DEBUG_OBJECT (self, "No caps specified");
return FALSE;
}
if (!gst_video_info_from_caps (&info, caps)) {
GST_DEBUG_OBJECT (self, "Invalid caps specified");
return FALSE;
}
/* Normal size of a frame */
size = GST_VIDEO_INFO_SIZE (&info);
if (need_pool) {
GstStructure *config = NULL;
GST_DEBUG_OBJECT (self, "Need to create upstream pool");
pool = bi_class->create_upstream_pool (self, &config);
if (pool) {
/* If we did not get config, use default one */
if (!config)
config = gst_buffer_pool_get_config (pool);
gst_buffer_pool_config_set_params (config, caps, size, 2, 0);
if (!gst_buffer_pool_set_config (pool, config)) {
gst_object_unref (pool);
GST_DEBUG_OBJECT (self, "Failed to set config");
return FALSE;
}
} else if (config) {
GST_WARNING_OBJECT (self, "Got pool config without a pool to apply it!");
gst_structure_free (config);
}
}
gst_query_add_allocation_pool (query, pool, size, 2, 0);
if (pool)
gst_object_unref (pool);
gst_query_add_allocation_meta (query,
GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, NULL);
gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
return TRUE;
}
static gboolean
gst_clapper_base_import_decide_allocation (GstBaseTransform *bt, GstQuery *query)
{
GstClapperBaseImport *self = GST_CLAPPER_BASE_IMPORT_CAST (bt);
GstBufferPool *pool = NULL;
GstCaps *caps;
GstVideoInfo info;
guint size = 0, min = 0, max = 0;
gboolean update_pool, need_pool = TRUE;
gst_query_parse_allocation (query, &caps, NULL);
if (!caps) {
GST_DEBUG_OBJECT (self, "No caps specified");
return FALSE;
}
if (!gst_video_info_from_caps (&info, caps)) {
GST_DEBUG_OBJECT (self, "Invalid caps specified");
return FALSE;
}
if ((update_pool = gst_query_get_n_allocation_pools (query) > 0)) {
gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
if (pool) {
if ((need_pool = !GST_IS_CLAPPER_GDK_BUFFER_POOL (pool)))
gst_clear_object (&pool);
}
} else {
size = GST_VIDEO_INFO_SIZE (&info);
}
if (need_pool) {
GstStructure *config;
GST_DEBUG_OBJECT (self, "Creating new downstream pool");
pool = gst_clapper_gdk_buffer_pool_new ();
config = gst_buffer_pool_get_config (pool);
gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
gst_buffer_pool_config_set_params (config, caps, size, min, max);
if (!gst_buffer_pool_set_config (pool, config)) {
gst_object_unref (pool);
GST_DEBUG_OBJECT (self, "Failed to set config");
return FALSE;
}
}
if (update_pool)
gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
else
gst_query_add_allocation_pool (query, pool, size, min, max);
if (pool)
gst_object_unref (pool);
return GST_BASE_TRANSFORM_CLASS (parent_class)->decide_allocation (bt, query);
}
static GstBufferPool *
gst_clapper_base_import_create_upstream_pool (GstClapperBaseImport *self, GstStructure **config)
{
GST_FIXME_OBJECT (self, "Need to create upstream buffer pool");
return NULL;
}
static void
gst_clapper_base_import_class_init (GstClapperBaseImportClass *klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
GstElementClass *gstelement_class = (GstElementClass *) klass;
GstBaseTransformClass *gstbasetransform_class = (GstBaseTransformClass *) klass;
GstClapperBaseImportClass *bi_class = (GstClapperBaseImportClass *) klass;
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clapperbaseimport", 0,
"Clapper Base Import");
gobject_class->finalize = gst_clapper_base_import_finalize;
gstelement_class->change_state = gst_clapper_base_import_change_state;
gstbasetransform_class->passthrough_on_same_caps = TRUE;
gstbasetransform_class->transform_ip_on_passthrough = FALSE;
gstbasetransform_class->start = gst_clapper_base_import_start;
gstbasetransform_class->stop = gst_clapper_base_import_stop;
gstbasetransform_class->transform_caps = gst_clapper_base_import_transform_caps;
gstbasetransform_class->fixate_caps = gst_clapper_base_import_fixate_caps;
gstbasetransform_class->set_caps = gst_clapper_base_import_set_caps;
gstbasetransform_class->propose_allocation = gst_clapper_base_import_import_propose_allocation;
gstbasetransform_class->decide_allocation = gst_clapper_base_import_decide_allocation;
bi_class->create_upstream_pool = gst_clapper_base_import_create_upstream_pool;
}
/*
* Maps input video frame and output memory from in/out buffers
* using flags passed to this method.
*
* Remember to unmap both using `gst_video_frame_unmap` and
* `gst_memory_unmap` when done with the data.
*/
gboolean
gst_clapper_base_import_map_buffers (GstClapperBaseImport *self,
GstBuffer *in_buf, GstBuffer *out_buf, GstMapFlags in_flags, GstMapFlags out_flags,
GstVideoFrame *frame, GstMapInfo *info, GstMemory **mem)
{
GST_LOG_OBJECT (self, "Transforming from %" GST_PTR_FORMAT
" into %" GST_PTR_FORMAT, in_buf, out_buf);
if (G_UNLIKELY (!gst_video_frame_map (frame, &self->in_info, in_buf, in_flags))) {
GST_ERROR_OBJECT (self, "Could not map input buffer for reading");
return FALSE;
}
*mem = gst_buffer_peek_memory (out_buf, 0);
if (G_UNLIKELY (!gst_memory_map (*mem, info, out_flags))) {
GST_ERROR_OBJECT (self, "Could not map output memory for writing");
gst_video_frame_unmap (frame);
return FALSE;
}
return TRUE;
}

69
lib/gst/plugin/gstclapperbaseimport.h vendored Normal file
View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) 2022 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include <gst/base/gstbasetransform.h>
#include <gst/video/video.h>
G_BEGIN_DECLS
#define GST_TYPE_CLAPPER_BASE_IMPORT (gst_clapper_base_import_get_type())
#define GST_IS_CLAPPER_BASE_IMPORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CLAPPER_BASE_IMPORT))
#define GST_IS_CLAPPER_BASE_IMPORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CLAPPER_BASE_IMPORT))
#define GST_CLAPPER_BASE_IMPORT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CLAPPER_BASE_IMPORT, GstClapperBaseImportClass))
#define GST_CLAPPER_BASE_IMPORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CLAPPER_BASE_IMPORT, GstClapperBaseImport))
#define GST_CLAPPER_BASE_IMPORT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_CLAPPER_BASE_IMPORT, GstClapperBaseImportClass))
#define GST_CLAPPER_BASE_IMPORT_CAST(obj) ((GstClapperBaseImport *)(obj))
#define GST_CLAPPER_BASE_IMPORT_GET_LOCK(obj) (&GST_CLAPPER_BASE_IMPORT_CAST(obj)->lock)
#define GST_CLAPPER_BASE_IMPORT_LOCK(obj) g_mutex_lock (GST_CLAPPER_BASE_IMPORT_GET_LOCK(obj))
#define GST_CLAPPER_BASE_IMPORT_UNLOCK(obj) g_mutex_unlock (GST_CLAPPER_BASE_IMPORT_GET_LOCK(obj))
typedef struct _GstClapperBaseImport GstClapperBaseImport;
typedef struct _GstClapperBaseImportClass GstClapperBaseImportClass;
#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GstClapperBaseImport, gst_object_unref)
#endif
struct _GstClapperBaseImport
{
GstBaseTransform parent;
GMutex lock;
GstVideoInfo in_info, out_info;
};
struct _GstClapperBaseImportClass
{
GstBaseTransformClass parent_class;
GstBufferPool * (* create_upstream_pool) (GstClapperBaseImport *bi,
GstStructure **config);
};
GType gst_clapper_base_import_get_type (void);
gboolean gst_clapper_base_import_map_buffers (GstClapperBaseImport *bi,
GstBuffer *in_buf, GstBuffer *out_buf, GstMapFlags in_flags, GstMapFlags out_flags,
GstVideoFrame *frame, GstMapInfo *info, GstMemory **mem);
G_END_DECLS

173
lib/gst/plugin/gstclappergdkbufferpool.c vendored Normal file
View File

@@ -0,0 +1,173 @@
/*
* Copyright (C) 2022 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstclappergdkbufferpool.h"
#define GST_CAT_DEFAULT gst_clapper_gdk_buffer_pool_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define parent_class gst_clapper_gdk_buffer_pool_parent_class
G_DEFINE_TYPE (GstClapperGdkBufferPool, gst_clapper_gdk_buffer_pool, GST_TYPE_BUFFER_POOL);
static void
gst_clapper_gdk_buffer_pool_init (GstClapperGdkBufferPool *pool)
{
}
static const gchar **
gst_clapper_gdk_buffer_pool_get_options (GstBufferPool *pool)
{
static const gchar *options[] = {
GST_BUFFER_POOL_OPTION_VIDEO_META,
NULL
};
return options;
}
static gboolean
gst_clapper_gdk_buffer_pool_set_config (GstBufferPool *pool, GstStructure *config)
{
GstClapperGdkBufferPool *self = GST_CLAPPER_GDK_BUFFER_POOL_CAST (pool);
GstCaps *caps = NULL;
guint size, min_buffers, max_buffers;
GstVideoInfo info;
GstClapperGdkMemory *clapper_mem;
if (!gst_buffer_pool_config_get_params (config, &caps, &size,
&min_buffers, &max_buffers)) {
GST_WARNING_OBJECT (self, "Invalid buffer pool config");
return FALSE;
}
if (!caps || !gst_video_info_from_caps (&info, caps)) {
GST_WARNING_OBJECT (pool, "Could not parse caps into video info");
return FALSE;
}
gst_clear_object (&self->allocator);
self->allocator = GST_CLAPPER_GDK_ALLOCATOR_CAST (
gst_allocator_find (GST_CLAPPER_GDK_MEMORY_TYPE_NAME));
if (G_UNLIKELY (!self->allocator)) {
GST_ERROR_OBJECT (self, "ClapperGdkAllocator is unavailable");
return FALSE;
}
clapper_mem = GST_CLAPPER_GDK_MEMORY_CAST (
gst_clapper_gdk_allocator_alloc (self->allocator, &info));
if (G_UNLIKELY (!clapper_mem)) {
GST_ERROR_OBJECT (self, "Cannot create ClapperGdkMemory");
return FALSE;
}
gst_buffer_pool_config_set_params (config, caps,
GST_VIDEO_INFO_SIZE (&clapper_mem->info), min_buffers, max_buffers);
gst_memory_unref (GST_MEMORY_CAST (clapper_mem));
self->info = info;
GST_DEBUG_OBJECT (self, "Set buffer pool config: %" GST_PTR_FORMAT, config);
return GST_BUFFER_POOL_CLASS (parent_class)->set_config (pool, config);
}
static GstFlowReturn
gst_clapper_gdk_buffer_pool_alloc (GstBufferPool *pool, GstBuffer **buffer,
GstBufferPoolAcquireParams *params)
{
GstClapperGdkBufferPool *self = GST_CLAPPER_GDK_BUFFER_POOL_CAST (pool);
GstMemory *mem;
GstClapperGdkMemory *clapper_mem;
mem = gst_clapper_gdk_allocator_alloc (self->allocator, &self->info);
if (G_UNLIKELY (!mem)) {
GST_ERROR_OBJECT (self, "Cannot create ClapperGdkMemory");
return GST_FLOW_ERROR;
}
clapper_mem = GST_CLAPPER_GDK_MEMORY_CAST (mem);
*buffer = gst_buffer_new ();
gst_buffer_append_memory (*buffer, mem);
gst_buffer_add_video_meta_full (*buffer, GST_VIDEO_FRAME_FLAG_NONE,
GST_VIDEO_INFO_FORMAT (&self->info), GST_VIDEO_INFO_WIDTH (&self->info),
GST_VIDEO_INFO_HEIGHT (&self->info), GST_VIDEO_INFO_N_PLANES (&self->info),
clapper_mem->info.offset, clapper_mem->info.stride);
GST_TRACE_OBJECT (self, "Allocated %" GST_PTR_FORMAT, *buffer);
return GST_FLOW_OK;
}
static void
gst_clapper_gdk_buffer_reset_buffer (GstBufferPool *pool, GstBuffer *buffer)
{
GstClapperGdkMemory *clapper_mem;
GST_TRACE ("Reset %" GST_PTR_FORMAT, buffer);
clapper_mem = GST_CLAPPER_GDK_MEMORY_CAST (gst_buffer_peek_memory (buffer, 0));
g_clear_object (&clapper_mem->texture);
return GST_BUFFER_POOL_CLASS (parent_class)->reset_buffer (pool, buffer);
}
static void
gst_clapper_gdk_buffer_pool_dispose (GObject *object)
{
GstClapperGdkBufferPool *self = GST_CLAPPER_GDK_BUFFER_POOL_CAST (object);
gst_clear_object (&self->allocator);
GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
}
static void
gst_clapper_gdk_buffer_pool_class_init (GstClapperGdkBufferPoolClass *klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
GstBufferPoolClass *bufferpool_class = (GstBufferPoolClass *) klass;
gobject_class->dispose = gst_clapper_gdk_buffer_pool_dispose;
bufferpool_class->get_options = gst_clapper_gdk_buffer_pool_get_options;
bufferpool_class->set_config = gst_clapper_gdk_buffer_pool_set_config;
bufferpool_class->alloc_buffer = gst_clapper_gdk_buffer_pool_alloc;
bufferpool_class->reset_buffer = gst_clapper_gdk_buffer_reset_buffer;
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clappergdkbufferpool", 0,
"Clapper Gdk Buffer Pool");
}
GstBufferPool *
gst_clapper_gdk_buffer_pool_new (void)
{
GstClapperGdkBufferPool *self;
self = g_object_new (GST_TYPE_CLAPPER_GDK_BUFFER_POOL, NULL);
gst_object_ref_sink (self);
return GST_BUFFER_POOL_CAST (self);
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (C) 2022 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include <gst/gstbufferpool.h>
#include <gst/video/video.h>
#include "gstclappergdkmemory.h"
G_BEGIN_DECLS
#define GST_TYPE_CLAPPER_GDK_BUFFER_POOL (gst_clapper_gdk_buffer_pool_get_type())
G_DECLARE_FINAL_TYPE (GstClapperGdkBufferPool, gst_clapper_gdk_buffer_pool, GST, CLAPPER_GDK_BUFFER_POOL, GstBufferPool)
#define GST_CLAPPER_GDK_BUFFER_POOL_CAST(obj) ((GstClapperGdkBufferPool *)(obj))
struct _GstClapperGdkBufferPool
{
GstBufferPool parent;
GstClapperGdkAllocator *allocator;
GstVideoInfo info;
};
GstBufferPool * gst_clapper_gdk_buffer_pool_new (void);
G_END_DECLS

141
lib/gst/plugin/gstclappergdkmemory.c vendored Normal file
View File

@@ -0,0 +1,141 @@
/*
* Copyright (C) 2022 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstclappergdkmemory.h"
#include "gstgtkutils.h"
#define GST_CAT_DEFAULT gst_clapper_gdk_allocator_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
static GstAllocator *_gst_clapper_gdk_allocator = NULL;
#define parent_class gst_clapper_gdk_allocator_parent_class
G_DEFINE_TYPE (GstClapperGdkAllocator, gst_clapper_gdk_allocator, GST_TYPE_ALLOCATOR);
static void
gst_clapper_gdk_allocator_free (GstAllocator *self, GstMemory *memory)
{
GstClapperGdkMemory *mem = GST_CLAPPER_GDK_MEMORY_CAST (memory);
GST_TRACE_OBJECT (self, "Freeing ClapperGdkMemory: %" GST_PTR_FORMAT, mem);
g_clear_object (&mem->texture);
g_free (mem);
}
static gpointer
gst_clapper_gdk_mem_map_full (GstMemory *memory, GstMapInfo *info, gsize maxsize)
{
GstClapperGdkMemory *mem = GST_CLAPPER_GDK_MEMORY_CAST (memory);
return &mem->texture;
}
static void
gst_clapper_gdk_mem_unmap_full (GstMemory *memory, GstMapInfo *info)
{
/* NOOP */
}
static GstMemory *
gst_clapper_gdk_mem_copy (GstMemory *memory, gssize offset, gssize size)
{
return NULL;
}
static GstMemory *
gst_clapper_gdk_mem_share (GstMemory *memory, gssize offset, gssize size)
{
return NULL;
}
static gboolean
gst_clapper_gdk_mem_is_span (GstMemory *mem1, GstMemory *mem2, gsize *offset)
{
return FALSE;
}
static void
gst_clapper_gdk_allocator_init (GstClapperGdkAllocator *self)
{
GstAllocator *alloc = GST_ALLOCATOR_CAST (self);
alloc->mem_type = GST_CLAPPER_GDK_MEMORY_TYPE_NAME;
alloc->mem_map_full = gst_clapper_gdk_mem_map_full;
alloc->mem_unmap_full = gst_clapper_gdk_mem_unmap_full;
alloc->mem_copy = gst_clapper_gdk_mem_copy;
alloc->mem_share = gst_clapper_gdk_mem_share;
alloc->mem_is_span = gst_clapper_gdk_mem_is_span;
GST_OBJECT_FLAG_SET (self, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
}
static void
gst_clapper_gdk_allocator_class_init (GstClapperGdkAllocatorClass *klass)
{
GstAllocatorClass *allocator_class = (GstAllocatorClass *) klass;
allocator_class->alloc = NULL;
allocator_class->free = GST_DEBUG_FUNCPTR (gst_clapper_gdk_allocator_free);
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clappergdkallocator", 0,
"Clapper Gdk Allocator");
}
void
gst_clapper_gdk_memory_init_once (void)
{
static gsize _alloc_init = 0;
if (g_once_init_enter (&_alloc_init)) {
_gst_clapper_gdk_allocator = GST_ALLOCATOR_CAST (
g_object_new (GST_TYPE_CLAPPER_GDK_ALLOCATOR, NULL));
gst_object_ref_sink (_gst_clapper_gdk_allocator);
gst_allocator_register (GST_CLAPPER_GDK_MEMORY_TYPE_NAME, _gst_clapper_gdk_allocator);
g_once_init_leave (&_alloc_init, 1);
}
}
gboolean
gst_is_clapper_gdk_memory (GstMemory *memory)
{
return (memory != NULL && memory->allocator != NULL
&& GST_IS_CLAPPER_GDK_ALLOCATOR (memory->allocator));
}
GstMemory *
gst_clapper_gdk_allocator_alloc (GstClapperGdkAllocator *self, const GstVideoInfo *info)
{
GstClapperGdkMemory *mem;
mem = g_new0 (GstClapperGdkMemory, 1);
mem->info = *info;
gst_memory_init (GST_MEMORY_CAST (mem), 0, GST_ALLOCATOR_CAST (self),
NULL, GST_VIDEO_INFO_SIZE (info), 0, 0, GST_VIDEO_INFO_SIZE (info));
GST_TRACE_OBJECT (self, "Allocated new ClapperGdkMemory: %" GST_PTR_FORMAT, mem);
return GST_MEMORY_CAST (mem);
}

67
lib/gst/plugin/gstclappergdkmemory.h vendored Normal file
View File

@@ -0,0 +1,67 @@
/*
* Copyright (C) 2022 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include <gtk/gtk.h>
#include <gst/gstmemory.h>
#include <gst/gstallocator.h>
#include <gst/video/video.h>
G_BEGIN_DECLS
#define GST_TYPE_CLAPPER_GDK_ALLOCATOR (gst_clapper_gdk_allocator_get_type())
G_DECLARE_FINAL_TYPE (GstClapperGdkAllocator, gst_clapper_gdk_allocator, GST, CLAPPER_GDK_ALLOCATOR, GstAllocator)
#define GST_CLAPPER_GDK_ALLOCATOR_CAST(obj) ((GstClapperGdkAllocator *)(obj))
#define GST_CLAPPER_GDK_MEMORY_CAST(mem) ((GstClapperGdkMemory *)(mem))
#define GST_CLAPPER_GDK_MEMORY_TYPE_NAME "gst.clapper.gdk.memory"
#define GST_CAPS_FEATURE_CLAPPER_GDK_MEMORY "memory:ClapperGdkMemory"
#define GST_CLAPPER_GDK_MEMORY_FORMATS \
"RGBA64_LE, RGBA64_BE, ABGR, BGRA, " \
"ARGB, RGBA, BGRx, RGBx, BGR, RGB" \
/* Formats that `GdkGLTexture` supports */
#define GST_CLAPPER_GDK_GL_TEXTURE_FORMATS \
"RGBA64_LE, RGBA64_BE, RGBA, RGBx, RGB" \
typedef struct _GstClapperGdkMemory GstClapperGdkMemory;
struct _GstClapperGdkMemory
{
GstMemory mem;
GdkTexture *texture;
GstVideoInfo info;
};
struct _GstClapperGdkAllocator
{
GstAllocator parent;
};
void gst_clapper_gdk_memory_init_once (void);
gboolean gst_is_clapper_gdk_memory (GstMemory *memory);
GstMemory * gst_clapper_gdk_allocator_alloc (GstClapperGdkAllocator *allocator, const GstVideoInfo *info);
G_END_DECLS

414
lib/gst/plugin/gstclapperglbaseimport.c vendored Normal file
View File

@@ -0,0 +1,414 @@
/*
* Copyright (C) 2022 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gtk/gtk.h>
#include <gst/gl/gstglfuncs.h>
#include "gstclapperglbaseimport.h"
#include "gstgtkutils.h"
#if GST_CLAPPER_GL_HAVE_WAYLAND
#include <gdk/wayland/gdkwayland.h>
#include <gst/gl/wayland/gstgldisplay_wayland.h>
#endif
#if GST_CLAPPER_GL_HAVE_X11
#include <gdk/x11/gdkx.h>
#endif
#if GST_CLAPPER_GL_HAVE_X11_GLX
#include <gst/gl/x11/gstgldisplay_x11.h>
#endif
#if GST_CLAPPER_GL_HAVE_X11_EGL
#include <gst/gl/egl/gstgldisplay_egl.h>
#endif
#define GST_CAT_DEFAULT gst_clapper_gl_base_import_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define parent_class gst_clapper_gl_base_import_parent_class
G_DEFINE_TYPE (GstClapperGLBaseImport, gst_clapper_gl_base_import, GST_TYPE_CLAPPER_BASE_IMPORT);
static void
gst_clapper_gl_base_import_init (GstClapperGLBaseImport *self)
{
g_mutex_init (&self->lock);
}
static void
gst_clapper_gl_base_import_finalize (GObject *object)
{
GstClapperGLBaseImport *self = GST_CLAPPER_GL_BASE_IMPORT_CAST (object);
g_clear_object (&self->gdk_context);
gst_clear_object (&self->gst_context);
gst_clear_object (&self->wrapped_context);
gst_clear_object (&self->gst_display);
g_mutex_clear (&self->lock);
GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
}
static GstGLContext *
wrap_current_gl (GstGLDisplay *display, GdkGLAPI gdk_gl_api, GstGLPlatform platform)
{
GstGLAPI gst_gl_api = GST_GL_API_NONE;
switch (gdk_gl_api) {
case GDK_GL_API_GL:
gst_gl_api = GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
break;
case GDK_GL_API_GLES:
gst_gl_api = GST_GL_API_GLES2;
break;
default:
g_assert_not_reached ();
break;
}
if (gst_gl_api != GST_GL_API_NONE) {
guintptr gl_handle;
gst_gl_display_filter_gl_api (display, gst_gl_api);
if ((gl_handle = gst_gl_context_get_current_gl_context (platform)))
return gst_gl_context_new_wrapped (display, gl_handle, platform, gst_gl_api);
}
return NULL;
}
static gboolean
retrieve_gl_context_on_main (GstClapperGLBaseImport *self)
{
GstClapperGLBaseImportClass *gl_bi_class = GST_CLAPPER_GL_BASE_IMPORT_GET_CLASS (self);
GdkDisplay *gdk_display;
GdkGLContext *gdk_context;
GError *error = NULL;
GdkGLAPI gdk_gl_api;
GstGLPlatform platform = GST_GL_PLATFORM_NONE;
gint gl_major = 0, gl_minor = 0;
if (!gtk_init_check ()) {
GST_ERROR_OBJECT (self, "Could not ensure GTK initialization");
return FALSE;
}
gdk_display = gdk_display_get_default ();
if (!(gdk_context = gdk_display_create_gl_context (gdk_display, &error))) {
GST_ERROR_OBJECT (self, "Error creating Gdk GL context: %s",
error ? error->message : "No error set by Gdk");
g_clear_error (&error);
return FALSE;
}
if (!gl_bi_class->gdk_context_realize (self, gdk_context)) {
GST_ERROR_OBJECT (self, "Could not realize Gdk context: %" GST_PTR_FORMAT,
gdk_context);
g_object_unref (gdk_context);
return FALSE;
}
gdk_gl_api = gdk_gl_context_get_api (gdk_context);
GST_CLAPPER_GL_BASE_IMPORT_LOCK (self);
self->gdk_context = gdk_context;
#if GST_CLAPPER_GL_HAVE_WAYLAND
if (GDK_IS_WAYLAND_DISPLAY (gdk_display)) {
struct wl_display *wayland_display =
gdk_wayland_display_get_wl_display (gdk_display);
self->gst_display = (GstGLDisplay *)
gst_gl_display_wayland_new_with_display (wayland_display);
}
#endif
#if GST_CLAPPER_GL_HAVE_X11
if (GDK_IS_X11_DISPLAY (gdk_display)) {
gpointer display_ptr;
#if GST_CLAPPER_GL_HAVE_X11_EGL
display_ptr = gdk_x11_display_get_egl_display (gdk_display);
if (display_ptr) {
self->gst_display = (GstGLDisplay *)
gst_gl_display_egl_new_with_egl_display (display_ptr);
}
#endif
#if GST_CLAPPER_GL_HAVE_X11_GLX
if (!self->gst_display) {
display_ptr = gdk_x11_display_get_xdisplay (gdk_display);
self->gst_display = (GstGLDisplay *)
gst_gl_display_x11_new_with_display (display_ptr);
}
}
#endif
#endif
/* Fallback to generic display */
if (G_UNLIKELY (!self->gst_display)) {
GST_WARNING_OBJECT (self, "Unknown Gdk display!");
self->gst_display = gst_gl_display_new ();
}
#if GST_CLAPPER_GL_HAVE_WAYLAND
if (GST_IS_GL_DISPLAY_WAYLAND (self->gst_display)) {
platform = GST_GL_PLATFORM_EGL;
GST_INFO_OBJECT (self, "Using EGL on Wayland");
goto have_display;
}
#endif
#if GST_CLAPPER_GL_HAVE_X11_EGL
if (GST_IS_GL_DISPLAY_EGL (self->gst_display)) {
platform = GST_GL_PLATFORM_EGL;
GST_INFO_OBJECT (self, "Using EGL on x11");
goto have_display;
}
#endif
#if GST_CLAPPER_GL_HAVE_X11_GLX
if (GST_IS_GL_DISPLAY_X11 (self->gst_display)) {
platform = GST_GL_PLATFORM_GLX;
GST_INFO_OBJECT (self, "Using GLX on x11");
goto have_display;
}
#endif
g_clear_object (&self->gdk_context);
gst_clear_object (&self->gst_display);
GST_CLAPPER_GL_BASE_IMPORT_UNLOCK (self);
GST_ERROR_OBJECT (self, "Unsupported GL platform");
return FALSE;
have_display:
gdk_gl_context_make_current (self->gdk_context);
self->wrapped_context = wrap_current_gl (self->gst_display, gdk_gl_api, platform);
if (!self->wrapped_context) {
GST_ERROR ("Could not retrieve Gdk OpenGL context");
gdk_gl_context_clear_current ();
g_clear_object (&self->gdk_context);
gst_clear_object (&self->gst_display);
GST_CLAPPER_GL_BASE_IMPORT_UNLOCK (self);
return FALSE;
}
GST_INFO ("Retrieved Gdk OpenGL context %" GST_PTR_FORMAT, self->wrapped_context);
gst_gl_context_activate (self->wrapped_context, TRUE);
if (!gst_gl_context_fill_info (self->wrapped_context, &error)) {
GST_ERROR ("Failed to fill Gdk context info: %s", error->message);
g_clear_error (&error);
gst_gl_context_activate (self->wrapped_context, FALSE);
gst_clear_object (&self->wrapped_context);
g_clear_object (&self->gdk_context);
gst_clear_object (&self->gst_display);
GST_CLAPPER_GL_BASE_IMPORT_UNLOCK (self);
return FALSE;
}
gst_gl_context_get_gl_version (self->wrapped_context, &gl_major, &gl_minor);
GST_INFO ("Using OpenGL%s %i.%i", (gdk_gl_api == GDK_GL_API_GLES) ? " ES" : "",
gl_major, gl_minor);
/* Deactivate in both places */
gst_gl_context_activate (self->wrapped_context, FALSE);
gdk_gl_context_clear_current ();
GST_CLAPPER_GL_BASE_IMPORT_UNLOCK (self);
return TRUE;
}
static gboolean
ensure_gl_context (GstClapperGLBaseImport *self)
{
GstGLDisplay *gst_display = NULL;
GstGLContext *gst_context = NULL;
GError *error = NULL;
gboolean has_gdk_contexts;
GST_CLAPPER_GL_BASE_IMPORT_LOCK (self);
has_gdk_contexts = (self->gdk_context && self->wrapped_context);
GST_CLAPPER_GL_BASE_IMPORT_UNLOCK (self);
if (!has_gdk_contexts) {
if (!(! !gst_gtk_invoke_on_main (
(GThreadFunc) (GCallback) retrieve_gl_context_on_main, self))) {
GST_ERROR_OBJECT (self, "Could not retrieve Gdk GL context");
return FALSE;
}
}
GST_CLAPPER_GL_BASE_IMPORT_LOCK (self);
gst_display = gst_object_ref (self->gst_display);
/* GstGLDisplay operations require object lock to be held */
GST_OBJECT_LOCK (gst_display);
if (!self->gst_context) {
GST_TRACE_OBJECT (self, "Creating new GstGLContext");
if (!gst_gl_display_create_context (gst_display, self->wrapped_context,
&self->gst_context, &error)) {
GST_WARNING ("Could not create OpenGL context: %s",
error ? error->message : "Unknown");
g_clear_error (&error);
GST_CLAPPER_GL_BASE_IMPORT_UNLOCK (self);
return FALSE;
}
}
gst_context = gst_object_ref (self->gst_context);
GST_CLAPPER_GL_BASE_IMPORT_UNLOCK (self);
/* Calls `set_context` internally, so we cannot be locked here */
gst_gl_display_add_context (gst_display, gst_context);
gst_gl_element_propagate_display_context (GST_ELEMENT_CAST (self), gst_display);
GST_OBJECT_UNLOCK (gst_display);
gst_object_unref (gst_display);
gst_object_unref (gst_context);
return TRUE;
}
static void
gst_clapper_gl_base_import_set_context (GstElement *element, GstContext *context)
{
GstClapperGLBaseImport *self = GST_CLAPPER_GL_BASE_IMPORT_CAST (element);
GST_DEBUG_OBJECT (self, "Set context");
GST_CLAPPER_GL_BASE_IMPORT_LOCK (self);
gst_gl_handle_set_context (element, context, &self->gst_display,
&self->wrapped_context);
GST_CLAPPER_GL_BASE_IMPORT_UNLOCK (self);
GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
}
static GstStateChangeReturn
gst_clapper_gl_base_import_change_state (GstElement *element, GstStateChange transition)
{
GstClapperGLBaseImport *self = GST_CLAPPER_GL_BASE_IMPORT_CAST (element);
GstStateChangeReturn ret;
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
if (ret == GST_STATE_CHANGE_FAILURE)
return ret;
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
if (!ensure_gl_context (self))
return GST_STATE_CHANGE_FAILURE;
break;
default:
break;
}
return ret;
}
static gboolean
gst_clapper_gl_base_import_query (GstBaseTransform *bt,
GstPadDirection direction, GstQuery *query)
{
GstClapperGLBaseImport *self = GST_CLAPPER_GL_BASE_IMPORT_CAST (bt);
gboolean res;
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_CONTEXT:
GST_CLAPPER_GL_BASE_IMPORT_LOCK (self);
res = gst_gl_handle_context_query (GST_ELEMENT_CAST (self), query,
self->gst_display, self->gst_context, self->wrapped_context);
GST_CLAPPER_GL_BASE_IMPORT_UNLOCK (self);
break;
default:
res = GST_BASE_TRANSFORM_CLASS (parent_class)->query (bt, direction, query);
break;
}
return res;
}
static gboolean
gst_clapper_gl_base_import_gdk_context_realize (GstClapperGLBaseImport *self, GdkGLContext *gdk_context)
{
GError *error = NULL;
gboolean success;
GST_DEBUG_OBJECT (self, "Realizing GdkGLContext with default implementation");
gdk_gl_context_set_allowed_apis (gdk_context, GDK_GL_API_GLES);
if (!(success = gdk_gl_context_realize (gdk_context, &error))) {
GST_WARNING_OBJECT (self, "Could not realize Gdk context with GLES: %s", error->message);
g_clear_error (&error);
}
if (!success) {
gdk_gl_context_set_allowed_apis (gdk_context, GDK_GL_API_GL);
if (!(success = gdk_gl_context_realize (gdk_context, &error))) {
GST_WARNING_OBJECT (self, "Could not realize Gdk context with GL: %s", error->message);
g_clear_error (&error);
}
}
return success;
}
static void
gst_clapper_gl_base_import_class_init (GstClapperGLBaseImportClass *klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
GstElementClass *gstelement_class = (GstElementClass *) klass;
GstBaseTransformClass *gstbasetransform_class = (GstBaseTransformClass *) klass;
GstClapperGLBaseImportClass *gl_bi_class = (GstClapperGLBaseImportClass *) klass;
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clapperglbaseimport", 0,
"Clapper GL Base Import");
gobject_class->finalize = gst_clapper_gl_base_import_finalize;
gstelement_class->set_context = gst_clapper_gl_base_import_set_context;
gstelement_class->change_state = gst_clapper_gl_base_import_change_state;
gstbasetransform_class->query = gst_clapper_gl_base_import_query;
gl_bi_class->gdk_context_realize = gst_clapper_gl_base_import_gdk_context_realize;
}

75
lib/gst/plugin/gstclapperglbaseimport.h vendored Normal file
View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2022 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include <gst/gl/gl.h>
#include <gtk/gtk.h>
#include "gstclapperbaseimport.h"
G_BEGIN_DECLS
#define GST_TYPE_CLAPPER_GL_BASE_IMPORT (gst_clapper_gl_base_import_get_type())
#define GST_IS_CLAPPER_GL_BASE_IMPORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CLAPPER_GL_BASE_IMPORT))
#define GST_IS_CLAPPER_GL_BASE_IMPORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CLAPPER_GL_BASE_IMPORT))
#define GST_CLAPPER_GL_BASE_IMPORT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CLAPPER_GL_BASE_IMPORT, GstClapperGLBaseImportClass))
#define GST_CLAPPER_GL_BASE_IMPORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CLAPPER_GL_BASE_IMPORT, GstClapperGLBaseImport))
#define GST_CLAPPER_GL_BASE_IMPORT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_CLAPPER_GL_BASE_IMPORT, GstClapperGLBaseImportClass))
#define GST_CLAPPER_GL_BASE_IMPORT_CAST(obj) ((GstClapperGLBaseImport *)(obj))
#define GST_CLAPPER_GL_BASE_IMPORT_GET_LOCK(obj) (&GST_CLAPPER_GL_BASE_IMPORT_CAST(obj)->lock)
#define GST_CLAPPER_GL_BASE_IMPORT_LOCK(obj) g_mutex_lock (GST_CLAPPER_GL_BASE_IMPORT_GET_LOCK(obj))
#define GST_CLAPPER_GL_BASE_IMPORT_UNLOCK(obj) g_mutex_unlock (GST_CLAPPER_GL_BASE_IMPORT_GET_LOCK(obj))
#define GST_CLAPPER_GL_HAVE_WAYLAND (GST_GL_HAVE_WINDOW_WAYLAND && defined (GDK_WINDOWING_WAYLAND))
#define GST_CLAPPER_GL_HAVE_X11 (GST_GL_HAVE_WINDOW_X11 && defined (GDK_WINDOWING_X11))
#define GST_CLAPPER_GL_HAVE_X11_GLX (GST_CLAPPER_GL_HAVE_X11 && GST_GL_HAVE_PLATFORM_GLX)
#define GST_CLAPPER_GL_HAVE_X11_EGL (GST_CLAPPER_GL_HAVE_X11 && GST_GL_HAVE_PLATFORM_EGL)
typedef struct _GstClapperGLBaseImport GstClapperGLBaseImport;
typedef struct _GstClapperGLBaseImportClass GstClapperGLBaseImportClass;
#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GstClapperGLBaseImport, gst_object_unref)
#endif
struct _GstClapperGLBaseImport
{
GstClapperBaseImport parent;
GMutex lock;
GdkGLContext *gdk_context;
GstGLContext *gst_context;
GstGLContext *wrapped_context;
GstGLDisplay *gst_display;
};
struct _GstClapperGLBaseImportClass
{
GstClapperBaseImportClass parent_class;
gboolean (* gdk_context_realize) (GstClapperGLBaseImport *gl_bi,
GdkGLContext *gdk_context);
};
GType gst_clapper_gl_base_import_get_type (void);
G_END_DECLS

178
lib/gst/plugin/gstclapperglimport.c vendored Normal file
View File

@@ -0,0 +1,178 @@
/*
* Copyright (C) 2022 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstclapperglimport.h"
#include "gstclappergdkmemory.h"
#define GST_CAT_DEFAULT gst_clapper_gl_import_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
static GstStaticPadTemplate gst_clapper_gl_import_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (
GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_GL_MEMORY,
"{ " GST_CLAPPER_GDK_GL_TEXTURE_FORMATS " }") ", "
"texture-target = (string) { " GST_GL_TEXTURE_TARGET_2D_STR " }"
"; "
GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_GL_MEMORY ", "
GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION,
"{ " GST_CLAPPER_GDK_GL_TEXTURE_FORMATS " }") ", "
"texture-target = (string) { " GST_GL_TEXTURE_TARGET_2D_STR " }"));
static GstStaticPadTemplate gst_clapper_gl_import_src_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (
GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_CLAPPER_GDK_MEMORY,
"{ " GST_CLAPPER_GDK_GL_TEXTURE_FORMATS " }")
"; "
GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_CLAPPER_GDK_MEMORY ", "
GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION,
"{ " GST_CLAPPER_GDK_GL_TEXTURE_FORMATS " }")));
#define parent_class gst_clapper_gl_import_parent_class
G_DEFINE_TYPE (GstClapperGLImport, gst_clapper_gl_import, GST_TYPE_CLAPPER_GL_BASE_IMPORT);
GST_ELEMENT_REGISTER_DEFINE (clapperglimport, "clapperglimport", GST_RANK_NONE,
GST_TYPE_CLAPPER_GL_IMPORT);
static GstBufferPool *
gst_clapper_gl_import_create_upstream_pool (GstClapperBaseImport *bi, GstStructure **config)
{
GstClapperGLBaseImport *gl_bi = GST_CLAPPER_GL_BASE_IMPORT_CAST (bi);
GstBufferPool *pool;
GstGLContext *context;
GST_DEBUG_OBJECT (bi, "Creating new pool");
GST_CLAPPER_GL_BASE_IMPORT_LOCK (gl_bi);
context = gst_object_ref (gl_bi->gst_context);
GST_CLAPPER_GL_BASE_IMPORT_UNLOCK (gl_bi);
pool = gst_gl_buffer_pool_new (context);
gst_object_unref (context);
*config = gst_buffer_pool_get_config (pool);
gst_buffer_pool_config_add_option (*config, GST_BUFFER_POOL_OPTION_GL_SYNC_META);
return pool;
}
static void
video_frame_unmap_and_free (GstVideoFrame *frame)
{
gst_video_frame_unmap (frame);
g_slice_free (GstVideoFrame, frame);
}
static GstFlowReturn
gst_clapper_gl_import_transform (GstBaseTransform *bt,
GstBuffer *in_buf, GstBuffer *out_buf)
{
GstClapperGLBaseImport *gl_bi = GST_CLAPPER_GL_BASE_IMPORT_CAST (bt);
GstClapperBaseImport *bi = GST_CLAPPER_BASE_IMPORT_CAST (bt);
GstVideoFrame *frame;
GstMapInfo info;
GstMemory *memory;
GstClapperGdkMemory *clapper_memory;
GstGLSyncMeta *sync_meta;
frame = g_slice_new (GstVideoFrame);
if (!gst_clapper_base_import_map_buffers (bi, in_buf, out_buf,
GST_MAP_READ | GST_MAP_GL, GST_MAP_WRITE, frame, &info, &memory)) {
g_slice_free (GstVideoFrame, frame);
return GST_FLOW_ERROR;
}
clapper_memory = GST_CLAPPER_GDK_MEMORY_CAST (memory);
GST_CLAPPER_GL_BASE_IMPORT_LOCK (gl_bi);
/* Must have context active here for both sync meta
* and Gdk texture format auto-detection to work */
gdk_gl_context_make_current (gl_bi->gdk_context);
gst_gl_context_activate (gl_bi->wrapped_context, TRUE);
sync_meta = gst_buffer_get_gl_sync_meta (in_buf);
/* Wait for all previous OpenGL commands to complete,
* before we start using the input texture */
if (sync_meta) {
gst_gl_sync_meta_set_sync_point (sync_meta, gl_bi->gst_context);
gst_gl_sync_meta_wait (sync_meta, gl_bi->wrapped_context);
}
/* Keep input data alive as long as necessary,
* unmap only after texture is destroyed */
clapper_memory->texture = gdk_gl_texture_new (
gl_bi->gdk_context,
*(guint *) GST_VIDEO_FRAME_PLANE_DATA (frame, 0),
GST_VIDEO_FRAME_WIDTH (frame),
GST_VIDEO_FRAME_HEIGHT (frame),
(GDestroyNotify) video_frame_unmap_and_free,
frame);
gst_gl_context_activate (gl_bi->wrapped_context, FALSE);
gdk_gl_context_clear_current ();
GST_CLAPPER_GL_BASE_IMPORT_UNLOCK (gl_bi);
gst_memory_unmap (memory, &info);
return GST_FLOW_OK;
}
static void
gst_clapper_gl_import_init (GstClapperGLImport *self)
{
}
static void
gst_clapper_gl_import_class_init (GstClapperGLImportClass *klass)
{
GstElementClass *gstelement_class = (GstElementClass *) klass;
GstBaseTransformClass *gstbasetransform_class = (GstBaseTransformClass *) klass;
GstClapperBaseImportClass *bi_class = (GstClapperBaseImportClass *) klass;
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clapperglimport", 0,
"Clapper GL Import");
gstbasetransform_class->transform = gst_clapper_gl_import_transform;
bi_class->create_upstream_pool = gst_clapper_gl_import_create_upstream_pool;
gst_element_class_set_metadata (gstelement_class,
"Clapper GL import",
"Filter/Video", "Imports GL memory into ClapperGdkMemory",
"Rafał Dzięgiel <rafostar.github@gmail.com>");
gst_element_class_add_static_pad_template (gstelement_class,
&gst_clapper_gl_import_sink_template);
gst_element_class_add_static_pad_template (gstelement_class,
&gst_clapper_gl_import_src_template);
}

38
lib/gst/plugin/gstclapperglimport.h vendored Normal file
View File

@@ -0,0 +1,38 @@
/*
* Copyright (C) 2022 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include "gstclapperglbaseimport.h"
G_BEGIN_DECLS
#define GST_TYPE_CLAPPER_GL_IMPORT (gst_clapper_gl_import_get_type())
G_DECLARE_FINAL_TYPE (GstClapperGLImport, gst_clapper_gl_import, GST, CLAPPER_GL_IMPORT, GstClapperGLBaseImport)
#define GST_CLAPPER_GL_IMPORT_CAST(obj) ((GstClapperGLImport *)(obj))
struct _GstClapperGLImport
{
GstClapperGLBaseImport parent;
};
GST_ELEMENT_REGISTER_DECLARE (clapperglimport);
G_END_DECLS

128
lib/gst/plugin/gstclapperimport.c vendored Normal file
View File

@@ -0,0 +1,128 @@
/*
* Copyright (C) 2022 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstclapperimport.h"
#include "gstclappergdkmemory.h"
#include "gstgtkutils.h"
#define GST_CAT_DEFAULT gst_clapper_import_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
static GstStaticPadTemplate gst_clapper_import_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (
GST_VIDEO_CAPS_MAKE ("{ " GST_CLAPPER_GDK_MEMORY_FORMATS " }")));
static GstStaticPadTemplate gst_clapper_import_src_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (
GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_CLAPPER_GDK_MEMORY,
"{ " GST_CLAPPER_GDK_MEMORY_FORMATS " }")));
#define parent_class gst_clapper_import_parent_class
G_DEFINE_TYPE (GstClapperImport, gst_clapper_import, GST_TYPE_CLAPPER_BASE_IMPORT);
GST_ELEMENT_REGISTER_DEFINE (clapperimport, "clapperimport", GST_RANK_NONE,
GST_TYPE_CLAPPER_IMPORT);
static GstBufferPool *
gst_clapper_import_create_upstream_pool (GstClapperBaseImport *bi, GstStructure **config)
{
GstClapperImport *self = GST_CLAPPER_IMPORT_CAST (bi);
GstBufferPool *pool;
GST_DEBUG_OBJECT (self, "Creating new upstream pool");
pool = gst_video_buffer_pool_new ();
*config = gst_buffer_pool_get_config (pool);
return pool;
}
static void
video_frame_unmap_and_free (GstVideoFrame *frame)
{
gst_video_frame_unmap (frame);
g_slice_free (GstVideoFrame, frame);
}
static GstFlowReturn
gst_clapper_import_transform (GstBaseTransform *bt,
GstBuffer *in_buf, GstBuffer *out_buf)
{
GstClapperBaseImport *bi = GST_CLAPPER_BASE_IMPORT_CAST (bt);
GstVideoFrame *frame;
GstMapInfo info;
GstMemory *memory;
frame = g_slice_new (GstVideoFrame);
if (!gst_clapper_base_import_map_buffers (bi, in_buf, out_buf,
GST_MAP_READ, GST_MAP_WRITE, frame, &info, &memory)) {
g_slice_free (GstVideoFrame, frame);
return GST_FLOW_ERROR;
}
/* Keep frame data alive as long as necessary,
* unmap only after bytes are destroyed */
GST_CLAPPER_GDK_MEMORY_CAST (memory)->texture = gst_video_frame_into_gdk_texture (
frame, (GDestroyNotify) video_frame_unmap_and_free);
gst_memory_unmap (memory, &info);
return GST_FLOW_OK;
}
static void
gst_clapper_import_init (GstClapperImport *self)
{
}
static void
gst_clapper_import_class_init (GstClapperImportClass *klass)
{
GstElementClass *gstelement_class = (GstElementClass *) klass;
GstBaseTransformClass *gstbasetransform_class = (GstBaseTransformClass *) klass;
GstClapperBaseImportClass *bi_class = (GstClapperBaseImportClass *) klass;
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clapperimport", 0,
"Clapper Import");
gstbasetransform_class->transform = gst_clapper_import_transform;
bi_class->create_upstream_pool = gst_clapper_import_create_upstream_pool;
gst_element_class_set_metadata (gstelement_class,
"Clapper import",
"Filter/Video", "Imports RAW video data into ClapperGdkMemory",
"Rafał Dzięgiel <rafostar.github@gmail.com>");
gst_element_class_add_static_pad_template (gstelement_class,
&gst_clapper_import_sink_template);
gst_element_class_add_static_pad_template (gstelement_class,
&gst_clapper_import_src_template);
}

38
lib/gst/plugin/gstclapperimport.h vendored Normal file
View File

@@ -0,0 +1,38 @@
/*
* Copyright (C) 2022 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include "gstclapperbaseimport.h"
G_BEGIN_DECLS
#define GST_TYPE_CLAPPER_IMPORT (gst_clapper_import_get_type())
G_DECLARE_FINAL_TYPE (GstClapperImport, gst_clapper_import, GST, CLAPPER_IMPORT, GstClapperBaseImport)
#define GST_CLAPPER_IMPORT_CAST(obj) ((GstClapperImport *)(obj))
struct _GstClapperImport
{
GstClapperBaseImport parent;
};
GST_ELEMENT_REGISTER_DECLARE (clapperimport);
G_END_DECLS

635
lib/gst/plugin/gstclapperpaintable.c vendored Normal file
View File

@@ -0,0 +1,635 @@
/*
* Copyright (C) 2022 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstclapperpaintable.h"
#include "gstclappergdkmemory.h"
#include "gstgtkutils.h"
#define DEFAULT_PAR_N 1
#define DEFAULT_PAR_D 1
#define GST_CAT_DEFAULT gst_clapper_paintable_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
typedef struct
{
GdkTexture *texture;
GstVideoOverlayRectangle *rectangle;
gint x, y;
guint width, height;
gboolean used;
} GstClapperGdkOverlay;
static void
gst_clapper_gdk_overlay_free (GstClapperGdkOverlay *overlay)
{
GST_TRACE ("Freeing overlay: %" GST_PTR_FORMAT, overlay);
g_object_unref (overlay->texture);
gst_video_overlay_rectangle_unref (overlay->rectangle);
g_slice_free (GstClapperGdkOverlay, overlay);
}
static void gst_clapper_paintable_iface_init (GdkPaintableInterface *iface);
static void gst_clapper_paintable_dispose (GObject *object);
static void gst_clapper_paintable_finalize (GObject *object);
#define parent_class gst_clapper_paintable_parent_class
G_DEFINE_TYPE_WITH_CODE (GstClapperPaintable, gst_clapper_paintable, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
gst_clapper_paintable_iface_init));
static void
gst_clapper_paintable_class_init (GstClapperPaintableClass *klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clapperpaintable", 0,
"Clapper Paintable");
gobject_class->dispose = gst_clapper_paintable_dispose;
gobject_class->finalize = gst_clapper_paintable_finalize;
}
static void
gst_clapper_paintable_init (GstClapperPaintable *self)
{
self->par_n = DEFAULT_PAR_N;
self->par_d = DEFAULT_PAR_D;
g_mutex_init (&self->lock);
gst_video_info_init (&self->v_info);
g_weak_ref_init (&self->widget, NULL);
self->overlays = g_ptr_array_new_with_free_func (
(GDestroyNotify) gst_clapper_gdk_overlay_free);
gdk_rgba_parse (&self->bg, "black");
}
static void
gst_clapper_paintable_dispose (GObject *object)
{
GstClapperPaintable *self = GST_CLAPPER_PAINTABLE (object);
GST_CLAPPER_PAINTABLE_LOCK (self);
if (self->draw_id > 0) {
g_source_remove (self->draw_id);
self->draw_id = 0;
}
GST_CLAPPER_PAINTABLE_UNLOCK (self);
GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
}
static void
gst_clapper_paintable_finalize (GObject *object)
{
GstClapperPaintable *self = GST_CLAPPER_PAINTABLE (object);
GST_TRACE ("Finalize");
GST_CLAPPER_PAINTABLE_LOCK (self);
g_weak_ref_clear (&self->widget);
gst_clear_buffer (&self->pending_buffer);
gst_clear_buffer (&self->buffer);
g_ptr_array_unref (self->overlays);
GST_CLAPPER_PAINTABLE_UNLOCK (self);
g_mutex_clear (&self->lock);
GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
}
static gboolean
calculate_display_par (GstClapperPaintable *self, GstVideoInfo *info)
{
gint width, height, par_n, par_d, req_par_n, req_par_d;
gboolean success;
width = GST_VIDEO_INFO_WIDTH (info);
height = GST_VIDEO_INFO_HEIGHT (info);
/* Cannot apply aspect ratio if there is no video */
if (width == 0 || height == 0)
return FALSE;
par_n = GST_VIDEO_INFO_PAR_N (info);
par_d = GST_VIDEO_INFO_PAR_D (info);
req_par_n = self->par_n;
req_par_d = self->par_d;
if (par_n == 0)
par_n = 1;
/* Use defaults if user set zero */
if (req_par_n == 0 || req_par_d == 0) {
req_par_n = DEFAULT_PAR_N;
req_par_d = DEFAULT_PAR_D;
}
GST_LOG_OBJECT (self, "PAR: %u/%u, DAR: %u/%u", par_n, par_d, req_par_n, req_par_d);
if (!(success = gst_video_calculate_display_ratio (&self->display_ratio_num,
&self->display_ratio_den, width, height, par_n, par_d,
req_par_n, req_par_d))) {
GST_ERROR_OBJECT (self, "Could not calculate display ratio values");
}
return success;
}
static void
invalidate_paintable_size_internal (GstClapperPaintable *self)
{
gint video_width, video_height;
guint display_ratio_num, display_ratio_den;
GST_CLAPPER_PAINTABLE_LOCK (self);
video_width = GST_VIDEO_INFO_WIDTH (&self->v_info);
video_height = GST_VIDEO_INFO_HEIGHT (&self->v_info);
display_ratio_num = self->display_ratio_num;
display_ratio_den = self->display_ratio_den;
GST_CLAPPER_PAINTABLE_UNLOCK (self);
if (video_height % display_ratio_den == 0) {
GST_LOG ("Keeping video height");
self->display_width = (guint)
gst_util_uint64_scale_int (video_height, display_ratio_num, display_ratio_den);
self->display_height = video_height;
} else if (video_width % display_ratio_num == 0) {
GST_LOG ("Keeping video width");
self->display_width = video_width;
self->display_height = (guint)
gst_util_uint64_scale_int (video_width, display_ratio_den, display_ratio_num);
} else {
GST_LOG ("Approximating while keeping video height");
self->display_width = (guint)
gst_util_uint64_scale_int (video_height, display_ratio_num, display_ratio_den);
self->display_height = video_height;
}
self->display_aspect_ratio = ((gdouble) self->display_width
/ (gdouble) self->display_height);
GST_DEBUG_OBJECT (self, "Invalidate paintable size, display: %dx%d",
self->display_width, self->display_height);
gdk_paintable_invalidate_size ((GdkPaintable *) self);
}
static gboolean
invalidate_paintable_size_on_main_cb (GstClapperPaintable *self)
{
GST_CLAPPER_PAINTABLE_LOCK (self);
self->draw_id = 0;
GST_CLAPPER_PAINTABLE_UNLOCK (self);
invalidate_paintable_size_internal (self);
return G_SOURCE_REMOVE;
}
static void
comp_frame_unmap_and_free (GstVideoFrame *frame)
{
gst_video_frame_unmap (frame);
g_slice_free (GstVideoFrame, frame);
}
static GstClapperGdkOverlay *
_get_cached_overlay (GPtrArray *overlays, GstVideoOverlayRectangle *rectangle, guint *index)
{
guint i;
for (i = 0; i < overlays->len; i++) {
GstClapperGdkOverlay *overlay = g_ptr_array_index (overlays, i);
if (overlay->rectangle != rectangle)
continue;
*index = i;
return overlay;
}
return NULL;
}
static void
gst_clapper_paintable_prepare_overlays (GstClapperPaintable *self)
{
GstVideoOverlayCompositionMeta *comp_meta;
guint num_overlays, i;
/* As long as this is called from main thread, no need to lock here */
if (G_UNLIKELY (!self->buffer)
|| !(comp_meta = gst_buffer_get_video_overlay_composition_meta (self->buffer))) {
guint n_pending = self->overlays->len;
/* Remove all cached overlays if new buffer does not have any */
if (n_pending > 0) {
GST_TRACE ("No overlays in buffer, removing all cached ones");
g_ptr_array_remove_range (self->overlays, 0, n_pending);
}
return;
}
GST_LOG_OBJECT (self, "Preparing overlays...");
/* Mark all old overlays as unused */
for (i = 0; i < self->overlays->len; i++) {
GstClapperGdkOverlay *overlay = g_ptr_array_index (self->overlays, i);
overlay->used = FALSE;
}
num_overlays = gst_video_overlay_composition_n_rectangles (comp_meta->overlay);
for (i = 0; i < num_overlays; i++) {
GdkTexture *texture;
GstBuffer *comp_buffer;
GstVideoFrame *comp_frame;
GstVideoMeta *vmeta;
GstVideoInfo vinfo;
GstVideoOverlayRectangle *rectangle;
GstClapperGdkOverlay *overlay;
GstVideoOverlayFormatFlags flags, alpha_flags = 0;
gint comp_x, comp_y;
guint comp_width, comp_height, cached_index;
rectangle = gst_video_overlay_composition_get_rectangle (comp_meta->overlay, i);
if ((overlay = _get_cached_overlay (self->overlays, rectangle, &cached_index))) {
overlay->used = TRUE;
/* Place overlay at expected position */
if (i != cached_index) {
GST_LOG ("Rearranging overlay position: %u => %u", cached_index, i);
overlay = g_ptr_array_steal_index_fast (self->overlays, cached_index);
g_ptr_array_insert (self->overlays, i, overlay);
}
GST_TRACE ("Reusing cached overlay: %" GST_PTR_FORMAT, overlay);
continue;
}
if (G_UNLIKELY (!gst_video_overlay_rectangle_get_render_rectangle (rectangle,
&comp_x, &comp_y, &comp_width, &comp_height))) {
GST_WARNING ("Invalid overlay rectangle dimensions: %" GST_PTR_FORMAT, rectangle);
continue;
}
flags = gst_video_overlay_rectangle_get_flags (rectangle);
if (flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA)
alpha_flags |= GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA;
comp_buffer = gst_video_overlay_rectangle_get_pixels_unscaled_argb (rectangle, alpha_flags);
comp_frame = g_slice_new (GstVideoFrame);
/* Update overlay video info from video meta */
if ((vmeta = gst_buffer_get_video_meta (comp_buffer))) {
gst_video_info_set_format (&vinfo, vmeta->format, vmeta->width, vmeta->height);
vinfo.stride[0] = vmeta->stride[0];
}
if (G_UNLIKELY (!gst_video_frame_map (comp_frame, &vinfo, comp_buffer, GST_MAP_READ))) {
g_slice_free (GstVideoFrame, comp_frame);
return;
}
if ((texture = gst_video_frame_into_gdk_texture (
comp_frame, (GDestroyNotify) comp_frame_unmap_and_free))) {
overlay = g_slice_new (GstClapperGdkOverlay);
overlay->texture = texture;
overlay->rectangle = gst_video_overlay_rectangle_ref (rectangle);
overlay->x = comp_x;
overlay->y = comp_y;
overlay->width = comp_width;
overlay->height = comp_height;
overlay->used = TRUE;
GST_TRACE ("Created overlay: %"
GST_PTR_FORMAT ", x: %i, y: %i, width: %u, height: %u",
overlay, overlay->x, overlay->y, overlay->width, overlay->height);
g_ptr_array_insert (self->overlays, i, overlay);
}
}
/* Remove all overlays that are not going to be used */
for (i = self->overlays->len; i > 0; i--) {
GstClapperGdkOverlay *overlay = g_ptr_array_index (self->overlays, i - 1);
if (!overlay->used) {
GST_TRACE ("Removing unused cached overlay: %" GST_PTR_FORMAT, overlay);
g_ptr_array_remove (self->overlays, overlay);
}
}
if (G_UNLIKELY (num_overlays != self->overlays->len)) {
GST_WARNING_OBJECT (self, "Some overlays could not be prepared, %u != %u",
num_overlays, self->overlays->len);
}
GST_LOG_OBJECT (self, "Prepared overlays: %u", self->overlays->len);
}
static gboolean
update_paintable_on_main_cb (GstClapperPaintable *self)
{
gboolean size_changed;
GST_CLAPPER_PAINTABLE_LOCK (self);
/* Check if we will need to invalidate size */
if ((size_changed = self->pending_resize))
self->pending_resize = FALSE;
gst_clear_buffer (&self->buffer);
self->buffer = self->pending_buffer;
self->pending_buffer = NULL;
self->draw_id = 0;
GST_CLAPPER_PAINTABLE_UNLOCK (self);
gst_clapper_paintable_prepare_overlays (self);
if (size_changed)
invalidate_paintable_size_internal (self);
GST_LOG_OBJECT (self, "Invalidate paintable contents");
gdk_paintable_invalidate_contents ((GdkPaintable *) self);
return G_SOURCE_REMOVE;
}
GstClapperPaintable *
gst_clapper_paintable_new (void)
{
return g_object_new (GST_TYPE_CLAPPER_PAINTABLE, NULL);
}
void
gst_clapper_paintable_set_widget (GstClapperPaintable *self, GtkWidget *widget)
{
g_weak_ref_set (&self->widget, widget);
}
void
gst_clapper_paintable_set_buffer (GstClapperPaintable *self, GstBuffer *buffer)
{
GST_CLAPPER_PAINTABLE_LOCK (self);
if (self->draw_id > 0) {
GST_CLAPPER_PAINTABLE_UNLOCK (self);
GST_TRACE ("Already have pending buffer, skipping %" GST_PTR_FORMAT, buffer);
return;
}
gst_buffer_replace (&self->pending_buffer, buffer);
self->draw_id = g_idle_add_full (G_PRIORITY_DEFAULT,
(GSourceFunc) update_paintable_on_main_cb, self, NULL);
GST_CLAPPER_PAINTABLE_UNLOCK (self);
}
gboolean
gst_clapper_paintable_set_video_info (GstClapperPaintable *self, GstVideoInfo *v_info)
{
GST_CLAPPER_PAINTABLE_LOCK (self);
if (gst_video_info_is_equal (&self->v_info, v_info)) {
GST_CLAPPER_PAINTABLE_UNLOCK (self);
return TRUE;
}
/* Reject info if values would cause integer overflow */
if (G_UNLIKELY (!calculate_display_par (self, v_info))) {
GST_CLAPPER_PAINTABLE_UNLOCK (self);
return FALSE;
}
self->pending_resize = TRUE;
self->v_info = *v_info;
GST_CLAPPER_PAINTABLE_UNLOCK (self);
return TRUE;
}
void
gst_clapper_paintable_set_pixel_aspect_ratio (GstClapperPaintable *self,
gint par_n, gint par_d)
{
gboolean success;
GST_CLAPPER_PAINTABLE_LOCK (self);
/* No change */
if (self->par_n == par_n && self->par_d == par_d) {
GST_CLAPPER_PAINTABLE_UNLOCK (self);
return;
}
self->par_n = par_n;
self->par_d = par_d;
/* Check if we can accept new values. This will update
* display `ratio_num` and `ratio_den` only when successful */
success = calculate_display_par (self, &self->v_info);
/* If paintable update is queued, wait for it, otherwise invalidate
* size only for change to be applied even when paused */
if (!success || self->draw_id > 0) {
GST_CLAPPER_PAINTABLE_UNLOCK (self);
return;
}
self->draw_id = g_idle_add_full (G_PRIORITY_DEFAULT,
(GSourceFunc) invalidate_paintable_size_on_main_cb, self, NULL);
GST_CLAPPER_PAINTABLE_UNLOCK (self);
return;
}
/*
* GdkPaintableInterface
*/
static void
gst_clapper_paintable_snapshot_internal (GstClapperPaintable *self,
GdkSnapshot *snapshot, gdouble width, gdouble height,
gint widget_width, gint widget_height)
{
GstMemory *memory;
GstMapInfo info;
gfloat scale_x, scale_y;
guint i;
scale_x = (gfloat) width / self->display_width;
scale_y = (gfloat) height / self->display_height;
/* Apply black borders when keeping aspect ratio */
if (scale_x == scale_y || abs (scale_x - scale_y) <= FLT_EPSILON) {
if (widget_height - height > 0) {
gdouble bar_height = (widget_height - height) / 2;
gtk_snapshot_append_color (snapshot, &self->bg, &GRAPHENE_RECT_INIT (0, 0, width, -bar_height));
gtk_snapshot_append_color (snapshot, &self->bg, &GRAPHENE_RECT_INIT (0, height, width, bar_height + 0.5));
} else if (widget_width - width > 0) {
gdouble bar_width = (widget_width - width) / 2;
gtk_snapshot_append_color (snapshot, &self->bg, &GRAPHENE_RECT_INIT (0, 0, -bar_width, height));
gtk_snapshot_append_color (snapshot, &self->bg, &GRAPHENE_RECT_INIT (width, 0, bar_width + 0.5, height));
}
}
/* Buffer is accessed only from main thread, so no locking required */
if (!self->buffer) {
gtk_snapshot_append_color (snapshot, &self->bg, &GRAPHENE_RECT_INIT (0, 0, width, height));
return;
}
GST_TRACE ("Snapshot %" GST_PTR_FORMAT, self->buffer);
memory = gst_buffer_peek_memory (self->buffer, 0);
/* If we cannot map, just draw black */
if (G_UNLIKELY (!gst_memory_map (memory, &info, GST_MAP_READ))) {
gtk_snapshot_append_color (snapshot, &self->bg, &GRAPHENE_RECT_INIT (0, 0, width, height));
GST_WARNING_OBJECT (self, "Could not map %" GST_PTR_FORMAT, self->buffer);
return;
}
gtk_snapshot_append_texture (snapshot,
GST_CLAPPER_GDK_MEMORY_CAST (memory)->texture,
&GRAPHENE_RECT_INIT (0, 0, width, height));
gst_memory_unmap (memory, &info);
/* FIXME: Draw black BG here when import format has-alpha */
//gtk_snapshot_append_color (snapshot, &self->bg, &GRAPHENE_RECT_INIT (0, 0, width, height));
/* Finally append prepared overlays */
for (i = 0; i < self->overlays->len; i++) {
GstClapperGdkOverlay *overlay = g_ptr_array_index (self->overlays, i);
gtk_snapshot_append_texture (snapshot, overlay->texture,
&GRAPHENE_RECT_INIT (overlay->x * scale_x, overlay->y * scale_y,
overlay->width * scale_x, overlay->height * scale_y));
}
}
static void
gst_clapper_paintable_snapshot (GdkPaintable *paintable,
GdkSnapshot *snapshot, gdouble width, gdouble height)
{
GstClapperPaintable *self = GST_CLAPPER_PAINTABLE_CAST (paintable);
GtkWidget *widget;
gint widget_width = 0, widget_height = 0;
if ((widget = g_weak_ref_get (&self->widget))) {
widget_width = gtk_widget_get_width (widget);
widget_height = gtk_widget_get_height (widget);
g_object_unref (widget);
}
gst_clapper_paintable_snapshot_internal (self, snapshot,
width, height, widget_width, widget_height);
}
static GdkPaintable *
gst_clapper_paintable_get_current_image (GdkPaintable *paintable)
{
GstClapperPaintable *self = GST_CLAPPER_PAINTABLE_CAST (paintable);
if (self->buffer) {
GtkSnapshot *snapshot;
GdkPaintable *ret;
snapshot = gtk_snapshot_new ();
/* Snapshot without widget size in order to get
* paintable without black borders */
gst_clapper_paintable_snapshot_internal (self, snapshot,
self->display_width, self->display_height, 0, 0);
if ((ret = gtk_snapshot_free_to_paintable (snapshot, NULL)))
return ret;
}
return gdk_paintable_new_empty (0, 0);
}
static gint
gst_clapper_paintable_get_intrinsic_width (GdkPaintable *paintable)
{
GstClapperPaintable *self = GST_CLAPPER_PAINTABLE_CAST (paintable);
return self->display_width;
}
static gint
gst_clapper_paintable_get_intrinsic_height (GdkPaintable *paintable)
{
GstClapperPaintable *self = GST_CLAPPER_PAINTABLE_CAST (paintable);
return self->display_height;
}
static gdouble
gst_clapper_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable)
{
GstClapperPaintable *self = GST_CLAPPER_PAINTABLE_CAST (paintable);
return self->display_aspect_ratio;
}
static void
gst_clapper_paintable_iface_init (GdkPaintableInterface *iface)
{
iface->snapshot = gst_clapper_paintable_snapshot;
iface->get_current_image = gst_clapper_paintable_get_current_image;
iface->get_intrinsic_width = gst_clapper_paintable_get_intrinsic_width;
iface->get_intrinsic_height = gst_clapper_paintable_get_intrinsic_height;
iface->get_intrinsic_aspect_ratio = gst_clapper_paintable_get_intrinsic_aspect_ratio;
}

74
lib/gst/plugin/gstclapperpaintable.h vendored Normal file
View File

@@ -0,0 +1,74 @@
/*
* Copyright (C) 2022 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include <gtk/gtk.h>
#include <gst/gst.h>
#include <gst/video/video.h>
G_BEGIN_DECLS
#define GST_TYPE_CLAPPER_PAINTABLE (gst_clapper_paintable_get_type())
G_DECLARE_FINAL_TYPE (GstClapperPaintable, gst_clapper_paintable, GST, CLAPPER_PAINTABLE, GObject)
#define GST_CLAPPER_PAINTABLE_CAST(obj) ((GstClapperPaintable *)(obj))
#define GST_CLAPPER_PAINTABLE_GET_LOCK(obj) (&GST_CLAPPER_PAINTABLE_CAST(obj)->lock)
#define GST_CLAPPER_PAINTABLE_LOCK(obj) g_mutex_lock (GST_CLAPPER_PAINTABLE_GET_LOCK(obj))
#define GST_CLAPPER_PAINTABLE_UNLOCK(obj) g_mutex_unlock (GST_CLAPPER_PAINTABLE_GET_LOCK(obj))
struct _GstClapperPaintable
{
GObject parent;
GMutex lock;
GstBuffer *pending_buffer, *buffer;
GPtrArray *overlays;
GstVideoInfo v_info;
GdkRGBA bg;
GWeakRef widget;
/* Sink properties */
gint par_n, par_d;
/* Resize */
gboolean pending_resize;
guint display_ratio_num;
guint display_ratio_den;
/* GdkPaintableInterface */
gint display_width;
gint display_height;
gdouble display_aspect_ratio;
/* Pending draw signal id */
guint draw_id;
};
GstClapperPaintable * gst_clapper_paintable_new (void);
void gst_clapper_paintable_set_widget (GstClapperPaintable *paintable, GtkWidget *widget);
void gst_clapper_paintable_set_buffer (GstClapperPaintable *paintable, GstBuffer *buffer);
gboolean gst_clapper_paintable_set_video_info (GstClapperPaintable *paintable, GstVideoInfo *v_info);
void gst_clapper_paintable_set_pixel_aspect_ratio (GstClapperPaintable *paintable, gint par_n, gint par_d);
G_END_DECLS

838
lib/gst/plugin/gstclappersink.c vendored Normal file
View File

@@ -0,0 +1,838 @@
/*
* Copyright (C) 2022 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstclappersink.h"
#include "gstclappergdkmemory.h"
#include "gstclappergdkbufferpool.h"
#include "gstgtkutils.h"
#define DEFAULT_FORCE_ASPECT_RATIO TRUE
#define DEFAULT_PAR_N 1
#define DEFAULT_PAR_D 1
#define DEFAULT_KEEP_LAST_FRAME FALSE
#define WINDOW_CSS_CLASS_NAME "clappersinkwindow"
enum
{
PROP_0,
PROP_WIDGET,
PROP_FORCE_ASPECT_RATIO,
PROP_PIXEL_ASPECT_RATIO,
PROP_KEEP_LAST_FRAME,
PROP_LAST
};
#define GST_CAT_DEFAULT gst_clapper_sink_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
static GstStaticPadTemplate gst_clapper_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (
GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_CLAPPER_GDK_MEMORY,
"{ " GST_CLAPPER_GDK_MEMORY_FORMATS " }")
"; "
GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_CLAPPER_GDK_MEMORY ", "
GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION,
"{ " GST_CLAPPER_GDK_MEMORY_FORMATS " }")));
static void gst_clapper_sink_navigation_interface_init (
GstNavigationInterface *iface);
#define parent_class gst_clapper_sink_parent_class
G_DEFINE_TYPE_WITH_CODE (GstClapperSink, gst_clapper_sink, GST_TYPE_VIDEO_SINK,
G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION,
gst_clapper_sink_navigation_interface_init));
GST_ELEMENT_REGISTER_DEFINE (clappersink, "clappersink", GST_RANK_NONE,
GST_TYPE_CLAPPER_SINK);
static void
window_clear_no_lock (GstClapperSink *self)
{
if (!self->window)
return;
GST_TRACE_OBJECT (self, "Window clear");
if (self->window_destroy_id) {
g_signal_handler_disconnect (self->window, self->window_destroy_id);
self->window_destroy_id = 0;
}
self->window = NULL;
}
static void
widget_clear_no_lock (GstClapperSink *self)
{
if (!self->widget)
return;
GST_TRACE_OBJECT (self, "Widget clear");
if (self->widget_destroy_id) {
g_signal_handler_disconnect (self->widget, self->widget_destroy_id);
self->widget_destroy_id = 0;
}
g_clear_object (&self->widget);
}
static void
widget_destroy_cb (GtkWidget *widget, GstClapperSink *self)
{
GST_CLAPPER_SINK_LOCK (self);
widget_clear_no_lock (self);
GST_CLAPPER_SINK_UNLOCK (self);
}
static void
window_destroy_cb (GtkWidget *window, GstClapperSink *self)
{
GST_DEBUG_OBJECT (self, "Window destroy");
GST_CLAPPER_SINK_LOCK (self);
widget_clear_no_lock (self);
window_clear_no_lock (self);
GST_CLAPPER_SINK_UNLOCK (self);
}
static void
calculate_stream_coords (GstClapperSink *self, GtkWidget *widget,
gdouble x, gdouble y, gdouble *stream_x, gdouble *stream_y)
{
GstVideoRectangle result;
gint scaled_width, scaled_height, scale_factor;
gint video_width, video_height;
gboolean force_aspect_ratio;
GST_CLAPPER_SINK_LOCK (self);
video_width = GST_VIDEO_INFO_WIDTH (&self->v_info);
video_height = GST_VIDEO_INFO_HEIGHT (&self->v_info);
force_aspect_ratio = self->force_aspect_ratio;
GST_CLAPPER_SINK_UNLOCK (self);
scale_factor = gtk_widget_get_scale_factor (widget);
scaled_width = gtk_widget_get_width (widget) * scale_factor;
scaled_height = gtk_widget_get_height (widget) * scale_factor;
if (force_aspect_ratio) {
GstVideoRectangle src, dst;
src.x = 0;
src.y = 0;
src.w = gdk_paintable_get_intrinsic_width ((GdkPaintable *) self->paintable);
src.h = gdk_paintable_get_intrinsic_height ((GdkPaintable *) self->paintable);
dst.x = 0;
dst.y = 0;
dst.w = scaled_width;
dst.h = scaled_height;
gst_video_center_rect (&src, &dst, &result, TRUE);
} else {
result.x = 0;
result.y = 0;
result.w = scaled_width;
result.h = scaled_height;
}
/* Display coordinates to stream coordinates */
*stream_x = (result.w > 0)
? (x - result.x) / result.w * video_width
: 0;
*stream_y = (result.h > 0)
? (y - result.y) / result.h * video_height
: 0;
/* Clip to stream size */
*stream_x = CLAMP (*stream_x, 0, video_width);
*stream_y = CLAMP (*stream_y, 0, video_height);
GST_LOG ("Transform coords %fx%f => %fx%f", x, y, *stream_x, *stream_y);
}
static void
gst_clapper_sink_widget_motion_event (GtkEventControllerMotion *motion,
gdouble x, gdouble y, GstClapperSink *self)
{
GtkWidget *widget;
gdouble stream_x, stream_y;
if ((x == self->last_pos_x && y == self->last_pos_y)
|| GST_STATE (self) < GST_STATE_PLAYING)
return;
self->last_pos_x = x;
self->last_pos_y = y;
widget = gtk_event_controller_get_widget ((GtkEventController *) motion);
calculate_stream_coords (self, widget, x, y, &stream_x, &stream_y);
GST_LOG ("Event \"mouse-move\", x: %f, y: %f", stream_x, stream_y);
gst_navigation_send_mouse_event ((GstNavigation *) self, "mouse-move",
0, stream_x, stream_y);
}
static void
gst_clapper_sink_widget_button_event (GtkGestureClick *click,
gint n_press, gdouble x, gdouble y, GstClapperSink *self)
{
GtkWidget *widget;
GdkEvent *event;
gdouble stream_x, stream_y;
GdkEventType event_type;
const gchar *event_name;
if (GST_STATE (self) < GST_STATE_PLAYING)
return;
event = gtk_event_controller_get_current_event ((GtkEventController *) click);
event_type = gdk_event_get_event_type (event);
/* FIXME: Touchscreen handling should probably use new touch events from GStreamer 1.22 */
event_name = (event_type == GDK_BUTTON_PRESS || event_type == GDK_TOUCH_BEGIN)
? "mouse-button-press"
: (event_type == GDK_BUTTON_RELEASE || event_type == GDK_TOUCH_END)
? "mouse-button-release"
: NULL;
/* Can be NULL on touch */
if (!event_name)
return;
widget = gtk_event_controller_get_widget ((GtkEventController *) click);
calculate_stream_coords (self, widget, x, y, &stream_x, &stream_y);
GST_LOG ("Event \"%s\", x: %f, y: %f", event_name, stream_x, stream_y);
/* Gesture is set to handle only primary button, so we do not have to check */
gst_navigation_send_mouse_event ((GstNavigation *) self, event_name,
1, stream_x, stream_y);
}
/* Must call from main thread only with a lock */
static GtkWidget *
gst_clapper_sink_get_widget (GstClapperSink *self)
{
if (G_UNLIKELY (!self->widget)) {
GtkEventController *controller;
GtkGesture *gesture;
/* Make sure GTK is initialized */
if (!gtk_init_check ()) {
GST_ERROR_OBJECT (self, "Could not ensure GTK initialization");
return NULL;
}
self->widget = gtk_picture_new ();
/* Otherwise widget in grid will appear as a 1x1px
* video which might be misleading for users */
gtk_widget_set_hexpand (self->widget, TRUE);
gtk_widget_set_vexpand (self->widget, TRUE);
gtk_widget_set_focusable (self->widget, TRUE);
gtk_widget_set_can_focus (self->widget, TRUE);
controller = gtk_event_controller_motion_new ();
g_signal_connect (controller, "motion",
G_CALLBACK (gst_clapper_sink_widget_motion_event), self);
gtk_widget_add_controller (self->widget, controller);
gesture = gtk_gesture_click_new ();
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), 1);
g_signal_connect (gesture, "pressed",
G_CALLBACK (gst_clapper_sink_widget_button_event), self);
g_signal_connect (gesture, "released",
G_CALLBACK (gst_clapper_sink_widget_button_event), self);
gtk_widget_add_controller (self->widget, GTK_EVENT_CONTROLLER (gesture));
/* TODO: Implement touch events once we depend on GStreamer 1.22 */
/* Take floating ref */
g_object_ref_sink (self->widget);
/* Set back pointer */
gst_clapper_paintable_set_widget (self->paintable, self->widget);
/* Set earlier remembered property */
gtk_picture_set_keep_aspect_ratio (GTK_PICTURE (self->widget),
self->force_aspect_ratio);
gtk_picture_set_paintable (GTK_PICTURE (self->widget), GDK_PAINTABLE (self->paintable));
self->widget_destroy_id = g_signal_connect (self->widget,
"destroy", G_CALLBACK (widget_destroy_cb), self);
}
return self->widget;
}
static GtkWidget *
gst_clapper_sink_obtain_widget (GstClapperSink *self)
{
GtkWidget *widget;
GST_CLAPPER_SINK_LOCK (self);
widget = gst_clapper_sink_get_widget (self);
if (widget)
g_object_ref (widget);
GST_CLAPPER_SINK_UNLOCK (self);
return widget;
}
static void
gst_clapper_sink_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
GstClapperSink *self = GST_CLAPPER_SINK_CAST (object);
GST_CLAPPER_SINK_LOCK (self);
switch (prop_id) {
case PROP_WIDGET:
if (self->widget) {
g_value_set_object (value, self->widget);
} else {
GtkWidget *widget;
GST_CLAPPER_SINK_UNLOCK (self);
widget = gst_gtk_invoke_on_main ((GThreadFunc) gst_clapper_sink_obtain_widget, self);
GST_CLAPPER_SINK_LOCK (self);
g_value_set_object (value, widget);
g_object_unref (widget);
}
break;
case PROP_FORCE_ASPECT_RATIO:
g_value_set_boolean (value, self->force_aspect_ratio);
break;
case PROP_PIXEL_ASPECT_RATIO:
gst_value_set_fraction (value, self->par_n, self->par_d);
break;
case PROP_KEEP_LAST_FRAME:
g_value_set_boolean (value, self->keep_last_frame);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
GST_CLAPPER_SINK_UNLOCK (self);
}
static void
gst_clapper_sink_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
GstClapperSink *self = GST_CLAPPER_SINK_CAST (object);
GST_CLAPPER_SINK_LOCK (self);
switch (prop_id) {
case PROP_FORCE_ASPECT_RATIO:
self->force_aspect_ratio = g_value_get_boolean (value);
if (self->widget) {
gtk_picture_set_keep_aspect_ratio (GTK_PICTURE (self->widget),
self->force_aspect_ratio);
}
break;
case PROP_PIXEL_ASPECT_RATIO:
self->par_n = gst_value_get_fraction_numerator (value);
self->par_d = gst_value_get_fraction_denominator (value);
gst_clapper_paintable_set_pixel_aspect_ratio (self->paintable,
self->par_n, self->par_d);
break;
case PROP_KEEP_LAST_FRAME:
self->keep_last_frame = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
GST_CLAPPER_SINK_UNLOCK (self);
}
static void
gst_clapper_sink_navigation_send_event (GstNavigation *navigation,
GstStructure *structure)
{
GstClapperSink *sink = GST_CLAPPER_SINK_CAST (navigation);
GstEvent *event;
GST_TRACE_OBJECT (sink, "Navigation event: %" GST_PTR_FORMAT, structure);
event = gst_event_new_navigation (structure);
if (G_LIKELY (event)) {
GstPad *pad;
pad = gst_pad_get_peer (GST_VIDEO_SINK_PAD (sink));
if (G_LIKELY (pad)) {
if (!gst_pad_send_event (pad, gst_event_ref (event))) {
/* If upstream didn't handle the event we'll post a message with it
* for the application in case it wants to do something with it */
gst_element_post_message (GST_ELEMENT_CAST (sink),
gst_navigation_message_new_event (GST_OBJECT_CAST (sink), event));
}
gst_object_unref (pad);
}
gst_event_unref (event);
}
}
static gboolean
gst_clapper_sink_propose_allocation (GstBaseSink *bsink, GstQuery *query)
{
GstClapperSink *self = GST_CLAPPER_SINK_CAST (bsink);
GstBufferPool *pool = NULL;
GstCaps *caps;
GstVideoInfo info;
guint size;
gboolean need_pool;
gst_query_parse_allocation (query, &caps, &need_pool);
if (!caps) {
GST_DEBUG_OBJECT (self, "No caps specified");
return FALSE;
}
if (!gst_video_info_from_caps (&info, caps)) {
GST_DEBUG_OBJECT (self, "Invalid caps specified");
return FALSE;
}
/* Normal size of a frame */
size = GST_VIDEO_INFO_SIZE (&info);
if (need_pool) {
GstStructure *config;
GST_DEBUG_OBJECT (self, "Creating new pool");
pool = gst_clapper_gdk_buffer_pool_new ();
config = gst_buffer_pool_get_config (pool);
gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
gst_buffer_pool_config_set_params (config, caps, size, 2, 0);
if (!gst_buffer_pool_set_config (pool, config)) {
gst_object_unref (pool);
GST_DEBUG_OBJECT (self, "Failed to set config");
return FALSE;
}
}
gst_query_add_allocation_pool (query, pool, size, 2, 0);
if (pool)
gst_object_unref (pool);
gst_query_add_allocation_meta (query,
GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, NULL);
/* We also support various metadata */
gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
return TRUE;
}
static gboolean
gst_clapper_sink_start_on_main (GstClapperSink *self)
{
GtkWidget *widget;
GST_CLAPPER_SINK_LOCK (self);
/* Make sure widget is created */
if (!(widget = gst_clapper_sink_get_widget (self))) {
GST_CLAPPER_SINK_UNLOCK (self);
return FALSE;
}
/* When no toplevel window, make our own */
if (G_UNLIKELY (!gtk_widget_get_root (widget) && !self->window)) {
GtkWidget *toplevel, *parent;
GtkCssProvider *provider;
gchar *win_title;
if ((parent = gtk_widget_get_parent (widget))) {
GtkWidget *temp_parent;
while ((temp_parent = gtk_widget_get_parent (parent)))
parent = temp_parent;
}
toplevel = (parent) ? parent : widget;
self->window = (GtkWindow *) gtk_window_new ();
gtk_widget_add_css_class (GTK_WIDGET (self->window), WINDOW_CSS_CLASS_NAME);
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_data (provider,
"." WINDOW_CSS_CLASS_NAME " { background: none; }", -1);
gtk_style_context_add_provider_for_display (
gdk_display_get_default (), GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
g_object_unref (provider);
win_title = g_strdup_printf ("Clapper Sink - GTK %u.%u.%u Window",
gtk_get_major_version (),
gtk_get_minor_version (),
gtk_get_micro_version ());
gtk_window_set_default_size (self->window, 640, 480);
gtk_window_set_title (self->window, win_title);
gtk_window_set_child (self->window, toplevel);
g_free (win_title);
self->window_destroy_id = g_signal_connect (self->window,
"destroy", G_CALLBACK (window_destroy_cb), self);
}
GST_CLAPPER_SINK_UNLOCK (self);
return TRUE;
}
static gboolean
window_present_on_main_idle (GtkWindow *window)
{
GST_INFO ("Presenting window");
gtk_window_present (window);
return G_SOURCE_REMOVE;
}
static gboolean
gst_clapper_sink_start (GstBaseSink *bsink)
{
GstClapperSink *self = GST_CLAPPER_SINK_CAST (bsink);
GST_INFO_OBJECT (self, "Start");
if (G_UNLIKELY (!(! !gst_gtk_invoke_on_main ((GThreadFunc) (GCallback)
gst_clapper_sink_start_on_main, self)))) {
GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
("GtkWidget could not be created"), (NULL));
return FALSE;
}
return TRUE;
}
static gboolean
gst_clapper_sink_stop_on_main (GstClapperSink *self)
{
GtkWindow *window = NULL;
GST_CLAPPER_SINK_LOCK (self);
if (self->window)
window = g_object_ref (self->window);
GST_CLAPPER_SINK_UNLOCK (self);
if (window) {
gtk_window_destroy (window);
g_object_unref (window);
}
return TRUE;
}
static gboolean
gst_clapper_sink_stop (GstBaseSink *bsink)
{
GstClapperSink *self = GST_CLAPPER_SINK_CAST (bsink);
gboolean has_window;
GST_INFO_OBJECT (self, "Stop");
GST_CLAPPER_SINK_LOCK (self);
has_window = (self->window != NULL);
GST_CLAPPER_SINK_UNLOCK (self);
if (G_UNLIKELY (has_window)) {
return (! !gst_gtk_invoke_on_main ((GThreadFunc) (GCallback)
gst_clapper_sink_stop_on_main, self));
}
return TRUE;
}
static GstStateChangeReturn
gst_clapper_sink_change_state (GstElement *element, GstStateChange transition)
{
GstClapperSink *self = GST_CLAPPER_SINK_CAST (element);
GST_DEBUG_OBJECT (self, "Changing state: %s => %s",
gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
GST_CLAPPER_SINK_LOCK (self);
if (!self->keep_last_frame)
gst_clapper_paintable_set_buffer (self->paintable, NULL);
GST_CLAPPER_SINK_UNLOCK (self);
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
GST_CLAPPER_SINK_LOCK (self);
if (G_UNLIKELY (self->window && !self->presented_window)) {
g_idle_add_full (G_PRIORITY_DEFAULT,
(GSourceFunc) window_present_on_main_idle,
g_object_ref (self->window), (GDestroyNotify) g_object_unref);
self->presented_window = TRUE;
}
GST_CLAPPER_SINK_UNLOCK (self);
break;
default:
break;
}
return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
}
static void
gst_clapper_sink_get_times (GstBaseSink *bsink, GstBuffer *buffer,
GstClockTime *start, GstClockTime *end)
{
if (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
return;
*start = GST_BUFFER_TIMESTAMP (buffer);
if (GST_BUFFER_DURATION_IS_VALID (buffer)) {
*end = *start + GST_BUFFER_DURATION (buffer);
} else {
GstClapperSink *self = GST_CLAPPER_SINK_CAST (bsink);
gint fps_n, fps_d;
GST_CLAPPER_SINK_LOCK (self);
fps_n = GST_VIDEO_INFO_FPS_N (&self->v_info);
fps_d = GST_VIDEO_INFO_FPS_D (&self->v_info);
GST_CLAPPER_SINK_UNLOCK (self);
if (fps_n > 0)
*end = *start + gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
}
}
static GstCaps *
gst_clapper_sink_get_caps (GstBaseSink *bsink, GstCaps *filter)
{
GstCaps *result, *tmp;
tmp = gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink));
if (filter) {
GST_DEBUG ("Intersecting with filter caps: %" GST_PTR_FORMAT, filter);
result = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (tmp);
} else {
result = tmp;
}
GST_DEBUG ("Returning caps: %" GST_PTR_FORMAT, result);
return result;
}
static gboolean
gst_clapper_sink_set_caps (GstBaseSink *bsink, GstCaps *caps)
{
GstClapperSink *self = GST_CLAPPER_SINK_CAST (bsink);
gboolean res;
GST_INFO_OBJECT (self, "Set caps: %" GST_PTR_FORMAT, caps);
GST_CLAPPER_SINK_LOCK (self);
if (!gst_video_info_from_caps (&self->v_info, caps)) {
GST_CLAPPER_SINK_UNLOCK (self);
return FALSE;
}
if (G_UNLIKELY (!self->widget)) {
GST_CLAPPER_SINK_UNLOCK (self);
GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
("Output widget was destroyed"), (NULL));
return FALSE;
}
res = gst_clapper_paintable_set_video_info (self->paintable, &self->v_info);
GST_CLAPPER_SINK_UNLOCK (self);
return res;
}
static GstFlowReturn
gst_clapper_sink_show_frame (GstVideoSink *vsink, GstBuffer *buffer)
{
GstClapperSink *self = GST_CLAPPER_SINK_CAST (vsink);
GST_TRACE ("Got %" GST_PTR_FORMAT, buffer);
GST_CLAPPER_SINK_LOCK (self);
if (G_UNLIKELY (!self->widget)) {
GST_CLAPPER_SINK_UNLOCK (self);
GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
("Output widget was destroyed"), (NULL));
return GST_FLOW_ERROR;
}
gst_clapper_paintable_set_buffer (self->paintable, buffer);
GST_CLAPPER_SINK_UNLOCK (self);
return GST_FLOW_OK;
}
static void
gst_clapper_sink_init (GstClapperSink *self)
{
GObjectClass *gobject_class;
gobject_class = (GObjectClass *) GST_CLAPPER_SINK_GET_CLASS (self);
/* HACK: install here instead of class init to avoid GStreamer
* plugin scanner GObject type conflicts with older GTK versions */
if (!g_object_class_find_property (gobject_class, "widget")) {
g_object_class_install_property (gobject_class, PROP_WIDGET,
g_param_spec_object ("widget", "GTK Widget",
"The GtkWidget to place in the widget hierarchy",
GTK_TYPE_WIDGET, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
}
self->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO;
self->par_n = DEFAULT_PAR_N;
self->par_d = DEFAULT_PAR_D;
self->keep_last_frame = DEFAULT_KEEP_LAST_FRAME;
g_mutex_init (&self->lock);
gst_video_info_init (&self->v_info);
self->paintable = gst_clapper_paintable_new ();
}
static void
gst_clapper_sink_dispose (GObject *object)
{
GstClapperSink *self = GST_CLAPPER_SINK_CAST (object);
GST_CLAPPER_SINK_LOCK (self);
window_clear_no_lock (self);
widget_clear_no_lock (self);
g_clear_object (&self->paintable);
GST_CLAPPER_SINK_UNLOCK (self);
GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
}
static void
gst_clapper_sink_finalize (GObject *object)
{
GstClapperSink *self = GST_CLAPPER_SINK_CAST (object);
GST_TRACE ("Finalize");
g_mutex_clear (&self->lock);
GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
}
static void
gst_clapper_sink_class_init (GstClapperSinkClass *klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
GstElementClass *gstelement_class = (GstElementClass *) klass;
GstBaseSinkClass *gstbasesink_class = (GstBaseSinkClass *) klass;
GstVideoSinkClass *gstvideosink_class = (GstVideoSinkClass *) klass;
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clappersink", 0,
"Clapper Sink");
gobject_class->get_property = gst_clapper_sink_get_property;
gobject_class->set_property = gst_clapper_sink_set_property;
gobject_class->dispose = gst_clapper_sink_dispose;
gobject_class->finalize = gst_clapper_sink_finalize;
g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio",
"When enabled, scaling will respect original aspect ratio",
DEFAULT_FORCE_ASPECT_RATIO,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
gst_param_spec_fraction ("pixel-aspect-ratio", "Pixel Aspect Ratio",
"The pixel aspect ratio of the device",
DEFAULT_PAR_N, DEFAULT_PAR_D,
G_MAXINT, 1, 1, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_KEEP_LAST_FRAME,
g_param_spec_boolean ("keep-last-frame", "Keep last frame",
"Keep showing last video frame after playback instead of black screen",
DEFAULT_KEEP_LAST_FRAME,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gstelement_class->change_state = gst_clapper_sink_change_state;
gstbasesink_class->get_caps = gst_clapper_sink_get_caps;
gstbasesink_class->set_caps = gst_clapper_sink_set_caps;
gstbasesink_class->get_times = gst_clapper_sink_get_times;
gstbasesink_class->propose_allocation = gst_clapper_sink_propose_allocation;
gstbasesink_class->start = gst_clapper_sink_start;
gstbasesink_class->stop = gst_clapper_sink_stop;
gstvideosink_class->show_frame = gst_clapper_sink_show_frame;
gst_element_class_set_metadata (gstelement_class,
"Clapper video sink",
"Sink/Video", "A GTK4 video sink used by Clapper media player",
"Rafał Dzięgiel <rafostar.github@gmail.com>");
gst_element_class_add_static_pad_template (gstelement_class,
&gst_clapper_sink_template);
}
/*
* GstNavigationInterface
*/
static void
gst_clapper_sink_navigation_interface_init (GstNavigationInterface *iface)
{
/* TODO: Port to "send_event_simple" once we depend on GStreamer 1.22 */
iface->send_event = gst_clapper_sink_navigation_send_event;
}

70
lib/gst/plugin/gstclappersink.h vendored Normal file
View File

@@ -0,0 +1,70 @@
/*
* Copyright (C) 2022 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include <gtk/gtk.h>
#include <gst/gst.h>
#include <gst/video/gstvideosink.h>
#include <gst/video/video.h>
#include "gstclapperpaintable.h"
G_BEGIN_DECLS
#define GST_TYPE_CLAPPER_SINK (gst_clapper_sink_get_type())
G_DECLARE_FINAL_TYPE (GstClapperSink, gst_clapper_sink, GST, CLAPPER_SINK, GstVideoSink)
#define GST_CLAPPER_SINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CLAPPER_SINK, GstClapperSinkClass))
#define GST_CLAPPER_SINK_CAST(obj) ((GstClapperSink *)(obj))
#define GST_CLAPPER_SINK_GET_LOCK(obj) (&GST_CLAPPER_SINK_CAST(obj)->lock)
#define GST_CLAPPER_SINK_LOCK(obj) g_mutex_lock (GST_CLAPPER_SINK_GET_LOCK(obj))
#define GST_CLAPPER_SINK_UNLOCK(obj) g_mutex_unlock (GST_CLAPPER_SINK_GET_LOCK(obj))
struct _GstClapperSink
{
GstVideoSink parent;
GMutex lock;
GstClapperPaintable *paintable;
GstVideoInfo v_info;
GtkWidget *widget;
GtkWindow *window;
gboolean presented_window;
/* Properties */
gboolean force_aspect_ratio;
gint par_n, par_d;
gboolean keep_last_frame;
/* Position coords */
gdouble last_pos_x;
gdouble last_pos_y;
gulong widget_destroy_id;
gulong window_destroy_id;
};
GST_ELEMENT_REGISTER_DECLARE (clappersink);
G_END_DECLS

131
lib/gst/plugin/gstgtkutils.c vendored Normal file
View File

@@ -0,0 +1,131 @@
/*
* GStreamer
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
* Copyright (C) 2015 Thibault Saunier <tsaunier@gnome.org>
* Copyright (C) 2022 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "gstgtkutils.h"
struct invoke_context
{
GThreadFunc func;
gpointer data;
GMutex lock;
GCond cond;
gboolean fired;
gpointer res;
};
static gboolean
gst_gtk_invoke_func (struct invoke_context *info)
{
g_mutex_lock (&info->lock);
info->res = info->func (info->data);
info->fired = TRUE;
g_cond_signal (&info->cond);
g_mutex_unlock (&info->lock);
return G_SOURCE_REMOVE;
}
gpointer
gst_gtk_invoke_on_main (GThreadFunc func, gpointer data)
{
GMainContext *main_context = g_main_context_default ();
struct invoke_context info;
g_mutex_init (&info.lock);
g_cond_init (&info.cond);
info.fired = FALSE;
info.func = func;
info.data = data;
g_main_context_invoke (main_context, (GSourceFunc) gst_gtk_invoke_func,
&info);
g_mutex_lock (&info.lock);
while (!info.fired)
g_cond_wait (&info.cond, &info.lock);
g_mutex_unlock (&info.lock);
g_mutex_clear (&info.lock);
g_cond_clear (&info.cond);
return info.res;
}
/* For use with `GdkMemoryTexture` only! */
GdkMemoryFormat
gst_video_format_to_gdk_memory_format (GstVideoFormat format)
{
switch (format) {
case GST_VIDEO_FORMAT_RGBA64_LE:
case GST_VIDEO_FORMAT_RGBA64_BE:
return GDK_MEMORY_R16G16B16A16_PREMULTIPLIED;
case GST_VIDEO_FORMAT_RGBA:
return GDK_MEMORY_R8G8B8A8;
case GST_VIDEO_FORMAT_BGRA:
return GDK_MEMORY_B8G8R8A8;
case GST_VIDEO_FORMAT_ARGB:
return GDK_MEMORY_A8R8G8B8;
case GST_VIDEO_FORMAT_ABGR:
return GDK_MEMORY_A8B8G8R8;
case GST_VIDEO_FORMAT_RGBx:
return GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
case GST_VIDEO_FORMAT_BGRx:
return GDK_MEMORY_B8G8R8A8_PREMULTIPLIED;
case GST_VIDEO_FORMAT_RGB:
return GDK_MEMORY_R8G8B8;
case GST_VIDEO_FORMAT_BGR:
return GDK_MEMORY_B8G8R8;
default:
break;
}
/* This should never happen as long as above switch statement
* is updated when new formats are added to caps */
g_assert_not_reached ();
/* Fallback format */
return GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
}
GdkTexture *
gst_video_frame_into_gdk_texture (GstVideoFrame *frame, GDestroyNotify free_func)
{
GdkTexture *texture;
GBytes *bytes;
bytes = g_bytes_new_with_free_func (
GST_VIDEO_FRAME_PLANE_DATA (frame, 0),
GST_VIDEO_FRAME_HEIGHT (frame) * GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0),
free_func, frame);
texture = gdk_memory_texture_new (
GST_VIDEO_FRAME_WIDTH (frame),
GST_VIDEO_FRAME_HEIGHT (frame),
gst_video_format_to_gdk_memory_format (GST_VIDEO_FRAME_FORMAT (frame)),
bytes,
GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0));
g_bytes_unref (bytes);
return texture;
}

33
lib/gst/plugin/gstgtkutils.h vendored Normal file
View File

@@ -0,0 +1,33 @@
/*
* GStreamer
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
* Copyright (C) 2015 Thibault Saunier <tsaunier@gnome.org>
* Copyright (C) 2022 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include <glib.h>
#include <gtk/gtk.h>
#include <gst/video/video.h>
gpointer gst_gtk_invoke_on_main (GThreadFunc func, gpointer data);
GdkMemoryFormat gst_video_format_to_gdk_memory_format (GstVideoFormat format);
GdkTexture * gst_video_frame_into_gdk_texture (GstVideoFrame *frame, GDestroyNotify free_func);

46
lib/gst/plugin/gstplugin.c vendored Normal file
View File

@@ -0,0 +1,46 @@
/*
* Copyright (C) 2022 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstclapperimport.h"
#include "gstclapperglimport.h"
#include "gstclappersink.h"
#include "gstclappergdkmemory.h"
static gboolean
plugin_init (GstPlugin *plugin)
{
gboolean res = FALSE;
res |= GST_ELEMENT_REGISTER (clapperimport, plugin);
res |= GST_ELEMENT_REGISTER (clapperglimport, plugin);
res |= GST_ELEMENT_REGISTER (clappersink, plugin);
if (res)
gst_clapper_gdk_memory_init_once ();
return res;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
clapper, "Clapper elements", plugin_init, VERSION, "LGPL",
GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

69
lib/gst/plugin/meson.build vendored Normal file
View File

@@ -0,0 +1,69 @@
gst_plugins_libdir = join_paths(prefix, libdir, 'gstreamer-1.0')
gst_clapper_plugin_args = [
'-DHAVE_CONFIG_H',
'-DGST_USE_UNSTABLE_API',
]
gst_clapper_plugin_deps = [
gtk4_dep,
gst_dep,
gstbase_dep,
gstvideo_dep,
gstallocators_dep,
]
if get_option('default_library') == 'static'
gst_clapper_plugin_args += ['-DGST_STATIC_COMPILATION']
endif
gst_clapper_plugin_option = get_option('gst-plugin')
if gst_clapper_plugin_option.disabled()
subdir_done()
endif
foreach dep : gst_clapper_plugin_deps
if not dep.found()
if gst_clapper_plugin_option.enabled()
error('GStreamer plugin was enabled, but required dependencies were not found')
endif
subdir_done()
endif
endforeach
if not have_gtk_gl_windowing
if gst_clapper_plugin_option.enabled()
error('GTK4 widget requires GL windowing')
else
subdir_done()
endif
endif
if not gtk4_dep.version().version_compare('>=4.6.0')
if gst_clapper_plugin_option.enabled()
error('GTK4 version on this system is too old, plugin needs 4.6.0+')
else
subdir_done()
endif
endif
gst_clapper_plugin_sources = [
'gstclappergdkmemory.c',
'gstclappergdkbufferpool.c',
'gstclapperbaseimport.c',
'gstclapperglbaseimport.c',
'gstclapperimport.c',
'gstclapperglimport.c',
'gstclappersink.c',
'gstclapperpaintable.c',
'gstgtkutils.c',
'gstplugin.c',
]
library('gstclapper',
gst_clapper_plugin_sources,
c_args: gst_clapper_plugin_args,
include_directories: configinc,
dependencies: gst_clapper_plugin_deps + gtk_deps,
install: true,
install_dir: gst_plugins_libdir,
)

49
lib/meson.build vendored
View File

@@ -1,5 +1,5 @@
glib_req = '>= 2.56.0'
gst_req = '>= 1.18.0'
gst_req = '>= 1.20.0'
api_version = '1.0'
libversion = meson.project_version()
@@ -132,7 +132,7 @@ cdata.set('SIZEOF_SHORT', cc.sizeof('short'))
cdata.set('SIZEOF_VOIDP', cc.sizeof('void*'))
cdata.set_quoted('VERSION', libversion)
cdata.set_quoted('PACKAGE', 'gst-plugins-clapper')
cdata.set_quoted('PACKAGE', 'clapper')
cdata.set_quoted('PACKAGE_VERSION', libversion)
cdata.set_quoted('PACKAGE_BUGREPORT', 'https://github.com/Rafostar/clapper/issues/new')
cdata.set_quoted('PACKAGE_NAME', 'GStreamer Clapper Libs')
@@ -184,7 +184,7 @@ foreach extra_arg : warning_flags
endif
endforeach
cdata.set_quoted('GST_PACKAGE_NAME', 'GStreamer Plugins Clapper')
cdata.set_quoted('GST_PACKAGE_NAME', 'gst-plugin-clapper')
cdata.set_quoted('GST_PACKAGE_ORIGIN', 'https://github.com/Rafostar/clapper')
# Mandatory GST deps
@@ -200,6 +200,8 @@ gsttag_dep = dependency('gstreamer-tag-1.0', version: gst_req,
fallback: ['gst-plugins-base', 'tag_dep'])
gstvideo_dep = dependency('gstreamer-video-1.0', version: gst_req,
fallback: ['gst-plugins-base', 'video_dep'])
gstallocators_dep = dependency('gstreamer-allocators-1.0', version: gst_req,
fallback : ['gst-plugins-base', 'allocators_dep'])
# GStreamer OpenGL
gstgl_dep = dependency('gstreamer-gl-1.0', version: gst_req,
@@ -247,24 +249,53 @@ libm = cc.find_library('m', required: false)
glib_dep = dependency('glib-2.0', version: glib_req, fallback: ['glib', 'libglib_dep'])
gmodule_dep = dependency('gmodule-2.0', fallback: ['glib', 'libgmodule_dep'])
gio_dep = dependency('gio-2.0', fallback: ['glib', 'libgio_dep'])
giounix_dep = dependency('gio-unix-2.0', version: glib_req, fallback: ['glib', 'libgiounix_dep'])
cdata.set('DISABLE_ORC', 1)
cdata.set('GST_ENABLE_EXTRA_CHECKS', get_option('devel-checks'))
cdata.set_quoted('GST_PACKAGE_RELEASE_DATETIME', 'Unknown')
configinc = include_directories('.')
libsinc = include_directories('gst')
gir = find_program('g-ir-scanner', required: true)
if not gir.found()
error('Clapper requires GI bindings to be compiled')
endif
gir = find_program('g-ir-scanner')
gir_init_section = ['--add-init-section=extern void gst_init(gint*,gchar**);' + \
'g_setenv("GST_REGISTRY_1.0", "@0@", TRUE);'.format(meson.current_build_dir() + '/gir_empty_registry.reg') + \
'g_setenv("GST_PLUGIN_PATH_1_0", "", TRUE);' + \
'g_setenv("GST_PLUGIN_SYSTEM_PATH_1_0", "", TRUE);' + \
'gst_init(NULL,NULL);', '--quiet'
]
gtk_deps = [gstgl_dep, gstglproto_dep]
have_gtk_gl_windowing = false
gtk4_dep = dependency('gtk4', required: true)
if not gtk4_dep.version().version_compare('>=4.0.0')
error('GTK4 version on this system is too old')
endif
if gst_gl_have_window_x11 and (gst_gl_have_platform_egl or gst_gl_have_platform_glx)
gtk_x11_dep = dependency('gtk4-x11', required: false)
if gtk_x11_dep.found()
gtk_deps += gtk_x11_dep
if gst_gl_have_platform_glx
gtk_deps += gstglx11_dep
endif
have_gtk_gl_windowing = true
endif
endif
if gst_gl_have_window_wayland and gst_gl_have_platform_egl
gtk_wayland_dep = dependency('gtk4-wayland', required: false)
if gtk_wayland_dep.found()
gtk_deps += [gtk_wayland_dep, gstglwayland_dep]
have_gtk_gl_windowing = true
endif
endif
if gst_gl_have_platform_egl
gtk_deps += gstglegl_dep
endif
subdir('gst')
configure_file(output: 'config.h', configuration: cdata)

View File

@@ -1,5 +1,5 @@
project('com.github.rafostar.Clapper', 'c', 'cpp',
version: '0.4.0',
version: '0.4.1',
meson_version: '>= 0.50.0',
license: 'GPL-3.0-or-later',
default_options: [
@@ -19,7 +19,7 @@ datadir = join_paths(get_option('prefix'), get_option('datadir'))
pkglibdir = join_paths(libdir, meson.project_name())
pkgdatadir = join_paths(datadir, meson.project_name())
if get_option('lib')
if get_option('lib') or not get_option('gst-plugin').disabled()
subdir('lib')
endif

View File

@@ -8,6 +8,11 @@ option('lib',
value: true,
description: 'Build GstClapper lib'
)
option('gst-plugin',
type: 'feature',
value: 'enabled',
description: 'Build GStreamer plugin (includes GTK video sink element)'
)
option('devel-checks',
type: 'boolean',
value: false,

View File

@@ -3,6 +3,10 @@
"runtime": "org.gnome.Platform",
"runtime-version": "master",
"sdk": "org.gnome.Sdk",
"sdk-extensions": [
"org.freedesktop.Sdk.Extension.rust-nightly",
"org.freedesktop.Sdk.Extension.llvm13"
],
"command": "com.github.rafostar.Clapper",
"finish-args": [
"--share=ipc",
@@ -19,10 +23,15 @@
"--env=GST_PLUGIN_SYSTEM_PATH=/app/lib/gstreamer-1.0",
"--env=GST_VAAPI_ALL_DRIVERS=1"
],
"build-options": {
"append-path": "/usr/lib/sdk/rust-nightly/bin:/usr/lib/sdk/llvm13/bin",
"prepend-ld-library-path": "/usr/lib/sdk/llvm13/lib"
},
"modules": [
"flathub/shared-modules/gudev/gudev.json",
"flathub/lib/libsass.json",
"flathub/lib/sassc.json",
"flathub/lib/libadwaita.json",
"flathub/lib/liba52.json",
"flathub/lib/libmpeg2.json",
"flathub/lib/libdv.json",
@@ -31,14 +40,9 @@
"flathub/lib/libdvdnav.json",
"flathub/lib/libass.json",
"flathub/lib/ffmpeg.json",
"testing/gstreamer-1.0/gstreamer.json",
"testing/gstreamer-1.0/gst-plugins-base.json",
"testing/gstreamer-1.0/gst-plugins-good.json",
"testing/gstreamer-1.0/gst-plugins-bad.json",
"testing/gstreamer-1.0/gst-plugins-ugly.json",
"testing/gstreamer-1.0/gst-libav.json",
"testing/gstreamer-1.0/gstreamer-vaapi.json",
"testing/libadwaita.json",
"testing/gstreamer.json",
"testing/gst-plugins-rs.json",
"testing/gtuber.json",
{
"name": "clapper",
"buildsystem": "meson",

View File

@@ -1,7 +1,7 @@
{
"app-id": "com.github.rafostar.Clapper",
"runtime": "org.gnome.Platform",
"runtime-version": "40",
"runtime-version": "42",
"sdk": "org.gnome.Sdk",
"command": "com.github.rafostar.Clapper",
"finish-args": [
@@ -20,7 +20,6 @@
"--env=GST_VAAPI_ALL_DRIVERS=1"
],
"modules": [
"flathub/lib/glib-networking.json",
"flathub/shared-modules/gudev/gudev.json",
"flathub/lib/pango.json",
"flathub/lib/libsass.json",
@@ -35,14 +34,9 @@
"flathub/lib/ffmpeg.json",
"flathub/lib/uchardet.json",
"flathub/gstreamer-1.0/gstreamer.json",
"flathub/gstreamer-1.0/gst-plugins-base.json",
"flathub/gstreamer-1.0/gst-plugins-good.json",
"flathub/gstreamer-1.0/gst-plugins-bad.json",
"flathub/gstreamer-1.0/gst-plugins-ugly.json",
"flathub/gstreamer-1.0/gst-libav.json",
"flathub/gstreamer-1.0/gstreamer-vaapi.json",
"flathub/lib/gtk4.json",
"testing/libadwaita.json",
"testing/gtk4.json",
"flathub/lib/libadwaita.json",
"testing/gtuber.json",
{
"name": "clapper",
"buildsystem": "meson",

View File

@@ -0,0 +1,23 @@
{
"name": "gst-plugins-rs",
"buildsystem": "simple",
"build-options": {
"build-args": [
"--share=network"
],
"env": {
"CARGO_HOME": "/run/build/gst-plugins-rs/cargo"
}
},
"sources": [
{
"type": "git",
"url": "https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git",
"branch": "main"
}
],
"build-commands": [
"cargo install cargo-c",
"cargo cinstall --prefix=/app -p gst-plugin-dav1d"
]
}

View File

@@ -1,15 +0,0 @@
{
"name": "gst-libav",
"buildsystem": "meson",
"config-opts": [
"-Ddoc=disabled",
"-Dtests=disabled"
],
"sources": [
{
"type": "git",
"url": "https://gitlab.freedesktop.org/gstreamer/gst-libav.git",
"branch": "master"
}
]
}

View File

@@ -1,28 +0,0 @@
{
"name": "gst-plugins-bad",
"buildsystem": "meson",
"config-opts": [
"-Ddoc=disabled",
"-Dexamples=disabled",
"-Dtests=disabled",
"-Dnls=disabled",
"-Dgobject-cast-checks=disabled",
"-Dglib-asserts=disabled",
"-Dglib-checks=disabled",
"-Dextra-checks=disabled",
"-Dvulkan=disabled",
"-Dwebrtc=disabled",
"-Dwasapi=disabled",
"-Dwasapi2=disabled",
"-Dwinks=disabled",
"-Dwinscreencap=disabled"
],
"sources": [
{
"type": "git",
"url": "https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad.git",
"branch": "master"
}
]
}

View File

@@ -1,25 +0,0 @@
{
"name": "gst-plugins-base",
"buildsystem": "meson",
"config-opts": [
"--wrap-mode=nofallback",
"-Ddoc=disabled",
"-Dexamples=disabled",
"-Dtests=disabled",
"-Dnls=disabled",
"-Dgobject-cast-checks=disabled",
"-Dglib-asserts=disabled",
"-Dglib-checks=disabled",
"-Dgl_api=opengl,gles2",
"-Dgl_platform=egl,glx"
],
"sources": [
{
"type": "git",
"url": "https://gitlab.freedesktop.org/gstreamer/gst-plugins-base.git",
"branch": "master"
}
]
}

View File

@@ -1,22 +0,0 @@
{
"name": "gst-plugins-good",
"buildsystem": "meson",
"config-opts": [
"-Ddoc=disabled",
"-Dexamples=disabled",
"-Dtests=disabled",
"-Dnls=disabled",
"-Dgobject-cast-checks=disabled",
"-Dglib-asserts=disabled",
"-Dglib-checks=disabled",
"-Dgtk3=disabled"
],
"sources": [
{
"type": "git",
"url": "https://gitlab.freedesktop.org/gstreamer/gst-plugins-good.git",
"branch": "master"
}
]
}

View File

@@ -1,21 +0,0 @@
{
"name": "gst-plugins-ugly",
"buildsystem": "meson",
"config-opts": [
"-Ddoc=disabled",
"-Dnls=disabled",
"-Dtests=disabled",
"-Dgobject-cast-checks=disabled",
"-Dglib-asserts=disabled",
"-Dglib-checks=disabled",
"-Dmpeg2dec=enabled"
],
"sources": [
{
"type": "git",
"url": "https://gitlab.freedesktop.org/gstreamer/gst-plugins-ugly.git",
"branch": "master"
}
]
}

View File

@@ -1,16 +0,0 @@
{
"name": "gstreamer-vaapi",
"buildsystem": "meson",
"config-opts": [
"-Ddoc=disabled",
"-Dexamples=disabled",
"-Dtests=disabled"
],
"sources": [
{
"type": "git",
"url": "https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi.git",
"branch": "master"
}
]
}

View File

@@ -1,23 +0,0 @@
{
"name": "gstreamer",
"buildsystem": "meson",
"config-opts": [
"-Ddoc=disabled",
"-Dgtk_doc=disabled",
"-Dexamples=disabled",
"-Dtests=disabled",
"-Dbenchmarks=disabled",
"-Dnls=disabled",
"-Dgobject-cast-checks=disabled",
"-Dglib-asserts=disabled",
"-Dglib-checks=disabled",
"-Dextra-checks=disabled"
],
"sources": [
{
"type": "git",
"url": "https://gitlab.freedesktop.org/gstreamer/gstreamer.git",
"branch": "master"
}
]
}

View File

@@ -0,0 +1,56 @@
{
"name": "gstreamer",
"buildsystem": "meson",
"config-opts": [
"--wrap-mode=nodownload",
"-Dbase=enabled",
"-Dgood=enabled",
"-Dbad=enabled",
"-Dugly=enabled",
"-Dlibav=enabled",
"-Dvaapi=enabled",
"-Dsharp=disabled",
"-Drs=disabled",
"-Dpython=disabled",
"-Ddevtools=disabled",
"-Dges=disabled",
"-Drtsp_server=disabled",
"-Dgst-examples=disabled",
"-Dqt5=disabled",
"-Dtests=disabled",
"-Dexamples=disabled",
"-Dintrospection=enabled",
"-Ddoc=disabled",
"-Dgtk_doc=disabled",
"-Dgpl=enabled",
"-Dgstreamer:benchmarks=disabled",
"-Dgst-plugins-base:gl_api=opengl,gles2",
"-Dgst-plugins-base:gl_platform=egl,glx",
"-Dgst-plugins-good:gtk3=disabled",
"-Dgst-plugins-bad:vulkan=disabled",
"-Dgst-plugins-bad:webrtc=disabled",
"-Dgst-plugins-bad:wasapi=disabled",
"-Dgst-plugins-bad:wasapi2=disabled",
"-Dgst-plugins-bad:winks=disabled",
"-Dgst-plugins-bad:winscreencap=disabled",
"-Dgst-plugins-bad:assrender=enabled",
"-Dgst-plugins-bad:nvcodec=enabled",
"-Dgst-plugins-bad:v4l2codecs=enabled",
"-Dgst-plugins-bad:va=enabled",
"-Dgst-plugins-ugly:mpeg2dec=enabled"
],
"sources": [
{
"type": "git",
"url": "https://gitlab.freedesktop.org/gstreamer/gstreamer.git",
"branch": "main",
"disable-submodules": true
}
]
}

View File

@@ -0,0 +1,31 @@
From b413ee2c7d458c7005d3d3d1da8822cd86893ac0 Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Fri, 4 Dec 2020 19:25:34 +0100
Subject: [PATCH] popover: Call unrealize on hide
When popover is shown "realize" method is called which creates a new
surface for popup. Unfortunately this causes performance drop on Wayland until that
surface is destroyed what happens inside "unrealize" method during popover destruction.
This commit changes default behavior in a way that surface will be destroyed
when popover is closed and app will ragain the performance it lost when
popover was shown.
---
gtk/gtkpopover.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c
index 504dcd6cc1..a7a764d483 100644
--- a/gtk/gtkpopover.c
+++ b/gtk/gtkpopover.c
@@ -951,6 +951,7 @@ gtk_popover_hide (GtkWidget *widget)
gtk_popover_set_mnemonics_visible (GTK_POPOVER (widget), FALSE);
_gtk_widget_set_visible_flag (widget, FALSE);
+ gtk_widget_unrealize (widget);
gtk_widget_unmap (widget);
g_signal_emit (widget, signals[CLOSED], 0);
}
--
GitLab

View File

@@ -0,0 +1,37 @@
{
"name": "gtk",
"buildsystem": "meson",
"build-options": {
"build-args": [
"--share=network"
]
},
"config-opts": [
"--buildtype=release",
"-Dwin32-backend=false",
"-Dmacos-backend=false",
"-Dmedia-ffmpeg=disabled",
"-Dprint-cups=disabled",
"-Dintrospection=enabled",
"-Ddemos=false",
"-Dbuild-examples=false",
"-Dbuild-tests=false"
],
"cleanup": [
"/bin/gtk4-builder-tool",
"/bin/gtk4-encode-symbolic-svg"
],
"sources": [
{
"type": "git",
"url": "https://gitlab.gnome.org/GNOME/gtk.git",
"tag": "4.6.2",
"commit": "aec7ca82007dbe07faee6be084d20758ebac2b91"
},
{
"type": "patch",
"path": "gtk4-popover-unrealize.patch"
}
]
}

View File

@@ -0,0 +1,20 @@
{
"name": "gtuber",
"buildsystem": "meson",
"config-opts": [
"-Dintrospection=disabled",
"-Dvapi=disabled",
"-Dgst-gtuber=enabled"
],
"cleanup": [
"/include",
"/lib/pkgconfig"
],
"sources": [
{
"type": "git",
"url": "https://github.com/Rafostar/gtuber.git",
"branch": "main"
}
]
}

View File

@@ -1,21 +0,0 @@
{
"name": "libadwaita",
"buildsystem": "meson",
"config-opts": [
"--buildtype=release",
"--wrap-mode=nofallback",
"-Dintrospection=enabled",
"-Dvapi=false",
"-Dgtk_doc=false",
"-Dtests=false",
"-Dexamples=false"
],
"sources": [
{
"type": "git",
"url": "https://gitlab.gnome.org/GNOME/libadwaita.git",
"tag": "1.0.0-alpha.2",
"commit": "f5932ab4250c8e709958c6e75a1a4941a5f0f386"
}
]
}

3
pkgs/rpm/.gitignore vendored
View File

@@ -1,3 +0,0 @@
.osc/
clapper/
.lock

View File

@@ -1 +0,0 @@
addFilter("explicit-lib-dependency")

View File

@@ -1,184 +0,0 @@
#
# spec file for package clapper
#
# Copyright (C) 2020 sp1rit
# Copyright (C) 2020-21 Rafostar
#
# This program 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 3 of the License, or
# (at your option) any later version.
#
# This program 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 program. If not, see <https://www.gnu.org/licenses/>.
%define debug_package %{nil}
%global appname com.github.rafostar.Clapper
%global gst_version 1.18.0
%global gtk4_version 4.0.0
%global meson_version 0.50
%global glib2_version 2.56.0
Name: clapper
Version: 0.4.0
Release: 1%{?dist}
Summary: Simple and modern GNOME media player
License: GPL-3.0
URL: https://github.com/Rafostar/clapper
BuildRoot: %{_builddir}/%{name}-%{version}-build
Source0: _service
BuildRequires: meson >= %{meson_version}
BuildRequires: gtk4-devel >= %{gtk4_version}
BuildRequires: glib2-devel >= %{glib2_version}
BuildRequires: gobject-introspection-devel
BuildRequires: gjs
BuildRequires: gcc-c++
BuildRequires: desktop-file-utils
BuildRequires: hicolor-icon-theme
Requires: gjs
Requires: gtk4 >= %{gtk4_version}
Requires: libadwaita
Requires: hicolor-icon-theme
%if 0%{?suse_version}
# SUSE recommends group tag, while Fedora discourages their use
Group: Productivity/Multimedia/Video/Players
BuildRequires: update-desktop-files
BuildRequires: gstreamer-devel >= %{gst_version}
BuildRequires: gstreamer-plugins-base-devel >= %{gst_version}
BuildRequires: Mesa-libGLESv2-devel
BuildRequires: Mesa-libGLESv3-devel
Requires: gstreamer >= %{gst_version}
Requires: gstreamer-plugins-base >= %{gst_version}
Requires: gstreamer-plugins-good >= %{gst_version}
Requires: gstreamer-plugins-bad >= %{gst_version}
# Popular video decoders
Recommends: gstreamer-plugins-libav >= %{gst_version}
# CD Playback
Suggests: gstreamer-plugins-ugly
# Intel/AMD video acceleration
Suggests: gstreamer-plugins-vaapi
%else
BuildRequires: glibc-all-langpacks
BuildRequires: gstreamer1-devel >= %{gst_version}
BuildRequires: gstreamer1-plugins-base-devel >= %{gst_version}
BuildRequires: mesa-libGL-devel
BuildRequires: mesa-libGLES-devel
BuildRequires: mesa-libGLU-devel
BuildRequires: mesa-libEGL-devel
Requires: gstreamer1 >= %{gst_version}
Requires: gstreamer1-plugins-base >= %{gst_version}
Requires: gstreamer1-plugins-good >= %{gst_version}
Requires: gstreamer1-plugins-bad-free >= %{gst_version}
# ASS subtitles (assrender)
Recommends: gstreamer1-plugins-bad-free-extras >= %{gst_version}
# CD Playback
Suggests: gstreamer1-plugins-ugly-free
# Intel/AMD video acceleration
Suggests: gstreamer1-vaapi
%endif
%description
A GNOME media player built using GJS with GTK4 toolkit and powered by GStreamer with OpenGL rendering.
%prep
%setup -q -n %{_sourcedir}/%{name}-%{version} -T -D
%build
%meson
%meson_build
%install
%meson_install
%if 0%{?suse_version}
%suse_update_desktop_file %{appname}
%endif
%check
desktop-file-validate %{buildroot}%{_datadir}/applications/*.desktop
%files
%license COPYING
%doc README.md
%{_bindir}/%{appname}*
%{_bindir}/clapper
%{_datadir}/%{appname}/
%{_datadir}/icons/hicolor/*/apps/*.svg
%{_datadir}/glib-2.0/schemas/%{appname}.gschema.xml
%{_datadir}/mime/packages/%{appname}.xml
%{_datadir}/applications/*.desktop
%{_datadir}/metainfo/*.metainfo.xml
%{_datadir}/gir-1.0/GstClapper-1.0.gir
%{_datadir}/locale/*/LC_MESSAGES/%{appname}.mo
%{_libdir}/%{appname}/
%changelog
* Sun Sep 12 2021 Rafostar <rafostar.github@gmail.com> - 0.4.0-1
- New version
* Thu Aug 26 2021 Rafostar <rafostar.github@gmail.com> - 0.3.0-4
- Install translations
* Thu Aug 26 2021 Rafostar <rafostar.github@gmail.com> - 0.3.0-3
- Install clapper symlink
* Mon Aug 23 2021 Rafostar <rafostar.github@gmail.com> - 0.3.0-2
- Require libadwaita
* Fri Jun 18 2021 Rafostar <rafostar.github@gmail.com> - 0.3.0-1
- New version
* Mon Apr 19 2021 Rafostar <rafostar.github@gmail.com> - 0.2.1-1
- New version
* Tue Apr 13 2021 Rafostar <rafostar.github@gmail.com> - 0.2.0-1
- New version
* Fri Feb 26 2021 Rafostar <rafostar.github@gmail.com> - 0.1.0-1
- New version
* Sun Feb 7 2021 Rafostar <rafostar.github@gmail.com> - 0.0.0-10
- Install gstclapper libs to app named subdirectory
* Fri Feb 5 2021 Rafostar <rafostar.github@gmail.com> - 0.0.0-9
- Update build with gstclapper libs support
* Thu Jan 21 2021 Rafostar <rafostar.github@gmail.com> - 0.0.0-8
- Use metainfo instead of deprecated appdata
* Mon Jan 18 2021 Rafostar <rafostar.github@gmail.com> - 0.0.0-7
- Remove gjs-1.0 files
* Sun Dec 20 2020 Rafostar <rafostar.github@gmail.com> - 0.0.0-6
- Include additional app binaries
* Sat Oct 31 2020 Rafostar <rafostar.github@gmail.com> - 0.0.0-5
- Added metainfo
* Sun Oct 25 2020 Rafostar <rafostar.github@gmail.com> - 0.0.0-4
- Added gschema
* Wed Oct 14 2020 Rafostar <rafostar.github@gmail.com> - 0.0.0-3
- Update to GTK4
* Sat Sep 19 22:02:00 CEST 2020 sp1rit - 0.0.0-2
- Added suse_update_desktop_file macro for SuSE packages
* Fri Sep 18 2020 Rafostar <rafostar.github@gmail.com> - 0.0.0-1
- Initial package

View File

@@ -1 +1 @@
ca de it nl pl
ca cs de es fr hu it nl pl pt pt_BR ru sv zh_CN

View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-06 18:31\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2021-09-14 15:25\n"
"Last-Translator: \n"
"Language-Team: Afrikaans\n"
"Language: af_ZA\n"
@@ -18,11 +18,11 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgid "Open Files"
msgstr ""
#: ui/clapper.ui:10
msgid "Open URI..."
msgid "Open URI"
msgstr ""
#: ui/clapper.ui:16 ui/preferences-window.ui:4
@@ -399,56 +399,61 @@ msgstr ""
msgid "Open"
msgstr ""
#: src/dialogs.js:217
#: src/dialogs.js:226
msgid "Title"
msgstr ""
#: src/dialogs.js:218
#: src/dialogs.js:227
msgid "Completed"
msgstr ""
#: src/dialogs.js:226
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr ""
#: src/dialogs.js:280
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:282
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:283
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr ""
#: src/dialogs.js:291
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr ""
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr ""
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr ""
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr ""

View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-06 18:31\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2021-09-14 15:25\n"
"Last-Translator: \n"
"Language-Team: Arabic\n"
"Language: ar_SA\n"
@@ -18,11 +18,11 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgid "Open Files"
msgstr ""
#: ui/clapper.ui:10
msgid "Open URI..."
msgid "Open URI"
msgstr ""
#: ui/clapper.ui:16 ui/preferences-window.ui:4
@@ -399,56 +399,61 @@ msgstr ""
msgid "Open"
msgstr ""
#: src/dialogs.js:217
#: src/dialogs.js:226
msgid "Title"
msgstr ""
#: src/dialogs.js:218
#: src/dialogs.js:227
msgid "Completed"
msgstr ""
#: src/dialogs.js:226
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr ""
#: src/dialogs.js:280
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:282
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:283
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr ""
#: src/dialogs.js:291
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr ""
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr ""
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr ""
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr ""

View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-06 20:37\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2021-09-14 16:21\n"
"Last-Translator: \n"
"Language-Team: Catalan\n"
"Language: ca_ES\n"
@@ -18,12 +18,12 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgstr "Obre fitxers..."
msgid "Open Files"
msgstr "Obre fitxers"
#: ui/clapper.ui:10
msgid "Open URI..."
msgstr "Obre l'URI..."
msgid "Open URI"
msgstr "Obre l'URI"
#: ui/clapper.ui:16 ui/preferences-window.ui:4
msgid "Preferences"
@@ -399,56 +399,61 @@ msgstr "Cancel·la"
msgid "Open"
msgstr "Obre"
#: src/dialogs.js:217
#: src/dialogs.js:226
msgid "Title"
msgstr "Títol"
#: src/dialogs.js:218
#: src/dialogs.js:227
msgid "Completed"
msgstr "Completat"
#: src/dialogs.js:226
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr "Reprèn la reproducció?"
#: src/dialogs.js:280
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr "Versió del GTK: %s"
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr "Versió del Adwaita: %s"
#: src/dialogs.js:282
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr "Versió del GStreamer: %s"
#: src/dialogs.js:283
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr "Versió del GJS: %s"
#: src/dialogs.js:291
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr "Un reproductor multimèdia del GNOME que usa GStreamer"
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr "Ícar Nin Solana <icar.nin@protonmail.com>, 2021"
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr "Acaba a la/les %s"
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr "Sense determinar"
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr "Canals"
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr "Deshabilitat"

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.github.rafostar.Clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -18,11 +18,11 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgid "Open Files"
msgstr ""
#: ui/clapper.ui:10
msgid "Open URI..."
msgid "Open URI"
msgstr ""
#: ui/clapper.ui:16 ui/preferences-window.ui:4
@@ -399,55 +399,60 @@ msgstr ""
msgid "Open"
msgstr ""
#: src/dialogs.js:217
#: src/dialogs.js:226
msgid "Title"
msgstr ""
#: src/dialogs.js:218
#: src/dialogs.js:227
msgid "Completed"
msgstr ""
#: src/dialogs.js:226
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr ""
#: src/dialogs.js:280
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:282
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:283
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr ""
#: src/dialogs.js:291
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr ""
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr ""
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr ""
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr ""

267
po/cs.po
View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-06 18:31\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2021-09-19 20:57\n"
"Last-Translator: \n"
"Language-Team: Czech\n"
"Language: cs_CZ\n"
@@ -18,437 +18,442 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgstr ""
msgid "Open Files"
msgstr "Otevřít soubory…"
#: ui/clapper.ui:10
msgid "Open URI..."
msgstr ""
msgid "Open URI"
msgstr "Otevřít URI…"
#: ui/clapper.ui:16 ui/preferences-window.ui:4
msgid "Preferences"
msgstr ""
msgstr "Předvolby"
#: ui/clapper.ui:20
msgid "Shortcuts"
msgstr ""
msgstr "Klávesové zkratky"
#: ui/clapper.ui:26
msgid "About Clapper"
msgstr ""
msgstr "O aplikaci Clapper"
#: ui/elapsed-time-button.ui:27
msgid "Speed"
msgstr ""
msgstr "Rychlost"
#: ui/elapsed-time-button.ui:41 ui/preferences-window.ui:83
#: ui/preferences-window.ui:215
msgid "Normal"
msgstr ""
msgstr "Normální"
#: ui/help-overlay.ui:10 ui/preferences-window.ui:12
msgid "General"
msgstr ""
msgstr "Obecné"
#: ui/help-overlay.ui:13
msgid "Show shortcuts"
msgstr ""
msgstr "Zobrazit klávesové zkratky"
#: ui/help-overlay.ui:19
msgid "Toggle fullscreen"
msgstr ""
msgstr "Celá obrazovka"
#: ui/help-overlay.ui:20
msgid "Double tap | Double click"
msgstr ""
msgstr "Dvojitým poklepáním | Dvojitým kliknutím"
#: ui/help-overlay.ui:26
msgid "Leave fullscreen"
msgstr ""
msgstr "Opustit režim celé obrazovky"
#: ui/help-overlay.ui:32
msgid "Reveal OSD (fullscreen only)"
msgstr ""
msgstr "Odhalit OSD (pouze při zobrazení na celou obrazovku)"
#: ui/help-overlay.ui:33
msgid "Tap"
msgstr ""
msgstr "Klepnutím"
#: ui/help-overlay.ui:39
msgid "Quit"
msgstr ""
msgstr "Ukončit"
#: ui/help-overlay.ui:47
msgid "Media"
msgstr ""
msgstr "Média"
#: ui/help-overlay.ui:50
msgid "Open files"
msgstr ""
msgstr "Otevřít soubory"
#: ui/help-overlay.ui:56 src/dialogs.js:137
msgid "Open URI"
msgstr ""
msgstr "Otevřít URI"
#: ui/help-overlay.ui:64
msgid "Playlist"
msgstr ""
msgstr "Playlisty"
#: ui/help-overlay.ui:67
msgid "Next item"
msgstr ""
msgstr "Další položka"
#: ui/help-overlay.ui:68
msgid "Double tap (right side)"
msgstr ""
msgstr "Dvojité poklepání (pravá strana)"
#: ui/help-overlay.ui:74
msgid "Previous item"
msgstr ""
msgstr "Předchozí položka"
#: ui/help-overlay.ui:75
msgid "Double tap (left side)"
msgstr ""
msgstr "Dvojité poklepání (levá strana)"
#: ui/help-overlay.ui:81
msgid "Change repeat mode"
msgstr ""
msgstr "Změnit režim opakování"
#: ui/help-overlay.ui:87
msgid "Export to file"
msgstr ""
msgstr "Exportovat do souboru"
#: ui/help-overlay.ui:95 ui/preferences-window.ui:119
msgid "Playback"
msgstr ""
msgstr "Přehrávání"
#: ui/help-overlay.ui:98
msgid "Toggle play"
msgstr ""
msgstr "Přepnout přehrávání"
#: ui/help-overlay.ui:99
msgid "Long press | Right click"
msgstr ""
msgstr "Dlouhým stisknutím | Klepnutím pravým tlačítkem"
#: ui/help-overlay.ui:105
msgid "Seek forward"
msgstr ""
msgstr "Přetočit vpřed"
#: ui/help-overlay.ui:106
msgid "Swipe right | Scroll right"
msgstr ""
msgstr "Přejetím vpravo | Scrollováním vpravo"
#: ui/help-overlay.ui:112
msgid "Seek backward"
msgstr ""
msgstr "Přetočit zpět"
#: ui/help-overlay.ui:113
msgid "Swipe left | Scroll left"
msgstr ""
msgstr "Přejetím vlevo | Scrollováním vlevo"
#: ui/help-overlay.ui:119
msgid "Volume up"
msgstr ""
msgstr "Zesílit"
#: ui/help-overlay.ui:120
msgid "Swipe up | Scroll up"
msgstr ""
msgstr "Přejetím nahoru | Scrollováním nahoru"
#: ui/help-overlay.ui:126
msgid "Volume down"
msgstr ""
msgstr "Zeslabit"
#: ui/help-overlay.ui:127
msgid "Swipe down | Scroll down"
msgstr ""
msgstr "Přejetím dolů | Scrollováním dolů"
#: ui/help-overlay.ui:133
msgid "Toggle mute"
msgstr ""
msgstr "Vypnout/zapnout zvuk"
#: ui/help-overlay.ui:139
msgid "Next chapter"
msgstr ""
msgstr "Další kapitola"
#: ui/help-overlay.ui:145
msgid "Previous chapter"
msgstr ""
msgstr "Předchozí kapitola"
#: ui/preferences-plugin-ranking-subpage.ui:11
msgid "Decoders"
msgstr ""
msgstr "Dekodéry"
#: ui/preferences-plugin-ranking-subpage.ui:18
msgid "Return to the preferences"
msgstr ""
msgstr "Zpět do předvoleb"
#: ui/preferences-window.ui:16
msgid "Behavior"
msgstr ""
msgstr "Chování"
#: ui/preferences-window.ui:19
msgid "Auto fullscreen"
msgstr ""
msgstr "Automaticky na celou obrazovku"
#: ui/preferences-window.ui:20
msgid "Enter fullscreen when playlist is replaced except floating mode"
msgstr ""
msgstr "Přejít do režimu na celou obrazovku při nahrazení seznamu skladeb s výjimkou plovoucího režimu"
#: ui/preferences-window.ui:26
msgid "Ask to resume recent media"
msgstr ""
msgstr "Zeptat se na obnovení nedávných médií"
#: ui/preferences-window.ui:32
msgid "Float on all workspaces"
msgstr ""
msgstr "Plovoucí režim na všech pracovních plochách"
#: ui/preferences-window.ui:33
msgid "This option only works on GNOME"
msgstr ""
msgstr "Tato možnost funguje pouze na GNOME"
#: ui/preferences-window.ui:39
msgid "After playback"
msgstr ""
msgstr "Po skončení přehrávání"
#: ui/preferences-window.ui:44
msgid "Do nothing"
msgstr ""
msgstr "Nedělat nic"
#: ui/preferences-window.ui:45
msgid "Freeze last frame"
msgstr ""
msgstr "Zůstat na posledním snímku"
#: ui/preferences-window.ui:46
msgid "Close the app"
msgstr ""
msgstr "Zavřít aplikaci"
#: ui/preferences-window.ui:56
msgid "Volume"
msgstr ""
msgstr "Hlasitost"
#: ui/preferences-window.ui:59
msgid "Custom initial value"
msgstr ""
msgstr "Vlastní počáteční hodnota"
#: ui/preferences-window.ui:60
msgid "Set custom volume at startup instead of restoring it"
msgstr ""
msgstr "Nastavit vlastní hlasitost při spuštění namísto obnovení předchozí hodnoty"
#: ui/preferences-window.ui:64
msgid "Volume percentage"
msgstr ""
msgstr "Procento hlasitosti"
#: ui/preferences-window.ui:75
msgid "Seeking"
msgstr ""
msgstr "Přetáčení"
#: ui/preferences-window.ui:78
msgid "Mode"
msgstr ""
msgstr "Režim"
#: ui/preferences-window.ui:84
msgid "Accurate"
msgstr ""
msgstr "Přesný"
#: ui/preferences-window.ui:85
msgid "Fast"
msgstr ""
msgstr "Rychlý"
#: ui/preferences-window.ui:93
msgid "Unit"
msgstr ""
msgstr "Jednotka"
#: ui/preferences-window.ui:98
msgid "Second"
msgstr ""
msgstr "Sekundy"
#: ui/preferences-window.ui:99
msgid "Minute"
msgstr ""
msgstr "Minuty"
#: ui/preferences-window.ui:100
msgid "Percentage"
msgstr ""
msgstr "Procenta"
#: ui/preferences-window.ui:108
msgid "Value"
msgstr ""
msgstr "Hodnota"
#: ui/preferences-window.ui:123
msgid "Audio"
msgstr ""
msgstr "Zvuk"
#: ui/preferences-window.ui:126
msgid "Offset in milliseconds"
msgstr ""
msgstr "Posunutí v milisekundách"
#: ui/preferences-window.ui:133
msgid "Only native audio formats"
msgstr ""
msgstr "Pouze nativní formáty zvuku"
#: ui/preferences-window.ui:141
msgid "Subtitles"
msgstr ""
msgstr "Titulky"
#: ui/preferences-window.ui:144
msgid "Default font"
msgstr ""
msgstr "Výchozí styl písma"
#: ui/preferences-window.ui:154
msgid "Network"
msgstr ""
msgstr "Síť"
#: ui/preferences-window.ui:158
msgid "Client"
msgstr ""
msgstr "Klient"
#: ui/preferences-window.ui:161
msgid "Progressive download buffering"
msgstr ""
msgstr "Postupné stahování do vyrovnávací paměti"
#: ui/preferences-window.ui:169
msgid "Server"
msgstr ""
msgstr "Server"
#: ui/preferences-window.ui:172
msgid "Control player remotely"
msgstr ""
msgstr "Vzdáleně ovládat přehrávač"
#: ui/preferences-window.ui:176
msgid "Listening port"
msgstr ""
msgstr "Naslouchat na portu"
#: ui/preferences-window.ui:183
msgid "Run web application in background"
msgstr ""
msgstr "Spustit webovou aplikaci na pozadí"
#: ui/preferences-window.ui:184
msgid "Requires GTK compiled with Broadway backend"
msgstr ""
msgstr "Vyžaduje GTK kompilovaný s Broadway backendem"
#: ui/preferences-window.ui:190
msgid "Web application port"
msgstr ""
msgstr "Port webové aplikace"
#: ui/preferences-window.ui:204
msgid "Prefer adaptive streaming"
msgstr ""
msgstr "Preferovat adaptivní streamování"
#: ui/preferences-window.ui:210
msgid "Max quality"
msgstr ""
msgstr "Maximální kvalita"
#: ui/preferences-window.ui:228
msgid "Tweaks"
msgstr ""
msgstr "Vylepšení"
#: ui/preferences-window.ui:232
msgid "Appearance"
msgstr ""
msgstr "Vzhled"
#: ui/preferences-window.ui:235
msgid "Dark theme"
msgstr ""
msgstr "Tmavý motiv"
#: ui/preferences-window.ui:241
msgid "Render window shadows"
msgstr ""
msgstr "Vykreslovat stíny okna"
#: ui/preferences-window.ui:242
msgid "Disable to increase performance when windowed"
msgstr ""
msgstr "Zakázat pro zvýšení výkonu"
#: ui/preferences-window.ui:253
msgid "Plugin ranking"
msgstr ""
msgstr "Pořadí pluginů"
#: ui/preferences-window.ui:254
msgid "Alter default ranks of GStreamer plugins"
msgstr ""
msgstr "Změna výchozího pořadí zásuvných modulů GStreameru"
#: ui/preferences-window.ui:259
msgid "Use playbin3"
msgstr ""
msgstr "Použít playbin3"
#: ui/preferences-window.ui:260 ui/preferences-window.ui:269
msgid "Requires player restart"
msgstr ""
msgstr "Vyžaduje restart přehrávače"
#: ui/preferences-window.ui:262 ui/preferences-window.ui:271
msgid "Experimental"
msgstr ""
msgstr "Experimentální"
#: ui/preferences-window.ui:268
msgid "Use PipeWire for audio output"
msgstr ""
msgstr "Použít PipeWire pro zvukový výstup"
#: src/buttons.js:201
#, javascript-format
msgid "Decoder: %s"
msgstr ""
msgstr "Dekodér: %s"
#: src/dialogs.js:152
msgid "Enter or drop URI here"
msgstr ""
msgstr "Zde zadejte nebo přetáhněte URI"
#: src/dialogs.js:157
msgid "Cancel"
msgstr ""
msgstr "Zrušit"
#: src/dialogs.js:158
msgid "Open"
msgstr ""
#: src/dialogs.js:217
msgid "Title"
msgstr ""
#: src/dialogs.js:218
msgid "Completed"
msgstr ""
msgstr "Otevřít"
#: src/dialogs.js:226
msgid "Resume playback?"
msgstr ""
msgid "Title"
msgstr "Název"
#: src/dialogs.js:280
#: src/dialogs.js:227
msgid "Completed"
msgstr "Přehráno"
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr "Pokračovat v přehrávání?"
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
msgstr "Verze GTK: %s"
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:282
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:283
#, javascript-format
msgid "GJS version: %s"
msgstr ""
msgstr "Verze Adwaita: %s"
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr "Verze GStreameru: %s"
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr "Verze GJS: %s"
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
msgstr "Přehrávač médií pro GNOME postavený na GStreameru"
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr "Vojtěch Perník <translations@pervoj.cz>"
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr ""
msgstr "Končí v: %s"
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
msgstr "Neurčeno"
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr ""
msgstr "Kanály"
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr ""
msgstr "Vypnuto"

View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-06 18:31\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2021-09-14 15:25\n"
"Last-Translator: \n"
"Language-Team: Danish\n"
"Language: da_DK\n"
@@ -18,11 +18,11 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgid "Open Files"
msgstr ""
#: ui/clapper.ui:10
msgid "Open URI..."
msgid "Open URI"
msgstr ""
#: ui/clapper.ui:16 ui/preferences-window.ui:4
@@ -399,56 +399,61 @@ msgstr ""
msgid "Open"
msgstr ""
#: src/dialogs.js:217
#: src/dialogs.js:226
msgid "Title"
msgstr ""
#: src/dialogs.js:218
#: src/dialogs.js:227
msgid "Completed"
msgstr ""
#: src/dialogs.js:226
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr ""
#: src/dialogs.js:280
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:282
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:283
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr ""
#: src/dialogs.js:291
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr ""
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr ""
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr ""
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr ""

View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-07 20:54\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2021-09-14 15:25\n"
"Last-Translator: \n"
"Language-Team: German\n"
"Language: de_DE\n"
@@ -18,12 +18,12 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgstr "Dateien öffnen..."
msgid "Open Files"
msgstr "Dateien öffnen"
#: ui/clapper.ui:10
msgid "Open URI..."
msgstr "Webquelle öffnen..."
msgid "Open URI"
msgstr "Webquelle öffnen"
#: ui/clapper.ui:16 ui/preferences-window.ui:4
msgid "Preferences"
@@ -399,56 +399,61 @@ msgstr "Abbrechen"
msgid "Open"
msgstr "Öffnen"
#: src/dialogs.js:217
#: src/dialogs.js:226
msgid "Title"
msgstr "Titel"
#: src/dialogs.js:218
#: src/dialogs.js:227
msgid "Completed"
msgstr "Abgespielt"
#: src/dialogs.js:226
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr "Wiedergabe fortfahren?"
#: src/dialogs.js:280
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr "GTK Version: %s"
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr "Adwaita Version: %s"
#: src/dialogs.js:282
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr "GStreamer Version: %s"
#: src/dialogs.js:283
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr "GJS Version: %s"
#: src/dialogs.js:291
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr "Ein von GStreamer betriebener GNOME Multimedia-Player"
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr ""
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr "Ended um %s"
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr "Unbestimmet"
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr "Audio-Kanäle"
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr "Deaktiviert"

View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-06 18:31\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2021-09-14 15:25\n"
"Last-Translator: \n"
"Language-Team: Greek\n"
"Language: el_GR\n"
@@ -18,11 +18,11 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgid "Open Files"
msgstr ""
#: ui/clapper.ui:10
msgid "Open URI..."
msgid "Open URI"
msgstr ""
#: ui/clapper.ui:16 ui/preferences-window.ui:4
@@ -399,56 +399,61 @@ msgstr ""
msgid "Open"
msgstr ""
#: src/dialogs.js:217
#: src/dialogs.js:226
msgid "Title"
msgstr ""
#: src/dialogs.js:218
#: src/dialogs.js:227
msgid "Completed"
msgstr ""
#: src/dialogs.js:226
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr ""
#: src/dialogs.js:280
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:282
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:283
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr ""
#: src/dialogs.js:291
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr ""
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr ""
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr ""
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr ""

267
po/es.po
View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-06 18:31\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2022-01-16 16:58\n"
"Last-Translator: \n"
"Language-Team: Spanish\n"
"Language: es_ES\n"
@@ -18,437 +18,442 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgstr ""
msgid "Open Files"
msgstr "Abrir archivos…"
#: ui/clapper.ui:10
msgid "Open URI..."
msgstr ""
msgid "Open URI"
msgstr "Abrir URI…"
#: ui/clapper.ui:16 ui/preferences-window.ui:4
msgid "Preferences"
msgstr ""
msgstr "Preferencias"
#: ui/clapper.ui:20
msgid "Shortcuts"
msgstr ""
msgstr "Atajos"
#: ui/clapper.ui:26
msgid "About Clapper"
msgstr ""
msgstr "Acerca de Clapper"
#: ui/elapsed-time-button.ui:27
msgid "Speed"
msgstr ""
msgstr "Velocidad"
#: ui/elapsed-time-button.ui:41 ui/preferences-window.ui:83
#: ui/preferences-window.ui:215
msgid "Normal"
msgstr ""
msgstr "Normal"
#: ui/help-overlay.ui:10 ui/preferences-window.ui:12
msgid "General"
msgstr ""
msgstr "General"
#: ui/help-overlay.ui:13
msgid "Show shortcuts"
msgstr ""
msgstr "Mostrar atajos"
#: ui/help-overlay.ui:19
msgid "Toggle fullscreen"
msgstr ""
msgstr "Fijar a pantalla completa"
#: ui/help-overlay.ui:20
msgid "Double tap | Double click"
msgstr ""
msgstr "Doble toque | Doble clic "
#: ui/help-overlay.ui:26
msgid "Leave fullscreen"
msgstr ""
msgstr "Salir de pantalla completa"
#: ui/help-overlay.ui:32
msgid "Reveal OSD (fullscreen only)"
msgstr ""
msgstr "Revelar OSD (solo pantalla completa)"
#: ui/help-overlay.ui:33
msgid "Tap"
msgstr ""
msgstr "Tocar"
#: ui/help-overlay.ui:39
msgid "Quit"
msgstr ""
msgstr "Renunciar"
#: ui/help-overlay.ui:47
msgid "Media"
msgstr ""
msgstr "Media"
#: ui/help-overlay.ui:50
msgid "Open files"
msgstr ""
msgstr "Abrir archivos"
#: ui/help-overlay.ui:56 src/dialogs.js:137
msgid "Open URI"
msgstr ""
msgstr "Abrir URI"
#: ui/help-overlay.ui:64
msgid "Playlist"
msgstr ""
msgstr "Lista de reproducción"
#: ui/help-overlay.ui:67
msgid "Next item"
msgstr ""
msgstr "Elemento siguiente"
#: ui/help-overlay.ui:68
msgid "Double tap (right side)"
msgstr ""
msgstr "Tocar doble (lado derecho)"
#: ui/help-overlay.ui:74
msgid "Previous item"
msgstr ""
msgstr "Elemento anterior"
#: ui/help-overlay.ui:75
msgid "Double tap (left side)"
msgstr ""
msgstr "Tocar doble (lado izquierdo)"
#: ui/help-overlay.ui:81
msgid "Change repeat mode"
msgstr ""
msgstr "Cambiar a modo repetir"
#: ui/help-overlay.ui:87
msgid "Export to file"
msgstr ""
msgstr "Exportar a archivo"
#: ui/help-overlay.ui:95 ui/preferences-window.ui:119
msgid "Playback"
msgstr ""
msgstr "Reproducir"
#: ui/help-overlay.ui:98
msgid "Toggle play"
msgstr ""
msgstr "Fijar a reproducir"
#: ui/help-overlay.ui:99
msgid "Long press | Right click"
msgstr ""
msgstr "Pulsación larga | Clic derecho"
#: ui/help-overlay.ui:105
msgid "Seek forward"
msgstr ""
msgstr "Buscar siguiente"
#: ui/help-overlay.ui:106
msgid "Swipe right | Scroll right"
msgstr ""
msgstr "Deslizar a derecha | Desplazar a derecha"
#: ui/help-overlay.ui:112
msgid "Seek backward"
msgstr ""
msgstr "Buscar anterior"
#: ui/help-overlay.ui:113
msgid "Swipe left | Scroll left"
msgstr ""
msgstr "Deslizar a izquierda | Desplazar a izquierda"
#: ui/help-overlay.ui:119
msgid "Volume up"
msgstr ""
msgstr "Volumen +"
#: ui/help-overlay.ui:120
msgid "Swipe up | Scroll up"
msgstr ""
msgstr "Deslizar + | Desplazar +"
#: ui/help-overlay.ui:126
msgid "Volume down"
msgstr ""
msgstr "Volumen -"
#: ui/help-overlay.ui:127
msgid "Swipe down | Scroll down"
msgstr ""
msgstr "Deslizar - | Desplazar -"
#: ui/help-overlay.ui:133
msgid "Toggle mute"
msgstr ""
msgstr "Fijar a mudo"
#: ui/help-overlay.ui:139
msgid "Next chapter"
msgstr ""
msgstr "Capítulo siguiente"
#: ui/help-overlay.ui:145
msgid "Previous chapter"
msgstr ""
msgstr "Capítulo anterior"
#: ui/preferences-plugin-ranking-subpage.ui:11
msgid "Decoders"
msgstr ""
msgstr "Decodificadores"
#: ui/preferences-plugin-ranking-subpage.ui:18
msgid "Return to the preferences"
msgstr ""
msgstr "Regresar a preferencias"
#: ui/preferences-window.ui:16
msgid "Behavior"
msgstr ""
msgstr "Configuraciones"
#: ui/preferences-window.ui:19
msgid "Auto fullscreen"
msgstr ""
msgstr "Pantalla completa automática"
#: ui/preferences-window.ui:20
msgid "Enter fullscreen when playlist is replaced except floating mode"
msgstr ""
msgstr "Entra a pantalla completa cuando se reemplaza la lista de reproducción, excepto en modo flotante"
#: ui/preferences-window.ui:26
msgid "Ask to resume recent media"
msgstr ""
msgstr "Preguntar al reanudar los medios recientes"
#: ui/preferences-window.ui:32
msgid "Float on all workspaces"
msgstr ""
msgstr "Flotar todos los espacios de trabajo"
#: ui/preferences-window.ui:33
msgid "This option only works on GNOME"
msgstr ""
msgstr "Esta opción solo funciona en GNOME"
#: ui/preferences-window.ui:39
msgid "After playback"
msgstr ""
msgstr "Después de reproducción "
#: ui/preferences-window.ui:44
msgid "Do nothing"
msgstr ""
msgstr "Nada por hacer"
#: ui/preferences-window.ui:45
msgid "Freeze last frame"
msgstr ""
msgstr "Detener último fotograma"
#: ui/preferences-window.ui:46
msgid "Close the app"
msgstr ""
msgstr "Cerrar la aplicación"
#: ui/preferences-window.ui:56
msgid "Volume"
msgstr ""
msgstr "Volumen"
#: ui/preferences-window.ui:59
msgid "Custom initial value"
msgstr ""
msgstr "Valor inicial personalizado"
#: ui/preferences-window.ui:60
msgid "Set custom volume at startup instead of restoring it"
msgstr ""
msgstr "Establece un volumen personalizado al inicio en lugar de restaurarlo"
#: ui/preferences-window.ui:64
msgid "Volume percentage"
msgstr ""
msgstr "Porcentaje de volumen"
#: ui/preferences-window.ui:75
msgid "Seeking"
msgstr ""
msgstr "Buscando"
#: ui/preferences-window.ui:78
msgid "Mode"
msgstr ""
msgstr "Modo"
#: ui/preferences-window.ui:84
msgid "Accurate"
msgstr ""
msgstr "Precisión"
#: ui/preferences-window.ui:85
msgid "Fast"
msgstr ""
msgstr "Rápido"
#: ui/preferences-window.ui:93
msgid "Unit"
msgstr ""
msgstr "Unidad"
#: ui/preferences-window.ui:98
msgid "Second"
msgstr ""
msgstr "Segundo"
#: ui/preferences-window.ui:99
msgid "Minute"
msgstr ""
msgstr "Minuto"
#: ui/preferences-window.ui:100
msgid "Percentage"
msgstr ""
msgstr "Porcentaje"
#: ui/preferences-window.ui:108
msgid "Value"
msgstr ""
msgstr "Valor"
#: ui/preferences-window.ui:123
msgid "Audio"
msgstr ""
msgstr "Audio"
#: ui/preferences-window.ui:126
msgid "Offset in milliseconds"
msgstr ""
msgstr "Compensación en milisegundos"
#: ui/preferences-window.ui:133
msgid "Only native audio formats"
msgstr ""
msgstr "Solo formatos de audio nativos"
#: ui/preferences-window.ui:141
msgid "Subtitles"
msgstr ""
msgstr "Subtítulos"
#: ui/preferences-window.ui:144
msgid "Default font"
msgstr ""
msgstr "Fuente por defecto"
#: ui/preferences-window.ui:154
msgid "Network"
msgstr ""
msgstr "Red"
#: ui/preferences-window.ui:158
msgid "Client"
msgstr ""
msgstr "Cliente"
#: ui/preferences-window.ui:161
msgid "Progressive download buffering"
msgstr ""
msgstr "Bajada progresiva de búfer"
#: ui/preferences-window.ui:169
msgid "Server"
msgstr ""
msgstr "Servidor"
#: ui/preferences-window.ui:172
msgid "Control player remotely"
msgstr ""
msgstr "Controlar el reproductor remotamente"
#: ui/preferences-window.ui:176
msgid "Listening port"
msgstr ""
msgstr "Puerto de escucha"
#: ui/preferences-window.ui:183
msgid "Run web application in background"
msgstr ""
msgstr "Ejecutar la aplicación web en modo demonio"
#: ui/preferences-window.ui:184
msgid "Requires GTK compiled with Broadway backend"
msgstr ""
msgstr "Requiere GTK compilado con el backend de Broadway"
#: ui/preferences-window.ui:190
msgid "Web application port"
msgstr ""
msgstr "Puerto de la aplicación web"
#: ui/preferences-window.ui:204
msgid "Prefer adaptive streaming"
msgstr ""
msgstr "Preferir la transmisión adaptativa "
#: ui/preferences-window.ui:210
msgid "Max quality"
msgstr ""
msgstr "Calidad máxima"
#: ui/preferences-window.ui:228
msgid "Tweaks"
msgstr ""
msgstr "Retoques"
#: ui/preferences-window.ui:232
msgid "Appearance"
msgstr ""
msgstr "Apariencia"
#: ui/preferences-window.ui:235
msgid "Dark theme"
msgstr ""
msgstr "Tema oscuro"
#: ui/preferences-window.ui:241
msgid "Render window shadows"
msgstr ""
msgstr "Renderizar sombras de ventana"
#: ui/preferences-window.ui:242
msgid "Disable to increase performance when windowed"
msgstr ""
msgstr "Deshabilitado aumenta el rendimiento cuando se abre en ventana"
#: ui/preferences-window.ui:253
msgid "Plugin ranking"
msgstr ""
msgstr "Rango de enchufes"
#: ui/preferences-window.ui:254
msgid "Alter default ranks of GStreamer plugins"
msgstr ""
msgstr "Altera los rangos predeterminados de los enchufes de GStreamer"
#: ui/preferences-window.ui:259
msgid "Use playbin3"
msgstr ""
msgstr "Usar Playbin3"
#: ui/preferences-window.ui:260 ui/preferences-window.ui:269
msgid "Requires player restart"
msgstr ""
msgstr "Require reiniciar el reproductor"
#: ui/preferences-window.ui:262 ui/preferences-window.ui:271
msgid "Experimental"
msgstr ""
msgstr "Experimental"
#: ui/preferences-window.ui:268
msgid "Use PipeWire for audio output"
msgstr ""
msgstr "Usar PipeWire"
#: src/buttons.js:201
#, javascript-format
msgid "Decoder: %s"
msgstr ""
msgstr "Decodificador: %s"
#: src/dialogs.js:152
msgid "Enter or drop URI here"
msgstr ""
msgstr "Introducir la URI"
#: src/dialogs.js:157
msgid "Cancel"
msgstr ""
msgstr "Cancelar"
#: src/dialogs.js:158
msgid "Open"
msgstr ""
#: src/dialogs.js:217
msgid "Title"
msgstr ""
#: src/dialogs.js:218
msgid "Completed"
msgstr ""
msgstr "Abrir"
#: src/dialogs.js:226
msgid "Resume playback?"
msgstr ""
msgid "Title"
msgstr "Título"
#: src/dialogs.js:280
#: src/dialogs.js:227
msgid "Completed"
msgstr "Completado"
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr "Resumir el reproductor?"
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
msgstr "Versión GTK: %s"
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:282
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:283
#, javascript-format
msgid "GJS version: %s"
msgstr ""
msgstr "Versión LibAdwaita: %s"
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr "Versión GStreamer: %s"
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr "Versión GJS: %s"
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
msgstr "Un reproductor multimedia de GNOME impulsado por GStreamer"
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr "carlosgonz"
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr ""
msgstr "Termina en: %s"
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
msgstr "Indeterminado"
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr ""
msgstr "Canales"
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr ""
msgstr "Deshabilitar"

459
po/eu.po Normal file
View File

@@ -0,0 +1,459 @@
msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2022-01-16 16:58\n"
"Last-Translator: \n"
"Language-Team: Basque\n"
"Language: eu_ES\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Crowdin-Project: clapper\n"
"X-Crowdin-Project-ID: 473374\n"
"X-Crowdin-Language: eu\n"
"X-Crowdin-File: /master/po/com.github.rafostar.Clapper.pot\n"
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files…"
msgstr ""
#: ui/clapper.ui:10
msgid "Open URI…"
msgstr ""
#: ui/clapper.ui:16 ui/preferences-window.ui:4
msgid "Preferences"
msgstr ""
#: ui/clapper.ui:20
msgid "Shortcuts"
msgstr ""
#: ui/clapper.ui:26
msgid "About Clapper"
msgstr ""
#: ui/elapsed-time-button.ui:27
msgid "Speed"
msgstr ""
#: ui/elapsed-time-button.ui:41 ui/preferences-window.ui:83
#: ui/preferences-window.ui:215
msgid "Normal"
msgstr ""
#: ui/help-overlay.ui:10 ui/preferences-window.ui:12
msgid "General"
msgstr ""
#: ui/help-overlay.ui:13
msgid "Show shortcuts"
msgstr ""
#: ui/help-overlay.ui:19
msgid "Toggle fullscreen"
msgstr ""
#: ui/help-overlay.ui:20
msgid "Double tap | Double click"
msgstr ""
#: ui/help-overlay.ui:26
msgid "Leave fullscreen"
msgstr ""
#: ui/help-overlay.ui:32
msgid "Reveal OSD (fullscreen only)"
msgstr ""
#: ui/help-overlay.ui:33
msgid "Tap"
msgstr ""
#: ui/help-overlay.ui:39
msgid "Quit"
msgstr ""
#: ui/help-overlay.ui:47
msgid "Media"
msgstr ""
#: ui/help-overlay.ui:50
msgid "Open files"
msgstr ""
#: ui/help-overlay.ui:56 src/dialogs.js:137
msgid "Open URI"
msgstr ""
#: ui/help-overlay.ui:64
msgid "Playlist"
msgstr ""
#: ui/help-overlay.ui:67
msgid "Next item"
msgstr ""
#: ui/help-overlay.ui:68
msgid "Double tap (right side)"
msgstr ""
#: ui/help-overlay.ui:74
msgid "Previous item"
msgstr ""
#: ui/help-overlay.ui:75
msgid "Double tap (left side)"
msgstr ""
#: ui/help-overlay.ui:81
msgid "Change repeat mode"
msgstr ""
#: ui/help-overlay.ui:87
msgid "Export to file"
msgstr ""
#: ui/help-overlay.ui:95 ui/preferences-window.ui:119
msgid "Playback"
msgstr ""
#: ui/help-overlay.ui:98
msgid "Toggle play"
msgstr ""
#: ui/help-overlay.ui:99
msgid "Long press | Right click"
msgstr ""
#: ui/help-overlay.ui:105
msgid "Seek forward"
msgstr ""
#: ui/help-overlay.ui:106
msgid "Swipe right | Scroll right"
msgstr ""
#: ui/help-overlay.ui:112
msgid "Seek backward"
msgstr ""
#: ui/help-overlay.ui:113
msgid "Swipe left | Scroll left"
msgstr ""
#: ui/help-overlay.ui:119
msgid "Volume up"
msgstr ""
#: ui/help-overlay.ui:120
msgid "Swipe up | Scroll up"
msgstr ""
#: ui/help-overlay.ui:126
msgid "Volume down"
msgstr ""
#: ui/help-overlay.ui:127
msgid "Swipe down | Scroll down"
msgstr ""
#: ui/help-overlay.ui:133
msgid "Toggle mute"
msgstr ""
#: ui/help-overlay.ui:139
msgid "Next chapter"
msgstr ""
#: ui/help-overlay.ui:145
msgid "Previous chapter"
msgstr ""
#: ui/preferences-plugin-ranking-subpage.ui:11
msgid "Decoders"
msgstr ""
#: ui/preferences-plugin-ranking-subpage.ui:18
msgid "Return to the preferences"
msgstr ""
#: ui/preferences-window.ui:16
msgid "Behavior"
msgstr ""
#: ui/preferences-window.ui:19
msgid "Auto fullscreen"
msgstr ""
#: ui/preferences-window.ui:20
msgid "Enter fullscreen when playlist is replaced except floating mode"
msgstr ""
#: ui/preferences-window.ui:26
msgid "Ask to resume recent media"
msgstr ""
#: ui/preferences-window.ui:32
msgid "Float on all workspaces"
msgstr ""
#: ui/preferences-window.ui:33
msgid "This option only works on GNOME"
msgstr ""
#: ui/preferences-window.ui:39
msgid "After playback"
msgstr ""
#: ui/preferences-window.ui:44
msgid "Do nothing"
msgstr ""
#: ui/preferences-window.ui:45
msgid "Freeze last frame"
msgstr ""
#: ui/preferences-window.ui:46
msgid "Close the app"
msgstr ""
#: ui/preferences-window.ui:56
msgid "Volume"
msgstr ""
#: ui/preferences-window.ui:59
msgid "Custom initial value"
msgstr ""
#: ui/preferences-window.ui:60
msgid "Set custom volume at startup instead of restoring it"
msgstr ""
#: ui/preferences-window.ui:64
msgid "Volume percentage"
msgstr ""
#: ui/preferences-window.ui:75
msgid "Seeking"
msgstr ""
#: ui/preferences-window.ui:78
msgid "Mode"
msgstr ""
#: ui/preferences-window.ui:84
msgid "Accurate"
msgstr ""
#: ui/preferences-window.ui:85
msgid "Fast"
msgstr ""
#: ui/preferences-window.ui:93
msgid "Unit"
msgstr ""
#: ui/preferences-window.ui:98
msgid "Second"
msgstr ""
#: ui/preferences-window.ui:99
msgid "Minute"
msgstr ""
#: ui/preferences-window.ui:100
msgid "Percentage"
msgstr ""
#: ui/preferences-window.ui:108
msgid "Value"
msgstr ""
#: ui/preferences-window.ui:123
msgid "Audio"
msgstr ""
#: ui/preferences-window.ui:126
msgid "Offset in milliseconds"
msgstr ""
#: ui/preferences-window.ui:133
msgid "Only native audio formats"
msgstr ""
#: ui/preferences-window.ui:141
msgid "Subtitles"
msgstr ""
#: ui/preferences-window.ui:144
msgid "Default font"
msgstr ""
#: ui/preferences-window.ui:154
msgid "Network"
msgstr ""
#: ui/preferences-window.ui:158
msgid "Client"
msgstr ""
#: ui/preferences-window.ui:161
msgid "Progressive download buffering"
msgstr ""
#: ui/preferences-window.ui:169
msgid "Server"
msgstr ""
#: ui/preferences-window.ui:172
msgid "Control player remotely"
msgstr ""
#: ui/preferences-window.ui:176
msgid "Listening port"
msgstr ""
#: ui/preferences-window.ui:183
msgid "Run web application in background"
msgstr ""
#: ui/preferences-window.ui:184
msgid "Requires GTK compiled with Broadway backend"
msgstr ""
#: ui/preferences-window.ui:190
msgid "Web application port"
msgstr ""
#: ui/preferences-window.ui:204
msgid "Prefer adaptive streaming"
msgstr ""
#: ui/preferences-window.ui:210
msgid "Max quality"
msgstr ""
#: ui/preferences-window.ui:228
msgid "Tweaks"
msgstr ""
#: ui/preferences-window.ui:232
msgid "Appearance"
msgstr ""
#: ui/preferences-window.ui:235
msgid "Dark theme"
msgstr ""
#: ui/preferences-window.ui:241
msgid "Render window shadows"
msgstr ""
#: ui/preferences-window.ui:242
msgid "Disable to increase performance when windowed"
msgstr ""
#: ui/preferences-window.ui:253
msgid "Plugin ranking"
msgstr ""
#: ui/preferences-window.ui:254
msgid "Alter default ranks of GStreamer plugins"
msgstr ""
#: ui/preferences-window.ui:259
msgid "Use playbin3"
msgstr ""
#: ui/preferences-window.ui:260 ui/preferences-window.ui:269
msgid "Requires player restart"
msgstr ""
#: ui/preferences-window.ui:262 ui/preferences-window.ui:271
msgid "Experimental"
msgstr ""
#: ui/preferences-window.ui:268
msgid "Use PipeWire for audio output"
msgstr ""
#: src/buttons.js:201
#, javascript-format
msgid "Decoder: %s"
msgstr ""
#: src/dialogs.js:152
msgid "Enter or drop URI here"
msgstr ""
#: src/dialogs.js:157
msgid "Cancel"
msgstr ""
#: src/dialogs.js:158
msgid "Open"
msgstr ""
#: src/dialogs.js:226
msgid "Title"
msgstr ""
#: src/dialogs.js:227
msgid "Completed"
msgstr ""
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr ""
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr ""
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr ""
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr ""
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
#: src/widget.js:243
msgid "Channels"
msgstr ""
#: src/widget.js:261
msgid "Disabled"
msgstr ""

View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-06 18:31\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2021-09-14 15:25\n"
"Last-Translator: \n"
"Language-Team: Finnish\n"
"Language: fi_FI\n"
@@ -18,11 +18,11 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgid "Open Files"
msgstr ""
#: ui/clapper.ui:10
msgid "Open URI..."
msgid "Open URI"
msgstr ""
#: ui/clapper.ui:16 ui/preferences-window.ui:4
@@ -399,56 +399,61 @@ msgstr ""
msgid "Open"
msgstr ""
#: src/dialogs.js:217
#: src/dialogs.js:226
msgid "Title"
msgstr ""
#: src/dialogs.js:218
#: src/dialogs.js:227
msgid "Completed"
msgstr ""
#: src/dialogs.js:226
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr ""
#: src/dialogs.js:280
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:282
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:283
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr ""
#: src/dialogs.js:291
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr ""
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr ""
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr ""
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr ""

267
po/fr.po
View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-06 18:31\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2022-01-18 20:57\n"
"Last-Translator: \n"
"Language-Team: French\n"
"Language: fr_FR\n"
@@ -18,437 +18,442 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgstr ""
msgid "Open Files"
msgstr "Ouvrir un fichier…"
#: ui/clapper.ui:10
msgid "Open URI..."
msgstr ""
msgid "Open URI"
msgstr "Ouvrir une URL…"
#: ui/clapper.ui:16 ui/preferences-window.ui:4
msgid "Preferences"
msgstr ""
msgstr "Préférences"
#: ui/clapper.ui:20
msgid "Shortcuts"
msgstr ""
msgstr "Raccourcis clavier"
#: ui/clapper.ui:26
msgid "About Clapper"
msgstr ""
msgstr "Á propos de Clapper"
#: ui/elapsed-time-button.ui:27
msgid "Speed"
msgstr ""
msgstr "Vitesse"
#: ui/elapsed-time-button.ui:41 ui/preferences-window.ui:83
#: ui/preferences-window.ui:215
msgid "Normal"
msgstr ""
msgstr "Normal"
#: ui/help-overlay.ui:10 ui/preferences-window.ui:12
msgid "General"
msgstr ""
msgstr "Général"
#: ui/help-overlay.ui:13
msgid "Show shortcuts"
msgstr ""
msgstr "Montrer les raccourcis"
#: ui/help-overlay.ui:19
msgid "Toggle fullscreen"
msgstr ""
msgstr "Basculer en plein écran"
#: ui/help-overlay.ui:20
msgid "Double tap | Double click"
msgstr ""
msgstr "Tapoter/cliquer deux fois"
#: ui/help-overlay.ui:26
msgid "Leave fullscreen"
msgstr ""
msgstr "Sortir du plein écran"
#: ui/help-overlay.ui:32
msgid "Reveal OSD (fullscreen only)"
msgstr ""
msgstr "Afficher les commandes de lecture (seulement en plein écran)"
#: ui/help-overlay.ui:33
msgid "Tap"
msgstr ""
msgstr "Taper"
#: ui/help-overlay.ui:39
msgid "Quit"
msgstr ""
msgstr "Quitter"
#: ui/help-overlay.ui:47
msgid "Media"
msgstr ""
msgstr "Média"
#: ui/help-overlay.ui:50
msgid "Open files"
msgstr ""
msgstr "Ouvrir un fichier"
#: ui/help-overlay.ui:56 src/dialogs.js:137
msgid "Open URI"
msgstr ""
msgstr "Ouvrir une URL"
#: ui/help-overlay.ui:64
msgid "Playlist"
msgstr ""
msgstr "Playlist"
#: ui/help-overlay.ui:67
msgid "Next item"
msgstr ""
msgstr "Prochain média"
#: ui/help-overlay.ui:68
msgid "Double tap (right side)"
msgstr ""
msgstr "Tapoter deux fois (côté droit)"
#: ui/help-overlay.ui:74
msgid "Previous item"
msgstr ""
msgstr "Média précédent"
#: ui/help-overlay.ui:75
msgid "Double tap (left side)"
msgstr ""
msgstr "Tapoter deux fois (côté gauche)"
#: ui/help-overlay.ui:81
msgid "Change repeat mode"
msgstr ""
msgstr "Changer le mode de répétition"
#: ui/help-overlay.ui:87
msgid "Export to file"
msgstr ""
msgstr "Exporter vers un fichier"
#: ui/help-overlay.ui:95 ui/preferences-window.ui:119
msgid "Playback"
msgstr ""
msgstr "Lecture"
#: ui/help-overlay.ui:98
msgid "Toggle play"
msgstr ""
msgstr "Relancer/stopper la lecture"
#: ui/help-overlay.ui:99
msgid "Long press | Right click"
msgstr ""
msgstr "Longue pression | Clic droit"
#: ui/help-overlay.ui:105
msgid "Seek forward"
msgstr ""
msgstr "Avancer dans la lecture"
#: ui/help-overlay.ui:106
msgid "Swipe right | Scroll right"
msgstr ""
msgstr "Glisser/Faire défiler vers la droite"
#: ui/help-overlay.ui:112
msgid "Seek backward"
msgstr ""
msgstr "Reculer dans la lecture"
#: ui/help-overlay.ui:113
msgid "Swipe left | Scroll left"
msgstr ""
msgstr "Glisser/Faire défiler vers la gauche"
#: ui/help-overlay.ui:119
msgid "Volume up"
msgstr ""
msgstr "Augmenter le volume"
#: ui/help-overlay.ui:120
msgid "Swipe up | Scroll up"
msgstr ""
msgstr "Glisser/Défiler vers le haut"
#: ui/help-overlay.ui:126
msgid "Volume down"
msgstr ""
msgstr "Baisser le volume"
#: ui/help-overlay.ui:127
msgid "Swipe down | Scroll down"
msgstr ""
msgstr "Glisser/Défiler vers le bas"
#: ui/help-overlay.ui:133
msgid "Toggle mute"
msgstr ""
msgstr "Basculer le mode silencieux"
#: ui/help-overlay.ui:139
msgid "Next chapter"
msgstr ""
msgstr "Prochain chapitre"
#: ui/help-overlay.ui:145
msgid "Previous chapter"
msgstr ""
msgstr "Chapitre précédent"
#: ui/preferences-plugin-ranking-subpage.ui:11
msgid "Decoders"
msgstr ""
msgstr "Décodeurs"
#: ui/preferences-plugin-ranking-subpage.ui:18
msgid "Return to the preferences"
msgstr ""
msgstr "Retourner aux préférences"
#: ui/preferences-window.ui:16
msgid "Behavior"
msgstr ""
msgstr "Comportement"
#: ui/preferences-window.ui:19
msgid "Auto fullscreen"
msgstr ""
msgstr "Lecture automatique en plein écran"
#: ui/preferences-window.ui:20
msgid "Enter fullscreen when playlist is replaced except floating mode"
msgstr ""
msgstr "Basculer en plein écran quand la playlisyt est remplacée sauf si le mode flottant est activé"
#: ui/preferences-window.ui:26
msgid "Ask to resume recent media"
msgstr ""
msgstr "Demander pour reprendre à la position des médias récents"
#: ui/preferences-window.ui:32
msgid "Float on all workspaces"
msgstr ""
msgstr "Flotter sur tous les bureaux virtuels"
#: ui/preferences-window.ui:33
msgid "This option only works on GNOME"
msgstr ""
msgstr "Cette option ne marche qu'avec GNOME"
#: ui/preferences-window.ui:39
msgid "After playback"
msgstr ""
msgstr "Après la lecture"
#: ui/preferences-window.ui:44
msgid "Do nothing"
msgstr ""
msgstr "Ne rien faire"
#: ui/preferences-window.ui:45
msgid "Freeze last frame"
msgstr ""
msgstr "Geler la dernière image"
#: ui/preferences-window.ui:46
msgid "Close the app"
msgstr ""
msgstr "Fermer l'application"
#: ui/preferences-window.ui:56
msgid "Volume"
msgstr ""
msgstr "Volume"
#: ui/preferences-window.ui:59
msgid "Custom initial value"
msgstr ""
msgstr "Valeur initiale personnalisée"
#: ui/preferences-window.ui:60
msgid "Set custom volume at startup instead of restoring it"
msgstr ""
msgstr "Régler une valeur personnalisée du volume au démarrage au lien de restorer la valeur précédente"
#: ui/preferences-window.ui:64
msgid "Volume percentage"
msgstr ""
msgstr "Pourcentage du volume"
#: ui/preferences-window.ui:75
msgid "Seeking"
msgstr ""
msgstr "Avancement"
#: ui/preferences-window.ui:78
msgid "Mode"
msgstr ""
msgstr "Comportement"
#: ui/preferences-window.ui:84
msgid "Accurate"
msgstr ""
msgstr "Précis"
#: ui/preferences-window.ui:85
msgid "Fast"
msgstr ""
msgstr "Rapide"
#: ui/preferences-window.ui:93
msgid "Unit"
msgstr ""
msgstr "Unité des sauts"
#: ui/preferences-window.ui:98
msgid "Second"
msgstr ""
msgstr "Seconde"
#: ui/preferences-window.ui:99
msgid "Minute"
msgstr ""
msgstr "Minute"
#: ui/preferences-window.ui:100
msgid "Percentage"
msgstr ""
msgstr "Pourcentage"
#: ui/preferences-window.ui:108
msgid "Value"
msgstr ""
msgstr "Longueur du saut"
#: ui/preferences-window.ui:123
msgid "Audio"
msgstr ""
msgstr "Audio"
#: ui/preferences-window.ui:126
msgid "Offset in milliseconds"
msgstr ""
msgstr "Décalage en millisecondes"
#: ui/preferences-window.ui:133
msgid "Only native audio formats"
msgstr ""
msgstr "Seulement des formats audios natifs"
#: ui/preferences-window.ui:141
msgid "Subtitles"
msgstr ""
msgstr "Sous-titres"
#: ui/preferences-window.ui:144
msgid "Default font"
msgstr ""
msgstr "Police par défaut"
#: ui/preferences-window.ui:154
msgid "Network"
msgstr ""
msgstr "Réseau"
#: ui/preferences-window.ui:158
msgid "Client"
msgstr ""
msgstr "Client"
#: ui/preferences-window.ui:161
msgid "Progressive download buffering"
msgstr ""
msgstr "Téléchargement progressif dans le tampon"
#: ui/preferences-window.ui:169
msgid "Server"
msgstr ""
msgstr "Serveur"
#: ui/preferences-window.ui:172
msgid "Control player remotely"
msgstr ""
msgstr "Controler le lecteur à distance"
#: ui/preferences-window.ui:176
msgid "Listening port"
msgstr ""
msgstr "Écouter sur le port"
#: ui/preferences-window.ui:183
msgid "Run web application in background"
msgstr ""
msgstr "Lancer l'application web en arrière plan"
#: ui/preferences-window.ui:184
msgid "Requires GTK compiled with Broadway backend"
msgstr ""
msgstr "Requiert GTK compilé avec l'interface Broadway"
#: ui/preferences-window.ui:190
msgid "Web application port"
msgstr ""
msgstr "Port de l'application web"
#: ui/preferences-window.ui:204
msgid "Prefer adaptive streaming"
msgstr ""
msgstr "Préférer le streaming adaptatif"
#: ui/preferences-window.ui:210
msgid "Max quality"
msgstr ""
msgstr "Qualité maximale"
#: ui/preferences-window.ui:228
msgid "Tweaks"
msgstr ""
msgstr "Réglages"
#: ui/preferences-window.ui:232
msgid "Appearance"
msgstr ""
msgstr "Apparence"
#: ui/preferences-window.ui:235
msgid "Dark theme"
msgstr ""
msgstr "Thème sombre"
#: ui/preferences-window.ui:241
msgid "Render window shadows"
msgstr ""
msgstr "Afficher les ombres de la fenêtre"
#: ui/preferences-window.ui:242
msgid "Disable to increase performance when windowed"
msgstr ""
msgstr "Désactiver pour améliorer les performances quand fenêtré"
#: ui/preferences-window.ui:253
msgid "Plugin ranking"
msgstr ""
msgstr "Liste des plugins"
#: ui/preferences-window.ui:254
msgid "Alter default ranks of GStreamer plugins"
msgstr ""
msgstr "Changer les options par défaut de plugins GStreamer"
#: ui/preferences-window.ui:259
msgid "Use playbin3"
msgstr ""
msgstr "Utiliser playbin3"
#: ui/preferences-window.ui:260 ui/preferences-window.ui:269
msgid "Requires player restart"
msgstr ""
msgstr "Requiert le redémarrage du lecteur"
#: ui/preferences-window.ui:262 ui/preferences-window.ui:271
msgid "Experimental"
msgstr ""
msgstr "Expérimental"
#: ui/preferences-window.ui:268
msgid "Use PipeWire for audio output"
msgstr ""
msgstr "Utiliser PipeWire pour la sortie audio"
#: src/buttons.js:201
#, javascript-format
msgid "Decoder: %s"
msgstr ""
msgstr "Décodeur: %s"
#: src/dialogs.js:152
msgid "Enter or drop URI here"
msgstr ""
msgstr "Entrer ou déposer une URL ici"
#: src/dialogs.js:157
msgid "Cancel"
msgstr ""
msgstr "Annuler"
#: src/dialogs.js:158
msgid "Open"
msgstr ""
#: src/dialogs.js:217
msgid "Title"
msgstr ""
#: src/dialogs.js:218
msgid "Completed"
msgstr ""
msgstr "Ouvrir"
#: src/dialogs.js:226
msgid "Resume playback?"
msgstr ""
msgid "Title"
msgstr "Titre"
#: src/dialogs.js:280
#: src/dialogs.js:227
msgid "Completed"
msgstr "Terminé"
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr "Reprendre la lecture?"
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
msgstr "Version de GTK: %s"
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:282
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:283
#, javascript-format
msgid "GJS version: %s"
msgstr ""
msgstr "Version d'Adwaita: %s"
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr "Version de GStreamer: %s"
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr "Version de GJS: %s"
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
msgstr "Un lecteur multimédia pour GNOME propulsé par GStreamer"
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr "Robin Verdenal-Tallieux"
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr ""
msgstr "Finit à: %s"
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
msgstr "Indéterminé"
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr ""
msgstr "Chaines"
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr ""
msgstr "Désactivé"

View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-06 18:31\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2021-09-14 15:25\n"
"Last-Translator: \n"
"Language-Team: Hebrew\n"
"Language: he_IL\n"
@@ -18,11 +18,11 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgid "Open Files"
msgstr ""
#: ui/clapper.ui:10
msgid "Open URI..."
msgid "Open URI"
msgstr ""
#: ui/clapper.ui:16 ui/preferences-window.ui:4
@@ -399,56 +399,61 @@ msgstr ""
msgid "Open"
msgstr ""
#: src/dialogs.js:217
#: src/dialogs.js:226
msgid "Title"
msgstr ""
#: src/dialogs.js:218
#: src/dialogs.js:227
msgid "Completed"
msgstr ""
#: src/dialogs.js:226
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr ""
#: src/dialogs.js:280
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:282
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:283
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr ""
#: src/dialogs.js:291
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr ""
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr ""
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr ""
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr ""

267
po/hu.po
View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-06 18:31\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2021-09-21 16:37\n"
"Last-Translator: \n"
"Language-Team: Hungarian\n"
"Language: hu_HU\n"
@@ -18,437 +18,442 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgstr ""
msgid "Open Files"
msgstr "Fájlok megnyitása…"
#: ui/clapper.ui:10
msgid "Open URI..."
msgstr ""
msgid "Open URI"
msgstr "URI megnyitása…"
#: ui/clapper.ui:16 ui/preferences-window.ui:4
msgid "Preferences"
msgstr ""
msgstr "Beállítások"
#: ui/clapper.ui:20
msgid "Shortcuts"
msgstr ""
msgstr "Gyorsbillentyűk"
#: ui/clapper.ui:26
msgid "About Clapper"
msgstr ""
msgstr "A Clapper -ről"
#: ui/elapsed-time-button.ui:27
msgid "Speed"
msgstr ""
msgstr "Sebesség"
#: ui/elapsed-time-button.ui:41 ui/preferences-window.ui:83
#: ui/preferences-window.ui:215
msgid "Normal"
msgstr ""
msgstr "Normál"
#: ui/help-overlay.ui:10 ui/preferences-window.ui:12
msgid "General"
msgstr ""
msgstr "Általános beállítások"
#: ui/help-overlay.ui:13
msgid "Show shortcuts"
msgstr ""
msgstr "Gyorsbillentyűk megjelenítése"
#: ui/help-overlay.ui:19
msgid "Toggle fullscreen"
msgstr ""
msgstr "Teljes képernyő be/ki"
#: ui/help-overlay.ui:20
msgid "Double tap | Double click"
msgstr ""
msgstr "Dupla koppintás | Dupla kattintás"
#: ui/help-overlay.ui:26
msgid "Leave fullscreen"
msgstr ""
msgstr "Teljes képernyő be/ki"
#: ui/help-overlay.ui:32
msgid "Reveal OSD (fullscreen only)"
msgstr ""
msgstr "Képernyőn megjelenő kijelző (OSD) mutatása (csak teljes képernyős módban)"
#: ui/help-overlay.ui:33
msgid "Tap"
msgstr ""
msgstr "Koppintás"
#: ui/help-overlay.ui:39
msgid "Quit"
msgstr ""
msgstr "Kilépés"
#: ui/help-overlay.ui:47
msgid "Media"
msgstr ""
msgstr "Média"
#: ui/help-overlay.ui:50
msgid "Open files"
msgstr ""
msgstr "Fájlok megnyitása"
#: ui/help-overlay.ui:56 src/dialogs.js:137
msgid "Open URI"
msgstr ""
msgstr "URI megnyitása"
#: ui/help-overlay.ui:64
msgid "Playlist"
msgstr ""
msgstr "Lejátszólista"
#: ui/help-overlay.ui:67
msgid "Next item"
msgstr ""
msgstr "Következő listaelem"
#: ui/help-overlay.ui:68
msgid "Double tap (right side)"
msgstr ""
msgstr "Dupla koppintás (jobb oldalon)"
#: ui/help-overlay.ui:74
msgid "Previous item"
msgstr ""
msgstr "Előző listaelem"
#: ui/help-overlay.ui:75
msgid "Double tap (left side)"
msgstr ""
msgstr "Dupla koppintás (bal oldalon)"
#: ui/help-overlay.ui:81
msgid "Change repeat mode"
msgstr ""
msgstr "Ismétlési típus változtatása"
#: ui/help-overlay.ui:87
msgid "Export to file"
msgstr ""
msgstr "Exportálás fájlba"
#: ui/help-overlay.ui:95 ui/preferences-window.ui:119
msgid "Playback"
msgstr ""
msgstr "Lejátszás"
#: ui/help-overlay.ui:98
msgid "Toggle play"
msgstr ""
msgstr "Lejátszás indítása/megállítása"
#: ui/help-overlay.ui:99
msgid "Long press | Right click"
msgstr ""
msgstr "Hosszú nyomás | Jobb kattintás"
#: ui/help-overlay.ui:105
msgid "Seek forward"
msgstr ""
msgstr "Előretekerés"
#: ui/help-overlay.ui:106
msgid "Swipe right | Scroll right"
msgstr ""
msgstr "Húzás jobbra | Görgetés jobbra"
#: ui/help-overlay.ui:112
msgid "Seek backward"
msgstr ""
msgstr "Visszatekerés"
#: ui/help-overlay.ui:113
msgid "Swipe left | Scroll left"
msgstr ""
msgstr "Húzás balra | Görgetés balra"
#: ui/help-overlay.ui:119
msgid "Volume up"
msgstr ""
msgstr "Hangerő növelése"
#: ui/help-overlay.ui:120
msgid "Swipe up | Scroll up"
msgstr ""
msgstr "Húzás felfelé | Görgetés felfelé"
#: ui/help-overlay.ui:126
msgid "Volume down"
msgstr ""
msgstr "Hangerő csökkentése"
#: ui/help-overlay.ui:127
msgid "Swipe down | Scroll down"
msgstr ""
msgstr "Húzás lefelé | Görgetés lefelé"
#: ui/help-overlay.ui:133
msgid "Toggle mute"
msgstr ""
msgstr "Némítás be-/kikapcsolása"
#: ui/help-overlay.ui:139
msgid "Next chapter"
msgstr ""
msgstr "Következő jelenet"
#: ui/help-overlay.ui:145
msgid "Previous chapter"
msgstr ""
msgstr "Előző jelenet"
#: ui/preferences-plugin-ranking-subpage.ui:11
msgid "Decoders"
msgstr ""
msgstr "Dekóderek"
#: ui/preferences-plugin-ranking-subpage.ui:18
msgid "Return to the preferences"
msgstr ""
msgstr "Visszatérés a beállításokhoz"
#: ui/preferences-window.ui:16
msgid "Behavior"
msgstr ""
msgstr "Viselkedés"
#: ui/preferences-window.ui:19
msgid "Auto fullscreen"
msgstr ""
msgstr "Automatikus teljes képernyős mód"
#: ui/preferences-window.ui:20
msgid "Enter fullscreen when playlist is replaced except floating mode"
msgstr ""
msgstr "Teljes képernyős módra váltás a lejátszólista megváltoztatásakor (kivétel ha lebegőablakos módban vagyunk)"
#: ui/preferences-window.ui:26
msgid "Ask to resume recent media"
msgstr ""
msgstr "Rákérdezés a legutóbbi média folytatására"
#: ui/preferences-window.ui:32
msgid "Float on all workspaces"
msgstr ""
msgstr "Lebegő ablak az összes munkaasztalon"
#: ui/preferences-window.ui:33
msgid "This option only works on GNOME"
msgstr ""
msgstr "Ez az opció csak GNOME asztali környezettel működik"
#: ui/preferences-window.ui:39
msgid "After playback"
msgstr ""
msgstr "Lejátszás után"
#: ui/preferences-window.ui:44
msgid "Do nothing"
msgstr ""
msgstr "Ne csináljon semmit"
#: ui/preferences-window.ui:45
msgid "Freeze last frame"
msgstr ""
msgstr "Utolsó képkocka mutatása"
#: ui/preferences-window.ui:46
msgid "Close the app"
msgstr ""
msgstr "Alkalmazás bezárása"
#: ui/preferences-window.ui:56
msgid "Volume"
msgstr ""
msgstr "Hangerő"
#: ui/preferences-window.ui:59
msgid "Custom initial value"
msgstr ""
msgstr "Egyedi kezdeti érték"
#: ui/preferences-window.ui:60
msgid "Set custom volume at startup instead of restoring it"
msgstr ""
msgstr "Induláskor egyedi hangerő az utolsó visszaállítása helyett"
#: ui/preferences-window.ui:64
msgid "Volume percentage"
msgstr ""
msgstr "Hangerő százalék"
#: ui/preferences-window.ui:75
msgid "Seeking"
msgstr ""
msgstr "Tekerés"
#: ui/preferences-window.ui:78
msgid "Mode"
msgstr ""
msgstr "Mód"
#: ui/preferences-window.ui:84
msgid "Accurate"
msgstr ""
msgstr "Precíz"
#: ui/preferences-window.ui:85
msgid "Fast"
msgstr ""
msgstr "Gyors"
#: ui/preferences-window.ui:93
msgid "Unit"
msgstr ""
msgstr "Mértékegység"
#: ui/preferences-window.ui:98
msgid "Second"
msgstr ""
msgstr "Másodperc"
#: ui/preferences-window.ui:99
msgid "Minute"
msgstr ""
msgstr "Perc"
#: ui/preferences-window.ui:100
msgid "Percentage"
msgstr ""
msgstr "Százalék"
#: ui/preferences-window.ui:108
msgid "Value"
msgstr ""
msgstr "Érték"
#: ui/preferences-window.ui:123
msgid "Audio"
msgstr ""
msgstr "Hang"
#: ui/preferences-window.ui:126
msgid "Offset in milliseconds"
msgstr ""
msgstr "Eltolás miliszekundumban"
#: ui/preferences-window.ui:133
msgid "Only native audio formats"
msgstr ""
msgstr "Csak natív hang formátumok"
#: ui/preferences-window.ui:141
msgid "Subtitles"
msgstr ""
msgstr "Feliratok"
#: ui/preferences-window.ui:144
msgid "Default font"
msgstr ""
msgstr "Alapértelmezett betűtípus"
#: ui/preferences-window.ui:154
msgid "Network"
msgstr ""
msgstr "Hálózat"
#: ui/preferences-window.ui:158
msgid "Client"
msgstr ""
msgstr "Kliens"
#: ui/preferences-window.ui:161
msgid "Progressive download buffering"
msgstr ""
msgstr "Progresszív letöltéspufferelés"
#: ui/preferences-window.ui:169
msgid "Server"
msgstr ""
msgstr "Szerver"
#: ui/preferences-window.ui:172
msgid "Control player remotely"
msgstr ""
msgstr "Lejátszó távirányítása"
#: ui/preferences-window.ui:176
msgid "Listening port"
msgstr ""
msgstr "Port figyelése"
#: ui/preferences-window.ui:183
msgid "Run web application in background"
msgstr ""
msgstr "Web alkalmazás háttérben való futtatása"
#: ui/preferences-window.ui:184
msgid "Requires GTK compiled with Broadway backend"
msgstr ""
msgstr "Broadway backenddel fordított GTK -t igényel"
#: ui/preferences-window.ui:190
msgid "Web application port"
msgstr ""
msgstr "Web alkalmazás portja"
#: ui/preferences-window.ui:204
msgid "Prefer adaptive streaming"
msgstr ""
msgstr "Adaptív streaming előnyben részesítése"
#: ui/preferences-window.ui:210
msgid "Max quality"
msgstr ""
msgstr "Maximális minőség"
#: ui/preferences-window.ui:228
msgid "Tweaks"
msgstr ""
msgstr "Finomhangolások"
#: ui/preferences-window.ui:232
msgid "Appearance"
msgstr ""
msgstr "Megjelenés"
#: ui/preferences-window.ui:235
msgid "Dark theme"
msgstr ""
msgstr "Sötét téma"
#: ui/preferences-window.ui:241
msgid "Render window shadows"
msgstr ""
msgstr "Ablak árnyékok renderelése"
#: ui/preferences-window.ui:242
msgid "Disable to increase performance when windowed"
msgstr ""
msgstr "Kikapcsolása javítja a teljesítményt ablakban futtatás esetén"
#: ui/preferences-window.ui:253
msgid "Plugin ranking"
msgstr ""
msgstr "Bővítményrangsor"
#: ui/preferences-window.ui:254
msgid "Alter default ranks of GStreamer plugins"
msgstr ""
msgstr "Az alapértelmezett GStreamer bővítményrangsor megváltoztatása"
#: ui/preferences-window.ui:259
msgid "Use playbin3"
msgstr ""
msgstr "A playbin3 használata"
#: ui/preferences-window.ui:260 ui/preferences-window.ui:269
msgid "Requires player restart"
msgstr ""
msgstr "A lejátszó újraindítását igényli"
#: ui/preferences-window.ui:262 ui/preferences-window.ui:271
msgid "Experimental"
msgstr ""
msgstr "Kísérleti funkció"
#: ui/preferences-window.ui:268
msgid "Use PipeWire for audio output"
msgstr ""
msgstr "A PipeWire használata hang kimenetként"
#: src/buttons.js:201
#, javascript-format
msgid "Decoder: %s"
msgstr ""
msgstr "Dekóder: %s"
#: src/dialogs.js:152
msgid "Enter or drop URI here"
msgstr ""
msgstr "Adjon meg egy URI -t itt, vagy húzza és ejtse ide"
#: src/dialogs.js:157
msgid "Cancel"
msgstr ""
msgstr "Mégsem"
#: src/dialogs.js:158
msgid "Open"
msgstr ""
#: src/dialogs.js:217
msgid "Title"
msgstr ""
#: src/dialogs.js:218
msgid "Completed"
msgstr ""
msgstr "Megnyitás"
#: src/dialogs.js:226
msgid "Resume playback?"
msgstr ""
msgid "Title"
msgstr "Cím"
#: src/dialogs.js:280
#: src/dialogs.js:227
msgid "Completed"
msgstr "Lejátszva"
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr "Lejátszás folytatása?"
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
msgstr "GTK verzió: %s"
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:282
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:283
#, javascript-format
msgid "GJS version: %s"
msgstr ""
msgstr "Adwaita verzió: %s"
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr "GStreamer verzió: %s"
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr "GJS verzió: %s"
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
msgstr "GNOME médialejátszó a GStreamer képességeivel"
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr "Ferenc Géczi"
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr ""
msgstr "%s-kor ér véget"
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
msgstr "Meghatározatlan"
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr ""
msgstr "Csatornák"
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr ""
msgstr "Kikapcsolva"

View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-10 19:43\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2021-10-04 08:30\n"
"Last-Translator: \n"
"Language-Team: Italian\n"
"Language: it_IT\n"
@@ -18,12 +18,12 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgstr "Apri i File..."
msgid "Open Files"
msgstr "Apri i File"
#: ui/clapper.ui:10
msgid "Open URI..."
msgstr "Apri URI..."
msgid "Open URI"
msgstr "Apri URI"
#: ui/clapper.ui:16 ui/preferences-window.ui:4
msgid "Preferences"
@@ -399,56 +399,61 @@ msgstr "Cancella"
msgid "Open"
msgstr "Apri"
#: src/dialogs.js:217
#: src/dialogs.js:226
msgid "Title"
msgstr "Titolo"
#: src/dialogs.js:218
#: src/dialogs.js:227
msgid "Completed"
msgstr "Completato"
#: src/dialogs.js:226
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr "Riprendere la riproduzione?"
#: src/dialogs.js:280
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr "Versione GTK: %s"
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr "Versione Adwaita: %s"
#: src/dialogs.js:282
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr "Versione GStreamer: %s"
#: src/dialogs.js:283
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr "Versione GJS: %s"
#: src/dialogs.js:291
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr "Un riproduttore multimediale per GNOME basato su GStreamer"
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr ""
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr "Termina alle: %s"
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr "Indeterminato"
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr "Canali"
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr "Disabilitato"

View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-06 18:31\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2021-09-14 15:25\n"
"Last-Translator: \n"
"Language-Team: Japanese\n"
"Language: ja_JP\n"
@@ -18,11 +18,11 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgid "Open Files"
msgstr ""
#: ui/clapper.ui:10
msgid "Open URI..."
msgid "Open URI"
msgstr ""
#: ui/clapper.ui:16 ui/preferences-window.ui:4
@@ -399,56 +399,61 @@ msgstr ""
msgid "Open"
msgstr ""
#: src/dialogs.js:217
#: src/dialogs.js:226
msgid "Title"
msgstr ""
#: src/dialogs.js:218
#: src/dialogs.js:227
msgid "Completed"
msgstr ""
#: src/dialogs.js:226
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr ""
#: src/dialogs.js:280
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:282
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:283
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr ""
#: src/dialogs.js:291
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr ""
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr ""
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr ""
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr ""

View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-06 18:30\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2021-09-14 15:24\n"
"Last-Translator: \n"
"Language-Team: Korean\n"
"Language: ko_KR\n"
@@ -18,11 +18,11 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgid "Open Files"
msgstr ""
#: ui/clapper.ui:10
msgid "Open URI..."
msgid "Open URI"
msgstr ""
#: ui/clapper.ui:16 ui/preferences-window.ui:4
@@ -399,56 +399,61 @@ msgstr ""
msgid "Open"
msgstr ""
#: src/dialogs.js:217
#: src/dialogs.js:226
msgid "Title"
msgstr ""
#: src/dialogs.js:218
#: src/dialogs.js:227
msgid "Completed"
msgstr ""
#: src/dialogs.js:226
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr ""
#: src/dialogs.js:280
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:282
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:283
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr ""
#: src/dialogs.js:291
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr ""
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr ""
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr ""
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr ""

View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-06 19:35\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2021-09-14 16:21\n"
"Last-Translator: \n"
"Language-Team: Dutch\n"
"Language: nl_NL\n"
@@ -18,11 +18,11 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgid "Open Files"
msgstr "Bestanden openen…"
#: ui/clapper.ui:10
msgid "Open URI..."
msgid "Open URI"
msgstr "URI openen…"
#: ui/clapper.ui:16 ui/preferences-window.ui:4
@@ -399,56 +399,61 @@ msgstr ""
msgid "Open"
msgstr ""
#: src/dialogs.js:217
#: src/dialogs.js:226
msgid "Title"
msgstr ""
#: src/dialogs.js:218
#: src/dialogs.js:227
msgid "Completed"
msgstr ""
#: src/dialogs.js:226
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr ""
#: src/dialogs.js:280
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:282
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:283
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr ""
#: src/dialogs.js:291
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr "Heimen Stoffels <vistausss@fastmail.com>"
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr "Eindigt op: %s"
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr ""
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr ""

View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-06 18:31\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2021-09-14 15:25\n"
"Last-Translator: \n"
"Language-Team: Norwegian\n"
"Language: no_NO\n"
@@ -18,11 +18,11 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgid "Open Files"
msgstr ""
#: ui/clapper.ui:10
msgid "Open URI..."
msgid "Open URI"
msgstr ""
#: ui/clapper.ui:16 ui/preferences-window.ui:4
@@ -399,56 +399,61 @@ msgstr ""
msgid "Open"
msgstr ""
#: src/dialogs.js:217
#: src/dialogs.js:226
msgid "Title"
msgstr ""
#: src/dialogs.js:218
#: src/dialogs.js:227
msgid "Completed"
msgstr ""
#: src/dialogs.js:226
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr ""
#: src/dialogs.js:280
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:282
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:283
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr ""
#: src/dialogs.js:291
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr ""
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr ""
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr ""
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr ""

View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-08 09:12\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2021-09-15 08:41\n"
"Last-Translator: \n"
"Language-Team: Polish\n"
"Language: pl_PL\n"
@@ -18,12 +18,12 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgstr "Otwórz pliki..."
msgid "Open Files"
msgstr "Otwórz pliki"
#: ui/clapper.ui:10
msgid "Open URI..."
msgstr "Otwórz URI..."
msgid "Open URI"
msgstr "Otwórz URI"
#: ui/clapper.ui:16 ui/preferences-window.ui:4
msgid "Preferences"
@@ -399,56 +399,61 @@ msgstr "Anuluj"
msgid "Open"
msgstr "Otwórz"
#: src/dialogs.js:217
#: src/dialogs.js:226
msgid "Title"
msgstr "Tytuł"
#: src/dialogs.js:218
#: src/dialogs.js:227
msgid "Completed"
msgstr "Ukończono"
#: src/dialogs.js:226
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr "Wznowić odtwarzanie?"
#: src/dialogs.js:280
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr "Wersja GTK: %s"
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr "Wersja Adwaity: %s"
#: src/dialogs.js:282
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr "Wersja GStreamera: %s"
#: src/dialogs.js:283
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr "Wersja GJS: %s"
#: src/dialogs.js:291
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr "Odtwarzacz multimedialny dla GNOME zasilany przez GStreamer"
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr "Rafał Dzięgiel <rafostar.github@gmail.com>"
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr "Koniec o: %s"
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr "Nieokreślony"
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr "Kanały"
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr "Wyłączony"

View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-06 18:31\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2021-10-21 00:29\n"
"Last-Translator: \n"
"Language-Team: Portuguese\n"
"Language: pt_PT\n"
@@ -18,89 +18,89 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgstr ""
msgid "Open Files"
msgstr "Abrir Arquivos…"
#: ui/clapper.ui:10
msgid "Open URI..."
msgstr ""
msgid "Open URI"
msgstr "Abrir URI…"
#: ui/clapper.ui:16 ui/preferences-window.ui:4
msgid "Preferences"
msgstr ""
msgstr "Preferências"
#: ui/clapper.ui:20
msgid "Shortcuts"
msgstr ""
msgstr "Atalhos"
#: ui/clapper.ui:26
msgid "About Clapper"
msgstr ""
msgstr "Sobre o Clapper"
#: ui/elapsed-time-button.ui:27
msgid "Speed"
msgstr ""
msgstr "Velocidade"
#: ui/elapsed-time-button.ui:41 ui/preferences-window.ui:83
#: ui/preferences-window.ui:215
msgid "Normal"
msgstr ""
msgstr "Predefinido"
#: ui/help-overlay.ui:10 ui/preferences-window.ui:12
msgid "General"
msgstr ""
msgstr "Geral"
#: ui/help-overlay.ui:13
msgid "Show shortcuts"
msgstr ""
msgstr "Mostrar atalhos"
#: ui/help-overlay.ui:19
msgid "Toggle fullscreen"
msgstr ""
msgstr "Mudar modo de ecrã"
#: ui/help-overlay.ui:20
msgid "Double tap | Double click"
msgstr ""
msgstr "Toque duplo duplo Clique duplo"
#: ui/help-overlay.ui:26
msgid "Leave fullscreen"
msgstr ""
msgstr "Sair do modo de ecrã completo"
#: ui/help-overlay.ui:32
msgid "Reveal OSD (fullscreen only)"
msgstr ""
msgstr "Revelar OSD (apenas em tela cheia)"
#: ui/help-overlay.ui:33
msgid "Tap"
msgstr ""
msgstr "Tocar"
#: ui/help-overlay.ui:39
msgid "Quit"
msgstr ""
msgstr "Sair"
#: ui/help-overlay.ui:47
msgid "Media"
msgstr ""
msgstr "Multimédia"
#: ui/help-overlay.ui:50
msgid "Open files"
msgstr ""
msgstr "Abrir ficheiro"
#: ui/help-overlay.ui:56 src/dialogs.js:137
msgid "Open URI"
msgstr ""
msgstr "Abrir URI"
#: ui/help-overlay.ui:64
msgid "Playlist"
msgstr ""
msgstr "Lista de reprodução"
#: ui/help-overlay.ui:67
msgid "Next item"
msgstr ""
msgstr "Próximo item"
#: ui/help-overlay.ui:68
msgid "Double tap (right side)"
msgstr ""
msgstr "Toque duplo (lado direito)"
#: ui/help-overlay.ui:74
msgid "Previous item"
@@ -399,56 +399,61 @@ msgstr ""
msgid "Open"
msgstr ""
#: src/dialogs.js:217
#: src/dialogs.js:226
msgid "Title"
msgstr ""
#: src/dialogs.js:218
#: src/dialogs.js:227
msgid "Completed"
msgstr ""
#: src/dialogs.js:226
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr ""
#: src/dialogs.js:280
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:282
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:283
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr ""
#: src/dialogs.js:291
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr ""
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr ""
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr ""
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr ""

View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-06 18:31\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2021-10-11 10:33\n"
"Last-Translator: \n"
"Language-Team: Portuguese, Brazilian\n"
"Language: pt_BR\n"
@@ -18,437 +18,442 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgstr ""
msgid "Open Files"
msgstr "Abrir Arquivos"
#: ui/clapper.ui:10
msgid "Open URI..."
msgstr ""
msgid "Open URI"
msgstr "Abrir URI"
#: ui/clapper.ui:16 ui/preferences-window.ui:4
msgid "Preferences"
msgstr ""
msgstr "Preferências"
#: ui/clapper.ui:20
msgid "Shortcuts"
msgstr ""
msgstr "Atalhos"
#: ui/clapper.ui:26
msgid "About Clapper"
msgstr ""
msgstr "Sobre o Clapper"
#: ui/elapsed-time-button.ui:27
msgid "Speed"
msgstr ""
msgstr "Velocidade"
#: ui/elapsed-time-button.ui:41 ui/preferences-window.ui:83
#: ui/preferences-window.ui:215
msgid "Normal"
msgstr ""
msgstr "Normal"
#: ui/help-overlay.ui:10 ui/preferences-window.ui:12
msgid "General"
msgstr ""
msgstr "Geral"
#: ui/help-overlay.ui:13
msgid "Show shortcuts"
msgstr ""
msgstr "Mostrar atalhos"
#: ui/help-overlay.ui:19
msgid "Toggle fullscreen"
msgstr ""
msgstr "Tela Cheia"
#: ui/help-overlay.ui:20
msgid "Double tap | Double click"
msgstr ""
msgstr "Toque duplo duplo Clique duplo"
#: ui/help-overlay.ui:26
msgid "Leave fullscreen"
msgstr ""
msgstr "Sair de tela cheia"
#: ui/help-overlay.ui:32
msgid "Reveal OSD (fullscreen only)"
msgstr ""
msgstr "Revelar OSD (apenas em tela cheia)"
#: ui/help-overlay.ui:33
msgid "Tap"
msgstr ""
msgstr "Tocar"
#: ui/help-overlay.ui:39
msgid "Quit"
msgstr ""
msgstr "Sair"
#: ui/help-overlay.ui:47
msgid "Media"
msgstr ""
msgstr "Mídia"
#: ui/help-overlay.ui:50
msgid "Open files"
msgstr ""
msgstr "Abrir Arquivos"
#: ui/help-overlay.ui:56 src/dialogs.js:137
msgid "Open URI"
msgstr ""
msgstr "Abrir o URL"
#: ui/help-overlay.ui:64
msgid "Playlist"
msgstr ""
msgstr "Lista de reprodução"
#: ui/help-overlay.ui:67
msgid "Next item"
msgstr ""
msgstr "Próximo"
#: ui/help-overlay.ui:68
msgid "Double tap (right side)"
msgstr ""
msgstr "Toque duplo (lado direito)"
#: ui/help-overlay.ui:74
msgid "Previous item"
msgstr ""
msgstr "Anterior"
#: ui/help-overlay.ui:75
msgid "Double tap (left side)"
msgstr ""
msgstr "Toque duplo (lado esquerdo)"
#: ui/help-overlay.ui:81
msgid "Change repeat mode"
msgstr ""
msgstr "Alternar modo de repetição"
#: ui/help-overlay.ui:87
msgid "Export to file"
msgstr ""
msgstr "Exportar arquivo"
#: ui/help-overlay.ui:95 ui/preferences-window.ui:119
msgid "Playback"
msgstr ""
msgstr "Reprodução"
#: ui/help-overlay.ui:98
msgid "Toggle play"
msgstr ""
msgstr "Alternar video"
#: ui/help-overlay.ui:99
msgid "Long press | Right click"
msgstr ""
msgstr "Toque longo (Clique com o botão direito)"
#: ui/help-overlay.ui:105
msgid "Seek forward"
msgstr ""
msgstr "Avançar para frente"
#: ui/help-overlay.ui:106
msgid "Swipe right | Scroll right"
msgstr ""
msgstr "Deslizar para a Direita Scroll para Direita"
#: ui/help-overlay.ui:112
msgid "Seek backward"
msgstr ""
msgstr "Volta video"
#: ui/help-overlay.ui:113
msgid "Swipe left | Scroll left"
msgstr ""
msgstr "Deslizar para a esquerda Scroll para a Esquerda"
#: ui/help-overlay.ui:119
msgid "Volume up"
msgstr ""
msgstr "Aumentar o volume"
#: ui/help-overlay.ui:120
msgid "Swipe up | Scroll up"
msgstr ""
msgstr "Deslizar para cima Scroll para cima"
#: ui/help-overlay.ui:126
msgid "Volume down"
msgstr ""
msgstr "Diminuir o volume"
#: ui/help-overlay.ui:127
msgid "Swipe down | Scroll down"
msgstr ""
msgstr "Deslizar para baixo ► Rolar para baixo"
#: ui/help-overlay.ui:133
msgid "Toggle mute"
msgstr ""
msgstr "Ativar/Desativar Som"
#: ui/help-overlay.ui:139
msgid "Next chapter"
msgstr ""
msgstr "Próximo Capítulo"
#: ui/help-overlay.ui:145
msgid "Previous chapter"
msgstr ""
msgstr "Capítulo Anterior"
#: ui/preferences-plugin-ranking-subpage.ui:11
msgid "Decoders"
msgstr ""
msgstr "Decodificadores"
#: ui/preferences-plugin-ranking-subpage.ui:18
msgid "Return to the preferences"
msgstr ""
msgstr "Voltar para as preferências"
#: ui/preferences-window.ui:16
msgid "Behavior"
msgstr ""
msgstr "Comportamento"
#: ui/preferences-window.ui:19
msgid "Auto fullscreen"
msgstr ""
msgstr "Tela cheia automaticamente"
#: ui/preferences-window.ui:20
msgid "Enter fullscreen when playlist is replaced except floating mode"
msgstr ""
msgstr "Insira em tela cheia quando a lista de reprodução for substituída, exceto o modo flutuante"
#: ui/preferences-window.ui:26
msgid "Ask to resume recent media"
msgstr ""
msgstr "Pedir para retomar o video recente"
#: ui/preferences-window.ui:32
msgid "Float on all workspaces"
msgstr ""
msgstr "Flutuar em todas as áreas de trabalho"
#: ui/preferences-window.ui:33
msgid "This option only works on GNOME"
msgstr ""
msgstr "Esta opção só funciona no GNOME"
#: ui/preferences-window.ui:39
msgid "After playback"
msgstr ""
msgstr "Pós reprodução"
#: ui/preferences-window.ui:44
msgid "Do nothing"
msgstr ""
msgstr "Não fazer nada"
#: ui/preferences-window.ui:45
msgid "Freeze last frame"
msgstr ""
msgstr "Congelar o último quadro"
#: ui/preferences-window.ui:46
msgid "Close the app"
msgstr ""
msgstr "Fechar aplicativo"
#: ui/preferences-window.ui:56
msgid "Volume"
msgstr ""
msgstr "Volume"
#: ui/preferences-window.ui:59
msgid "Custom initial value"
msgstr ""
msgstr "Valor inicial personalizado"
#: ui/preferences-window.ui:60
msgid "Set custom volume at startup instead of restoring it"
msgstr ""
msgstr "Definir volume personalizado na inicialização ao invés de restaurá-lo"
#: ui/preferences-window.ui:64
msgid "Volume percentage"
msgstr ""
msgstr "Percentual do volume"
#: ui/preferences-window.ui:75
msgid "Seeking"
msgstr ""
msgstr "Buscando"
#: ui/preferences-window.ui:78
msgid "Mode"
msgstr ""
msgstr "Modo"
#: ui/preferences-window.ui:84
msgid "Accurate"
msgstr ""
msgstr "Preciso"
#: ui/preferences-window.ui:85
msgid "Fast"
msgstr ""
msgstr "Rápido"
#: ui/preferences-window.ui:93
msgid "Unit"
msgstr ""
msgstr "Unidade"
#: ui/preferences-window.ui:98
msgid "Second"
msgstr ""
msgstr "Segundo"
#: ui/preferences-window.ui:99
msgid "Minute"
msgstr ""
msgstr "Minuto"
#: ui/preferences-window.ui:100
msgid "Percentage"
msgstr ""
msgstr "Porcentagem"
#: ui/preferences-window.ui:108
msgid "Value"
msgstr ""
msgstr "Valor"
#: ui/preferences-window.ui:123
msgid "Audio"
msgstr ""
msgstr "Audio"
#: ui/preferences-window.ui:126
msgid "Offset in milliseconds"
msgstr ""
msgstr "tempo de desvanecimento em milissegundos"
#: ui/preferences-window.ui:133
msgid "Only native audio formats"
msgstr ""
msgstr "Apenas formatos de áudio nativos"
#: ui/preferences-window.ui:141
msgid "Subtitles"
msgstr ""
msgstr "Legendas"
#: ui/preferences-window.ui:144
msgid "Default font"
msgstr ""
msgstr "Fonte padrão"
#: ui/preferences-window.ui:154
msgid "Network"
msgstr ""
msgstr "Rede"
#: ui/preferences-window.ui:158
msgid "Client"
msgstr ""
msgstr "Cliente"
#: ui/preferences-window.ui:161
msgid "Progressive download buffering"
msgstr ""
msgstr "buffering progressivo de download"
#: ui/preferences-window.ui:169
msgid "Server"
msgstr ""
msgstr "Servidor"
#: ui/preferences-window.ui:172
msgid "Control player remotely"
msgstr ""
msgstr "Controle o video remotamente "
#: ui/preferences-window.ui:176
msgid "Listening port"
msgstr ""
msgstr "Porta de escuta"
#: ui/preferences-window.ui:183
msgid "Run web application in background"
msgstr ""
msgstr "Executar web app em segundo plano"
#: ui/preferences-window.ui:184
msgid "Requires GTK compiled with Broadway backend"
msgstr ""
msgstr "Requer GTK compilado com backend de Broadway"
#: ui/preferences-window.ui:190
msgid "Web application port"
msgstr ""
msgstr "Porta do aplicativo Web"
#: ui/preferences-window.ui:204
msgid "Prefer adaptive streaming"
msgstr ""
msgstr "Preferir streaming adaptável"
#: ui/preferences-window.ui:210
msgid "Max quality"
msgstr ""
msgstr "Qualidade Máxima"
#: ui/preferences-window.ui:228
msgid "Tweaks"
msgstr ""
msgstr "Ajustes"
#: ui/preferences-window.ui:232
msgid "Appearance"
msgstr ""
msgstr "Aparência"
#: ui/preferences-window.ui:235
msgid "Dark theme"
msgstr ""
msgstr "Tema Escuro"
#: ui/preferences-window.ui:241
msgid "Render window shadows"
msgstr ""
msgstr "Renderizar sombras das janelas"
#: ui/preferences-window.ui:242
msgid "Disable to increase performance when windowed"
msgstr ""
msgstr "Desabilite para aumentar o desempenho em placas gráficas mais fracas."
#: ui/preferences-window.ui:253
msgid "Plugin ranking"
msgstr ""
msgstr "Classificação do plugin"
#: ui/preferences-window.ui:254
msgid "Alter default ranks of GStreamer plugins"
msgstr ""
msgstr "Altera os ranks padrão dos plugins do GStreamer"
#: ui/preferences-window.ui:259
msgid "Use playbin3"
msgstr ""
msgstr "Usar playbin3"
#: ui/preferences-window.ui:260 ui/preferences-window.ui:269
msgid "Requires player restart"
msgstr ""
msgstr "Requer reinicialização do Clapper"
#: ui/preferences-window.ui:262 ui/preferences-window.ui:271
msgid "Experimental"
msgstr ""
msgstr "Experimental"
#: ui/preferences-window.ui:268
msgid "Use PipeWire for audio output"
msgstr ""
msgstr "Usar PipeWire para saída de áudio"
#: src/buttons.js:201
#, javascript-format
msgid "Decoder: %s"
msgstr ""
msgstr "Decodificador: %s"
#: src/dialogs.js:152
msgid "Enter or drop URI here"
msgstr ""
msgstr "Digite ou solte o URI aqui"
#: src/dialogs.js:157
msgid "Cancel"
msgstr ""
msgstr "Cancelar"
#: src/dialogs.js:158
msgid "Open"
msgstr ""
#: src/dialogs.js:217
msgid "Title"
msgstr ""
#: src/dialogs.js:218
msgid "Completed"
msgstr ""
msgstr "Abrir"
#: src/dialogs.js:226
msgid "Resume playback?"
msgstr ""
msgid "Title"
msgstr "Título"
#: src/dialogs.js:280
#: src/dialogs.js:227
msgid "Completed"
msgstr "Completado"
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr "Retomar a reprodução?"
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
msgstr "Versão do GTK: %s"
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:282
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:283
#, javascript-format
msgid "GJS version: %s"
msgstr ""
msgstr "Adwaita versão:"
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr "Versão do GStreamer: %s"
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr "Versão do GJS: %s"
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
msgstr "Um player de mídia GNOME desenvolvido por GStreamer"
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr "KevenDoriaLinuxBR"
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr ""
msgstr "termina em %s"
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
msgstr "Indeterminado"
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr ""
msgstr "Canais"
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr ""
msgstr "Desabilitado"

View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-06 18:30\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2021-09-14 15:24\n"
"Last-Translator: \n"
"Language-Team: Romanian\n"
"Language: ro_RO\n"
@@ -18,11 +18,11 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgid "Open Files"
msgstr ""
#: ui/clapper.ui:10
msgid "Open URI..."
msgid "Open URI"
msgstr ""
#: ui/clapper.ui:16 ui/preferences-window.ui:4
@@ -399,56 +399,61 @@ msgstr ""
msgid "Open"
msgstr ""
#: src/dialogs.js:217
#: src/dialogs.js:226
msgid "Title"
msgstr ""
#: src/dialogs.js:218
#: src/dialogs.js:227
msgid "Completed"
msgstr ""
#: src/dialogs.js:226
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr ""
#: src/dialogs.js:280
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:282
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:283
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr ""
#: src/dialogs.js:291
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr ""
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr ""
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr ""
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr ""

267
po/ru.po
View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-06 18:31\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2022-01-16 14:15\n"
"Last-Translator: \n"
"Language-Team: Russian\n"
"Language: ru_RU\n"
@@ -18,437 +18,442 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgstr ""
msgid "Open Files"
msgstr "Открыть файлы…"
#: ui/clapper.ui:10
msgid "Open URI..."
msgstr ""
msgid "Open URI"
msgstr "Открыть URI…"
#: ui/clapper.ui:16 ui/preferences-window.ui:4
msgid "Preferences"
msgstr ""
msgstr "Параметры"
#: ui/clapper.ui:20
msgid "Shortcuts"
msgstr ""
msgstr "Комбинации клавиш"
#: ui/clapper.ui:26
msgid "About Clapper"
msgstr ""
msgstr "О приложении"
#: ui/elapsed-time-button.ui:27
msgid "Speed"
msgstr ""
msgstr "Скорость"
#: ui/elapsed-time-button.ui:41 ui/preferences-window.ui:83
#: ui/preferences-window.ui:215
msgid "Normal"
msgstr ""
msgstr "Обычная"
#: ui/help-overlay.ui:10 ui/preferences-window.ui:12
msgid "General"
msgstr ""
msgstr "Общие"
#: ui/help-overlay.ui:13
msgid "Show shortcuts"
msgstr ""
msgstr "Комбинации клавиш"
#: ui/help-overlay.ui:19
msgid "Toggle fullscreen"
msgstr ""
msgstr "Включить полноэкранный режим"
#: ui/help-overlay.ui:20
msgid "Double tap | Double click"
msgstr ""
msgstr "Двойное нажатие | Двойной клик"
#: ui/help-overlay.ui:26
msgid "Leave fullscreen"
msgstr ""
msgstr "Выйти из полноэкранного режима"
#: ui/help-overlay.ui:32
msgid "Reveal OSD (fullscreen only)"
msgstr ""
msgstr "Показывать OSD (только в полноэкранном режиме)"
#: ui/help-overlay.ui:33
msgid "Tap"
msgstr ""
msgstr "Нажатие"
#: ui/help-overlay.ui:39
msgid "Quit"
msgstr ""
msgstr "Выйти из приложения"
#: ui/help-overlay.ui:47
msgid "Media"
msgstr ""
msgstr "Медиа"
#: ui/help-overlay.ui:50
msgid "Open files"
msgstr ""
msgstr "Открыть файлы"
#: ui/help-overlay.ui:56 src/dialogs.js:137
msgid "Open URI"
msgstr ""
msgstr "Открыть URI"
#: ui/help-overlay.ui:64
msgid "Playlist"
msgstr ""
msgstr "Плейлист"
#: ui/help-overlay.ui:67
msgid "Next item"
msgstr ""
msgstr "Следующий элемент"
#: ui/help-overlay.ui:68
msgid "Double tap (right side)"
msgstr ""
msgstr "Двойное нажатие (правая сторона)"
#: ui/help-overlay.ui:74
msgid "Previous item"
msgstr ""
msgstr "Предыдущий элемент"
#: ui/help-overlay.ui:75
msgid "Double tap (left side)"
msgstr ""
msgstr "Двойное нажатие (левая сторона)"
#: ui/help-overlay.ui:81
msgid "Change repeat mode"
msgstr ""
msgstr "Изменить режим повторения"
#: ui/help-overlay.ui:87
msgid "Export to file"
msgstr ""
msgstr "Экспорт в файл"
#: ui/help-overlay.ui:95 ui/preferences-window.ui:119
msgid "Playback"
msgstr ""
msgstr "Воспроизведение"
#: ui/help-overlay.ui:98
msgid "Toggle play"
msgstr ""
msgstr "Управление воспроизведением"
#: ui/help-overlay.ui:99
msgid "Long press | Right click"
msgstr ""
msgstr "Длительное нажатие | Щелкните правой кнопкой мыши"
#: ui/help-overlay.ui:105
msgid "Seek forward"
msgstr ""
msgstr "Перемотка вперед"
#: ui/help-overlay.ui:106
msgid "Swipe right | Scroll right"
msgstr ""
msgstr "Проведите вправо | Прокрутите вправо"
#: ui/help-overlay.ui:112
msgid "Seek backward"
msgstr ""
msgstr "Перемотка назад"
#: ui/help-overlay.ui:113
msgid "Swipe left | Scroll left"
msgstr ""
msgstr "Проведите влево | Прокрутите влево"
#: ui/help-overlay.ui:119
msgid "Volume up"
msgstr ""
msgstr "Увеличить громкость"
#: ui/help-overlay.ui:120
msgid "Swipe up | Scroll up"
msgstr ""
msgstr "Проведите вверх | Прокрутите вверх"
#: ui/help-overlay.ui:126
msgid "Volume down"
msgstr ""
msgstr "Уменьшить громкость"
#: ui/help-overlay.ui:127
msgid "Swipe down | Scroll down"
msgstr ""
msgstr "Проведите вниз | Прокрутить вниз"
#: ui/help-overlay.ui:133
msgid "Toggle mute"
msgstr ""
msgstr "Отключить звук"
#: ui/help-overlay.ui:139
msgid "Next chapter"
msgstr ""
msgstr "Следующая глава"
#: ui/help-overlay.ui:145
msgid "Previous chapter"
msgstr ""
msgstr "Предыдущая глава"
#: ui/preferences-plugin-ranking-subpage.ui:11
msgid "Decoders"
msgstr ""
msgstr "Декодеры"
#: ui/preferences-plugin-ranking-subpage.ui:18
msgid "Return to the preferences"
msgstr ""
msgstr "Вернуться к настройкам"
#: ui/preferences-window.ui:16
msgid "Behavior"
msgstr ""
msgstr "Поведение"
#: ui/preferences-window.ui:19
msgid "Auto fullscreen"
msgstr ""
msgstr "Автоматический полноэкранный режим"
#: ui/preferences-window.ui:20
msgid "Enter fullscreen when playlist is replaced except floating mode"
msgstr ""
msgstr "Переход в полноэкранный режим при замене списка воспроизведения, кроме плавающего режима"
#: ui/preferences-window.ui:26
msgid "Ask to resume recent media"
msgstr ""
msgstr "Спрашивать о возобновление недавние медиа"
#: ui/preferences-window.ui:32
msgid "Float on all workspaces"
msgstr ""
msgstr "Показывать «плавающий режим» на всех рабочих столах"
#: ui/preferences-window.ui:33
msgid "This option only works on GNOME"
msgstr ""
msgstr "Эта опция работает только в GNOME"
#: ui/preferences-window.ui:39
msgid "After playback"
msgstr ""
msgstr "После воспроизведения"
#: ui/preferences-window.ui:44
msgid "Do nothing"
msgstr ""
msgstr "Ничего не делать"
#: ui/preferences-window.ui:45
msgid "Freeze last frame"
msgstr ""
msgstr "Заморозить последний кадр"
#: ui/preferences-window.ui:46
msgid "Close the app"
msgstr ""
msgstr "Закрыть приложение"
#: ui/preferences-window.ui:56
msgid "Volume"
msgstr ""
msgstr "Громкость"
#: ui/preferences-window.ui:59
msgid "Custom initial value"
msgstr ""
msgstr "Пользовательское начальное значение"
#: ui/preferences-window.ui:60
msgid "Set custom volume at startup instead of restoring it"
msgstr ""
msgstr "Установите настраиваемую громкость при запуске вместо ее восстановления"
#: ui/preferences-window.ui:64
msgid "Volume percentage"
msgstr ""
msgstr "Процент громкости"
#: ui/preferences-window.ui:75
msgid "Seeking"
msgstr ""
msgstr "Перемотка"
#: ui/preferences-window.ui:78
msgid "Mode"
msgstr ""
msgstr "Режим"
#: ui/preferences-window.ui:84
msgid "Accurate"
msgstr ""
msgstr "Точный"
#: ui/preferences-window.ui:85
msgid "Fast"
msgstr ""
msgstr "Быстрый"
#: ui/preferences-window.ui:93
msgid "Unit"
msgstr ""
msgstr "Ед. изм"
#: ui/preferences-window.ui:98
msgid "Second"
msgstr ""
msgstr "Секунды"
#: ui/preferences-window.ui:99
msgid "Minute"
msgstr ""
msgstr "Минуты"
#: ui/preferences-window.ui:100
msgid "Percentage"
msgstr ""
msgstr "Проценты"
#: ui/preferences-window.ui:108
msgid "Value"
msgstr ""
msgstr "Значение"
#: ui/preferences-window.ui:123
msgid "Audio"
msgstr ""
msgstr "Аудио"
#: ui/preferences-window.ui:126
msgid "Offset in milliseconds"
msgstr ""
msgstr "Смещение в миллисекундах"
#: ui/preferences-window.ui:133
msgid "Only native audio formats"
msgstr ""
msgstr "Только нативные аудиоформаты"
#: ui/preferences-window.ui:141
msgid "Subtitles"
msgstr ""
msgstr "Субтитры"
#: ui/preferences-window.ui:144
msgid "Default font"
msgstr ""
msgstr "Шрифт по умолчанию"
#: ui/preferences-window.ui:154
msgid "Network"
msgstr ""
msgstr "Сеть"
#: ui/preferences-window.ui:158
msgid "Client"
msgstr ""
msgstr "Клиент"
#: ui/preferences-window.ui:161
msgid "Progressive download buffering"
msgstr ""
msgstr "Прогрессивная буферизация загрузки"
#: ui/preferences-window.ui:169
msgid "Server"
msgstr ""
msgstr "Сервер"
#: ui/preferences-window.ui:172
msgid "Control player remotely"
msgstr ""
msgstr "Удаленное управление плеером"
#: ui/preferences-window.ui:176
msgid "Listening port"
msgstr ""
msgstr "Порт прослушивания"
#: ui/preferences-window.ui:183
msgid "Run web application in background"
msgstr ""
msgstr "Запустить веб-приложение в фоновом режиме"
#: ui/preferences-window.ui:184
msgid "Requires GTK compiled with Broadway backend"
msgstr ""
msgstr "Требуется GTK, скомпилированный с бэкэндом Broadway"
#: ui/preferences-window.ui:190
msgid "Web application port"
msgstr ""
msgstr "Порт веб-приложения"
#: ui/preferences-window.ui:204
msgid "Prefer adaptive streaming"
msgstr ""
msgstr "Предпочитайте адаптивную потоковую передачу"
#: ui/preferences-window.ui:210
msgid "Max quality"
msgstr ""
msgstr "Максимальное качество"
#: ui/preferences-window.ui:228
msgid "Tweaks"
msgstr ""
msgstr "Твики"
#: ui/preferences-window.ui:232
msgid "Appearance"
msgstr ""
msgstr "Внешний вид"
#: ui/preferences-window.ui:235
msgid "Dark theme"
msgstr ""
msgstr "Тёмная тема"
#: ui/preferences-window.ui:241
msgid "Render window shadows"
msgstr ""
msgstr "Рендеринг оконных теней"
#: ui/preferences-window.ui:242
msgid "Disable to increase performance when windowed"
msgstr ""
msgstr "Отключить, чтобы повысить производительность в оконном режиме"
#: ui/preferences-window.ui:253
msgid "Plugin ranking"
msgstr ""
msgstr "Рейтинг плагинов"
#: ui/preferences-window.ui:254
msgid "Alter default ranks of GStreamer plugins"
msgstr ""
msgstr "Изменить ранги плагинов GStreamer по умолчанию"
#: ui/preferences-window.ui:259
msgid "Use playbin3"
msgstr ""
msgstr "Использовать playbin3"
#: ui/preferences-window.ui:260 ui/preferences-window.ui:269
msgid "Requires player restart"
msgstr ""
msgstr "Требуется перезапуск плеера"
#: ui/preferences-window.ui:262 ui/preferences-window.ui:271
msgid "Experimental"
msgstr ""
msgstr "Экспериментально"
#: ui/preferences-window.ui:268
msgid "Use PipeWire for audio output"
msgstr ""
msgstr "Использовать PipeWire для вывода звука"
#: src/buttons.js:201
#, javascript-format
msgid "Decoder: %s"
msgstr ""
msgstr "Декодер: %s"
#: src/dialogs.js:152
msgid "Enter or drop URI here"
msgstr ""
msgstr "Введите URI"
#: src/dialogs.js:157
msgid "Cancel"
msgstr ""
msgstr "Отмена"
#: src/dialogs.js:158
msgid "Open"
msgstr ""
#: src/dialogs.js:217
msgid "Title"
msgstr ""
#: src/dialogs.js:218
msgid "Completed"
msgstr ""
msgstr "Открыть"
#: src/dialogs.js:226
msgid "Resume playback?"
msgstr ""
msgid "Title"
msgstr "Заголовок"
#: src/dialogs.js:280
#: src/dialogs.js:227
msgid "Completed"
msgstr "Завершенный"
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr "Возобновить воспроизведение?"
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
msgstr "Версия GTK: %s"
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:282
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:283
#, javascript-format
msgid "GJS version: %s"
msgstr ""
msgstr "Версия Adwaita: %s"
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr "Версия GStreamer: %s"
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr "Версия GJS: %s"
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
msgstr "Медиаплеер для GNOME на базе GStreamer"
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr "Игорь Дятлов"
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr ""
msgstr "Окончание: %s"
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
msgstr "Неопределенный"
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr ""
msgstr "Каналы"
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr ""
msgstr "Отключено"

View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-06 18:31\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2021-09-14 15:25\n"
"Last-Translator: \n"
"Language-Team: Serbian (Cyrillic)\n"
"Language: sr_SP\n"
@@ -18,11 +18,11 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgid "Open Files"
msgstr ""
#: ui/clapper.ui:10
msgid "Open URI..."
msgid "Open URI"
msgstr ""
#: ui/clapper.ui:16 ui/preferences-window.ui:4
@@ -399,56 +399,61 @@ msgstr ""
msgid "Open"
msgstr ""
#: src/dialogs.js:217
#: src/dialogs.js:226
msgid "Title"
msgstr ""
#: src/dialogs.js:218
#: src/dialogs.js:227
msgid "Completed"
msgstr ""
#: src/dialogs.js:226
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr ""
#: src/dialogs.js:280
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:282
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:283
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr ""
#: src/dialogs.js:291
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr ""
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr ""
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr ""
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr ""

267
po/sv.po
View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-06 18:31\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2022-01-16 14:15\n"
"Last-Translator: \n"
"Language-Team: Swedish\n"
"Language: sv_SE\n"
@@ -18,437 +18,442 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgstr ""
msgid "Open Files"
msgstr "Öppna filer…"
#: ui/clapper.ui:10
msgid "Open URI..."
msgstr ""
msgid "Open URI"
msgstr "Öppna URL…"
#: ui/clapper.ui:16 ui/preferences-window.ui:4
msgid "Preferences"
msgstr ""
msgstr "Inställningar"
#: ui/clapper.ui:20
msgid "Shortcuts"
msgstr ""
msgstr "Tangentbordsgenvägar"
#: ui/clapper.ui:26
msgid "About Clapper"
msgstr ""
msgstr "Om Clapper"
#: ui/elapsed-time-button.ui:27
msgid "Speed"
msgstr ""
msgstr "Hastighet"
#: ui/elapsed-time-button.ui:41 ui/preferences-window.ui:83
#: ui/preferences-window.ui:215
msgid "Normal"
msgstr ""
msgstr "Normal"
#: ui/help-overlay.ui:10 ui/preferences-window.ui:12
msgid "General"
msgstr ""
msgstr "Allmänt"
#: ui/help-overlay.ui:13
msgid "Show shortcuts"
msgstr ""
msgstr "Visa tangentbordsgenvägar"
#: ui/help-overlay.ui:19
msgid "Toggle fullscreen"
msgstr ""
msgstr "Växla helskärmsläge"
#: ui/help-overlay.ui:20
msgid "Double tap | Double click"
msgstr ""
msgstr "Dubbeltryck | Dubbelklicka"
#: ui/help-overlay.ui:26
msgid "Leave fullscreen"
msgstr ""
msgstr "Lämna helskärmsläge"
#: ui/help-overlay.ui:32
msgid "Reveal OSD (fullscreen only)"
msgstr ""
msgstr "Visa OSD (endast helskärmsläge)"
#: ui/help-overlay.ui:33
msgid "Tap"
msgstr ""
msgstr "Tryck"
#: ui/help-overlay.ui:39
msgid "Quit"
msgstr ""
msgstr "Avsluta"
#: ui/help-overlay.ui:47
msgid "Media"
msgstr ""
msgstr "Media"
#: ui/help-overlay.ui:50
msgid "Open files"
msgstr ""
msgstr "Öppna filer"
#: ui/help-overlay.ui:56 src/dialogs.js:137
msgid "Open URI"
msgstr ""
msgstr "Öppna URI"
#: ui/help-overlay.ui:64
msgid "Playlist"
msgstr ""
msgstr "Spellista"
#: ui/help-overlay.ui:67
msgid "Next item"
msgstr ""
msgstr "Nästa föremål"
#: ui/help-overlay.ui:68
msgid "Double tap (right side)"
msgstr ""
msgstr "Dubbeltryck (höger sida)"
#: ui/help-overlay.ui:74
msgid "Previous item"
msgstr ""
msgstr "Föregående föremål"
#: ui/help-overlay.ui:75
msgid "Double tap (left side)"
msgstr ""
msgstr "Dubbeltryck (vänster sida)"
#: ui/help-overlay.ui:81
msgid "Change repeat mode"
msgstr ""
msgstr "Ändra upprepningsläge"
#: ui/help-overlay.ui:87
msgid "Export to file"
msgstr ""
msgstr "Exportera till fil"
#: ui/help-overlay.ui:95 ui/preferences-window.ui:119
msgid "Playback"
msgstr ""
msgstr "Uppspelning"
#: ui/help-overlay.ui:98
msgid "Toggle play"
msgstr ""
msgstr "Spela/pausa"
#: ui/help-overlay.ui:99
msgid "Long press | Right click"
msgstr ""
msgstr "Långtryck | Högerklicka"
#: ui/help-overlay.ui:105
msgid "Seek forward"
msgstr ""
msgstr "Spola framåt"
#: ui/help-overlay.ui:106
msgid "Swipe right | Scroll right"
msgstr ""
msgstr "Svep höger | Skrolla höger"
#: ui/help-overlay.ui:112
msgid "Seek backward"
msgstr ""
msgstr "Spola bakåt"
#: ui/help-overlay.ui:113
msgid "Swipe left | Scroll left"
msgstr ""
msgstr "Svep vänster | Skrolla vänster"
#: ui/help-overlay.ui:119
msgid "Volume up"
msgstr ""
msgstr "Höj volymen"
#: ui/help-overlay.ui:120
msgid "Swipe up | Scroll up"
msgstr ""
msgstr "Svep uppåt | Skrolla uppåt"
#: ui/help-overlay.ui:126
msgid "Volume down"
msgstr ""
msgstr "Sänk volymen"
#: ui/help-overlay.ui:127
msgid "Swipe down | Scroll down"
msgstr ""
msgstr "Svep nedåt | Skrolla nedåt"
#: ui/help-overlay.ui:133
msgid "Toggle mute"
msgstr ""
msgstr "Växla ljudet på/av"
#: ui/help-overlay.ui:139
msgid "Next chapter"
msgstr ""
msgstr "Nästa kapitel"
#: ui/help-overlay.ui:145
msgid "Previous chapter"
msgstr ""
msgstr "Föregående kapitel"
#: ui/preferences-plugin-ranking-subpage.ui:11
msgid "Decoders"
msgstr ""
msgstr "Avkodare"
#: ui/preferences-plugin-ranking-subpage.ui:18
msgid "Return to the preferences"
msgstr ""
msgstr "Återgå till inställningarna"
#: ui/preferences-window.ui:16
msgid "Behavior"
msgstr ""
msgstr "Beteende"
#: ui/preferences-window.ui:19
msgid "Auto fullscreen"
msgstr ""
msgstr "Automatiskt helskärmsläge"
#: ui/preferences-window.ui:20
msgid "Enter fullscreen when playlist is replaced except floating mode"
msgstr ""
msgstr "Växla till fullskärmsläge när en spellista ersätts, förutom i flytande läge"
#: ui/preferences-window.ui:26
msgid "Ask to resume recent media"
msgstr ""
msgstr "Be att återuppta senaste media"
#: ui/preferences-window.ui:32
msgid "Float on all workspaces"
msgstr ""
msgstr "Flyt på alla arbetsytor"
#: ui/preferences-window.ui:33
msgid "This option only works on GNOME"
msgstr ""
msgstr "Det här alternativet fungerar endast i GNOME"
#: ui/preferences-window.ui:39
msgid "After playback"
msgstr ""
msgstr "Efter uppspelning"
#: ui/preferences-window.ui:44
msgid "Do nothing"
msgstr ""
msgstr "Gör ingenting"
#: ui/preferences-window.ui:45
msgid "Freeze last frame"
msgstr ""
msgstr "Frys sista bildruta"
#: ui/preferences-window.ui:46
msgid "Close the app"
msgstr ""
msgstr "Stäng appen"
#: ui/preferences-window.ui:56
msgid "Volume"
msgstr ""
msgstr "Volym"
#: ui/preferences-window.ui:59
msgid "Custom initial value"
msgstr ""
msgstr "Anpassat startvärde"
#: ui/preferences-window.ui:60
msgid "Set custom volume at startup instead of restoring it"
msgstr ""
msgstr "Ställ in anpassad volym vid start istället för att återställa den"
#: ui/preferences-window.ui:64
msgid "Volume percentage"
msgstr ""
msgstr "Volymprocent"
#: ui/preferences-window.ui:75
msgid "Seeking"
msgstr ""
msgstr "Spolning"
#: ui/preferences-window.ui:78
msgid "Mode"
msgstr ""
msgstr "Läge"
#: ui/preferences-window.ui:84
msgid "Accurate"
msgstr ""
msgstr "Riktig"
#: ui/preferences-window.ui:85
msgid "Fast"
msgstr ""
msgstr "Snabbt"
#: ui/preferences-window.ui:93
msgid "Unit"
msgstr ""
msgstr "Enhet"
#: ui/preferences-window.ui:98
msgid "Second"
msgstr ""
msgstr "Sekund"
#: ui/preferences-window.ui:99
msgid "Minute"
msgstr ""
msgstr "Minut"
#: ui/preferences-window.ui:100
msgid "Percentage"
msgstr ""
msgstr "Procent"
#: ui/preferences-window.ui:108
msgid "Value"
msgstr ""
msgstr "Värde"
#: ui/preferences-window.ui:123
msgid "Audio"
msgstr ""
msgstr "Ljud"
#: ui/preferences-window.ui:126
msgid "Offset in milliseconds"
msgstr ""
msgstr "Förskjutning i millisekunder"
#: ui/preferences-window.ui:133
msgid "Only native audio formats"
msgstr ""
msgstr "Endast inbyggda ljudformat"
#: ui/preferences-window.ui:141
msgid "Subtitles"
msgstr ""
msgstr "Undertexter"
#: ui/preferences-window.ui:144
msgid "Default font"
msgstr ""
msgstr "Standardteckensnitt"
#: ui/preferences-window.ui:154
msgid "Network"
msgstr ""
msgstr "Nätverk"
#: ui/preferences-window.ui:158
msgid "Client"
msgstr ""
msgstr "Klient"
#: ui/preferences-window.ui:161
msgid "Progressive download buffering"
msgstr ""
msgstr "Progressiv nedladdningsbuffert"
#: ui/preferences-window.ui:169
msgid "Server"
msgstr ""
msgstr "Server"
#: ui/preferences-window.ui:172
msgid "Control player remotely"
msgstr ""
msgstr "Fjärrstyra spelaren"
#: ui/preferences-window.ui:176
msgid "Listening port"
msgstr ""
msgstr "Lyssningsport"
#: ui/preferences-window.ui:183
msgid "Run web application in background"
msgstr ""
msgstr "Kör webbprogram i bakgrunden"
#: ui/preferences-window.ui:184
msgid "Requires GTK compiled with Broadway backend"
msgstr ""
msgstr "Kräver GTK kompilerad med Broadway backend"
#: ui/preferences-window.ui:190
msgid "Web application port"
msgstr ""
msgstr "Port för webbprogram"
#: ui/preferences-window.ui:204
msgid "Prefer adaptive streaming"
msgstr ""
msgstr "Föredra adaptiv streaming"
#: ui/preferences-window.ui:210
msgid "Max quality"
msgstr ""
msgstr "Max kvalitet"
#: ui/preferences-window.ui:228
msgid "Tweaks"
msgstr ""
msgstr "Tweaks"
#: ui/preferences-window.ui:232
msgid "Appearance"
msgstr ""
msgstr "Utseende"
#: ui/preferences-window.ui:235
msgid "Dark theme"
msgstr ""
msgstr "Mörkt Tema"
#: ui/preferences-window.ui:241
msgid "Render window shadows"
msgstr ""
msgstr "Rendera fönsterskuggor"
#: ui/preferences-window.ui:242
msgid "Disable to increase performance when windowed"
msgstr ""
msgstr "Inaktivera för att öka prestanda när fönsterläge är på"
#: ui/preferences-window.ui:253
msgid "Plugin ranking"
msgstr ""
msgstr "Rangordning av plugin"
#: ui/preferences-window.ui:254
msgid "Alter default ranks of GStreamer plugins"
msgstr ""
msgstr "Ändra standardrankningar för GStreamer-plugins"
#: ui/preferences-window.ui:259
msgid "Use playbin3"
msgstr ""
msgstr "Använd playbin3"
#: ui/preferences-window.ui:260 ui/preferences-window.ui:269
msgid "Requires player restart"
msgstr ""
msgstr "Kräver omstart av spelaren"
#: ui/preferences-window.ui:262 ui/preferences-window.ui:271
msgid "Experimental"
msgstr ""
msgstr "Exprimentalt"
#: ui/preferences-window.ui:268
msgid "Use PipeWire for audio output"
msgstr ""
msgstr "Använd PipeWire för Ljudutgång"
#: src/buttons.js:201
#, javascript-format
msgid "Decoder: %s"
msgstr ""
msgstr "Avkodare: %s"
#: src/dialogs.js:152
msgid "Enter or drop URI here"
msgstr ""
msgstr "Ange eller släpp URI här"
#: src/dialogs.js:157
msgid "Cancel"
msgstr ""
msgstr "Avbryt"
#: src/dialogs.js:158
msgid "Open"
msgstr ""
#: src/dialogs.js:217
msgid "Title"
msgstr ""
#: src/dialogs.js:218
msgid "Completed"
msgstr ""
msgstr "Öppna"
#: src/dialogs.js:226
msgid "Resume playback?"
msgstr ""
msgid "Title"
msgstr "Titel"
#: src/dialogs.js:280
#: src/dialogs.js:227
msgid "Completed"
msgstr "Klar"
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr "Återuppta uppspelningen?"
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
msgstr "GTK version: %s"
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:282
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:283
#, javascript-format
msgid "GJS version: %s"
msgstr ""
msgstr "Adwaita version: %s"
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr "GStreamer version: %s"
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr "GJS version: %s"
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
msgstr "En media spelare för GNOME som drivs av GStreamer"
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr "SA ST (sastofficial)"
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr ""
msgstr "Slutar vid: %s"
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
msgstr "Obestämd"
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr ""
msgstr "Kanaler"
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr ""
msgstr "Avstängd"

View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-06 18:31\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2021-09-14 15:24\n"
"Last-Translator: \n"
"Language-Team: Turkish\n"
"Language: tr_TR\n"
@@ -18,11 +18,11 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgid "Open Files"
msgstr ""
#: ui/clapper.ui:10
msgid "Open URI..."
msgid "Open URI"
msgstr ""
#: ui/clapper.ui:16 ui/preferences-window.ui:4
@@ -399,56 +399,61 @@ msgstr ""
msgid "Open"
msgstr ""
#: src/dialogs.js:217
#: src/dialogs.js:226
msgid "Title"
msgstr ""
#: src/dialogs.js:218
#: src/dialogs.js:227
msgid "Completed"
msgstr ""
#: src/dialogs.js:226
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr ""
#: src/dialogs.js:280
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:282
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:283
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr ""
#: src/dialogs.js:291
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr ""
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr ""
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr ""
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr ""

View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-06 18:30\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2021-09-14 15:24\n"
"Last-Translator: \n"
"Language-Team: Ukrainian\n"
"Language: uk_UA\n"
@@ -18,11 +18,11 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgid "Open Files"
msgstr ""
#: ui/clapper.ui:10
msgid "Open URI..."
msgid "Open URI"
msgstr ""
#: ui/clapper.ui:16 ui/preferences-window.ui:4
@@ -399,56 +399,61 @@ msgstr ""
msgid "Open"
msgstr ""
#: src/dialogs.js:217
#: src/dialogs.js:226
msgid "Title"
msgstr ""
#: src/dialogs.js:218
#: src/dialogs.js:227
msgid "Completed"
msgstr ""
#: src/dialogs.js:226
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr ""
#: src/dialogs.js:280
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:282
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:283
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr ""
#: src/dialogs.js:291
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr ""
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr ""
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr ""
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr ""

View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-06 18:30\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2021-09-14 15:24\n"
"Last-Translator: \n"
"Language-Team: Vietnamese\n"
"Language: vi_VN\n"
@@ -18,11 +18,11 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgid "Open Files"
msgstr ""
#: ui/clapper.ui:10
msgid "Open URI..."
msgid "Open URI"
msgstr ""
#: ui/clapper.ui:16 ui/preferences-window.ui:4
@@ -399,56 +399,61 @@ msgstr ""
msgid "Open"
msgstr ""
#: src/dialogs.js:217
#: src/dialogs.js:226
msgid "Title"
msgstr ""
#: src/dialogs.js:218
#: src/dialogs.js:227
msgid "Completed"
msgstr ""
#: src/dialogs.js:226
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr ""
#: src/dialogs.js:280
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:282
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:283
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr ""
#: src/dialogs.js:291
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr ""
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr ""
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr ""
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr ""

View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-06 18:30\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2022-01-16 14:15\n"
"Last-Translator: \n"
"Language-Team: Chinese Simplified\n"
"Language: zh_CN\n"
@@ -18,37 +18,37 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgstr ""
msgid "Open Files"
msgstr "打开文件…"
#: ui/clapper.ui:10
msgid "Open URI..."
msgstr ""
msgid "Open URI"
msgstr "打开 URI…"
#: ui/clapper.ui:16 ui/preferences-window.ui:4
msgid "Preferences"
msgstr ""
msgstr "选项"
#: ui/clapper.ui:20
msgid "Shortcuts"
msgstr ""
msgstr "快捷键"
#: ui/clapper.ui:26
msgid "About Clapper"
msgstr ""
msgstr "关于 Claper"
#: ui/elapsed-time-button.ui:27
msgid "Speed"
msgstr ""
msgstr "速度"
#: ui/elapsed-time-button.ui:41 ui/preferences-window.ui:83
#: ui/preferences-window.ui:215
msgid "Normal"
msgstr ""
msgstr "一般"
#: ui/help-overlay.ui:10 ui/preferences-window.ui:12
msgid "General"
msgstr ""
msgstr "常规​​​​​"
#: ui/help-overlay.ui:13
msgid "Show shortcuts"
@@ -64,11 +64,11 @@ msgstr ""
#: ui/help-overlay.ui:26
msgid "Leave fullscreen"
msgstr ""
msgstr "离开全屏"
#: ui/help-overlay.ui:32
msgid "Reveal OSD (fullscreen only)"
msgstr ""
msgstr "显示 OSD仅全屏"
#: ui/help-overlay.ui:33
msgid "Tap"
@@ -76,27 +76,27 @@ msgstr ""
#: ui/help-overlay.ui:39
msgid "Quit"
msgstr ""
msgstr "退出"
#: ui/help-overlay.ui:47
msgid "Media"
msgstr ""
msgstr "媒体"
#: ui/help-overlay.ui:50
msgid "Open files"
msgstr ""
msgstr "打开文件"
#: ui/help-overlay.ui:56 src/dialogs.js:137
msgid "Open URI"
msgstr ""
msgstr "打开 URI"
#: ui/help-overlay.ui:64
msgid "Playlist"
msgstr ""
msgstr "播放列表"
#: ui/help-overlay.ui:67
msgid "Next item"
msgstr ""
msgstr "下一项"
#: ui/help-overlay.ui:68
msgid "Double tap (right side)"
@@ -104,7 +104,7 @@ msgstr ""
#: ui/help-overlay.ui:74
msgid "Previous item"
msgstr ""
msgstr "上一项"
#: ui/help-overlay.ui:75
msgid "Double tap (left side)"
@@ -112,7 +112,7 @@ msgstr ""
#: ui/help-overlay.ui:81
msgid "Change repeat mode"
msgstr ""
msgstr "更改循环模式"
#: ui/help-overlay.ui:87
msgid "Export to file"
@@ -128,11 +128,11 @@ msgstr ""
#: ui/help-overlay.ui:99
msgid "Long press | Right click"
msgstr ""
msgstr "长按 | 右键点击"
#: ui/help-overlay.ui:105
msgid "Seek forward"
msgstr ""
msgstr "快进"
#: ui/help-overlay.ui:106
msgid "Swipe right | Scroll right"
@@ -140,7 +140,7 @@ msgstr ""
#: ui/help-overlay.ui:112
msgid "Seek backward"
msgstr ""
msgstr "快退"
#: ui/help-overlay.ui:113
msgid "Swipe left | Scroll left"
@@ -148,19 +148,19 @@ msgstr ""
#: ui/help-overlay.ui:119
msgid "Volume up"
msgstr ""
msgstr "提高音量"
#: ui/help-overlay.ui:120
msgid "Swipe up | Scroll up"
msgstr ""
msgstr "向上滑动 | 向上滚动"
#: ui/help-overlay.ui:126
msgid "Volume down"
msgstr ""
msgstr "降低音量"
#: ui/help-overlay.ui:127
msgid "Swipe down | Scroll down"
msgstr ""
msgstr "向下滑动 | 向下滚动"
#: ui/help-overlay.ui:133
msgid "Toggle mute"
@@ -176,7 +176,7 @@ msgstr ""
#: ui/preferences-plugin-ranking-subpage.ui:11
msgid "Decoders"
msgstr ""
msgstr "解码器"
#: ui/preferences-plugin-ranking-subpage.ui:18
msgid "Return to the preferences"
@@ -184,11 +184,11 @@ msgstr ""
#: ui/preferences-window.ui:16
msgid "Behavior"
msgstr ""
msgstr "行为"
#: ui/preferences-window.ui:19
msgid "Auto fullscreen"
msgstr ""
msgstr "自动全屏"
#: ui/preferences-window.ui:20
msgid "Enter fullscreen when playlist is replaced except floating mode"
@@ -204,31 +204,31 @@ msgstr ""
#: ui/preferences-window.ui:33
msgid "This option only works on GNOME"
msgstr ""
msgstr "此选项仅适用于 GNOME"
#: ui/preferences-window.ui:39
msgid "After playback"
msgstr ""
msgstr "播放结束后"
#: ui/preferences-window.ui:44
msgid "Do nothing"
msgstr ""
msgstr "不执行任何操作"
#: ui/preferences-window.ui:45
msgid "Freeze last frame"
msgstr ""
msgstr "停留在最后一帧"
#: ui/preferences-window.ui:46
msgid "Close the app"
msgstr ""
msgstr "关闭应用程序"
#: ui/preferences-window.ui:56
msgid "Volume"
msgstr ""
msgstr "音量"
#: ui/preferences-window.ui:59
msgid "Custom initial value"
msgstr ""
msgstr "自定义初始值"
#: ui/preferences-window.ui:60
msgid "Set custom volume at startup instead of restoring it"
@@ -236,47 +236,47 @@ msgstr ""
#: ui/preferences-window.ui:64
msgid "Volume percentage"
msgstr ""
msgstr "音量百分比"
#: ui/preferences-window.ui:75
msgid "Seeking"
msgstr ""
msgstr "定位播放"
#: ui/preferences-window.ui:78
msgid "Mode"
msgstr ""
msgstr "模式"
#: ui/preferences-window.ui:84
msgid "Accurate"
msgstr ""
msgstr "精确"
#: ui/preferences-window.ui:85
msgid "Fast"
msgstr ""
msgstr "快速"
#: ui/preferences-window.ui:93
msgid "Unit"
msgstr ""
msgstr "单位"
#: ui/preferences-window.ui:98
msgid "Second"
msgstr ""
msgstr "秒钟"
#: ui/preferences-window.ui:99
msgid "Minute"
msgstr ""
msgstr "分钟"
#: ui/preferences-window.ui:100
msgid "Percentage"
msgstr ""
msgstr "百分比"
#: ui/preferences-window.ui:108
msgid "Value"
msgstr ""
msgstr ""
#: ui/preferences-window.ui:123
msgid "Audio"
msgstr ""
msgstr "音频"
#: ui/preferences-window.ui:126
msgid "Offset in milliseconds"
@@ -288,19 +288,19 @@ msgstr ""
#: ui/preferences-window.ui:141
msgid "Subtitles"
msgstr ""
msgstr "字幕"
#: ui/preferences-window.ui:144
msgid "Default font"
msgstr ""
msgstr "默认字体"
#: ui/preferences-window.ui:154
msgid "Network"
msgstr ""
msgstr "网络"
#: ui/preferences-window.ui:158
msgid "Client"
msgstr ""
msgstr "客户端"
#: ui/preferences-window.ui:161
msgid "Progressive download buffering"
@@ -308,15 +308,15 @@ msgstr ""
#: ui/preferences-window.ui:169
msgid "Server"
msgstr ""
msgstr "服务器"
#: ui/preferences-window.ui:172
msgid "Control player remotely"
msgstr ""
msgstr "远程控制播放器"
#: ui/preferences-window.ui:176
msgid "Listening port"
msgstr ""
msgstr "监听端口"
#: ui/preferences-window.ui:183
msgid "Run web application in background"
@@ -328,7 +328,7 @@ msgstr ""
#: ui/preferences-window.ui:190
msgid "Web application port"
msgstr ""
msgstr "Web 应用程序端口"
#: ui/preferences-window.ui:204
msgid "Prefer adaptive streaming"
@@ -340,19 +340,19 @@ msgstr ""
#: ui/preferences-window.ui:228
msgid "Tweaks"
msgstr ""
msgstr "微调"
#: ui/preferences-window.ui:232
msgid "Appearance"
msgstr ""
msgstr "界面"
#: ui/preferences-window.ui:235
msgid "Dark theme"
msgstr ""
msgstr "暗色主题"
#: ui/preferences-window.ui:241
msgid "Render window shadows"
msgstr ""
msgstr "渲染窗口阴影"
#: ui/preferences-window.ui:242
msgid "Disable to increase performance when windowed"
@@ -368,24 +368,24 @@ msgstr ""
#: ui/preferences-window.ui:259
msgid "Use playbin3"
msgstr ""
msgstr "使用 playbin3"
#: ui/preferences-window.ui:260 ui/preferences-window.ui:269
msgid "Requires player restart"
msgstr ""
msgstr "需要重启播放器"
#: ui/preferences-window.ui:262 ui/preferences-window.ui:271
msgid "Experimental"
msgstr ""
msgstr "实验性功能"
#: ui/preferences-window.ui:268
msgid "Use PipeWire for audio output"
msgstr ""
msgstr "使用 PipeWire 输出音频"
#: src/buttons.js:201
#, javascript-format
msgid "Decoder: %s"
msgstr ""
msgstr "解码器:%s"
#: src/dialogs.js:152
msgid "Enter or drop URI here"
@@ -393,62 +393,67 @@ msgstr ""
#: src/dialogs.js:157
msgid "Cancel"
msgstr ""
msgstr "取消"
#: src/dialogs.js:158
msgid "Open"
msgstr ""
#: src/dialogs.js:217
msgid "Title"
msgstr ""
#: src/dialogs.js:218
msgid "Completed"
msgstr ""
msgstr "打开"
#: src/dialogs.js:226
msgid "Resume playback?"
msgstr ""
msgid "Title"
msgstr "标题"
#: src/dialogs.js:280
#: src/dialogs.js:227
msgid "Completed"
msgstr "已播放"
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr "继续播放?"
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
msgstr "GTK 版本:%s"
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:282
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:283
#, javascript-format
msgid "GJS version: %s"
msgstr ""
msgstr "Adwaita 版本:%s"
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr "GStreamer 版本:%s"
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr "GJS 版本:%s"
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr ""
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr ""
msgstr "结束于:%s"
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr ""
msgstr "声道"
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr ""
msgstr "禁用"

View File

@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: clapper\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-06 20:22+0200\n"
"PO-Revision-Date: 2021-09-06 18:30\n"
"POT-Creation-Date: 2021-09-14 16:35+0200\n"
"PO-Revision-Date: 2021-09-14 15:24\n"
"Last-Translator: \n"
"Language-Team: Chinese Traditional\n"
"Language: zh_TW\n"
@@ -18,11 +18,11 @@ msgstr ""
"X-Crowdin-File-ID: 31\n"
#: ui/clapper.ui:6
msgid "Open Files..."
msgid "Open Files"
msgstr ""
#: ui/clapper.ui:10
msgid "Open URI..."
msgid "Open URI"
msgstr ""
#: ui/clapper.ui:16 ui/preferences-window.ui:4
@@ -399,56 +399,61 @@ msgstr ""
msgid "Open"
msgstr ""
#: src/dialogs.js:217
#: src/dialogs.js:226
msgid "Title"
msgstr ""
#: src/dialogs.js:218
#: src/dialogs.js:227
msgid "Completed"
msgstr ""
#: src/dialogs.js:226
#: src/dialogs.js:235
msgid "Resume playback?"
msgstr ""
#: src/dialogs.js:280
#: src/dialogs.js:289
#, javascript-format
msgid "GTK version: %s"
msgstr ""
#: src/dialogs.js:281
#: src/dialogs.js:290
#, javascript-format
msgid "Adwaita version: %s"
msgstr ""
#: src/dialogs.js:282
#: src/dialogs.js:291
#, javascript-format
msgid "GStreamer version: %s"
msgstr ""
#: src/dialogs.js:283
#: src/dialogs.js:292
#, javascript-format
msgid "GJS version: %s"
msgstr ""
#: src/dialogs.js:291
#: src/dialogs.js:300
msgid "A GNOME media player powered by GStreamer"
msgstr ""
#. TRANSLATORS: Put your name(s) here for credits or leave untranslated
#: src/dialogs.js:305
msgid "translator-credits"
msgstr ""
#: src/revealers.js:170
#, javascript-format
msgid "Ends at: %s"
msgstr ""
#: src/widget.js:225 src/widget.js:234 src/widget.js:240 src/widget.js:246
#: src/widget.js:227 src/widget.js:236 src/widget.js:242 src/widget.js:248
msgid "Undetermined"
msgstr ""
#: src/widget.js:241
#: src/widget.js:243
msgid "Channels"
msgstr ""
#: src/widget.js:259
#: src/widget.js:261
msgid "Disabled"
msgstr ""

View File

@@ -18,13 +18,13 @@ var actions = {
prev_track: ['<Ctrl>Left'],
volume_up: ['Up'],
volume_down: ['Down'],
mute: ['<Ctrl>m'],
mute: ['<Ctrl>M', 'M'],
toggle_play: ['space'],
change_repeat: ['<Ctrl>r'],
change_repeat: ['<Ctrl>R'],
reveal_controls: ['Return'],
toggle_fullscreen: ['F11', 'f'],
toggle_fullscreen: ['F11', 'F'],
leave_fullscreen: ['Escape'],
quit: ['<Ctrl>q', 'q'],
quit: ['<Ctrl>Q', 'Q'],
};
function handleAction(action, window)

View File

@@ -96,13 +96,6 @@ class ClapperAppBase extends Gtk.Application
if(accels)
this.set_accels_for_action(`app.${name}`, accels);
}
const gtkSettings = Gtk.Settings.get_default();
settings.bind(
'dark-theme', gtkSettings,
'gtk-application-prefer-dark-theme',
Gio.SettingsBindFlags.GET
);
this.doneFirstActivate = true;
}
});

View File

@@ -1,25 +0,0 @@
const { GObject } = imports.gi;
const { AppBase } = imports.src.appBase;
const { HeaderBarRemote } = imports.src.headerbarRemote;
const { WidgetRemote } = imports.src.widgetRemote;
var AppRemote = GObject.registerClass({
GTypeName: 'ClapperAppRemote',
},
class ClapperAppRemote extends AppBase
{
vfunc_startup()
{
super.vfunc_startup();
const window = this.active_window;
const clapperWidget = new WidgetRemote();
window.set_child(clapperWidget);
const headerBar = new HeaderBarRemote();
window.set_titlebar(headerBar);
window.maximize();
}
});

View File

@@ -1,151 +0,0 @@
/* Copyright (C) 2012-present by fent
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
const jsVarStr = '[a-zA-Z_\\$][a-zA-Z_0-9]*';
const jsSingleQuoteStr = `'[^'\\\\]*(:?\\\\[\\s\\S][^'\\\\]*)*'`;
const jsDoubleQuoteStr = `"[^"\\\\]*(:?\\\\[\\s\\S][^"\\\\]*)*"`;
const jsQuoteStr = `(?:${jsSingleQuoteStr}|${jsDoubleQuoteStr})`;
const jsKeyStr = `(?:${jsVarStr}|${jsQuoteStr})`;
const jsPropStr = `(?:\\.${jsVarStr}|\\[${jsQuoteStr}\\])`;
const jsEmptyStr = `(?:''|"")`;
const reverseStr = ':function\\(a\\)\\{' +
'(?:return )?a\\.reverse\\(\\)' +
'\\}';
const sliceStr = ':function\\(a,b\\)\\{' +
'return a\\.slice\\(b\\)' +
'\\}';
const spliceStr = ':function\\(a,b\\)\\{' +
'a\\.splice\\(0,b\\)' +
'\\}';
const swapStr = ':function\\(a,b\\)\\{' +
'var c=a\\[0\\];a\\[0\\]=a\\[b(?:%a\\.length)?\\];a\\[b(?:%a\\.length)?\\]=c(?:;return a)?' +
'\\}';
const actionsObjRegexp = new RegExp(
`var (${jsVarStr})=\\{((?:(?:${
jsKeyStr}${reverseStr}|${
jsKeyStr}${sliceStr}|${
jsKeyStr}${spliceStr}|${
jsKeyStr}${swapStr
}),?\\r?\\n?)+)\\};`);
const actionsFuncRegexp = new RegExp(`${`function(?: ${jsVarStr})?\\(a\\)\\{` +
`a=a\\.split\\(${jsEmptyStr}\\);\\s*` +
`((?:(?:a=)?${jsVarStr}`}${
jsPropStr
}\\(a,\\d+\\);)+)` +
`return a\\.join\\(${jsEmptyStr}\\)` +
`\\}`);
const reverseRegexp = new RegExp(`(?:^|,)(${jsKeyStr})${reverseStr}`, 'm');
const sliceRegexp = new RegExp(`(?:^|,)(${jsKeyStr})${sliceStr}`, 'm');
const spliceRegexp = new RegExp(`(?:^|,)(${jsKeyStr})${spliceStr}`, 'm');
const swapRegexp = new RegExp(`(?:^|,)(${jsKeyStr})${swapStr}`, 'm');
const swapHeadAndPosition = (arr, position) => {
const first = arr[0];
arr[0] = arr[position % arr.length];
arr[position] = first;
return arr;
}
function decipher(sig, tokens) {
sig = sig.split('');
tokens = tokens.split(',');
for(let i = 0, len = tokens.length; i < len; i++) {
let token = tokens[i], pos;
switch (token[0]) {
case 'r':
sig = sig.reverse();
break;
case 'w':
pos = ~~token.slice(1);
sig = swapHeadAndPosition(sig, pos);
break;
case 's':
pos = ~~token.slice(1);
sig = sig.slice(pos);
break;
case 'p':
pos = ~~token.slice(1);
sig.splice(0, pos);
break;
}
}
return sig.join('');
};
function extractActions(body) {
const objResult = actionsObjRegexp.exec(body);
const funcResult = actionsFuncRegexp.exec(body);
if(!objResult || !funcResult)
return null;
const obj = objResult[1].replace(/\$/g, '\\$');
const objBody = objResult[2].replace(/\$/g, '\\$');
const funcBody = funcResult[1].replace(/\$/g, '\\$');
let result = reverseRegexp.exec(objBody);
const reverseKey = result && result[1]
.replace(/\$/g, '\\$')
.replace(/\$|^'|^"|'$|"$/g, '');
result = sliceRegexp.exec(objBody);
const sliceKey = result && result[1]
.replace(/\$/g, '\\$')
.replace(/\$|^'|^"|'$|"$/g, '');
result = spliceRegexp.exec(objBody);
const spliceKey = result && result[1]
.replace(/\$/g, '\\$')
.replace(/\$|^'|^"|'$|"$/g, '');
result = swapRegexp.exec(objBody);
const swapKey = result && result[1]
.replace(/\$/g, '\\$')
.replace(/\$|^'|^"|'$|"$/g, '');
const keys = `(${[reverseKey, sliceKey, spliceKey, swapKey].join('|')})`;
const myreg = `(?:a=)?${obj
}(?:\\.${keys}|\\['${keys}'\\]|\\["${keys}"\\])` +
`\\(a,(\\d+)\\)`;
const tokenizeRegexp = new RegExp(myreg, 'g');
const tokens = [];
while((result = tokenizeRegexp.exec(funcBody)) !== null) {
const key = result[1] || result[2] || result[3];
const pos = result[4];
switch (key) {
case swapKey:
tokens.push(`w${result[4]}`);
break;
case reverseKey:
tokens.push('r');
break;
case sliceKey:
tokens.push(`s${result[4]}`);
break;
case spliceKey:
tokens.push(`p${result[4]}`);
break;
}
}
return tokens.join(',');
}

View File

@@ -165,7 +165,7 @@ class ClapperElapsedTimeButton extends PopoverButtonBase
setInitialState()
{
this.label = '00:00/00:00';
this.label = '00000000';
}
setFullscreenMode(isFullscreen, isMobileMonitor)

6
src/controls.js vendored
View File

@@ -7,8 +7,6 @@ const Revealers = imports.src.revealers;
const { debug } = Debug;
const { settings } = Misc;
const INITIAL_ELAPSED = '00:00/00:00';
var Controls = GObject.registerClass({
GTypeName: 'ClapperControls',
},
@@ -29,7 +27,7 @@ class ClapperControls extends Gtk.Box
this.isMobile = false;
this.showHours = false;
this.durationFormatted = '00:00';
this.durationFormatted = '0000';
this.revealersArr = [];
this.chapters = null;
@@ -148,7 +146,7 @@ class ClapperControls extends Gtk.Box
value = value || 0;
const elapsed = Misc.getFormattedTime(value, this.showHours)
+ '/' + this.durationFormatted;
+ '' + this.durationFormatted;
this.elapsedButton.label = elapsed;
}

View File

@@ -1,70 +0,0 @@
const { Gio, GLib, GObject } = imports.gi;
const Debug = imports.src.debug;
const { debug } = Debug;
var Daemon = GObject.registerClass({
GTypeName: 'ClapperDaemon',
},
class ClapperDaemon extends Gio.SubprocessLauncher
{
_init()
{
const port = ARGV[0] || 8080;
/* FIXME: show output when debugging is on */
const flags = Gio.SubprocessFlags.STDOUT_SILENCE
| Gio.SubprocessFlags.STDERR_SILENCE;
super._init({ flags });
this.errMsg = 'exited with error or was forced to close';
this.loop = GLib.MainLoop.new(null, false);
this.broadwayd = this.spawnv(['gtk4-broadwayd', '--port=' + port]);
this.broadwayd.wait_async(null, this._onBroadwaydClosed.bind(this));
this.setenv('GDK_BACKEND', 'broadway', true);
const remoteApp = this.spawnv(['com.github.rafostar.Clapper.Remote']);
remoteApp.wait_async(null, this._onRemoteClosed.bind(this));
this.loop.run();
}
_checkProcResult(proc, result)
{
let hadError = false;
try {
hadError = proc.wait_finish(result);
}
catch(err) {
debug(err);
}
return hadError;
}
_onBroadwaydClosed(proc, result)
{
const hadError = this._checkProcResult(proc, result);
if(hadError)
debug(`broadwayd ${this.errMsg}`);
this.broadwayd = null;
this.loop.quit();
}
_onRemoteClosed(proc, result)
{
const hadError = this._checkProcResult(proc, result);
if(hadError)
debug(`remote app ${this.errMsg}`);
if(this.broadwayd)
this.broadwayd.force_exit();
}
});

View File

@@ -1,165 +0,0 @@
const Debug = imports.src.debug;
const FileOps = imports.src.fileOps;
const Misc = imports.src.misc;
const { debug } = Debug;
function generateDash(dashInfo)
{
debug('generating dash');
const bufferSec = Math.min(4, dashInfo.duration);
const dash = [
`<?xml version="1.0" encoding="UTF-8"?>`,
`<MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"`,
` xmlns="urn:mpeg:dash:schema:mpd:2011"`,
` xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd"`,
` type="static"`,
` mediaPresentationDuration="PT${dashInfo.duration}S"`,
` minBufferTime="PT${bufferSec}S"`,
` profiles="urn:mpeg:dash:profile:isoff-on-demand:2011">`,
` <Period>`
];
for(let adaptation of dashInfo.adaptations)
dash.push(_addAdaptationSet(adaptation));
dash.push(
` </Period>`,
`</MPD>`
);
debug('dash generated');
return dash.join('\n');
}
function _addAdaptationSet(streamsArr)
{
/* We just need it for adaptation type,
* so any stream will do */
const { mimeInfo } = streamsArr[0];
const adaptArr = [
`contentType="${mimeInfo.content}"`,
`mimeType="${mimeInfo.type}"`,
`subsegmentAlignment="true"`,
`subsegmentStartsWithSAP="1"`,
];
const widthArr = [];
const heightArr = [];
const fpsArr = [];
const representations = [];
for(let stream of streamsArr) {
/* No point parsing if no URL */
if(!stream.url)
continue;
if(stream.width && stream.height) {
widthArr.push(stream.width);
heightArr.push(stream.height);
}
if(stream.fps)
fpsArr.push(stream.fps);
representations.push(_getStreamRepresentation(stream));
}
if(widthArr.length && heightArr.length) {
const maxWidth = Math.max.apply(null, widthArr);
const maxHeight = Math.max.apply(null, heightArr);
const par = _getPar(maxWidth, maxHeight);
adaptArr.push(`maxWidth="${maxWidth}"`);
adaptArr.push(`maxHeight="${maxHeight}"`);
adaptArr.push(`par="${par}"`);
}
if(fpsArr.length) {
const maxFps = Math.max.apply(null, fpsArr);
adaptArr.push(`maxFrameRate="${maxFps}"`);
}
const adaptationSet = [
` <AdaptationSet ${adaptArr.join(' ')}>`,
representations.join('\n'),
` </AdaptationSet>`
];
return adaptationSet.join('\n');
}
function _getStreamRepresentation(stream)
{
const repOptsArr = [
`id="${stream.itag}"`,
`codecs="${stream.mimeInfo.codecs}"`,
`bandwidth="${stream.bitrate}"`,
];
if(stream.width && stream.height) {
repOptsArr.push(`width="${stream.width}"`);
repOptsArr.push(`height="${stream.height}"`);
repOptsArr.push(`sar="1:1"`);
}
if(stream.fps)
repOptsArr.push(`frameRate="${stream.fps}"`);
const repArr = [
` <Representation ${repOptsArr.join(' ')}>`,
];
if(stream.audioChannels) {
const audioConfArr = [
`schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011"`,
`value="${stream.audioChannels}"`,
];
repArr.push(` <AudioChannelConfiguration ${audioConfArr.join(' ')}/>`);
}
repArr.push(
` <BaseURL>${stream.url}</BaseURL>`
);
if(stream.indexRange) {
const segRange = `${stream.indexRange.start}-${stream.indexRange.end}`;
repArr.push(
` <SegmentBase indexRange="${segRange}">`
);
if(stream.initRange) {
const initRange = `${stream.initRange.start}-${stream.initRange.end}`;
repArr.push(
` <Initialization range="${initRange}"/>`
);
}
repArr.push(
` </SegmentBase>`
);
}
repArr.push(
` </Representation>`
);
return repArr.join('\n');
}
function _getPar(width, height)
{
const gcd = _getGCD(width, height);
width /= gcd;
height /= gcd;
return `${width}:${height}`;
}
function _getGCD(width, height)
{
return (height)
? _getGCD(height, width % height)
: width;
}

View File

@@ -20,17 +20,6 @@ clapperDebugger.enabled = (
&& G_DEBUG_ENV.includes('Clapper')
);
const ytDebugger = new Debug.Debugger('YouTube', {
name_printer: new Ink.Printer({
font: Ink.Font.BOLD,
color: Ink.Color.RED
}),
time_printer: new Ink.Printer({
color: Ink.Color.LIGHT_BLUE
}),
high_precision: true,
});
function _logStructured(debuggerName, msg, level)
{
GLib.log_structured(
@@ -52,14 +41,7 @@ function _debug(debuggerName, msg)
return;
}
switch(debuggerName) {
case 'Clapper':
clapperDebugger.debug(msg);
break;
case 'YouTube':
ytDebugger.debug(msg);
break;
}
clapperDebugger.debug(msg);
}
function debug(msg)
@@ -67,11 +49,6 @@ function debug(msg)
_debug('Clapper', msg);
}
function ytDebug(msg)
{
_debug('YouTube', msg);
}
function warn(msg)
{
_logStructured('Clapper', msg, GLib.LogLevelFlags.LEVEL_WARNING);

View File

@@ -193,8 +193,17 @@ class ClapperUriDialog extends Gtk.Dialog
_readTextAsyncCb(clipboard, result)
{
const uri = clipboard.read_text_finish(result);
if(!uri || !Gst.uri_is_valid(uri)) return;
let uri = null;
try {
uri = clipboard.read_text_finish(result);
}
catch(err) {
debug(`could not read clipboard: ${err.message}`);
}
if(!uri || !Gst.uri_is_valid(uri))
return;
const contentBox = this.get_content_area();
const linkEntry = contentBox.get_last_child();
@@ -292,6 +301,8 @@ class ClapperAboutDialog extends Gtk.AboutDialog
version: pkg.version,
authors: ['Rafał Dzięgiel'],
artists: ['Rafał Dzięgiel'],
/* TRANSLATORS: Put your name(s) here for credits or leave untranslated */
translator_credits: _('translator-credits'),
license_type: Gtk.License.GPL_3_0,
logo_icon_name: 'com.github.rafostar.Clapper',
website: 'https://rafostar.github.io/clapper',

View File

@@ -1,22 +0,0 @@
const { GObject } = imports.gi;
const { HeaderBarBase } = imports.src.headerbarBase;
var HeaderBarRemote = GObject.registerClass({
GTypeName: 'ClapperHeaderBarRemote',
},
class ClapperHeaderBarRemote extends HeaderBarBase
{
_init()
{
super._init();
this.extraButtonsBox.visible = false;
}
_onWindowButtonActivate(action)
{
if(action === 'toggle-maximized')
action = 'toggle_maximized';
this.root.child.sendWs(action);
}
});

View File

@@ -1,6 +1,6 @@
imports.gi.versions.Gdk = '4.0';
imports.gi.versions.Gtk = '4.0';
imports.gi.versions.Soup = '2.4';
imports.gi.versions.Soup = '3.0';
pkg.initGettext();
pkg.initFormat();

View File

@@ -1,6 +0,0 @@
const { Daemon } = imports.src.daemon;
function main()
{
new Daemon();
}

View File

@@ -1,19 +0,0 @@
imports.gi.versions.Gdk = '4.0';
imports.gi.versions.Gtk = '4.0';
imports.gi.versions.Soup = '2.4';
pkg.initGettext();
const Misc = imports.src.misc;
Misc.appId += '.Remote';
const { Gtk, Adw } = imports.gi;
const { AppRemote } = imports.src.appRemote;
function main(argv)
{
Gtk.init();
Adw.init();
new AppRemote().run(argv);
}

Some files were not shown because too many files have changed in this diff Show More