394 Commits

Author SHA1 Message Date
Rafał Dzięgiel
aa0be37cb9 New translations clapper-app.pot (Arabic) 2025-06-14 19:10:30 +02:00
Rafał Dzięgiel
9aee805b6d New translations clapper-app.pot (Arabic) 2025-06-14 17:48:59 +02:00
Rafał Dzięgiel
6ee406c11d New translations clapper-gtk.pot (Arabic) 2025-06-14 17:48:58 +02:00
Rafał Dzięgiel
fcc41b2e9c New translations clapper-app.pot (Persian) 2025-05-18 16:52:10 +02:00
Rafał Dzięgiel
fb8ee8497a New translations clapper-gtk.pot (Chinese Simplified) 2025-05-08 09:56:58 +02:00
Rafał Dzięgiel
3ba2611901 New translations clapper-app.pot (Chinese Simplified) 2025-05-01 15:53:00 +02:00
Rafał Dzięgiel
f5731957dc New Crowdin updates (#524)
* New translations clapper-app.pot (Chinese Simplified)

* New translations clapper-app.pot (Chinese Simplified)

* New translations clapper-app.pot (Romanian)

* New translations clapper-app.pot (French)

* New translations clapper-app.pot (Spanish)

* New translations clapper-app.pot (Afrikaans)

* New translations clapper-app.pot (Arabic)

* New translations clapper-app.pot (Catalan)

* New translations clapper-app.pot (Czech)

* New translations clapper-app.pot (Danish)

* New translations clapper-app.pot (German)

* New translations clapper-app.pot (Greek)

* New translations clapper-app.pot (Basque)

* New translations clapper-app.pot (Finnish)

* New translations clapper-app.pot (Hebrew)

* New translations clapper-app.pot (Hungarian)

* New translations clapper-app.pot (Italian)

* New translations clapper-app.pot (Japanese)

* New translations clapper-app.pot (Korean)

* New translations clapper-app.pot (Lithuanian)

* New translations clapper-app.pot (Dutch)

* New translations clapper-app.pot (Norwegian)

* New translations clapper-app.pot (Polish)

* New translations clapper-app.pot (Portuguese)

* New translations clapper-app.pot (Russian)

* New translations clapper-app.pot (Slovak)

* New translations clapper-app.pot (Serbian (Cyrillic))

* New translations clapper-app.pot (Swedish)

* New translations clapper-app.pot (Turkish)

* New translations clapper-app.pot (Ukrainian)

* New translations clapper-app.pot (Chinese Simplified)

* New translations clapper-app.pot (Chinese Traditional)

* New translations clapper-app.pot (Vietnamese)

* New translations clapper-app.pot (Portuguese, Brazilian)

* New translations clapper-app.pot (Persian)

* New translations clapper-app.pot (Croatian)

* New translations clapper-app.pot (Hindi)

* New translations clapper-app.pot (Asturian)

* New translations clapper-app.pot (Occitan)

* New translations clapper-app.pot (Persian)

* New translations clapper-app.pot (Portuguese, Brazilian)

* New translations clapper-app.pot (Finnish)

* New translations clapper-app.pot (Russian)

* New translations clapper-gtk.pot (Russian)

* New translations clapper-app.pot (French)

* New translations clapper-app.pot (Portuguese)

* New translations clapper-app.pot (German)
2025-04-27 15:20:33 +02:00
Rafał Dzięgiel
2e3c98d9b4 Merge pull request #530 from Rafostar/pipeline-preview-launcher
Ability to show GStreamer pipeline
2025-04-27 13:04:04 +02:00
Rafał Dzięgiel
d09824fb1a clapper-app: Show error dialog on pipeline preview failure 2025-04-26 21:25:13 +02:00
Rafał Dzięgiel
366315077e clapper-app: Use user data dir for storing pipeline exports
System tmp directory does not work within containers such as Flatpak
for our usage with file launcher, so make our own temp in app data dir
2025-04-26 18:33:02 +02:00
Rafał Dzięgiel
a75184a471 flatpak: Build graphviz
Needed for pipeline preview app functionality
2025-04-26 18:32:59 +02:00
Rafał Dzięgiel
5bd6ba8948 meson: Add "pipeline-preview" to printed summary 2025-04-26 18:32:57 +02:00
Rafał Dzięgiel
160dbce265 clapper-app: Add "show pipeline" key shortcut to help overlay 2025-04-26 18:32:55 +02:00
Rafał Dzięgiel
224326857b clapper-app: Create pipeline preview file async 2025-04-26 18:32:42 +02:00
Rafał Dzięgiel
f9b31c51a7 Merge pull request #538 from fritteli/fix-typo-in-german-translation
chore: Fix typo in german translation
2025-04-11 20:11:27 +02:00
Manuel Friedli
be1de8bc77 chore: Fix typo in german translation 2025-04-04 23:06:42 +02:00
Rafał Dzięgiel
b8a4a90b6c clapper-app: Delete temp dir on exit
Pipeline preview creates temp files, so delete whole directory
recursively on app exit. Since these files are used through
launcher/portal with another app, we do not know when user finished
using them, thus we cannot detect and remove them earlier.
2025-02-18 18:30:09 +01:00
Rafał Dzięgiel
d73f33785d clapper-app: Fix a file path in POTFILES
Since #479 "window" was renamed to "dialog".
We also need to update POTFILES accordingly.
2025-02-16 17:49:11 +01:00
Rafał Dzięgiel
dca8fbd336 clapper-app: Add GStreamer pipeline preview
Allow to preview GStreamer pipeline while playing content.
This makes it easier to check what is used underneath.
2025-02-16 17:36:05 +01:00
Rafał Dzięgiel
681d5b8699 clapper: Add a function to get pipeline graph data 2025-02-16 17:23:34 +01:00
Rafał Dzięgiel
009f272f64 Merge pull request #479 from geopjr-forks/fix/adw-1-6-deprecations
clapper-app: Fix libadwaita 1.6 deprecations
2025-02-16 13:22:54 +01:00
Evan Paterakis
a5bc1b5578 clapper-app: set uri-dialog's content width to 420
Co-authored-by: Rafał Dzięgiel <40623528+Rafostar@users.noreply.github.com>
2025-02-15 19:17:04 +02:00
Rafał Dzięgiel
49471882c1 clapper-app: Update POT file 2025-02-15 12:48:42 +01:00
Evan Paterakis
069be30225 clapper-app: fix adw 1.6 deprecations 2025-02-12 17:49:22 +02:00
Rafał Dzięgiel
5f83d93374 Merge pull request #525 from abhijeeth-babu/patch-1
Remove "Music" from Clapper's keywords to lower its priority as a music player
2025-02-10 19:59:51 +01:00
Rafał Dzięgiel
d0a9122833 Merge pull request #528 from Rafostar/ci-arm64
workflows: Build natively on arm64
2025-02-10 19:26:16 +01:00
Rafał Dzięgiel
c29b8871a3 workflows: Build natively on arm64
Replace QEMU with native arm64 runners, now that they are available
2025-02-10 18:21:37 +01:00
Rafał Dzięgiel
d4d0f9e95e flatpak: Sync with Flathub 2025-02-08 12:48:37 +01:00
Rafał Dzięgiel
291c6e35f2 Back to development 2025-02-08 11:48:12 +01:00
Abhijeeth Babu
69bace7150 Remove other unneeded keywords (Album, GNOME, Clapper) from desktop file 2025-01-27 22:57:01 +05:30
Abhijeeth Babu
401e33b1c0 Remove "Music" from Clapper's keywords to lower its priority as a music player
This PR removes the keyword "Music" from Clapper's `.desktop` file to lower its priority as a music player in desktop search results. This ensures that Clapper is not prominently suggested when searching for music-related applications, while retaining its functionality as a video player.

### Changes:
- Removed "Music" from the `Keywords` field in the `.desktop` file.

This change does not affect Clapper's ability to play audio files but adjusts its visibility in application search results.
2025-01-25 22:10:10 +05:30
Rafał Dzięgiel
a449b6b3f5 0.8.0 2025-01-20 21:29:59 +01:00
Rafał Dzięgiel
2d12c8980d clapper-app: Update LINGUAS file 2025-01-20 21:17:53 +01:00
Rafał Dzięgiel
ea102ed870 clapper-gtk: Update LINGUAS file 2025-01-20 21:17:13 +01:00
Rafał Dzięgiel
ee6f3cccdb New Crowdin updates (#517)
* New translations clapper-gtk.pot (German)

* New translations clapper-app.pot (German)

* New translations clapper-app.pot (German)

* New translations clapper-app.pot (Portuguese)

* New translations clapper-gtk.pot (Portuguese)

* New translations clapper-app.pot (Portuguese)

* New translations clapper-app.pot (Russian)

* New translations clapper-app.pot (French)

* New translations clapper-gtk.pot (French)

* New translations clapper-app.pot (French)

* New translations clapper-app.pot (Chinese Simplified)

* New translations clapper-app.pot (Chinese Simplified)

* New translations clapper-gtk.pot (Polish)

* New translations clapper-app.pot (Polish)

* New translations clapper-gtk.pot (Romanian)

* New translations clapper-app.pot (Romanian)

* New translations clapper-app.pot (Romanian)
2025-01-20 21:13:13 +01:00
Rafał Dzięgiel
63d393662e metainfo: Update version history 2025-01-20 20:46:59 +01:00
Rafał Dzięgiel
80285fb50b clapper: Fix importing enhancers with extra path
We cannot use "goto" here, like it was before, as we would fall into an endless loop.
2025-01-20 17:43:48 +01:00
Rafał Dzięgiel
e9377f0c6a Merge pull request #519 from Rafostar/misc-fixes
Miscellaneous fixes
2025-01-19 18:02:10 +01:00
Rafał Dzięgiel
ce102b9c76 workflows: Use flatpak-builder action master version
Since "flatpak-builder" action uses deprecated "upload-artifact"
version, that can stop working soon, disable it and upload ourselves.
This is supported in master, but not in any tagged version,
so for now switch to using action from master branch.

Also bump used runtime to GNOME 47 when building.
2025-01-19 17:42:08 +01:00
Rafał Dzięgiel
4df812066f clapper: enhancers-loader: Support loading extra enhancers
Allow setting an additional dir(s) with "CLAPPER_ENHANCERS_EXTRA_PATH" env.

This should allow to add other enhancers without removing default ones.
If app/user needs to remove default ones, "CLAPPER_ENHANCERS_PATH" env
can be set to empty.
2025-01-19 15:48:45 +01:00
Rafał Dzięgiel
8752d08113 clapper: enhancers-loader: Fix default enhancers dir on Win32 2025-01-19 15:48:34 +01:00
Rafał Dzięgiel
fe30ba24fa clapper-gtk: extra-menu-button: Drop popover focus on unmap
Fixes #496
2025-01-18 18:31:03 +01:00
Rafał Dzięgiel
4472d87f8b clapper-app: Show sink bin child name in info window
Sinks that are bin types often take another configurable sink through a property.
We want to show what was set there in info window too.
2025-01-18 17:27:39 +01:00
Rafał Dzięgiel
e35d04a742 clapper-app: Fix internal functions visibility
We have to export functions that are used from UI files, otherwise they are
not accessible. For this reason add a special internal visibility header.
2025-01-18 15:59:12 +01:00
Rafał Dzięgiel
f017b23798 Merge pull request #518 from Rafostar/win-installer
Provide Windows installer
2025-01-18 11:50:42 +01:00
Rafał Dzięgiel
3513c37f97 clapper-app: Fix declaration-after-statement warning 2025-01-17 21:57:34 +01:00
Rafał Dzięgiel
2225cc68c4 workflows: windows: Add cleanup step
Removal of things that will not be used in an installed app
2025-01-17 21:57:11 +01:00
Rafał Dzięgiel
228ef3e556 workflows: windows: Create installer instead of portable
It makes things much easier for the user, such as automatically associating
video files with Clapper, makes menu entries, optional desktop icon and takes
care of eventual uninstall and/or update later.
2025-01-17 21:53:36 +01:00
Rafał Dzięgiel
21417a1ae7 pkgs: Generate Inno Setup based Windows installer 2025-01-17 21:53:20 +01:00
Rafał Dzięgiel
5906d1b78e clapper-app: Add Windows icon 2025-01-17 21:51:16 +01:00
Rafał Dzięgiel
b7b33172fe New Crowdin updates (#514)
* New translations clapper-gtk.pot (Romanian)

* New translations clapper-app.pot (Romanian)

* New translations clapper-gtk.pot (French)

* New translations clapper-app.pot (French)

* New translations clapper-gtk.pot (Spanish)

* New translations clapper-app.pot (Spanish)

* New translations clapper-gtk.pot (Afrikaans)

* New translations clapper-app.pot (Afrikaans)

* New translations clapper-gtk.pot (Arabic)

* New translations clapper-app.pot (Arabic)

* New translations clapper-gtk.pot (Catalan)

* New translations clapper-app.pot (Catalan)

* New translations clapper-gtk.pot (Czech)

* New translations clapper-app.pot (Czech)

* New translations clapper-gtk.pot (Danish)

* New translations clapper-app.pot (Danish)

* New translations clapper-gtk.pot (German)

* New translations clapper-app.pot (German)

* New translations clapper-gtk.pot (Greek)

* New translations clapper-app.pot (Greek)

* New translations clapper-gtk.pot (Basque)

* New translations clapper-app.pot (Basque)

* New translations clapper-gtk.pot (Finnish)

* New translations clapper-app.pot (Finnish)

* New translations clapper-gtk.pot (Hebrew)

* New translations clapper-app.pot (Hebrew)

* New translations clapper-gtk.pot (Hungarian)

* New translations clapper-app.pot (Hungarian)

* New translations clapper-gtk.pot (Italian)

* New translations clapper-app.pot (Italian)

* New translations clapper-gtk.pot (Japanese)

* New translations clapper-app.pot (Japanese)

* New translations clapper-gtk.pot (Korean)

* New translations clapper-app.pot (Korean)

* New translations clapper-gtk.pot (Lithuanian)

* New translations clapper-app.pot (Lithuanian)

* New translations clapper-gtk.pot (Dutch)

* New translations clapper-app.pot (Dutch)

* New translations clapper-gtk.pot (Norwegian)

* New translations clapper-app.pot (Norwegian)

* New translations clapper-gtk.pot (Polish)

* New translations clapper-app.pot (Polish)

* New translations clapper-gtk.pot (Portuguese)

* New translations clapper-app.pot (Portuguese)

* New translations clapper-gtk.pot (Russian)

* New translations clapper-app.pot (Russian)

* New translations clapper-gtk.pot (Slovak)

* New translations clapper-app.pot (Slovak)

* New translations clapper-gtk.pot (Serbian (Cyrillic))

* New translations clapper-app.pot (Serbian (Cyrillic))

* New translations clapper-gtk.pot (Swedish)

* New translations clapper-app.pot (Swedish)

* New translations clapper-gtk.pot (Turkish)

* New translations clapper-app.pot (Turkish)

* New translations clapper-gtk.pot (Ukrainian)

* New translations clapper-app.pot (Ukrainian)

* New translations clapper-gtk.pot (Chinese Simplified)

* New translations clapper-app.pot (Chinese Simplified)

* New translations clapper-gtk.pot (Chinese Traditional)

* New translations clapper-app.pot (Chinese Traditional)

* New translations clapper-gtk.pot (Vietnamese)

* New translations clapper-app.pot (Vietnamese)

* New translations clapper-gtk.pot (Portuguese, Brazilian)

* New translations clapper-app.pot (Portuguese, Brazilian)

* New translations clapper-gtk.pot (Persian)

* New translations clapper-app.pot (Persian)

* New translations clapper-gtk.pot (Croatian)

* New translations clapper-app.pot (Croatian)

* New translations clapper-gtk.pot (Hindi)

* New translations clapper-app.pot (Hindi)

* New translations clapper-gtk.pot (Asturian)

* New translations clapper-app.pot (Asturian)

* New translations clapper-gtk.pot (Occitan)

* New translations clapper-app.pot (Occitan)
2025-01-13 18:32:37 +01:00
Rafał Dzięgiel
d4d82034a4 Merge pull request #515 from Rafostar/win-hi-clock
clapper-app: Support high resolution clock on MS Windows
2025-01-12 20:47:59 +01:00
Rafał Dzięgiel
09b3ef8f39 clapper-app: Do not enforce GSK renderer on Windows 2025-01-12 17:12:33 +01:00
Rafał Dzięgiel
d9b20dcc18 clapper-app: Support Windows high resolution clock
Windows high resolution clock improves accuracy of various Windows
timer APIs and precision of GstSystemClock during playback
2025-01-12 17:12:24 +01:00
Rafał Dzięgiel
60e7d56611 clapper-app: Update POT file 2025-01-11 15:24:07 +01:00
Rafał Dzięgiel
e3bc87ba11 clapper-app: Add "Clear Queue" menu option
An option to clear playback queue from UI. This is quckier
and easier than manually dragging every item to bin.

Closes #434
2025-01-11 15:17:50 +01:00
Rafał Dzięgiel
b542aa1e76 clapper: Wait with flush after streams are selected
Instead flushing right after select streams request, wait until
they are selected before doing a flush.

This fixes a hang when changing audio language with hlsdemux2.
2025-01-10 23:54:29 +01:00
Rafał Dzięgiel
6534fb1e22 clapper-app: Update LINGUAS file 2025-01-07 19:22:15 +01:00
Rafał Dzięgiel
c8b3e28299 clapper-gtk: Update LINGUAS file 2025-01-07 19:21:58 +01:00
Rafał Dzięgiel
35424bf8cf clapper-app: Update POT file 2025-01-07 19:06:11 +01:00
Rafał Dzięgiel
6989b86249 clapper-gtk: Update POT file 2025-01-07 19:05:57 +01:00
Rafał Dzięgiel
fed0c0a972 clapper-app: Add do not translate desktop app name comment 2025-01-07 19:03:10 +01:00
Rafał Dzięgiel
496cc60272 Merge pull request #512 from Rafostar/video-placeholder
clapper-gtk: Add video placeholder widget
2025-01-02 14:18:52 +01:00
Rafał Dzięgiel
a91ce5b0ab clapper-gtk: Add video placeholder widget
A simple placeholder to be shown when "ClapperGtkVideo" is used with a video
sink that cannot be embedded in it (with a text explaining that).
2025-01-02 13:34:36 +01:00
Rafał Dzięgiel
93b1be3147 New Crowdin updates (#503)
* New translations clapper-app.pot (Turkish)

* New translations clapper-gtk.pot (Spanish)

* New translations clapper-app.pot (Spanish)
2024-11-22 22:41:54 +01:00
Rafał Dzięgiel
cca4b002b6 Merge pull request #492 from danialbehzadi/i18n
Make dektop file i18n.
2024-11-22 22:40:50 +01:00
Rafał Dzięgiel
8e6599ae81 Merge pull request #508 from Rafostar/nightly-fix
Update Flatpak Nightly
2024-11-16 22:33:31 +01:00
Rafał Dzięgiel
77ee519f8c flatpak-nightly: Update manifest
Use 24.08 for ffmpeg and switch to Rust stable with added recommended env vars
2024-11-16 17:25:49 +01:00
Rafał Dzięgiel
c42e12d2be workflows: Update nightly extensions to 24.08
Also change to Rust stable to fix build failing
2024-11-16 17:25:03 +01:00
Rafał Dzięgiel
2b916ef856 Merge pull request #506 from Rafostar/adaptive
Add adaptive streaming bitrate control to Clapper API
2024-11-16 16:15:19 +01:00
Rafał Dzięgiel
303bda4d65 clapper: Do not reset "adaptive-bandwidth" to zero
When new instance of adaptive demuxer is created (different video is played)
this prop value would become zero. We want to avoid that and instead report
only bandwidth after fragment is downloaded, so when video will be unplayable,
next one will not start from lowest quality.
2024-11-16 15:26:24 +01:00
Rafał Dzięgiel
22430620a8 clapper-app: Apply "adaptive-start-bitrate" on startup
Watch for "adaptive-bandwidth" changes during adaptive streaming, use these to
set "adaptive-start-bitrate" player property, so we do not always start streaming
from some constant bitrate value which might not be the best for everyone.

Additionally, store last value in GSettings on app exit and also add a command
line arg to set this too.
2024-11-15 23:39:00 +01:00
Rafał Dzięgiel
e4045b98b3 clapper: Add "adaptive-bandwidth" readable property
Apps can use it to determine and set an optimal value for
start bitrate instead of starting at some constant value.
2024-11-15 23:38:50 +01:00
Rafał Dzięgiel
aa819cf2d3 flatpak: Update runtime to 47 2024-11-14 23:19:38 +01:00
Rafał Dzięgiel
a065b81846 flatpak: Add GStreamer 1.24 for testing
We do not yet have GStreamer 1.24 in Flathub repo, so for testing purposes add it here temporarily
2024-11-14 23:18:16 +01:00
Rafał Dzięgiel
9fbba4d66a meson: Bump min required GStreamer version
Setting "start-bitrate" property requires at least GStreamer 1.24.

We do not want to introduce APIs that work only if user has a certain
dependency version, thus this bump instead of version check.

Related work on GStreamer side:
https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3894
https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3895

Since these were contributed to GStreamer almost 2 years ago with the intention
of using them in Clapper, I think its about time to start do so.
2024-11-14 22:28:21 +01:00
Rafał Dzięgiel
ab659d0951 clapper: Use playbin3 by default
New GStreamer adaptive demuxers work only within playbin3. In order to not
introduce new APIs (setting adaptive bitrate) that do not work by default
and to have the whole "clapper-enhancers" concept working correctly, its
about time to move on to playbin3.
2024-11-13 20:06:34 +01:00
Rafał Dzięgiel
bd3ce28716 clapper: Ability to request adaptive bitrates
Add APIs to allow apps to select start, min and max bitrates for adaptive streaming.

Combining min+max values can allow to implement a video quality selector,
although possible bitrates/qualities are not communicated with an app yet.
2024-11-13 20:00:59 +01:00
Rafał Dzięgiel
0a15e70d02 Merge pull request #501 from Rafostar/libpeas
Support libpeas based plugin system
2024-11-11 13:22:10 +01:00
Rafał Dzięgiel
d42b17a749 workflows: Add libpeas to windows build
Required for enhancers loader
2024-11-11 12:49:23 +01:00
Rafał Dzięgiel
719a4043b5 workflows: Disable "enhancers-loader" for docs build
Not needed to build the docs, so disable it
2024-11-11 12:49:19 +01:00
Rafał Dzięgiel
ee3d07b158 flatpak: Replace gtuber with Clapper enhancers
Also add all required dependencies
2024-11-11 12:49:17 +01:00
Rafał Dzięgiel
c8ef0f891d clapper: Support libpeas based plugin system
Allow loading external plugins called "Enhancers" that as the name suggests,
enhance Clapper library capabilities.

Currently implemented is a "ClapperExtractable" interface meant to extract
an actual media that GStreamer can later play from an initial input URI.
Additionally, an internal GStreamer elements that work with it are ported/moved
here from "gtuber" library that this functionality replaces.
2024-11-11 12:49:07 +01:00
Rafał Dzięgiel
220913de14 Merge pull request #499 from Rafostar/esc-unfullscreen
clapper-app: Add unfullscreen keyboard shortcut
2024-10-15 19:53:32 +02:00
Rafał Dzięgiel
2d1f6f471b clapper-app: Add unfullscreen keyboard shortcut
Unfullscreen with Escape key

Closes #494
2024-10-15 19:32:48 +02:00
Rafał Dzięgiel
af4a876edc New Crowdin updates (#473)
* New translations clapper-gtk.pot (Hindi)

* New translations clapper-app.pot (Russian)

* New translations clapper-gtk.pot (Czech)

* New translations clapper-gtk.pot (Persian)

* New translations clapper-gtk.pot (Norwegian)
2024-10-10 20:23:28 +02:00
Danial Behzadi
e81bcb2f9a Update src/bin/clapper-app/data/meson.build
Co-authored-by: Rafał Dzięgiel <40623528+Rafostar@users.noreply.github.com>
2024-09-28 13:02:29 +03:30
Danial Behzadi
ba64ff224e Make dektop file i18n. 2024-09-28 03:37:21 +03:30
Rafał Dzięgiel
14cdbef81c clapper-gtk: Fix metadata ignore for different languages
Since missing plugin string is translated, word describing its type
(e.g. Decoder) might come before plugin name itself, so we need to
check whole text to find substring instead of checking only prefix.

Fixes #477
2024-08-02 17:22:27 +02:00
Rafał Dzięgiel
931dc255c1 clapper-gtk: Fix some video props not being writable
They should have been writable as we even have setters for them
2024-07-23 17:55:11 +02:00
Rafał Dzięgiel
2f39fef47b readme: Update screenshots 2024-06-30 21:38:29 +02:00
Rafał Dzięgiel
c05a6361b7 clapper-app: metainfo: Add captions to screenshots 2024-06-30 21:29:26 +02:00
Rafał Dzięgiel
c152f3d791 clapper-app: Update LINGUAS file 2024-06-29 18:24:40 +02:00
Rafał Dzięgiel
f967e169b5 clapper-gtk: Update LINGUAS file 2024-06-29 18:24:26 +02:00
Rafał Dzięgiel
04a5bc8523 New Crowdin updates (#431)
* New translations clapper-gtk.pot (Portuguese, Brazilian)

* New translations clapper-app.pot (Portuguese, Brazilian)

* New translations clapper-app.pot (Catalan)

* New translations clapper-app.pot (Chinese Simplified)

* New translations clapper-gtk.pot (Chinese Simplified)

* New translations clapper-gtk.pot (Occitan)

* New translations clapper-app.pot (Occitan)
2024-06-29 18:18:06 +02:00
Rafał Dzięgiel
135be60497 clapper-gtk: billboard: Make transition a tad faster 2024-06-29 17:49:41 +02:00
Rafał Dzięgiel
736fddbe46 meson: Do not list Clapper API features when not building it
No need to list API features if API is not being built.

This avoids an issue with meson script error when Clapper API
build is skipped, since these are not declared then.

Fixes #468
2024-06-29 17:35:47 +02:00
Rafał Dzięgiel
63f2fa1946 examples: Start playback after assembling app window
This is the correct order of how things should be done, so teach what is right
2024-06-29 15:07:59 +02:00
Rafał Dzięgiel
99708e1267 clapper-gtk: status: Apply ".osd" style class
Otherwise text is invisible on light themed apps,
since it renders as black letters on a black background
2024-06-29 15:05:12 +02:00
Rafał Dzięgiel
636e61ead1 clapper-gtk: video: Use "scaletempo" by default
Do not require applications to import GStreamer and their devs to learn its
basics just to set this single element. Similarly as ClapperGtkVideo sets
"clappersink" during construction, it can also set "scaletempo" as this is
the most common choice for an audio filter.

Elements can still be changed like before if desired by setting corresponding
player properties.
2024-06-29 14:52:25 +02:00
Rafał Dzięgiel
147399afd8 clapper: media-item: Fix construct with NULL as "cache-location" 2024-06-28 19:47:07 +02:00
Rafał Dzięgiel
2843a17879 Merge pull request #467 from Rafostar/cached-items
clapper: Add media item creation with cached file
2024-06-27 22:13:36 +02:00
Rafał Dzięgiel
bf0a8b68db clapper: Add media item creation with cached file
Allow creating item with a previously downloaded cache file.
When set, file at location will be tried to be loaded first.
If this fails, URI will be used as normal.
2024-06-27 20:57:59 +02:00
Rafał Dzięgiel
af4ae2c942 clapper: Fix missing "download-complete" signal on short videos
Short video might be fully downloaded before playback starts.
This prevents us from emitting "download-complete" signal with
corresponding media item when download cache is enabled.

Check if we have pending item, as this will be the item downloaded
in such case (before it becomes playing item).
2024-06-22 11:20:57 +02:00
Rafał Dzięgiel
c0221dedc8 examples: Fix typo 2024-06-22 11:12:10 +02:00
Rafał Dzięgiel
9f54c1058c Merge pull request #463 from Rafostar/ms-win
Support MS Windows
2024-06-21 20:32:50 +02:00
Rafał Dzięgiel
07f850d58a workflows: Add windows build job 2024-06-21 18:50:24 +02:00
Rafał Dzięgiel
650b568319 clapper-app: meson: Do not install mimes on Windows
They are unsupported. We use file extensions instead.
2024-06-21 18:50:21 +02:00
Rafał Dzięgiel
abff579b70 clapper-app: Fix missing media in file dialog on Windows
Windows does not support mime-types file filters, so use file extensions instead
2024-06-21 18:50:13 +02:00
Rafał Dzięgiel
0b253b41f6 clapper-app: meson: Binaries with/without console on Windows 2024-06-20 18:32:50 +02:00
Rafał Dzięgiel
d5832bd2db gst-plugin: Improve importers lookup on Win32 2024-06-19 22:44:27 +02:00
Rafał Dzięgiel
98371e822e gst-plugin: Allow overriding importers path with env variable 2024-06-17 21:41:11 +02:00
Rafał Dzięgiel
3f2e5d569d clapper-gtk: video: Fix signals disconnection after dispose
A possibility exists that something else keeps a reference to the player
even after video is disposed. In this case signals from the player would
not be disconnected.

We have to disconnect them manually here to ensure their callbacks will
not be used after disposal.
2024-06-17 19:26:18 +02:00
Rafał Dzięgiel
f58e722002 clapper-app: Fix unused variable warning when no MPRIS
When compiling without MPRIS feature "instance_count" is left unused,
so skip it with preprocessor in order to avoid warning.
2024-06-16 17:35:06 +02:00
Rafał Dzięgiel
262983e857 clapper-app: Ensure private types for GtkBuilder
We need to ensure types that are not part of public API, otherwise GtkBuilder will fail to use them
(e81aad25a1/gtk/glade/README.glade (L15)).
2024-06-16 15:21:23 +02:00
Rafał Dzięgiel
6ca1bccd1a clapper-gtk: Ensure private types before template init
We need to ensure types that are not part of public API, otherwise GtkBuilder will fail to use them
(e81aad25a1/gtk/glade/README.glade (L15)).
2024-06-16 14:51:56 +02:00
Rafał Dzięgiel
c25cfd9598 clapper-app: meson: Do not skip whole data install on non-linux
We cannot run app without schemas, thus we need to compile and install them on any OS
2024-06-16 13:50:54 +02:00
Rafał Dzięgiel
3ce937c2b9 gst-plugin: Properly export external API symbols
We do not install headers from gst-plugin, but still need to export
symbols to compile modules that use plugin provided shared libraries.
2024-06-16 13:50:49 +02:00
Rafał Dzięgiel
521a83bad0 clapper: meson: Add additional check for gdbus-codegen
Check at meson level if "gdbus-codegen" is available and otherwise
exit cleanly, possibly building without MPRIS feature instead of failing.
2024-06-16 13:50:41 +02:00
Rafał Dzięgiel
d4598846d3 clapper-gtk: Properly export external API symbols 2024-06-16 13:48:27 +02:00
Rafał Dzięgiel
50d4fbe43b clapper: Properly export external API symbols 2024-06-16 13:48:17 +02:00
Rafał Dzięgiel
df371c698a clapper-app: Fix opened file content type detection
Fixes issues with detecting whether file has one of supported subtitles mime types
2024-06-14 17:32:03 +02:00
Rafał Dzięgiel
2eaf5032cd Merge pull request #451 from Rafostar/resize-me
Resize app window to match aspect ratio with middle click
2024-05-26 17:06:58 +02:00
Rafał Dzięgiel
28de283a98 clapper-app: Add auto window resize keyboard shortcut
In addition to middle click, also add "Super+r" keyboard shortcut to perform window resize to fit video action
2024-05-25 21:30:26 +02:00
Rafał Dzięgiel
ae6512b233 clapper-app: Resize window to match aspect ratio with middle click 2024-05-25 21:16:59 +02:00
Rafał Dzięgiel
5049f620eb Merge pull request #449 from Rafostar/new-window
Add "New Window" functionality in UI
2024-05-20 22:55:14 +02:00
Rafał Dzięgiel
439e5831e2 clapper-app: Apply options from active window to newly created one
When a new window is created, apply all current values to it (volume, speed,
set GStreamer elements, etc.). It would not be the best experience when user
opens a new window, plays something and 100% volume is used in it.
2024-05-20 22:40:28 +02:00
Rafał Dzięgiel
6484599e46 clapper-gtk: Fix GtkWindowControls style when OSD on video 2024-05-15 21:37:48 +02:00
Rafał Dzięgiel
333f8b4692 clapper-app: Make info window close with Esc key
Fixes #448
2024-05-14 21:13:02 +02:00
Rafał Dzięgiel
9b7c12c3d0 flatpak: Fix MPRIS permission
Since now we do multiple windows, an instance number is added
to owned connection name (as specified in MPRIS spec).

Update Flatpak MPRIS permission to handle that.
2024-05-13 20:32:54 +02:00
Rafał Dzięgiel
6fb25dd22b clapper-app: Add new window keyboard shortcut 2024-05-13 20:05:59 +02:00
Rafał Dzięgiel
cc5c2b2403 clapper-app: Add "New Window" menu option
Allow creating new windows from within the app
2024-05-13 19:15:31 +02:00
Rafał Dzięgiel
71142ab0c6 Merge pull request #444 from Rafostar/cmd-options
Add more command line options
2024-05-12 20:47:45 +02:00
Rafał Dzięgiel
cc8ed7b488 clapper-app: Do not store "enqueue" value in options
It is used immediately, so no need to store it.
2024-05-12 20:30:19 +02:00
Rafał Dzięgiel
6f0ed93b08 clapper-app: Only restore saved settings to new windows 2024-05-12 20:30:16 +02:00
Rafał Dzięgiel
10e0421342 clapper-app: Clamp command line args to allowed values
Instead of running into warnings or other problems when user
specifies an out of range value for command line option, just
clamp them to nearest allowed one.
2024-05-12 20:30:14 +02:00
Rafał Dzięgiel
bcd1d48922 clapper-app: Add command line context params string
Describe what kind of remaining (non-options) strings can
be passed when launching via command line.
2024-05-12 20:30:11 +02:00
Rafał Dzięgiel
aac050e252 clapper-app: Add command line option to enter fullscreen 2024-05-12 20:30:09 +02:00
Rafał Dzięgiel
1330e49ed8 clapper-app: Add command line option to set progression mode 2024-05-12 20:30:07 +02:00
Rafał Dzięgiel
22fb88d0f2 clapper-app: Support creating multiple windows 2024-05-12 20:30:01 +02:00
Rafał Dzięgiel
42b5acd967 clapper: mpris: Fix MPRIS own-name documentation 2024-05-12 20:16:28 +02:00
Rafał Dzięgiel
8e14ec1697 clapper-app: Cleanup to not store app options as global and static
Now that we are using both local and global command line vfuncs, we
can just get and apply options in them and free values later.

This avoids having options global and static.
2024-05-12 19:34:37 +02:00
Rafał Dzięgiel
a257d3f003 clapper-app: Add command line option to enqueue files 2024-05-12 19:34:33 +02:00
Rafał Dzięgiel
eb0baa6fe6 clapper-app: Add command line option to set speed 2024-05-12 16:50:04 +02:00
Rafał Dzięgiel
1001fda256 clapper-app: Add command line option to set volume 2024-05-12 16:50:02 +02:00
Rafał Dzięgiel
6edffb9a4b clapper-app: Add command line options to set GStreamer elements
Allows setting audio/video filters and sinks.
By setting value to "none" default filter can be disabled.
2024-05-12 16:49:54 +02:00
Rafał Dzięgiel
b013cb7405 Merge pull request #438 from Rafostar/download-cache
clapper: Add media caching via download to local storage
2024-05-10 00:14:28 +02:00
Rafał Dzięgiel
07ca728b5b workflows: doc: Do not error on nothing to commit
Not always there are changes to the documentation
2024-05-09 23:50:25 +02:00
Rafał Dzięgiel
938cd44d7e workflows: doc: Continue on commit/push errors 2024-05-09 23:43:30 +02:00
Rafał Dzięgiel
8f4723906f Merge pull request #447 from Rafostar/auto-doc
workflows: Add build documentation job
2024-05-09 23:15:58 +02:00
Rafał Dzięgiel
419354fe8f doc: Add "clapper" GIR path when building "clapper-gtk" doc
Fixes building of clapper-gtk documentation on a clean system
2024-05-09 22:54:08 +02:00
Rafał Dzięgiel
4ec7349a04 workflows: Add build documentation job 2024-05-09 22:53:58 +02:00
Rafał Dzięgiel
03b2cb099f examples: Add download cache code example 2024-05-07 22:15:34 +02:00
Rafał Dzięgiel
f67d5bef2e clapper: Add media caching via download to local storage
The aim here is to stream an online video/audio while also at the
same time download/cache it to disk (excluding adaptive content).

After download is complete, further playback and seeking are done using the
locally cached file. This functionality uses GStreamer "downloadbuffer" element.

Player will emit a signal with a local download location after it completes,
so application will know where downloaded file for media item is stored in
case it wants to reuse it in the future.

It is up to application to set download dir and later manage downloaded
content in it, removing files its not going to use on next application
run and any incomplete downloads.
2024-05-07 22:15:25 +02:00
Rafał Dzięgiel
8f4107aab6 examples: Add simple clapper-gtk usage example 2024-05-07 22:09:41 +02:00
Rafał Dzięgiel
6941f1b042 clapper: Small fix for "init_check" doc
The error arg was removed, but documentation was not updated then
2024-05-02 14:38:25 +02:00
Rafał Dzięgiel
df50802871 clapper-gtk: billboard: Documentation fixes
Billboard does not post automatic volume/speed announcements. It did at
some point during development, but it was scrapped in favour of letting
app use callbacks of "notify" signals to call announce speed/volume.
2024-05-02 13:17:09 +02:00
Rafał Dzięgiel
b1613273d0 gst-plugin: Avoid GTK crash after context is destroyed
It seems GTK continues using created contexts, so we cannot unref it here.
Looking at GTK sink implementation for GtkVideo, I see that they do not
unref it either, but since we use surfaceless context it would be probably
better to have a static GstDisplay and reuse the same context in future.
2024-05-02 11:14:29 +02:00
Rafał Dzięgiel
35527e5c14 clapper-gtk: Ignore missing plugins for metadata
Some media files have custom/proprietary metadata.
It should be safe to simply ignore these, since we do
not map metadata to any sort of Clapper stream anyway.

Fixes #441
2024-05-01 16:32:35 +02:00
Rafał Dzięgiel
e060048969 Merge pull request #429 from 1Maxnet1/patch-1
Complement com.github.rafostar.Clapper.metainfo.xml
2024-05-01 11:45:25 +02:00
Rafał Dzięgiel
09648bbc43 Mention Rust bindings in README.md
Closes #411
2024-04-29 21:38:37 +02:00
Max Buchholz
9e5f9e3d07 Add comment to document categories
Co-authored-by: Rafał Dzięgiel <40623528+Rafostar@users.noreply.github.com>
2024-04-29 20:19:10 +02:00
Rafał Dzięgiel
23c5e7ca65 clapper: Fix MARKER_NO_END value in GIR
Needs a cast from int, otherwise GIR is generated
incorrectly and it ends up as positive number.
2024-04-29 17:50:54 +02:00
Rafał Dzięgiel
6d47aa3c6d clapper-app: metainfo: Update branding colors
Change to values suggested by Tobias Bernard
2024-04-27 16:20:33 +02:00
Rafał Dzięgiel
ae3d75a8b5 clapper-app: metainfo: Update app summary
Change to a text suggested by Tobias Bernard
2024-04-27 16:20:17 +02:00
Rafał Dzięgiel
3561bc8c6f Update README.md 2024-04-27 15:59:28 +02:00
Rafał Dzięgiel
368a484741 flatpak: Sync with Flathub 2024-04-27 15:40:38 +02:00
Rafał Dzięgiel
b3ac64e5b1 clapper-app: Show development versions in about window
Since during development we do not put new release tag into metainfo
which about window uses to know app version, set it manually to the
library version since they are the same.
2024-04-27 14:19:45 +02:00
Rafał Dzięgiel
c873c35fa7 Back to development 2024-04-27 14:14:39 +02:00
Max Buchholz
af47dcb5e5 Complement com.github.rafostar.Clapper.metainfo.xml 2024-04-25 10:54:09 +02:00
Rafał Dzięgiel
f0f4801819 0.6.0 2024-04-22 22:27:06 +02:00
Rafał Dzięgiel
b9f3cbef7f clapper-app: metainfo: Add branding colors 2024-04-22 22:04:21 +02:00
Rafał Dzięgiel
772191a396 clapper-app: metainfo: Restore "developer_name" tag
Needed for older appstream compatibility
2024-04-22 21:52:57 +02:00
Rafał Dzięgiel
f4a766ea9d clapper-gtk: seek-bar: Fix marker popover position on RTL
On RTL we need to subtract position from upper scale value to end up at correct coordinates
2024-04-22 21:14:10 +02:00
Rafał Dzięgiel
c928e601bf clapper: Add pipeline debug graph dump support 2024-04-22 20:16:08 +02:00
Rafał Dzięgiel
8fb62d773f New Crowdin updates (#406)
* New translations clapper-app.pot (Polish)

* New translations clapper-gtk.pot (Turkish)

* New translations clapper-app.pot (Turkish)

* New translations clapper-gtk.pot (Turkish)

* New translations clapper-app.pot (Portuguese)

* New translations clapper-app.pot (Turkish)

* New translations clapper-app.pot (Catalan)

* New translations clapper-gtk.pot (Catalan)

* New translations clapper-app.pot (Catalan)

* New translations clapper-gtk.pot (Portuguese)

* New translations clapper-app.pot (Portuguese)

* New translations clapper-app.pot (Portuguese)

* New translations clapper-app.pot (Portuguese)

* New translations clapper-app.pot (Hungarian)

* New translations clapper-gtk.pot (Hungarian)

* New translations clapper-app.pot (Hungarian)

* New translations clapper-app.pot (Hungarian)

* New translations clapper-gtk.pot (Romanian)

* New translations clapper-gtk.pot (French)

* New translations clapper-gtk.pot (Spanish)

* New translations clapper-gtk.pot (Afrikaans)

* New translations clapper-gtk.pot (Arabic)

* New translations clapper-gtk.pot (Catalan)

* New translations clapper-gtk.pot (Czech)

* New translations clapper-gtk.pot (Danish)

* New translations clapper-gtk.pot (German)

* New translations clapper-gtk.pot (Greek)

* New translations clapper-gtk.pot (Basque)

* New translations clapper-gtk.pot (Finnish)

* New translations clapper-gtk.pot (Hebrew)

* New translations clapper-gtk.pot (Hungarian)

* New translations clapper-gtk.pot (Italian)

* New translations clapper-gtk.pot (Japanese)

* New translations clapper-gtk.pot (Korean)

* New translations clapper-gtk.pot (Lithuanian)

* New translations clapper-gtk.pot (Dutch)

* New translations clapper-gtk.pot (Norwegian)

* New translations clapper-gtk.pot (Polish)

* New translations clapper-gtk.pot (Portuguese)

* New translations clapper-gtk.pot (Russian)

* New translations clapper-gtk.pot (Slovak)

* New translations clapper-gtk.pot (Serbian (Cyrillic))

* New translations clapper-gtk.pot (Swedish)

* New translations clapper-gtk.pot (Turkish)

* New translations clapper-gtk.pot (Ukrainian)

* New translations clapper-gtk.pot (Chinese Simplified)

* New translations clapper-gtk.pot (Chinese Traditional)

* New translations clapper-gtk.pot (Vietnamese)

* New translations clapper-gtk.pot (Portuguese, Brazilian)

* New translations clapper-gtk.pot (Persian)

* New translations clapper-gtk.pot (Croatian)

* New translations clapper-gtk.pot (Asturian)

* New translations clapper-gtk.pot (German)

* New translations clapper-gtk.pot (Portuguese)

* New translations clapper-app.pot (German)

* New translations clapper-gtk.pot (Turkish)

* New translations clapper-gtk.pot (Catalan)

* New translations clapper-gtk.pot (Finnish)

* New translations clapper-app.pot (Finnish)

* New translations clapper-gtk.pot (Finnish)

* New translations clapper-app.pot (Finnish)

* New translations clapper-gtk.pot (Hungarian)

* New translations clapper-gtk.pot (Hungarian)

* New translations clapper-app.pot (French)

* New translations clapper-gtk.pot (French)

* New translations clapper-app.pot (French)

* New translations clapper-app.pot (Polish)

* New translations clapper-gtk.pot (Polish)

* New translations clapper-app.pot (French)

* New translations clapper-app.pot (Polish)

* New translations clapper-app.pot (Polish)

* New translations clapper-app.pot (Romanian)

* New translations clapper-app.pot (French)

* New translations clapper-app.pot (Spanish)

* New translations clapper-app.pot (Afrikaans)

* New translations clapper-app.pot (Arabic)

* New translations clapper-app.pot (Catalan)

* New translations clapper-app.pot (Czech)

* New translations clapper-app.pot (Danish)

* New translations clapper-app.pot (German)

* New translations clapper-app.pot (Greek)

* New translations clapper-app.pot (Basque)

* New translations clapper-app.pot (Finnish)

* New translations clapper-app.pot (Hebrew)

* New translations clapper-app.pot (Hungarian)

* New translations clapper-app.pot (Italian)

* New translations clapper-app.pot (Japanese)

* New translations clapper-app.pot (Korean)

* New translations clapper-app.pot (Lithuanian)

* New translations clapper-app.pot (Dutch)

* New translations clapper-app.pot (Norwegian)

* New translations clapper-app.pot (Polish)

* New translations clapper-app.pot (Portuguese)

* New translations clapper-app.pot (Russian)

* New translations clapper-app.pot (Slovak)

* New translations clapper-app.pot (Serbian (Cyrillic))

* New translations clapper-app.pot (Swedish)

* New translations clapper-app.pot (Turkish)

* New translations clapper-app.pot (Ukrainian)

* New translations clapper-app.pot (Chinese Simplified)

* New translations clapper-app.pot (Chinese Traditional)

* New translations clapper-app.pot (Vietnamese)

* New translations clapper-app.pot (Portuguese, Brazilian)

* New translations clapper-app.pot (Persian)

* New translations clapper-app.pot (Croatian)

* New translations clapper-app.pot (Asturian)
2024-04-21 23:24:54 +02:00
Rafał Dzięgiel
f299e1be57 Merge pull request #420 from Rafostar/prerelease-updates
Prerelease updates
2024-04-21 22:48:16 +02:00
Rafał Dzięgiel
9f38f527be clapper-app: Sync POT file 2024-04-21 20:25:15 +02:00
Rafał Dzięgiel
10f626637b Update install steps in README.md 2024-04-21 19:58:44 +02:00
Rafał Dzięgiel
22c93c00f7 clapper-app: gschema: Fix gettext-domain value
In rewritten code "clapper-app" is used for gettext
2024-04-21 19:50:05 +02:00
Rafał Dzięgiel
7a38b605b3 clapper-app: metainfo: Update values
Update description and some other values. Also update whatever
was nowadays considered as deprecated in metainfo guidelines.
2024-04-21 16:07:28 +02:00
Rafał Dzięgiel
5c41c3a8c7 clapper-app: metainfo: Fix invalid values
Flathub validation no longer allows words for "display_length" - should be 360.
Also all "Purism" keys are nowadays invalid. They cause problems as metainfo is
parsed into hash table, thus there cannot be multiple keys with the same name.
2024-04-21 15:22:17 +02:00
Rafał Dzięgiel
51e1dd8493 Remove .gitattributes file
All linguist-vendored stuff was removed, so this git attributes file is unused and no longer needed.
2024-04-20 12:09:41 +02:00
Rafał Dzięgiel
654e6be72a clapper-app: Be more restrictive about key modifiers
Ignore key presses with additional modifiers if we describe them
in shortcuts as sole letters. Combinations might be needed in the future.
2024-04-19 23:10:14 +02:00
Rafał Dzięgiel
681da9e2f3 clapper-gtk: video: Add workaround for better GStreamer 1.24 support 2024-04-19 16:51:44 +02:00
Rafał Dzięgiel
36c166813e clapper-gtk: video: Support finding widget within bin elements
When a video sink is set to some bin, also check sinks within it
in search for a widget that can be used as video main child
2024-04-19 16:39:08 +02:00
Rafał Dzięgiel
2aecd65735 clapper-app: help-overlay: Update progression key accelerator
We allow just "p" key (including any combination with it) for changing
progression mode. Fix its description in help overlay to be just "p" then.

Fixes #417
2024-04-17 19:11:02 +02:00
Rafał Dzięgiel
a46846c24d clapper-app: Use "GDK_MODIFIER_MASK" with key controller state
We need to use "GDK_MODIFIER_MASK" to remove all private fields from key
controller state mask, otherwise its not zero on Xorg.

Fixes #416
2024-04-17 18:26:16 +02:00
Rafał Dzięgiel
fab168283d clapper: player: Make GstElement setters nullable
Allow to set NULL in order to use default value. With this, API users
will not have to check if the element they make from registry is not NULL.
2024-04-16 19:07:16 +02:00
Rafał Dzięgiel
1b38a169dd clapper-gtk: video: Debug message with used video sink
So we can know from debug logging what sink someone is using
2024-04-16 19:03:34 +02:00
Rafał Dzięgiel
a00aea50b0 Merge pull request #413 from Rafostar/workflows
Update workflows
2024-04-15 22:46:58 +02:00
Rafał Dzięgiel
6fc2c78d59 Remove unused OBS service file
This file was referencing build scripts that are no longer in this repo.
An up-to-date OBS config is kept in my opensuse build system account itself.
2024-04-15 22:43:04 +02:00
Rafał Dzięgiel
85038a669f clapper-app: Restore "q" to quit app shortcut
We used to have this and some other players (e.g. Totem) have it too, so no harm in restoring it.
2024-04-15 20:53:32 +02:00
Rafał Dzięgiel
484f2402a3 flatpak-nightly: Update manifest
In latest git, binary name is now simply "clapper". Also we now depend on libmicrodns for the server feature to be available.
2024-04-15 20:07:07 +02:00
Rafał Dzięgiel
1a0158e775 flatpak-nightly: Build dav1d from git master 2024-04-14 20:36:25 +02:00
Rafał Dzięgiel
1d92539b76 clapper-gtk: Various documentation cleanups and fixes 2024-04-14 20:17:38 +02:00
Rafał Dzięgiel
bab3d34349 clapper: Various documentation cleanups and fixes 2024-04-14 20:17:12 +02:00
Rafał Dzięgiel
e751428d6c workflows: Update to use latest versions of actions 2024-04-14 17:23:33 +02:00
Rafał Dzięgiel
a9769f9537 gst-plugin: sink: Stop preferring GL over GLES with GStreamer 1.24+
GStreamer 1.24 have implemented DRM modifiers negotiation that its lack of we were
working around with using GL on unpatched GStreamer (non-Flatpak builds).

Since GStreamer 1.24 does this and moreover it has disabled DMABuf codepath for
non-GLES we should start preferring GLES with this version always.
2024-04-14 15:47:20 +02:00
Rafał Dzięgiel
fe6b3fcf29 clapper-app: Fix window buttons on initial state
Also handle different buttons placements on initial state, similarly as we do now in headerbar.
With this commit, application menu is replicated in initial state UI, but its actually a good thing,
since this will allow us to have more current video related items in it only in main window.
2024-04-14 15:11:18 +02:00
Rafał Dzięgiel
6447944b21 clapper-app: Handle alternative headerbar buttons placements
Handle all possible combinations of window state buttons placement.
These are "right" and "left" combined along with either LTR or RTL.

Fixes #402
2024-04-13 18:32:36 +02:00
Rafał Dzięgiel
42fa31cc4b Merge pull request #404 from Rafostar/scroll-fixes
Scroll fixes
2024-04-13 14:28:23 +02:00
Rafał Dzięgiel
4baade3b32 Merge pull request #408 from sp1ritCS/devenv
meson: Ensure clapper uses local translations within the devenv
2024-04-12 21:38:16 +02:00
Florian "sp1rit"​
bcd8e470ad po: Updated German translation
I've taken a bit of liberty with some of the translations, but I feel
like they should be fine.

Signed-off-by: Florian "sp1rit"​ <sp1rit@disroot.org>
2024-04-12 20:57:04 +02:00
Florian "sp1rit"​
3841a906fd meson: Ensure clapper uses local translations within the devenv
This patch modifies the initialization routines of clapper to check for
    CLAPPER_GTK_OVERRIDE_LOCALEDIR and
    CLAPPER_APP_OVERRIDE_LOCALEDIR
and uses that instead of the LOCALEDIR specified in the config.h.

It also fixes the bug where libclapper-gtk loads the translations for
the clapper application and the clapper application loads the
translations for the libclapper-gtk. (It took me shockingly long to
figure out why the translations weren't working 🙃)

Co-authored-by: Rafał Dzięgiel <rafostar.github@gmail.com>
Signed-off-by: Florian "sp1rit"​ <sp1rit@disroot.org>
2024-04-12 20:38:46 +02:00
Rafał Dzięgiel
5e7305516e clapper-gtk: Update POT file 2024-04-12 20:29:30 +02:00
Rafał Dzięgiel
f1ef299c10 clapper-gtk: status: Fix missing translations 2024-04-12 20:28:23 +02:00
Rafał Dzięgiel
1606a165e4 clapper-gtk: extra-menu-button: Use "Show Subtitles" text
As pointed in #410, the word "Enabled" and a checkmark next to it is a bad UX.
Change this text to "Show Subtitles" instead.
2024-04-12 20:25:49 +02:00
Rafał Dzięgiel
87f51c6755 clapper: Also update decoders after preroll
Sometimes decoders might not be active yet until media starts playing, to fix that being racy also try to update them after preroll
2024-04-12 20:22:48 +02:00
Rafał Dzięgiel
ca73b3a3ef clapper-gtk: extra-menu-button: Make text->number conversion more forgiving
Try to parse into a number as much of the string as possible, without caring
about a sign suffix. This way input will be more forgiving instead of resetting
itself to lowest allowed number.

Also when a number exceeds allowed range, set it to maximal allowed value
instead of once again resetting to minimum.
2024-04-11 20:49:36 +02:00
Rafał Dzięgiel
6f1277a2e6 server: Fix invalid JSON caused by locale decimal conversion
When creating JSON data, we must ensure that our decimal numbers are converted
to a string with a "." as separator, otherwise it would be an invalid JSON.
2024-04-11 20:20:37 +02:00
Rafał Dzięgiel
76f830fa6e Merge pull request #409 from sp1ritCS/fix_pbspeed
clapper-gtk/extra-menu: Fixed speed being forced to the lowest value
2024-04-11 20:07:44 +02:00
Florian "sp1rit"​
a63d92601f clapper-gtk/extra-menu: Fixed speed being forced to the lowest value
As the SpinButton input callback attempted to parse the value inserted
as a string by printf using g_ascii_strtod, only if the language also
used . (full stop / u002E) as decimal seperator worked correctly.
Otherwise, parsing would fail and result (after a few iterations) in the
lowest value being set.

The usually correct approach is to use g_ascii_dtostr / g_ascii_formatd
instead of printf to format a decimal number, but given that this number
is actually presented to the user, going with g_strtod seems like a
better choice (I've decided against just using the stdlib strtod as to
allow the SpinButton to also recognize manual user input containing the
full stop  instead of their languages native decimal seperator (not
that that'll ever happen, given the user can't focus the SpinButton
entry while media is running).

I've also fixed this for the volume SpinButton too, but it wasn't really
affected in the first place as it appearently always gets rounded up to
a number without decimal places.

Signed-off-by: Florian "sp1rit"​ <sp1rit@disroot.org>
2024-04-10 12:26:50 +02:00
Rafał Dzięgiel
0c9973ef85 Add .flatpak-builder to .gitignore 2024-04-09 20:02:31 +02:00
Rafał Dzięgiel
65c974d539 Merge pull request #407 from sp1ritCS/devenv
Allow clapper to be ran within the meson devenv
2024-04-09 17:21:54 +02:00
Florian "sp1rit"​
43e2e88a4c meson: Use gnome.compile_schemas()
This causes meson to automatically build the clapper gsettings schemas
and set GSETTINGS_SCHEMA_DIR to the correct location within the devenv.

This means that can now be ran without needing to install it somewhere
using:
    meson devenv -C <builddir>
    clapper
    exit

More devenv overrides should be investigated (such as automatically
adopting the correct directory for translated locales etc.)

Signed-off-by: Florian "sp1rit"​ <sp1rit@disroot.org>
2024-04-09 11:39:32 +02:00
Rafał Dzięgiel
c327734ca6 clapper-app: Do not trigger default scroll handler on GtkRange
In addition to GtkScrolledWindow, when also hovering over GtkRange
subclassing widgets like GtkScale, do not trigger accidentally
default app window scroll handler.

We want the hovered upon widget and only that widget to handle scroll
events in such case.
2024-04-08 20:37:32 +02:00
Rafał Dzięgiel
48b5a7c12a Remove TODO.md
Most of it was implemented and what is left already has an open issue which is easier to track progress
2024-04-08 19:07:21 +02:00
Rafał Dzięgiel
1dd47ad2a9 Remove old translation files
They are no longer used and translated strings from them were moved to new files
2024-04-08 19:04:35 +02:00
Rafał Dzięgiel
fbeafbccd1 crowdin: Remove legacy app translations
Now that old translated strings are moved to new .po files, remove what is left unused.
2024-04-08 18:34:12 +02:00
Rafał Dzięgiel
f391e2ea87 New Crowdin updates (#405)
* New translations clapper-gtk.pot (Romanian)

* New translations clapper-gtk.pot (French)

* New translations clapper-gtk.pot (Spanish)

* New translations clapper-gtk.pot (Afrikaans)

* New translations clapper-gtk.pot (Arabic)

* New translations clapper-gtk.pot (Catalan)

* New translations clapper-gtk.pot (Czech)

* New translations clapper-gtk.pot (Danish)

* New translations clapper-gtk.pot (German)

* New translations clapper-gtk.pot (Greek)

* New translations clapper-gtk.pot (Basque)

* New translations clapper-gtk.pot (Finnish)

* New translations clapper-gtk.pot (Hebrew)

* New translations clapper-gtk.pot (Hungarian)

* New translations clapper-gtk.pot (Italian)

* New translations clapper-gtk.pot (Japanese)

* New translations clapper-gtk.pot (Korean)

* New translations clapper-gtk.pot (Lithuanian)

* New translations clapper-gtk.pot (Dutch)

* New translations clapper-gtk.pot (Norwegian)

* New translations clapper-gtk.pot (Polish)

* New translations clapper-gtk.pot (Portuguese)

* New translations clapper-gtk.pot (Russian)

* New translations clapper-gtk.pot (Slovak)

* New translations clapper-gtk.pot (Serbian (Cyrillic))

* New translations clapper-gtk.pot (Swedish)

* New translations clapper-gtk.pot (Turkish)

* New translations clapper-gtk.pot (Ukrainian)

* New translations clapper-gtk.pot (Chinese Simplified)

* New translations clapper-gtk.pot (Chinese Traditional)

* New translations clapper-gtk.pot (Vietnamese)

* New translations clapper-gtk.pot (Portuguese, Brazilian)

* New translations clapper-gtk.pot (Persian)

* New translations clapper-gtk.pot (Croatian)

* New translations clapper-gtk.pot (Asturian)

* New translations clapper-app.pot (Romanian)

* New translations clapper-app.pot (French)

* New translations clapper-app.pot (Spanish)

* New translations clapper-app.pot (Afrikaans)

* New translations clapper-app.pot (Arabic)

* New translations clapper-app.pot (Catalan)

* New translations clapper-app.pot (Czech)

* New translations clapper-app.pot (Danish)

* New translations clapper-app.pot (German)

* New translations clapper-app.pot (Greek)

* New translations clapper-app.pot (Basque)

* New translations clapper-app.pot (Finnish)

* New translations clapper-app.pot (Hebrew)

* New translations clapper-app.pot (Hungarian)

* New translations clapper-app.pot (Italian)

* New translations clapper-app.pot (Japanese)

* New translations clapper-app.pot (Korean)

* New translations clapper-app.pot (Lithuanian)

* New translations clapper-app.pot (Dutch)

* New translations clapper-app.pot (Norwegian)

* New translations clapper-app.pot (Polish)

* New translations clapper-app.pot (Portuguese)

* New translations clapper-app.pot (Russian)

* New translations clapper-app.pot (Slovak)

* New translations clapper-app.pot (Serbian (Cyrillic))

* New translations clapper-app.pot (Swedish)

* New translations clapper-app.pot (Turkish)

* New translations clapper-app.pot (Ukrainian)

* New translations clapper-app.pot (Chinese Simplified)

* New translations clapper-app.pot (Chinese Traditional)

* New translations clapper-app.pot (Vietnamese)

* New translations clapper-app.pot (Portuguese, Brazilian)

* New translations clapper-app.pot (Persian)

* New translations clapper-app.pot (Croatian)

* New translations clapper-app.pot (Asturian)
2024-04-08 18:22:06 +02:00
Rafał Dzięgiel
37bf374283 crowdin: Add new translation paths to config 2024-04-08 17:33:41 +02:00
Rafał Dzięgiel
1327dc23e4 clapper-gtk: Fix seek bar touchpad scrolling
Since we only do seek on scale drop, handle scrubbing using touchpad
the same way by marking it as "dragging" after scrubbing starts and
doing seek after it ends.
2024-04-07 20:08:53 +02:00
Rafał Dzięgiel
6e17996691 clapper-app: Fix wrong direction of touchpad scrolling
We should not invert axis. Otherwise its opposite compared to the same gesture performed on GtkScale.
2024-04-07 20:05:20 +02:00
Rafał Dzięgiel
606b9c5170 Update README.md 2024-04-06 18:17:38 +02:00
Rafał Dzięgiel
e4814877de Merge pull request #374 from Rafostar/libclapper
Introduce Clapper libraries
2024-04-05 22:30:55 +02:00
Rafał Dzięgiel
6b135d51f3 flatpak: Switch to using Adelie Linux a52dec
Original repo is removed, change to maintained fork.
Others are doing the same e.g. FreeBSD
2024-04-05 21:18:46 +02:00
Rafał Dzięgiel
1a52576be3 flatpak: Update Flatpak manifests
Update GitHub Flatpak builds to latest runtime version, add new libs
that we need and remove the ones that are not needed anymore.
2024-04-05 21:18:42 +02:00
Rafał Dzięgiel
cc004a8144 bin: Rewrite Clapper player binary
A rewritten Clapper video player made using "Clapper" and "ClapperGtk" libraries.

Since both libraries from this repo are in C, newly rewritten Clapper binary is also in C to
avoid mixing different programming languages in a single repo, thus making maintenance easier.
Not depending on GJS gives us also an additional benefit of supporting different operating
systems or linux shells without pulling GJS as dependency.

Licensed under GPL-3.0-or-later.
2024-04-05 21:18:39 +02:00
Rafał Dzięgiel
675ddc85a1 lib: Introduce Clapper GTK integration library
An easy to use GTK integration library. Meant as a GtkVideo alternative.

While GtkVideo is more of a simple example of video playback under GTK4, this
acts as a full-fledged video player in the form of a GtkWidget that can be placed
anywhere within application.

The widget offers customization options for both top header and bottom playback
controls panels. The Clapper playback API is exposed under widget "player" property
making it easy for the programmer to set media and control playback programically.

The new library will be distributed with Clapper player. This includes public headers
and GObject Introspection support.

Licensed under LGPL-2.1-or-later.
2024-04-05 21:18:35 +02:00
Rafał Dzięgiel
d7f069d6c3 lib: Introduce Clapper playback library
An easy to use media playback library (libclapper) as a GstPlayer replacement.

Previously we tried to use upstream `gstplayer` library to control playback and
pass all events from multiple threads GStreamer uses into an app main thread.
Since this caused some thread racy problems and we needed additional ABI breaking
changes to better suit our needs, we ended up with a modified fork of said library
renamed to `gstclapper` as a temporary solution.

This new library simply named `clapper` replaces our previous `gstclapper` solution
and is written completely from scratch by myself. The aim here is to have an easy to
use playback library better suited to work with (but not limited to) GTK and GObject
properties bindings by relying on "notify" signals.

Major differences include:
* Operates on a playback queue (inherits `GListModel` interface) instead of a single URI
* Uses "notify" signals for property changes always dispatched to app thread
* Time is passed/read as decimal number in seconds instead of int64 in nanoseconds
* Integrates `GstDiscoverer` to figure out media info (such as title) before playback
* Easy to use MPRIS support as part of library
* Optional playback remote controls with WebSocket messages

The new library will be distributed with Clapper player. This includes public headers
and GObject Introspection support.

Licensed under LGPL-2.1-or-later.

Enjoy
2024-04-05 21:18:08 +02:00
Rafał Dzięgiel
edaba00658 Merge pull request #378 from TriVoxel/master
Add standard shortcut for preferences
2023-10-31 21:19:30 +01:00
Rafał Dzięgiel
8cf3e57d51 Merge pull request #385 from Rafostar/nightly-fix
flatpak-nightly: Update to 23.08 runtime
2023-10-31 18:49:37 +01:00
Rafał Dzięgiel
32723c49ad flatpak-nightly: Update to 23.08 runtime 2023-10-30 23:08:37 +01:00
cadenmitchell
058844c010 Add standard shortcut for preferences 2023-09-06 12:53:01 -06:00
Rafał Dzięgiel
b4aaea1940 Merge pull request #364 from Rafostar/ws-fix
webServer: Listen on all interfaces
2023-06-27 19:58:49 +02:00
Rafał Dzięgiel
2dd08b7b33 webServer: Listen on all interfaces
Listen on all network interfaces for incoming connections.

Previous soup_server_listen_local() only listens on local
loopback device preventing access from network, so use
listen_all() instead to allow access through any interface.

Fixes #362
2023-06-27 18:44:59 +02:00
Rafał Dzięgiel
086b134483 flatpak: Sync with Flathub 2023-06-05 21:25:05 +02:00
Rafał Dzięgiel
9da04c549b Update LINGUAS file 2023-06-05 21:22:40 +02:00
Rafał Dzięgiel
ac7ec5fc12 New Crowdin updates (#355)
* New translations com.github.rafostar.Clapper.pot (Croatian)

* New translations com.github.rafostar.Clapper.pot (Swedish)
2023-06-05 21:17:45 +02:00
Rafał Dzięgiel
6e705485f5 Merge pull request #354 from milotype/Croatian-translation
Croatian translation
2023-05-06 20:31:30 +02:00
Rafał Dzięgiel
18caee32d7 New Crowdin updates (#348)
* New translations com.github.rafostar.Clapper.pot (Lithuanian)

* New translations com.github.rafostar.Clapper.pot (Finnish)
2023-05-05 13:51:08 +02:00
Milo Ivir
c7590b653b Add Croatian translation 2023-05-03 19:05:52 +02:00
Milo Ivir
dce74148a7 Add hr for Croatian 2023-05-03 19:05:17 +02:00
Rafał Dzięgiel
5ed9861530 Merge pull request #349 from g7/rotation
Allow detecting and setting media rotation
2023-05-02 20:47:58 +02:00
Rafał Dzięgiel
3f86b236d9 flatpak: Sync with Flathub 2023-04-29 16:38:58 +02:00
Eugenio Paolantonio (g7)
e275c3017a plugin: sink: allow detecting and/or setting media rotation. Fixes #310
GstClapperSink now allows to specify the media rotation via the `rotation`
property, which should be of type GstVideoOrientationMethod.

The default behaviour is to detect the media rotation automatically.

Signed-off-by: Eugenio Paolantonio (g7) <me@medesimo.eu>
2023-04-23 22:43:22 +02:00
Eugenio Paolantonio (g7)
4e250c8f2a plugin: paintable: Support setting media rotation. Contributes to #310
Rotation can be set by passing a GstVideoOrientationMethod to the
gst_clapper_paintable_set_rotation() function.

The actual rotation is done through GskTransforms directly on the
Snapshot.

Signed-off-by: Eugenio Paolantonio (g7) <me@medesimo.eu>
2023-04-23 22:24:29 +02:00
Eugenio Paolantonio (g7)
7fc93fbebc plugin: Add helper to get the actual width and height for a specific rotation
Signed-off-by: Eugenio Paolantonio (g7) <me@medesimo.eu>
2023-04-23 22:24:29 +02:00
Rafał Dzięgiel
bf52197896 plugin: Present fallback window right after assembled UI
When started from gst-play/launch-1.0 show window right after it was created.
No need to idle dispatch window present when changing state, since we are
already on correct thread when opening resources using start() method.
2023-02-12 13:53:51 +01:00
Rafał Dzięgiel
9556ec4da2 plugin: Ensure allocation using the same importer
Instead of locking mutex twice and praying that importer will not change in between, just ref it to ensure that
2023-02-12 13:16:18 +01:00
Rafał Dzięgiel
bd8f0280e2 plugin: Check importer presence before proposing allocation
In some cases importer might not be determined here yet.
Check if we have it to avoid a crash.
2023-02-09 11:38:36 +01:00
Rafał Dzięgiel
40b6f4c724 Update LINGUAS file 2023-01-08 19:00:16 +01:00
Rafał Dzięgiel
456d621ee3 New Crowdin updates (#332)
* New translations com.github.rafostar.Clapper.pot (Slovak)
2023-01-08 18:57:28 +01:00
Rafał Dzięgiel
263d3f8196 Merge pull request #324 from Rafostar/flatpak-translated
flatpak: Build with translations included
2023-01-08 18:54:20 +01:00
Rafał Dzięgiel
44db8c0d3b flatpak: Sync with Flathub 2023-01-07 18:55:01 +01:00
Rafał Dzięgiel
272e3a036c flatpak-nightly: Build with translations included
Flatpak git action does not support uploading a separate .Locale runtime.
Build it as part of the main app then.
2022-11-18 22:51:20 +01:00
Rafał Dzięgiel
540c294b2a flatpak: Build with translations included
Flatpak git action does not support uploading a separate .Locale runtime.
Build it as part of the main app then.
2022-11-18 22:50:54 +01:00
Rafał Dzięgiel
6c5753db53 Merge pull request #317 from Rafostar/gnome43
flatpak: Update to GNOME 43
2022-10-14 08:13:17 +02:00
Rafał Dzięgiel
a25bfa5418 flatpak: Update to GNOME 43
Update git actions builds to GNOME 43 runtime. #315
2022-10-13 20:54:26 +02:00
Rafał Dzięgiel
aaa3f6c4da Merge pull request #316 from Rafostar/nights
Update nightly Flatpak builds
2022-10-10 22:45:48 +02:00
Rafał Dzięgiel
845de1db8b flatpak-nightly: Only build GStreamer Rust plugins on x64
We are no longer able to build them on aarch64, as CI either runs out of memory or time limit
2022-10-10 18:06:32 +02:00
Rafał Dzięgiel
301e1f2ade flatpak-nightly: Skip compiling libadwaita
Nightly has now newer version, so we do not need to build it ourselves anymore
2022-10-09 20:17:56 +02:00
Rafał Dzięgiel
ff5091e7d3 flatpak-nightly: Update to llvm14 2022-10-09 15:00:22 +02:00
Rafał Dzięgiel
0d74fbb3e6 workflow: Update Flatpak nightly to 22.08 2022-10-09 14:22:19 +02:00
Rafał Dzięgiel
9d6ec43b0a Merge pull request #312 from jakedane/jakedane-patch-1
plugin: sink: Replace deprecated method
2022-09-28 22:10:40 +02:00
Jake Dane
cbc3061714 plugin: sink: Replace deprecated method
The method gtk_picture_set_keep_aspect_ratio is deprecated. As per the
warnings given when compiling clapper, it is replaced with
gtk_picture_set_content_fit with the same behavior as before.
2022-09-27 20:50:16 +02:00
Rafał Dzięgiel
d8b02824f3 Update gitattributes
The contents of extras and lib/plugin folders should not be marked as linguist-vendored since they include only my own code made for Clapper. Lets include them in git stats.
2022-09-07 13:15:34 +02:00
Rafał Dzięgiel
dd255dd337 New translations com.github.rafostar.Clapper.pot (Persian) (#305) 2022-09-03 20:40:35 +02:00
Rafał Dzięgiel
447c6f30d0 meson: Validate appstream file with "--nonet" arg
We do not need network connection to validate our appstream file.
Make it easier to run tests in containers that do not have network access.

Closes #307
2022-07-31 19:12:42 +02:00
Rafał Dzięgiel
afa06d4579 Merge pull request #299 from Rafostar/web-fix
api: Do not set default user-agent string
2022-07-25 10:23:27 +02:00
Rafał Dzięgiel
b04bf11c42 api: Do not set default user-agent string
Similarly as with other properties, we should aim to make this into user config option.
For the time being remove, as our outdated default user-agent seems to be breaking
few HLS streaming services.
2022-07-24 19:39:11 +02:00
Rafał Dzięgiel
939f75763d Merge pull request #302 from Rafostar/crowdin_sync
New Crowdin updates
2022-07-21 18:07:18 +02:00
Rafał Dzięgiel
d4c44049ca New translations com.github.rafostar.Clapper.pot (Chinese Simplified) 2022-07-18 10:48:44 +02:00
Rafał Dzięgiel
11c27eccaa Merge pull request #279 from Rafostar/fix-gl-caps
Make GL caps negotiation check what HW supports
2022-07-04 18:51:45 +02:00
Rafał Dzięgiel
823cb0a894 Update LINGUAS file 2022-07-04 18:20:40 +02:00
Rafał Dzięgiel
b27db1ac22 New Crowdin updates (#283)
* New translations com.github.rafostar.Clapper.pot (Persian)

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

* New translations com.github.rafostar.Clapper.pot (Asturian)
2022-07-04 18:16:55 +02:00
Rafał Dzięgiel
564c6e7299 flatpak: Sync with Flathub 2022-07-04 12:30:27 +02:00
Rafał Dzięgiel
6f4632d940 New translations com.github.rafostar.Clapper.pot (German) (#282) 2022-06-24 20:23:50 +02:00
Rafał Dzięgiel
23bb253ca2 0.5.2 2022-06-24 10:05:02 +02:00
Rafał Dzięgiel
8ebf4e3b2f plugin: gluploader: Check for formats actually supported
Do not assume that HW can do every format that GLUpload/GLColorConvert can.
Check what video formats GL context actually supports and advertise that,
so a format that HW cannot do will never be picked up.
2022-06-16 15:41:44 +02:00
Rafał Dzięgiel
04a028d689 plugin: Rework code to use new GL context handler
Create a GL context handler subclass of recently added context handler base class and
rework code to use it. This simplifies a lot of things, like: switching of importers
at runtime, handling context queries, sharing data between importers, etc.
2022-06-16 15:41:30 +02:00
Rafał Dzięgiel
0920914b89 plugin: Add context handler base class
In order to bridge work with GL between GTK and GStreamer reliably, we need to create and
check context capabilities ahead of time. We also need to be able to query context at any
time during playback. Also we should avoid changing importers on context queries, this can
lead to all sort of problems.

To be able to achieve all of above, introduce new context handler base class that works
separately of importers.
2022-06-12 13:58:51 +02:00
Rafał Dzięgiel
2343e84a41 plugin: Use set_static_metadata in class init
Use static version of this function, so our static strings will not be copied
2022-06-06 21:04:17 +02:00
Rafał Dzięgiel
c288223321 Merge pull request #278 from Rafostar/flatpak-gvfs
flatpak: Add missing GVFS access permissions
2022-06-06 20:48:53 +02:00
Rafał Dzięgiel
2ba6645462 flatpak-nightly: Add missing GVFS access permissions
Needed to make GVFS mounted filesystems work with GVFS 1.48+.
See: https://docs.flatpak.org/en/latest/sandbox-permissions.html#gvfs-access
2022-06-06 09:32:12 +02:00
Rafał Dzięgiel
adcbb5d827 flatpak: Add missing GVFS access permissions
Needed to make GVFS mounted filesystems work with GVFS 1.48+.
See: https://docs.flatpak.org/en/latest/sandbox-permissions.html#gvfs-access
2022-06-06 09:31:55 +02:00
Rafał Dzięgiel
9885a2f424 Merge pull request #275 from Rafostar/smart-colon
Use U+003A colon character on RTL languages
2022-06-03 16:17:27 +02:00
Rafał Dzięgiel
66b2d8c7de plugin: Also use min GL version when auto selecting context
When we prefer GLES, make sure its no lower then 3.1 version, so it can color convert 10bit videos,
otherwise core GL 3.2 that GTK4 normally defaults to takes precedence.

With auto behavior we should select the best one, both performance and support wise.
Otherwise user can request one or another with GST_GL_API env that works best
with his specific HW.
2022-06-03 14:36:34 +02:00
Rafał Dzięgiel
2c5d65d0b3 flatpak: Sync with Flathub 2022-06-02 14:08:17 +02:00
Rafał Dzięgiel
e37f2a0a30 Use U+003A colon character on RTL languages
Unfortunately U+2236 seems to break time labels on RTL languages. Check text direction at startup and select best one that works.
2022-06-01 17:09:39 +02:00
Rafał Dzięgiel
387bc7a2f3 Update LINGUAS file 2022-06-01 16:44:05 +02:00
Rafał Dzięgiel
495a59a07a New Crowdin updates (#274)
* New translations com.github.rafostar.Clapper.pot (Hebrew)
2022-06-01 16:41:59 +02:00
Rafał Dzięgiel
e5723cd25a 0.5.1 2022-05-29 14:17:25 +02:00
Rafostar
e7808df7cc plugin: paintable: Fix widget size calculations on non-100% display scaling
Unlike legacy sink that used GLArea, GdkPaintable snapshots without pre-multiplying
sizes with scale factor. Remove scaling multiply of our widget dimensions,
so both video and widget width/height will be calculated correctly.

This fixes both image and black borders displaying issues on displays with
non-100% scaling applied.
2022-05-29 10:19:48 +02:00
Rafał Dzięgiel
8f22b36045 0.5.0 2022-05-28 19:19:05 +02:00
Rafał Dzięgiel
dc257846ce New Crowdin updates (#268)
* 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 (Basque)

* 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 (Italian)

* New translations com.github.rafostar.Clapper.pot (German)
2022-05-27 19:48:48 +02:00
Rafał Dzięgiel
af77873205 plugin: paintable: Remove unused value 2022-05-27 19:46:54 +02:00
Rafał Dzięgiel
5289b2f0a4 plugin: Fix scaled subtitles position on anamorph video
GStreamer does not take pixel aspect ratio into account for overlay rectangles.
If we do so, we end up with subtitles that are displayed off-center.
Behave like any other GStreamer sink on this matter.
2022-05-27 19:38:10 +02:00
Rafał Dzięgiel
87b3fbc15a Update POT file 2022-05-26 18:43:34 +02:00
Rafał Dzięgiel
59ff5bc006 Merge pull request #267 from Rafostar/fix-glx
Fix caps negotiation on GLX
2022-05-26 11:51:11 +02:00
Rafał Dzięgiel
91efc4ecdb plugin: gluploader: Use GLUpload provided propose_allocation method
Instead figuring out what kind of pool we should make just use the upstream provided
functionality that comes as part of GLUpload API.

Fixes uploads with GstVideoGLTextureUploadMeta, which legacy VAAPI plugin uses on GLX.
2022-05-26 10:21:11 +02:00
Rafał Dzięgiel
713449b4ab plugin: sink: Only add pool to query if there is one 2022-05-26 10:17:36 +02:00
Rafał Dzięgiel
3f7ba0674f plugin: importers: Support different template and actual caps
Make a template caps during class_init. It will be used for e.g. gst-inspect-1.0, while do and use an actual caps that current HW can handle.
2022-05-25 20:37:18 +02:00
Rafał Dzięgiel
5b89879031 plugin: gluploader: Remove DMABuf caps features on GLX
GLX cannot do DMABufs. Do not advertise its support in caps, so upstream elements will never try using this kind of memory on GLX.
2022-05-25 15:46:04 +02:00
Rafał Dzięgiel
2385af9b94 Merge pull request #265 from Rafostar/devel
Merge devel branch changes
2022-05-25 10:42:35 +02:00
Rafał Dzięgiel
54e4644236 app: Call window_present without timestamp
GTK4 now handles this internally via xdg-activation. To make it work correctly we should stop using custom timestamp so default handlers will be used.
2022-05-24 18:23:15 +02:00
Rafał Dzięgiel
3c248250f3 plugin: Always make sure we have Gdk display
Give up creating GL context in an unlikely situation that there is no default display
2022-05-24 16:48:00 +02:00
Rafał Dzięgiel
51619cbd2a plugin: Temporarily try to avoid direct DMABuf import on desktop
This tries to avoid "scrambled" image on Linux with Intel GPUs that are mostly used
together with x86 CPUs at the expense of using slightly slower non-direct DMABuf import,
by not going with GLES by default on EGL.

The "GST_GL_API" env can still be used to force one or another context type.

We need for GStreamer to be aware of currently used DRM modifier first. On the other
hand forcing GL everywhere would break most embedded systems that only work with GLES,
so do it for x86 processors only... and pray for it to work.

See: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1236
2022-05-24 16:36:43 +02:00
Rafał Dzięgiel
f9e84ac99b plugin: Improve GL context realization code
We only want GLES on EGL display, so check for it one by one instead of always trying to realize GLES with everything that is not a macOS
2022-05-24 16:36:32 +02:00
Rafał Dzięgiel
1bd371dabd app: Always activate before opening files
Make sure app window was created and bring it on top when started with file(s) as args
2022-05-23 15:32:32 +02:00
Rafał Dzięgiel
5f6c0922c0 plugin: Clear paintable importer in dispose
Remove our ref on importer a little earlier, with a lock taken
2022-05-23 15:02:25 +02:00
Rafał Dzięgiel
041deb559c headerbar: Merge code into single subclass
We no longer ship the web app that was reusing parts of this code.
Combine it into single file without additional subclass.
2022-05-23 14:19:37 +02:00
Rafał Dzięgiel
fce8ec59b8 app: Merge code into single subclass
We no longer ship the web app that was reusing parts of this code.
Combine it into single file without additional subclass.

Also put window creation inside first activate code instead of startup
in order to fix running app as a gapplication service.
2022-05-23 14:18:00 +02:00
Rafał Dzięgiel
306505dc4d data: Add missing desktop file options
Mark as DBusActivatable and enable StartupNotify
2022-05-23 11:55:15 +02:00
Rafał Dzięgiel
60234419c2 data: Add DBus service file 2022-05-23 11:54:50 +02:00
Rafał Dzięgiel
c395c6b9be Merge pull request #262 from Rafostar/reloaded
plugin: Make modules management separate per instance
2022-05-20 11:28:27 +02:00
Rafał Dzięgiel
8301cded2f plugin: Make modules management separate per instance
There were various problems with importer loader code. One defect was that
it kept managing a single global list of available importers and marking
which one is currently used on it. This made it not work correctly for
multiple sink instances in single process and was not thread safe.

This commit changes importer loader code into a GstObject subclass, which
keeps its own list of importers per instance and unlike before makes it
possible to free this data from memory when destroyed.

Now only open modules are kept always in memory until process finishes
since we cannot unload them once loaded anyway.
2022-05-20 10:13:14 +02:00
Rafał Dzięgiel
34386bc96c plugin: Use different lock for importer within paintable
This way we can avoid an additional importer ref + unref for every frame draw
2022-05-18 19:25:00 +02:00
Rafał Dzięgiel
2b85afc03e plugin: Do not use weak ref on importer
There is no good reason to keep using weak ref on importer within paintable object. Change that to a gst_object_ref which is faster.
2022-05-18 18:28:20 +02:00
Rafał Dzięgiel
bb56efa705 Merge pull request #261 from Rafostar/adw-fixes
libadwaita CSS fixes
2022-05-18 12:26:52 +02:00
Rafał Dzięgiel
82922e51f9 flatpak: Update GTK4 to 4.6.4
With latest GTK 4.6.4 the issues with opening popovers are finally fixed. Stop patching older version and just build the latest one.
2022-05-18 11:39:07 +02:00
Rafał Dzięgiel
ca64d9d2ee flatpak: Build recent libadwaita version
With updated CSS we use some variables intoduced in stable versions of libadwaita. To make it work properly, stop using alpha.2 and build recent stable version.
2022-05-18 11:39:04 +02:00
Rafostar
2a18c6a374 css: Misc fixes for recent Adwaita theme
Fixes for recent libadwaita provided theme, mainly needed to workaround:
https://gitlab.gnome.org/GNOME/libadwaita/-/issues/454

Devs rejected my idea of fixing it upstream. They said to override it
in my own app. So here it is.
2022-05-18 11:38:56 +02:00
Rafał Dzięgiel
af6cf01c98 player: Remove hardcoded ring buffer value
We should aim to have this as a configurable option.
Until then lets use the default value.
2022-05-17 22:07:21 +02:00
Rafał Dzięgiel
85bdbb1132 plugin: Prefer GL over GLES on macOS
Apple decoder uses rectangle texture-target, which GLES does not support
2022-05-16 19:16:36 +02:00
Rafał Dzięgiel
8e89b0d8ca gschema: Make resume video option disabled by default
A resume video question dialog that keeps poping confuses new Clapper users.
Looks like some spam. Change default option value to be disabled, so people
that are interested in this feature can enable it in preferences.
2022-05-16 09:45:36 +02:00
Rafostar
4e3cc3e23f plugin: Set initial display resolution to 1x1
We do not support zero width/height (described in our caps). Set initial video
dimensions to 1x1. They are going to be updated on first buffer after video info is set.

This avoids running into https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1139
and makes sure we do not do any divisions by zero here either.
2022-05-15 20:02:01 +02:00
Rafostar
c6c43346fa lib: Replace usage of "g_str_equal" with "g_strcmp0"
The first one is meant for hash tables comparisons and does not guard against NULL values (#259).
2022-05-15 14:45:49 +02:00
Rafał Dzięgiel
be58af2256 Merge pull request #256 from Rafostar/gl-win
plugin: Add GL support for Windows OS
2022-05-13 16:34:26 +02:00
Rafał Dzięgiel
343eef5894 plugin: Add GL support for Windows OS
Add support for both WGL and EGL on Win32
2022-05-13 15:17:53 +02:00
Rafał Dzięgiel
04657017f9 Merge pull request #257 from Rafostar/gl-macos
plugin: Add GL support for macOS
2022-05-13 14:12:09 +02:00
Rafał Dzięgiel
1cdaa36559 plugin: Add GL support for macOS 2022-05-13 13:53:35 +02:00
Rafał Dzięgiel
f351982067 plugin: Handle premultiplied alpha in RAW frames
Add support for premultiplied alpha flag detection when creating GdkMemoryTextures.
Also check if overlays have premultiplied alpha and if they do set this flag for
their video info, so it will be detected when creating a GdkMemoryTexture out of them.

Fixes performance issues with karaoke subtitles, as now GTK does not have to perform
unnecessary multiplication.
2022-05-12 18:08:53 +02:00
Rafał Dzięgiel
ae531db2b7 plugin: Have a separate mutex lock in GL base class
Make GL base importer class and all its subclasses that access parent props,
use a different mutex lock then the main importer class.

This way main importer class can continue processing buffers without waiting for
GL-based subclasses, as most GL operations (e.g. upload) are time consuming.
2022-05-11 22:00:49 +02:00
Rafał Dzięgiel
66fb8d4a1f Merge pull request #255 from Rafostar/fixes
Misc fixes
2022-05-11 21:21:33 +02:00
Rafał Dzięgiel
8f0ad12795 meson: Make sink compile on Windows OS
We cannot compile app as a whole on MS Windows yet, but with those changes it is now possible to compile and run our new video sink alone on Windows OS
2022-05-11 18:55:06 +02:00
Rafał Dzięgiel
908a388f68 meson: Give up on building GL base without GL windowing
We do not want to build GL-based importers when GTK GL windowing support is missing,
which might happen because of missing deps or on unsupported platform
2022-05-11 18:55:03 +02:00
Rafał Dzięgiel
7f33db4159 plugin: Fix possible buffer and v_info mismatch 2022-05-11 18:54:48 +02:00
Rafał Dzięgiel
288b829139 Further alter default plugin feature ranks on startup
Too many problems with VAAPI decodebin, meanwhile VA works fine and there is already
a pending MR on GStreamer to enable it by default, so we do that a little early.

We also do promise working HW accel out of box, so enable all common NVDEC elements too.
They can always be disabled back in player preferences window if any problems do happen.

We can now remove the alternations of v4l2codecs as those are PRIMARY+1 by default and we
now require GStreamer 1.20+ so no need for version checking there too.

Fixes #236
2022-05-11 11:50:15 +02:00
Rafał Dzięgiel
aa6d21973c gschema: Disable download buffering by default
We had this option enabled to workaround problems with old YT code.
Adaptive streaming now seems to work correctly, so restoring the
default play flags value.
2022-05-10 13:57:11 +02:00
Rafał Dzięgiel
e506063409 gschema: Remove leftover web app settings 2022-05-10 12:09:30 +02:00
Rafał Dzięgiel
e679430d3e meson: Set plugin option to be auto by default
This should allow to still compile and use the player with the legacy sink, without changing meson default options
2022-05-09 12:39:41 +02:00
Rafał Dzięgiel
4b93d4d132 meson: Cleanup plugin build script 2022-05-08 18:47:13 +02:00
Rafał Dzięgiel
b7b99c20cf meson: Do not go down in lib versioning
Install plugin lib stuff into a dir named "clapper-1.0" instead of "clapper-0.0". Even through our API is still very unstable, we cannot go down with versioning. The sink importers being installed there are not part of public API anyway.
2022-05-08 13:54:55 +02:00
Rafał Dzięgiel
5775738f67 plugin: Fix possible dir enumerator NULL unref
On an unlikely chance that sink was compiled without any importers, iterated dir does not exists thus we try to unref a NULL. Avoid doing that.
2022-05-07 13:43:51 +02:00
Rafał Dzięgiel
7159459160 meson: Cleanup of plugin build script 2022-05-06 21:08:03 +02:00
Rafał Dzięgiel
00650a596f obs: Use "trigger_services" step
Instead "rebuild_package" use "trigger_services" for OBS integration, otherwise the same old package is rebuild again and again.
2022-05-06 18:57:12 +02:00
Rafał Dzięgiel
6a995e2143 Merge pull request #253 from Rafostar/clappersink2
Move away from GtkGLArea
2022-05-06 17:52:56 +02:00
Rafał Dzięgiel
01b3feb213 New Crowdin updates (#247)
* New translations com.github.rafostar.Clapper.pot (Chinese Simplified)

* New translations com.github.rafostar.Clapper.pot (Portuguese)
2022-05-06 17:36:53 +02:00
Rafał Dzięgiel
5b9e7eacba meson: Do not auto build rawimporter when building gluploader
No need to auto build rawimporter if we are building gluploader as it
will be always loaded on startup, but never used.

Skip the build of it when its meson option is set to "auto".
2022-05-06 11:42:47 +02:00
Rafostar
b37ab432d7 player: 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-05-05 11:17:28 +02:00
Rafostar
0410c6e9b5 plugin: Add GL uploader
Add "clappergluploader" module which uses "glupload" and "glcolorconvert" internally,
allowing either uploading RAW system memory into GPU with GL colorspace conversion or
importing DMABufs into GL memory and making a GdkTexture out of them at one go.
2022-05-05 11:17:17 +02:00
Rafostar
3e0a0e0555 plugin: Add GL memory importer
Add "clapperglimporter" and a base class for creating GL importers. This module allows importing GL memory into GdkTexture.
2022-05-05 11:17:04 +02:00
Rafostar
5b7b7085e4 plugin: Add RAW system memory importer
Add "clapperrawimporter" module which allows importing RAW system memory mapped frames
2022-05-05 11:16:44 +02:00
Rafostar
044710f97e plugin: Add clapper GStreamer plugin
Add new GStreamer plugin with custom video sink 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 by other GTK4 apps if they wish to integrate it.

In order to not depend on GL stuff at build time, this plugin uses seperate GModules
called "importers" in order to import different kind of memories into GdkTexture. This
allows expanding its capabilities further then we were able to do before.
2022-05-05 11:16:34 +02:00
Rafał Dzięgiel
b83d500352 Merge pull request #245 from Rafostar/crowdin_sync
New Crowdin updates
2022-04-11 21:02:50 +02:00
Rafał Dzięgiel
3fadf13125 api: Also check "USE_PLAYBIN3" env
Some mobile distros seem to be under assumption that playbin3 is required to
get HW accel and setting this env by default is good idea. Both are wrong.

Check this env presence to avoid problems as factory will always return
playbin3 if set (even if playbin2 was requested).
2022-04-11 19:44:05 +02:00
Rafał Dzięgiel
f8fe49a809 obs: Add "workflows.yml" file 2022-04-11 18:08:52 +02:00
Rafał Dzięgiel
264f0abb64 New translations com.github.rafostar.Clapper.pot (Dutch) 2022-04-08 18:14:27 +02:00
Rafał Dzięgiel
b330aa1ccd workflow: Increase default timeout time
AArch64 build is taking a lot of time...
2022-04-08 17:27:38 +02:00
Rafał Dzięgiel
de8ecb8f82 flatpak: Do not build pango anymore
GNOME 42 runtime includes version that is new enough
2022-04-08 17:08:32 +02:00
Rafał Dzięgiel
a2bb927502 Update LINGUAS file 2022-04-08 10:08:05 +02:00
Rafał Dzięgiel
df728f383b Merge pull request #237 from Rafostar/crowdin_sync
New Crowdin updates
2022-04-08 10:01:39 +02:00
Rafał Dzięgiel
c80d2e9fd6 New translations com.github.rafostar.Clapper.pot (Turkish) 2022-04-02 03:43:30 +02:00
Rafał Dzięgiel
5a00301935 New translations com.github.rafostar.Clapper.pot (Turkish) 2022-04-02 02:44:03 +02:00
Rafał Dzięgiel
46b5a6df96 New translations com.github.rafostar.Clapper.pot (Japanese) 2022-04-01 11:06:26 +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
4f27739287 New translations com.github.rafostar.Clapper.pot (Japanese) 2022-03-31 10:08:37 +02:00
Rafał Dzięgiel
52aa7710dc Update README.md 2022-03-30 11:21:01 +02:00
Rafał Dzięgiel
0e49eaec7e New translations com.github.rafostar.Clapper.pot (Arabic) 2022-03-26 14:37:46 +01:00
Rafał Dzięgiel
62a923a3c1 New translations com.github.rafostar.Clapper.pot (Arabic) 2022-03-26 13:39:14 +01:00
Rafał Dzięgiel
f59b937316 New translations com.github.rafostar.Clapper.pot (Arabic) 2022-03-26 12:42:32 +01:00
Rafał Dzięgiel
8c914d0555 New translations com.github.rafostar.Clapper.pot (Arabic) 2022-03-25 22:09:19 +01:00
Rafał Dzięgiel
d2fab16093 New translations com.github.rafostar.Clapper.pot (Arabic) 2022-03-25 20:58:27 +01:00
Rafał Dzięgiel
67e877af0f New translations com.github.rafostar.Clapper.pot (Basque) 2022-03-25 17:45:32 +01:00
Rafał Dzięgiel
c825649a71 New translations com.github.rafostar.Clapper.pot (Basque) 2022-03-25 16:34:21 +01: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
490 changed files with 70443 additions and 36463 deletions

5
.gitattributes vendored
View File

@@ -1,5 +0,0 @@
extras/**/* linguist-vendored
lib/**/* linguist-vendored
lib/**/**/* linguist-vendored
lib/gst/clapper/gstclapper-mpris* linguist-vendored=false
lib/gst/clapper/gtk4/* linguist-vendored=false

58
.github/workflows/documentation.yml vendored Normal file
View File

@@ -0,0 +1,58 @@
on:
workflow_dispatch:
push:
branches:
- master
pull_request:
branches:
- master
name: "Documentation"
jobs:
documentation:
runs-on: ubuntu-latest
container:
image: registry.fedoraproject.org/fedora
options: --privileged
steps:
- name: Prepare
run: |
dnf -y install git gcc meson glib2-devel \
gstreamer1-devel gstreamer1-plugins-base-devel \
gtk4-devel libsoup3-devel libmicrodns-devel \
gobject-introspection-devel graphviz gi-docgen
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: false
fetch-depth: 0
- name: Build
run: |
meson setup builddir -Dauto_features=enabled \
-Denhancers-loader=disabled \
-Dclapper-app=disabled -Dvapi=disabled -Ddoc=true \
-Dglimporter=auto -Dgluploader=auto -Drawimporter=auto
cd builddir
meson compile
- name: Commit files
if: ${{ success() && github.ref == 'refs/heads/master' }}
continue-on-error: true
run: |
git config --global --add safe.directory $GITHUB_WORKSPACE
git checkout gh-pages
rm -rf doc/clapper/*
rm -rf doc/clapper-gtk/*
mv builddir/doc/reference/clapper/clapper.toml doc/clapper/
mv builddir/doc/reference/clapper/clapper/* doc/clapper/
mv builddir/doc/reference/clapper-gtk/clapper-gtk.toml doc/clapper-gtk/
mv builddir/doc/reference/clapper-gtk/clapper-gtk/* doc/clapper-gtk/
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add doc/clapper/* doc/clapper-gtk/*
git commit -m "doc: Update" || true
- name: Push changes
uses: ad-m/github-push-action@master
if: ${{ success() && github.ref == 'refs/heads/master' }}
continue-on-error: true
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: gh-pages

View File

@@ -1,32 +1,39 @@
on:
workflow_dispatch:
schedule:
- cron: "0 0 * * *"
name: "Flatpak Nightly"
jobs:
flatpak:
name: "Flatpak"
runs-on: ubuntu-latest
container:
image: bilelmoussaoui/flatpak-github-actions:gnome-nightly
options: --privileged
strategy:
matrix:
arch: [x86_64, aarch64]
os: [ubuntu-24.04, ubuntu-24.04-arm]
include:
- os: ubuntu-24.04
arch: x86_64
- os: ubuntu-24.04-arm
arch: aarch64
fail-fast: false
runs-on: ${{ matrix.os }}
container:
image: registry.fedoraproject.org/fedora
options: --privileged
steps:
- uses: actions/checkout@v2
- name: Prepare
run: |
dnf install -y git git-lfs dbus-daemon flatpak flatpak-builder libappstream-glib ccache zstd xorg-x11-server-Xvfb
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
flatpak remote-add --if-not-exists gnome-nightly https://nightly.gnome.org/gnome-nightly.flatpakrepo
flatpak --system install -y --noninteractive flathub org.freedesktop.Sdk.Extension.rust-stable/${{ matrix.arch }}/24.08
flatpak --system install -y --noninteractive flathub org.freedesktop.Sdk.Extension.llvm18/${{ matrix.arch }}/24.08
flatpak --system install -y --noninteractive flathub org.flatpak.Builder
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Docker
run: |
dnf -y install docker
- name: Setup QEMU
id: qemu
uses: docker/setup-qemu-action@v1
with:
platforms: arm64
- uses: bilelmoussaoui/flatpak-github-actions/flatpak-builder@v4
name: "Build"
- name: Build
uses: flatpak/flatpak-github-actions/flatpak-builder@master
with:
bundle: com.github.rafostar.Clapper.flatpak
manifest-path: pkgs/flatpak/com.github.rafostar.Clapper-nightly.json
@@ -34,3 +41,10 @@ jobs:
repository-url: https://nightly.gnome.org/gnome-nightly.flatpakrepo
cache-key: flatpak-builder-${{ github.sha }}-testing-${{ github.run_number }}
arch: ${{ matrix.arch }}
upload-artifact: false
- name: Upload
uses: actions/upload-artifact@v4
with:
name: clapper-flatpak-nightly-${{ matrix.arch }}
path: com.github.rafostar.Clapper.flatpak
if-no-files-found: error

View File

@@ -1,4 +1,5 @@
on:
workflow_dispatch:
push:
branches:
- master
@@ -9,30 +10,40 @@ name: "Flatpak"
jobs:
flatpak:
name: "Flatpak"
runs-on: ubuntu-latest
container:
image: bilelmoussaoui/flatpak-github-actions:gnome-41
options: --privileged
strategy:
matrix:
arch: [x86_64, aarch64]
os: [ubuntu-24.04, ubuntu-24.04-arm]
include:
- os: ubuntu-24.04
arch: x86_64
- os: ubuntu-24.04-arm
arch: aarch64
fail-fast: false
runs-on: ${{ matrix.os }}
container:
image: registry.fedoraproject.org/fedora
options: --privileged
steps:
- uses: actions/checkout@v2
- name: Prepare
run: |
dnf install -y git git-lfs dbus-daemon flatpak flatpak-builder libappstream-glib ccache zstd xorg-x11-server-Xvfb
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
flatpak --system install -y --noninteractive flathub org.flatpak.Builder
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Docker
run: |
dnf -y install docker
- name: Setup QEMU
id: qemu
uses: docker/setup-qemu-action@v1
with:
platforms: arm64
- uses: bilelmoussaoui/flatpak-github-actions/flatpak-builder@v4
name: "Build"
- name: Build
uses: flatpak/flatpak-github-actions/flatpak-builder@master
with:
bundle: com.github.rafostar.Clapper.flatpak
manifest-path: pkgs/flatpak/com.github.rafostar.Clapper.json
cache-key: flatpak-builder-${{ github.sha }}
arch: ${{ matrix.arch }}
upload-artifact: false
- name: Upload
uses: actions/upload-artifact@v4
with:
name: clapper-flatpak-${{ matrix.arch }}
path: com.github.rafostar.Clapper.flatpak
if-no-files-found: error

101
.github/workflows/windows.yml vendored Normal file
View File

@@ -0,0 +1,101 @@
on:
workflow_dispatch:
push:
branches:
- master
pull_request:
branches:
- master
name: "Windows"
jobs:
windows:
name: "Windows"
runs-on: windows-latest
strategy:
matrix:
arch: [x86_64]
defaults:
run:
shell: msys2 {0}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: MINGW64
update: true
install: |-
mingw-w64-${{ matrix.arch }}-meson
mingw-w64-${{ matrix.arch }}-gcc
mingw-w64-${{ matrix.arch }}-glib2
mingw-w64-${{ matrix.arch }}-gstreamer
mingw-w64-${{ matrix.arch }}-gst-plugins-base
mingw-w64-${{ matrix.arch }}-gst-plugins-good
mingw-w64-${{ matrix.arch }}-gst-plugins-bad
mingw-w64-${{ matrix.arch }}-gst-plugins-ugly
mingw-w64-${{ matrix.arch }}-gst-libav
mingw-w64-${{ matrix.arch }}-libpeas2
mingw-w64-${{ matrix.arch }}-libsoup3
mingw-w64-${{ matrix.arch }}-libmicrodns
mingw-w64-${{ matrix.arch }}-gtk4
mingw-w64-${{ matrix.arch }}-libadwaita
- name: Prepare
run: |
BUILD_PREFIX="$GITHUB_WORKSPACE/clapper-win-${{ matrix.arch }}"
mkdir -p $BUILD_PREFIX/bin
cp /mingw64/bin/gdbus.exe $BUILD_PREFIX/bin/
cp /mingw64/bin/gst-inspect-1.0.exe $BUILD_PREFIX/bin/
mkdir -p $BUILD_PREFIX/lib
cp -r /mingw64/lib/gio $BUILD_PREFIX/lib/
cp -r /mingw64/lib/gstreamer-1.0 $BUILD_PREFIX/lib/
cp -r /mingw64/lib/gdk-pixbuf-2.0 $BUILD_PREFIX/lib/
mkdir -p $BUILD_PREFIX/share/glib-2.0/schemas
cp -r /mingw64/share/glib-2.0/schemas/*.xml $BUILD_PREFIX/share/glib-2.0/schemas/
cp -r /mingw64/share/icons $BUILD_PREFIX/share/
mkdir -p $BUILD_PREFIX/share/xml/iso-codes
cp /mingw64/share/xml/iso-codes/iso_639.xml $BUILD_PREFIX/share/xml/iso-codes/
cd "$BUILD_PREFIX/lib/gstreamer-1.0"
rm -f \
libgstadpcmenc.dll libgstamfcodec.dll libgstdvbsubenc.dll libgstencoding.dll \
libgstfrei0r.dll libgstinter.dll libgstlame.dll libgstldac.dll libgstmpeg2enc.dll \
libgstmpegpsmux.dll libgstmpegtsmux.dll libgstmplex.dll libgstrealmedia.dll \
libgstsubenc.dll libgstsvtav1.dll libgstsvthevcenc.dll libgsttwolame.dll \
libgstvoamrwbenc.dll libgstwavenc.dll libgstx264.dll libgstx265.dll \
libgstxingmux.dll libgsty4menc.dll libgstzbar.dll
- name: Build
run: |
meson setup builddir --prefix=$GITHUB_WORKSPACE/clapper-win-${{ matrix.arch }}
cd builddir
meson compile
meson install
- name: Package
run: |
BUILD_PREFIX="$GITHUB_WORKSPACE/clapper-win-${{ matrix.arch }}"
ldd $BUILD_PREFIX/bin/clapper.exe | grep '\/mingw.*\.dll' -o | xargs -I{} cp -n "{}" $BUILD_PREFIX/bin
find $BUILD_PREFIX/lib/clapper-0.0/ -name '*\.dll' -type f -exec ldd "{}" \; | grep '\/mingw.*\.dll' -o | xargs -I{} cp -n "{}" $BUILD_PREFIX/bin
find $BUILD_PREFIX/lib/gstreamer-1.0/ -name '*\.dll' -type f -exec ldd "{}" \; | grep '\/mingw.*\.dll' -o | xargs -I{} cp -n "{}" $BUILD_PREFIX/bin
find $BUILD_PREFIX/lib/gio/ -name '*\.dll' -type f -exec ldd "{}" \; | grep '\/mingw.*\.dll' -o | xargs -I{} cp -n "{}" $BUILD_PREFIX/bin
- name: Cleanup
run: |
BUILD_PREFIX="$GITHUB_WORKSPACE/clapper-win-${{ matrix.arch }}"
rm -rf $BUILD_PREFIX/include
rm -rf $BUILD_PREFIX/lib/pkgconfig
- name: Installer
uses: Minionguyjpro/Inno-Setup-Action@v1.2.5
with:
path: builddir/pkgs/windows-installer/clapper.iss
options: /O+
- name: Upload
uses: actions/upload-artifact@v4
with:
name: clapper-win-${{ matrix.arch }}
path: builddir/pkgs/windows-installer/InstallerOutput/Clapper*.exe
if-no-files-found: error

3
.gitignore vendored
View File

@@ -2,3 +2,6 @@
build/
install/
builddir/
# flatpak
.flatpak-builder/

10
.obs/workflows.yml Normal file
View File

@@ -0,0 +1,10 @@
rebuild_master:
steps:
- trigger_services:
project: home:Rafostar
package: clapper
filters:
event: push
branches:
only:
- master

View File

@@ -55,7 +55,7 @@ modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
@@ -111,7 +111,7 @@ modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
@@ -158,7 +158,7 @@ Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
@@ -216,7 +216,7 @@ instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
@@ -267,7 +267,7 @@ Library will still fall under Section 6.)
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
@@ -329,7 +329,7 @@ restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
@@ -370,7 +370,7 @@ subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
@@ -422,7 +422,7 @@ conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
@@ -456,7 +456,7 @@ SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
@@ -485,7 +485,8 @@ convey the exclusion of warranty; and each file should have at least the
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA
Also add information on how to contact you by electronic and paper mail.
@@ -494,7 +495,8 @@ school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
library `Frob' (a library for tweaking knobs) written by James Random
Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice

View File

@@ -2,58 +2,62 @@
[![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).
Clapper is a modern media player designed for simplicity and ease of use. Powered by [GStreamer](https://gstreamer.freedesktop.org/) and built for the GNOME
desktop environment using [GTK4](https://www.gtk.org/) toolkit, it has a clean and stylish interface that lets you focus on enjoying your favorite videos.
This application aim is to offer all the essentials features you'd expect from a video player in a simple form.
<p align="center">
<img src="https://raw.githubusercontent.com/wiki/Rafostar/clapper/media/screenshot-windowed.png"><br>
<b>Windowed Mode</b>
<img src="https://raw.githubusercontent.com/wiki/Rafostar/clapper/media/screenshot_01.png">
</p>
Clapper uses a playback queue where you can add multiple media files. Think of it like a playlist that you can build.
You can easily reorder items or remove them from the queue with a simple drag and drop operation.
<p align="center">
<img src="https://raw.githubusercontent.com/wiki/Rafostar/clapper/media/screenshot-fullscreen.png"><br>
<b>Fullscreen Mode</b>
<img src="https://raw.githubusercontent.com/wiki/Rafostar/clapper/media/screenshot_03.png">
</p>
<p align="center">
<img src="https://raw.githubusercontent.com/wiki/Rafostar/clapper/media/screenshot-floating.png"><br>
<b>Floating Mode</b>
</p>
### Components
Clapper's codebase consists of 2 libraries using which main application is built:
* [Clapper](https://rafostar.github.io/clapper/doc/clapper/) - a playback library
* [ClapperGtk](https://rafostar.github.io/clapper/doc/clapper-gtk/) - a GTK integration library
### Features:
* [Hardware acceleration](https://github.com/Rafostar/clapper/wiki/Hardware-acceleration)
* [Floating mode](https://github.com/Rafostar/clapper/wiki/Floating-mode)
* [Adaptive UI](https://raw.githubusercontent.com/wiki/Rafostar/clapper/media/screenshot-mobile.png)
* [Playlist from file](https://github.com/Rafostar/clapper/wiki/Playlists)
* Chapters on progress bar
* MPRIS support
Both libraries support *GObject Introspection* bindings. A simple application example can be found [here](https://github.com/Rafostar/clapper-vala-test).
Above libraries are licensed under `LGPL-2.1-or-later`. You are free to use them in your own projects as long as you comply with license terms.
Please note that until version 1.0 they should be considered as an unstable API (some things may change without prior notice).
Clapper `Vala` bindings are part of this repo, while `Rust` bindings can be found [here](https://gitlab.gnome.org/JanGernert/clapper-rs).
## Installation from Flatpak
The `Flatpak` package includes all required dependencies and codecs.
Additionally it also has a few patches, thus some functionalities work better (or are only available) in `Flatpak` version (until my changes are accepted upstream).
Additionally it also has a few patches, thus some functionalities work better in `Flatpak` version (until my changes are accepted upstream).
List of patches used in this version can be found [here](https://github.com/Rafostar/clapper/issues/35).
<a href='https://flathub.org/apps/details/com.github.rafostar.Clapper'>
<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
meson setup builddir
cd builddir
meson compile
sudo meson install
```
If you want to compile app as `Flatpak`, remember to clone this repo with `--recurse-submodules` option.
## Questions?
Feel free to ask me any questions. Come and talk on Matrix: [#clapper-player:matrix.org](https://matrix.to/#/#clapper-player:matrix.org)
@@ -68,5 +72,6 @@ so if your language is not available, please contact me first.
Many thanks to [sp1ritCS](https://github.com/sp1ritCS) for creating and maintaining package build files.
Big thanks to [bridadan](https://github.com/bridadan) and [Uniformbuffer3](https://github.com/Uniformbuffer3) for helping
with testing V4L2 and NVDEC hardware acceleration methods.
Also words of appreciation for [JanGernert](https://gitlab.gnome.org/JanGernert) who made and is sharing Clapper Rust bindings.
Thanks a lot to all the people who are supporting the development with their anonymous donations through [Liberapay](https://liberapay.com/Clapper/). I :heart: U.

46
TODO.md
View File

@@ -1,46 +0,0 @@
- [X] Implement GstPlayer API
- [X] Update to custom GstClapper API
- [X] Inhibit screen locking
- [X] Hide cursor on video window
- Adaptive GUI:
- [X] Darker and bigger in fullscreen
- [X] Mobile/narrow widths transitions
- [ ] Mobile friendly other windows e.g. prefs window (libadwaita)
- [X] Dragging player by video (MPV)
- [X] Switching video/audio/subtitles tracks from bottom bar (MPV)
- [X] Over-amplification supported by default (VLC)
- [X] Audio visualizations (VLC)
- [X] Clock with current hour and "Ends at" time on top overlay (Kodi)
- [ ] Auto select subtitles matching OS language (Totem)
- [X] Picture-in-Picture mode window (floating window)
- [ ] Touch gestures/swipes support
- Media playlists:
- [X] Add more items to playlist via D&D
- [X] Select video from playlist
- [ ] Reorder playlist items via D&D
- [X] Load special playlist file (.claps)
- [X] Save to playlist file from GUI
- Seeking:
- [X] Customizable seek time
- [X] Set seek mode (default, accurate, fast)
- [ ] Statistics and codec info page (VLC)
- [X] Resume playback from last position
- [X] Chapters support
- [ ] Set tracks time offset
- [ ] Subtitles offset
- [X] Audio offset
- [ ] MDNS and UPNP (discovering media in local network)
- [X] DND files from Nautilus to play (ignore incompatible ones)
- [X] Support dropping whole folders
- [ ] Search for subtitles, download and activate (SMplayer)
- [ ] Auto add subtitles from same folder
- [ ] Set global subtitles folders
- [X] RSTP streaming
- [X] Playback speed
- [X] Remote playback controls via HTTP (VLC) + WebSockets
- [ ] Expand available API
- [ ] API documentation
- [X] Integration with the top bar
- [X] MPRIS support
- [X] Controls in the notifications panel
- [ ] Progress bar in the notifications panel (maybe via extension)

View File

@@ -1,14 +0,0 @@
<services>
<service name="obs_scm">
<param name="scm">git</param>
<param name="url">https://github.com/Rafostar/clapper.git</param>
<param name="extract">pkgs/rpm/clapper.spec</param>
<param name="extract">pkgs/rpm/clapper.rpmlintrc</param>
</service>
<service name="tar" mode="buildtime"/>
<service name="recompress" mode="buildtime">
<param name="compression">xz</param>
<param name="file">*.tar</param>
</service>
<service name="set_version" mode="buildtime"/>
</services>

View File

@@ -1,9 +0,0 @@
#!@GJS@
imports.package.init({
name: '@PACKAGE_NAME@',
version: '@PACKAGE_VERSION@',
prefix: '@prefix@',
libdir: '@libdir@',
});
imports.package.run(imports.src.main);

View File

@@ -1,22 +0,0 @@
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('prefix', get_option('prefix'))
bin_conf.set('libdir', libdir)
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',
join_paths(bindir, 'clapper')
)
meson.add_install_script('sh', '-c', clapper_symlink_cmd)

View File

@@ -1,22 +0,0 @@
#!/usr/bin/env python3
from os import environ, path
from subprocess import call
prefix = environ.get('MESON_INSTALL_PREFIX', '/usr/local')
sharedir = path.join(prefix, 'share')
destdir = environ.get('DESTDIR', '')
# Package managers set this so we don't need to run
if not destdir:
print('Updating icon cache...')
call(['gtk4-update-icon-cache', '-qtf', path.join(sharedir, 'icons', 'hicolor')])
print('Updating mime database...')
call(['update-mime-database', path.join(sharedir, 'mime')])
print('Updating desktop database...')
call(['update-desktop-database', '-q', path.join(sharedir, 'applications')])
print('Compiling GSettings schemas...')
call(['glib-compile-schemas', path.join(sharedir, 'glib-2.0', 'schemas')])

View File

@@ -1,3 +1,5 @@
files:
- source: /po/com.github.rafostar.Clapper.pot
translation: /po/%osx_locale%.po
- source: /src/lib/clapper-gtk/po/clapper-gtk.pot
translation: /src/lib/clapper-gtk/po/%osx_locale%.po
- source: /src/bin/clapper-app/po/clapper-app.pot
translation: /src/bin/clapper-app/po/%osx_locale%.po

View File

@@ -1,387 +0,0 @@
/* Defaults */
scale marks {
color: currentColor;
}
radio {
margin-left: -2px;
}
scrolledwindow scrollbar.vertical slider {
min-height: 16px;
}
/* Adwaita is missing osd ListBox */
.clapperplaylist {
background: none;
}
.clapperplaylist row {
border-radius: 5px;
}
.clapperplaylist row {
color: @theme_fg_color;
}
.clapperplaylist row button {
margin: 0px;
padding: 0px;
min-width: 28px;
min-height: 28px;
}
.fullscreen.tvmode .clapperplaylist row button {
min-width: 36px;
min-height: 36px;
margin-left: 2px;
margin-right: 2px;
}
.osd .clapperplaylist row image {
-gtk-icon-shadow: none;
}
.osdheaderbar {
background: transparent;
}
.osdheaderbar button {
border: transparent;
}
.linkseparator {
background: rgba(24,24,24,0.72);
min-width: 1px;
}
.linkedleft image {
margin-left: 2px;
}
.linkedright image {
margin-right: 2px;
}
/* Flat popovers */
popover arrow,
popover contents {
border-color: transparent;
box-shadow: none;
}
.popoverseparator separator {
background-color: @insensitive_fg_color;
}
/* Rounded corners */
.adwrounded.csd {
border-radius: 8px;
}
.adwrounded.fullscreen,
.adwrounded.maximized,
.adwrounded.tiled,
.adwrounded.tiled-top,
.adwrounded.tiled-left,
.adwrounded.tiled-right,
.adwrounded.tiled-bottom {
border-radius: 0px;
}
.roundedcorners {
border-radius: 8px;
}
/* Reduce sliders size */
scale trough slider {
min-height: 18px;
min-width: 18px;
}
.fullscreen.tvmode scale trough slider {
min-height: 20px;
min-width: 20px;
}
.videowidget {
min-width: 320px;
min-height: 180px;
}
.fullscreen.tvmode popover box {
text-shadow: none;
font-size: 21px;
font-weight: 500;
}
.clappercontrols {
margin-left: 2px;
margin-right: 2px;
}
.fullscreen.tvmode .clappercontrols {
margin-left: 1px;
margin-right: 1px;
}
.clappercontrolsbutton {
margin: 3px;
margin-left: 1px;
margin-right: 1px;
}
.fullscreen.tvmode .clappercontrolsbutton {
min-width: 32px;
min-height: 32px;
margin: 5px;
margin-left: 4px;
margin-right: 4px;
}
.clappercontrolsbutton.text-button {
padding-left: 4px;
padding-right: 4px;
}
.fullscreen.tvmode button image {
-gtk-icon-shadow: none;
}
.fullscreen.tvmode radio {
margin-left: 0px;
margin-right: 4px;
border: 2px solid;
min-width: 17px;
min-height: 17px;
}
/* Also affects popover buttons */
.fullscreen.tvmode .clappercontrols button image {
-gtk-icon-size: 26px;
}
.clappercontrolsbutton.text-button label {
font-family: 'Cantarell', sans-serif;
font-variant-numeric: tabular-nums;
font-weight: 600;
}
.fullscreen.tvmode .clappercontrolsbutton.text-button label {
font-size: 22px;
text-shadow: none;
}
/* Top Revealer */
.fullscreen.tvmode .revealertopgrid {
font-family: 'Cantarell', sans-serif;
}
.fullscreen.tvmode .tvtitle {
font-size: 28px;
font-weight: 500;
text-shadow: none;
}
.fullscreen.tvmode .tvtime {
margin-top: -2px;
margin-bottom: -2px;
min-height: 4px;
font-size: 38px;
font-weight: 700;
font-variant-numeric: tabular-nums;
}
.fullscreen.tvmode .tvendtime {
margin-top: -4px;
margin-bottom: 2px;
min-height: 6px;
font-size: 24px;
font-weight: 600;
font-variant-numeric: tabular-nums;
}
/* Position Scale */
.positionscale {
margin: -2px;
}
.positionscale trough highlight {
min-height: 6px;
}
.fullscreen.tvmode .positionscale {
padding-left: 12px;
padding-right: 12px;
}
.fullscreen.tvmode .positionscale.fine-tune {
padding-left: 12px;
padding-right: 12px;
}
.fullscreen.tvmode .positionscale trough slider {
color: transparent;
background: transparent;
border-color: transparent;
box-shadow: none;
outline: none;
}
.positionscale mark indicator {
min-height: 6px;
}
.positionscale.fine-tune mark indicator {
min-height: 6px;
}
.fullscreen.tvmode .positionscale mark indicator {
min-height: 7px;
min-width: 2px;
}
.fullscreen.tvmode .positionscale.fine-tune mark indicator {
min-height: 7px;
min-width: 2px;
}
.positionscale marks.top {
margin-top: -6px;
margin-bottom: 4px;
}
.positionscale marks.bottom {
margin-top: 4px;
margin-bottom: -6px;
}
.fullscreen.tvmode .positionscale marks.top {
margin-bottom: 2px;
}
.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;
}
.fullscreen.tvmode .positionscale.fine-tune trough highlight {
border-radius: 3px;
min-height: 20px;
}
/* Volume Scale */
.volumescale {
margin: -2px;
margin-left: -8px;
margin-right: -6px;
min-height: 180px;
}
.fullscreen.tvmode .volumescale {
margin: 2px;
margin-left: -6px;
margin-right: -4px;
min-height: 260px;
}
.volumescale marks label {
margin-right: 4px;
margin-top: -4px;
margin-bottom: -6px;
}
.volumescale trough highlight {
min-width: 4px;
}
.fullscreen.tvmode .volumescale trough highlight {
min-width: 6px;
}
.overamp trough highlight {
background: @error_color;
}
/* Elapsed Popover */
.elapsedpopover {
min-width: 326px;
}
.fullscreen.tvmode .elapsedpopover {
min-width: 448px;
}
.elapsedpopover contents {
padding-bottom: 0px;
}
.speedscale {
margin-left: 4px;
margin-right: 4px;
}
.speedscale trough highlight {
min-height: 4px;
}
.fullscreen.tvmode .speedscale trough highlight {
min-height: 6px;
}
.narrowbutton {
min-width: 8px;
}
@keyframes halfrotation {
to { transform: rotate(0.5turn); }
}
.halfrotate {
animation-name: halfrotation;
animation-duration: 200ms;
animation-delay: 280ms;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-iteration-count: 1;
}
/* Chapters */
.chapterlabel {
min-width: 32px;
}
.fullscreen.tvmode .chapterlabel {
min-width: 40px;
text-shadow: none;
font-size: 22px;
font-weight: 600;
}
/* Open URI Dialog */
.uridialogbox {
margin: 10px;
}
/* Tweaks */
.nobackground {
background: none;
}
.noborder {
border: none;
}
.controlsbox {
background: @theme_bg_color;
}
.gpufriendly {
box-shadow: -8px -8px transparent, 8px 8px transparent;
}
.fullscreen.gpufriendlyfs {
box-shadow: none;
}
/* Error BG */
.blackbackground {
background: black;
}
/** SCALING LOW-RES **/
.fullscreen.tvmode.lowres .clappercontrols button image {
-gtk-icon-size: 22px;
}
.fullscreen.tvmode.lowres .clappercontrolsbutton {
min-width: 28px;
min-height: 28px;
}
.fullscreen.tvmode.lowres .clappercontrolsbutton.text-button label {
font-size: 21px;
}
.fullscreen.tvmode.lowres .positionscale trough highlight {
min-height: 18px;
}
.fullscreen.tvmode.lowres .positionscale.fine-tune trough highlight {
min-height: 18px;
}
.fullscreen.tvmode.lowres popover box {
font-size: 19px;
}
.fullscreen.tvmode.lowres radio {
min-width: 15px;
min-height: 15px;
}
.fullscreen.tvmode.lowres .clapperplaylist row button {
min-width: 32px;
min-height: 32px;
}
.fullscreen.tvmode.lowres .tvtitle {
font-size: 26px;
}
.fullscreen.tvmode.lowres .tvtime {
font-size: 34px;
}
.fullscreen.tvmode.lowres .tvendtime {
font-size: 21px;
}
.fullscreen.tvmode.lowres .elapsedpopover {
min-width: 410px;
}
.fullscreen.tvmode.lowres .chapterlabel {
font-size: 21px;
}
/** SCALING HI-RES **/
.fullscreen.tvmode.hires .clappercontrols button image {
-gtk-icon-size: 24px; /* Sharpest on 2160p with scaling 2x */
}

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/com/github/rafostar/Clapper">
<file preprocess="xml-stripblanks" alias="icons/scalable/actions/play-symbolic.svg">icons/play-symbolic.svg</file>
<file preprocess="xml-stripblanks" alias="icons/scalable/actions/pause-symbolic.svg">icons/pause-symbolic.svg</file>
<file preprocess="xml-stripblanks" alias="icons/scalable/actions/pip-in-symbolic.svg">icons/pip-in-symbolic.svg</file>
<file preprocess="xml-stripblanks" alias="icons/scalable/actions/pip-out-symbolic.svg">icons/pip-out-symbolic.svg</file>
</gresource>
</gresources>

View File

@@ -1,116 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<schemalist gettext-domain="com.github.rafostar.Clapper">
<schema id="com.github.rafostar.Clapper" path="/com/github/rafostar/Clapper/">
<!-- General -->
<key name="fullscreen-auto" type="b">
<default>false</default>
<summary>Automatically enter fullscreen when first file is loaded</summary>
</key>
<key name="volume-custom" type="b">
<default>false</default>
<summary>Set custom volume value at startup</summary>
</key>
<key name="volume-value" type="i">
<default>100</default>
<summary>Custom initial volume value in percentage after startup</summary>
</key>
<key name="after-playback" type="i">
<default>0</default>
<summary>What to do after playback finishes</summary>
</key>
<!-- Behavior -->
<key name="seeking-mode" type="i">
<default>0</default>
<summary>Mode used for seeking</summary>
</key>
<key name="seeking-value" type="i">
<default>10</default>
<summary>Time amount to seek with single press of arrow keys</summary>
</key>
<key name="seeking-unit" type="i">
<default>0</default>
<summary>Unit ID to use with seeking value</summary>
</key>
<key name="resume-enabled" type="b">
<default>true</default>
<summary>Ask to resume unfinished video</summary>
</key>
<key name="resume-database" type="s">
<default>'[]'</default>
<summary>Data storing unfinished videos resume info</summary>
</key>
<key name="floating-stick" type="b">
<default>false</default>
<summary>Auto stick floating window to all workspaces</summary>
</key>
<!-- Audio -->
<key name="audio-offset" type="i">
<default>0</default>
<summary>Offset time for audio tracks relative to video (milliseconds)</summary>
</key>
<!-- Subtitles -->
<key name="subtitle-font" type="s">
<default>"Sans 12"</default>
<summary>The subtitles font description</summary>
</key>
<!-- Network -->
<key name="webserver-enabled" type="b">
<default>false</default>
<summary>Enable WebSocket server for remote playback control</summary>
</key>
<key name="webserver-port" type="i">
<default>6446</default>
<summary>Listening port to use for incoming WebSocket connections</summary>
</key>
<key name="webapp-enabled" type="b">
<default>false</default>
<summary>Run built-in broadway based web application</summary>
</key>
<key name="webapp-port" type="i">
<default>8086</default>
<summary>Port for running broadwayd service</summary>
</key>
<!-- Tweaks -->
<key name="dark-theme" type="b">
<default>true</default>
<summary>Enable to force the app to use dark theme variant</summary>
</key>
<key name="render-shadows" type="b">
<default>true</default>
<summary>Enable rendering window shadows (only if theme has them)</summary>
</key>
<!-- GStreamer -->
<key name="plugin-ranking" type="s">
<default>'{}'</default>
<summary>Custom values for GStreamer plugin ranking</summary>
</key>
<key name="use-playbin3" type="b">
<default>false</default>
<summary>Use playbin3 element instead of playbin2</summary>
</key>
<key name="use-pipewire" type="b">
<default>false</default>
<summary>Use PipeWire for audio output</summary>
</key>
<key name="play-flags" type="i">
<default>1687</default>
<summary>Set PlayFlags for playbin</summary>
</key>
<!-- Other -->
<key name="window-size" type="s">
<default>'[800, 490]'</default>
<summary>Stores window size to restore on next launch</summary>
</key>
<key name="volume-last" type="d">
<default>1</default>
<summary>Stores last linear volume value to apply on startup</summary>
</key>
</schema>
</schemalist>

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<g fill="#2e3436">
<path d="m 3 3 h 4 v 10 h -4 z m 0 0"/>
<path d="m 9 3 h 4 v 10 h -4 z m 0 0"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 262 B

View File

@@ -1,112 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<filter id="a" height="100%" width="100%" x="0%" y="0%">
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
</filter>
<mask id="b">
<g filter="url(#a)">
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.3"/>
</g>
</mask>
<clipPath id="c">
<path d="m 0 0 h 1024 v 800 h -1024 z"/>
</clipPath>
<mask id="d">
<g filter="url(#a)">
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
</g>
</mask>
<clipPath id="e">
<path d="m 0 0 h 1024 v 800 h -1024 z"/>
</clipPath>
<mask id="f">
<g filter="url(#a)">
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
</g>
</mask>
<clipPath id="g">
<path d="m 0 0 h 1024 v 800 h -1024 z"/>
</clipPath>
<mask id="h">
<g filter="url(#a)">
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
</g>
</mask>
<clipPath id="i">
<path d="m 0 0 h 1024 v 800 h -1024 z"/>
</clipPath>
<mask id="j">
<g filter="url(#a)">
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
</g>
</mask>
<clipPath id="k">
<path d="m 0 0 h 1024 v 800 h -1024 z"/>
</clipPath>
<mask id="l">
<g filter="url(#a)">
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
</g>
</mask>
<clipPath id="m">
<path d="m 0 0 h 1024 v 800 h -1024 z"/>
</clipPath>
<mask id="n">
<g filter="url(#a)">
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
</g>
</mask>
<clipPath id="o">
<path d="m 0 0 h 1024 v 800 h -1024 z"/>
</clipPath>
<mask id="p">
<g filter="url(#a)">
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.3"/>
</g>
</mask>
<clipPath id="q">
<path d="m 0 0 h 1024 v 800 h -1024 z"/>
</clipPath>
<mask id="r">
<g filter="url(#a)">
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.5"/>
</g>
</mask>
<clipPath id="s">
<path d="m 0 0 h 1024 v 800 h -1024 z"/>
</clipPath>
<g fill="#2e3436">
<path d="m 1 2.007812 c -0.550781 0 -1 0.449219 -1 1 v 9 c 0 0.550782 0.449219 1 1 1 h 4 v -2 h -3 v -7 h 10 v 3 h 2 v -4 c 0 -0.550781 -0.449219 -1 -1 -1 z m 0 0" fill-opacity="0.35"/>
<path d="m 9 10 c -0.550781 0 -1 0.449219 -1 1 v 4.007812 c 0 0.550782 0.449219 1 1 1 h 6 c 0.550781 0 1 -0.449218 1 -1 v -4.007812 c 0 -0.550781 -0.449219 -1 -1 -1 z m 1 2 h 4 v 2.007812 h -4 z m 0 0"/>
<path d="m 3.132812 5.140625 c 0.171876 -0.164063 0.496094 -0.1875 0.757813 0.015625 l 3.109375 3.089844 v 0.753906 h -0.753906 l -3.109375 -3.089844 c -0.191407 -0.191406 -0.179688 -0.597656 -0.003907 -0.769531 z m 0 0"/>
<path d="m 4 9 h 4 v 1 h -4 z m 0 0"/>
<path d="m 7 6 h 1 v 4 h -1 z m 0 0"/>
</g>
<g clip-path="url(#c)" mask="url(#b)" transform="matrix(1 0 0 1 -580 -764)">
<path d="m 562.460938 212.058594 h 10.449218 c -1.183594 0.492187 -1.296875 2.460937 0 3 h -10.449218 z m 0 0" fill="#2e3436"/>
</g>
<g clip-path="url(#e)" mask="url(#d)" transform="matrix(1 0 0 1 -580 -764)">
<path d="m 16 632 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
</g>
<g clip-path="url(#g)" mask="url(#f)" transform="matrix(1 0 0 1 -580 -764)">
<path d="m 17 631 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
</g>
<g clip-path="url(#i)" mask="url(#h)" transform="matrix(1 0 0 1 -580 -764)">
<path d="m 18 634 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
</g>
<g clip-path="url(#k)" mask="url(#j)" transform="matrix(1 0 0 1 -580 -764)">
<path d="m 16 634 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
</g>
<g clip-path="url(#m)" mask="url(#l)" transform="matrix(1 0 0 1 -580 -764)">
<path d="m 17 635 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
</g>
<g clip-path="url(#o)" mask="url(#n)" transform="matrix(1 0 0 1 -580 -764)">
<path d="m 19 635 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
</g>
<g clip-path="url(#q)" mask="url(#p)" transform="matrix(1 0 0 1 -580 -764)">
<path d="m 136 660 v 7 h 7 v -7 z m 0 0" fill="#2e3436"/>
</g>
<g clip-path="url(#s)" mask="url(#r)" transform="matrix(1 0 0 1 -580 -764)">
<path d="m 219 642 h 3 v 12 h -3 z m 0 0" fill="#2e3436"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.6 KiB

View File

@@ -1,112 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<filter id="a" height="100%" width="100%" x="0%" y="0%">
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
</filter>
<mask id="b">
<g filter="url(#a)">
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.3"/>
</g>
</mask>
<clipPath id="c">
<path d="m 0 0 h 1024 v 800 h -1024 z"/>
</clipPath>
<mask id="d">
<g filter="url(#a)">
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
</g>
</mask>
<clipPath id="e">
<path d="m 0 0 h 1024 v 800 h -1024 z"/>
</clipPath>
<mask id="f">
<g filter="url(#a)">
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
</g>
</mask>
<clipPath id="g">
<path d="m 0 0 h 1024 v 800 h -1024 z"/>
</clipPath>
<mask id="h">
<g filter="url(#a)">
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
</g>
</mask>
<clipPath id="i">
<path d="m 0 0 h 1024 v 800 h -1024 z"/>
</clipPath>
<mask id="j">
<g filter="url(#a)">
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
</g>
</mask>
<clipPath id="k">
<path d="m 0 0 h 1024 v 800 h -1024 z"/>
</clipPath>
<mask id="l">
<g filter="url(#a)">
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
</g>
</mask>
<clipPath id="m">
<path d="m 0 0 h 1024 v 800 h -1024 z"/>
</clipPath>
<mask id="n">
<g filter="url(#a)">
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
</g>
</mask>
<clipPath id="o">
<path d="m 0 0 h 1024 v 800 h -1024 z"/>
</clipPath>
<mask id="p">
<g filter="url(#a)">
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.3"/>
</g>
</mask>
<clipPath id="q">
<path d="m 0 0 h 1024 v 800 h -1024 z"/>
</clipPath>
<mask id="r">
<g filter="url(#a)">
<path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.5"/>
</g>
</mask>
<clipPath id="s">
<path d="m 0 0 h 1024 v 800 h -1024 z"/>
</clipPath>
<g fill="#2e3436">
<path d="m 1 2.007812 c -0.550781 0 -1 0.449219 -1 1 v 9 c 0 0.550782 0.449219 1 1 1 h 4 v -2 h -3 v -7 h 10 v 3 h 2 v -4 c 0 -0.550781 -0.449219 -1 -1 -1 z m 0 0"/>
<path d="m 9 10 c -0.550781 0 -1 0.449219 -1 1 v 4.007812 c 0 0.550782 0.449219 1 1 1 h 6 c 0.550781 0 1 -0.449218 1 -1 v -4.007812 c 0 -0.550781 -0.449219 -1 -1 -1 z m 1 2 h 4 v 2.007812 h -4 z m 0 0" fill-opacity="0.35"/>
<path d="m 7.863281 9.871094 c -0.167969 0.164062 -0.492187 0.1875 -0.753906 -0.019532 l -3.113281 -3.085937 v -0.753906 h 0.753906 l 3.109375 3.085937 c 0.191406 0.191406 0.179687 0.601563 0.003906 0.773438 z m 0 0"/>
<path d="m 6.996094 6.011719 h -4 v -1 h 4 z m 0 0"/>
<path d="m 3.996094 9.011719 h -1 v -4 h 1 z m 0 0"/>
</g>
<g clip-path="url(#c)" mask="url(#b)" transform="matrix(1 0 0 1 -600 -764)">
<path d="m 562.460938 212.058594 h 10.449218 c -1.183594 0.492187 -1.296875 2.460937 0 3 h -10.449218 z m 0 0" fill="#2e3436"/>
</g>
<g clip-path="url(#e)" mask="url(#d)" transform="matrix(1 0 0 1 -600 -764)">
<path d="m 16 632 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
</g>
<g clip-path="url(#g)" mask="url(#f)" transform="matrix(1 0 0 1 -600 -764)">
<path d="m 17 631 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
</g>
<g clip-path="url(#i)" mask="url(#h)" transform="matrix(1 0 0 1 -600 -764)">
<path d="m 18 634 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
</g>
<g clip-path="url(#k)" mask="url(#j)" transform="matrix(1 0 0 1 -600 -764)">
<path d="m 16 634 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
</g>
<g clip-path="url(#m)" mask="url(#l)" transform="matrix(1 0 0 1 -600 -764)">
<path d="m 17 635 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
</g>
<g clip-path="url(#o)" mask="url(#n)" transform="matrix(1 0 0 1 -600 -764)">
<path d="m 19 635 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
</g>
<g clip-path="url(#q)" mask="url(#p)" transform="matrix(1 0 0 1 -600 -764)">
<path d="m 136 660 v 7 h 7 v -7 z m 0 0" fill="#2e3436"/>
</g>
<g clip-path="url(#s)" mask="url(#r)" transform="matrix(1 0 0 1 -600 -764)">
<path d="m 219 642 h 3 v 12 h -3 z m 0 0" fill="#2e3436"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.7 KiB

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="2 2 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<path d="M 5 3.746094 L 5 16.246094 L 6.25 16.246094 C 6.46875 16.246094 6.683594 16.195312 6.875 16.089844 L 15.625 11.089844 C 16.015625 10.875 16.210938 10.433594 16.210938 9.996094 C 16.210938 9.554688 16.015625 9.117188 15.625 8.902344 L 6.875 3.902344 C 6.683594 3.792969 6.46875 3.746094 6.25 3.746094 Z M 5 3.746094" fill="#2e3436"/>
</svg>

Before

Width:  |  Height:  |  Size: 480 B

View File

@@ -1,34 +0,0 @@
iconsdir = join_paths(datadir, 'icons', 'hicolor')
appstream_util = find_program('appstream-util', required: false)
if appstream_util.found()
test('Validate appstream file', appstream_util, args: [
'validate-relax',
join_paths(meson.current_source_dir(), 'com.github.rafostar.Clapper.metainfo.xml')
])
endif
install_data('com.github.rafostar.Clapper.svg',
install_dir: join_paths(iconsdir, 'scalable', 'apps')
)
install_data('com.github.rafostar.Clapper-symbolic.svg',
install_dir: join_paths(iconsdir, 'symbolic', 'apps')
)
install_data('com.github.rafostar.Clapper.gschema.xml',
install_dir: join_paths(datadir, 'glib-2.0', 'schemas')
)
install_data('com.github.rafostar.Clapper.xml',
install_dir: join_paths(datadir, 'mime', 'packages')
)
install_data('com.github.rafostar.Clapper.desktop',
install_dir: join_paths(datadir, 'applications')
)
install_data('com.github.rafostar.Clapper.metainfo.xml',
install_dir: join_paths(datadir, 'metainfo')
)
gnome.compile_resources('com.github.rafostar.Clapper.data',
'com.github.rafostar.Clapper.data.gresource.xml',
gresource_bundle: true,
install: true,
install_dir: pkgdatadir,
)

10
doc/meson.build Normal file
View File

@@ -0,0 +1,10 @@
gi_docgen = find_program('gi-docgen', required: get_option('doc'))
dot = find_program('dot', required: get_option('doc')) # Class hierarchy generation
build_doc = (gi_docgen.found() and dot.found() and get_option('doc'))
if build_doc
if not build_gir
error('Building documentation requires introspection to be compiled')
endif
subdir('reference')
endif

View File

@@ -0,0 +1,63 @@
[library]
version = "@CLAPPER_VERSION@"
browse_url = "https://github.com/Rafostar/clapper/"
repository_url = "https://github.com/Rafostar/clapper.git"
website_url = "https://rafostar.github.io/clapper/"
docs_url = "https://rafostar.github.io/clapper/doc/clapper-gtk/"
authors = "Rafał Dzięgiel"
logo_url = "clapper-logo.svg"
license = "LGPL-2.1-or-later"
description = "Clapper GTK integration library"
devhelp = true
search_index = true
dependencies = ["Clapper@CLAPPER_VERSION_SUFFIX@", "Gtk-4.0"]
[dependencies."Clapper@CLAPPER_VERSION_SUFFIX@"]
name = "Clapper"
description = "Clapper playback library"
docs_url = "https://rafostar.github.io/clapper/doc/clapper/"
[dependencies."Gtk-4.0"]
name = "Gtk"
description = "The GTK toolkit"
docs_url = "https://docs.gtk.org/gtk4/"
related = ["GLib-2.0", "GObject-2.0", "Gio-2.0", "Gst-1.0"]
[related."GLib-2.0"]
name = "GLib"
description = "A general-purpose, portable utility library"
docs_url = "https://docs.gtk.org/glib/"
[related."GObject-2.0"]
name = "GObject"
description = "The base type system library"
docs_url = "https://docs.gtk.org/gobject/"
[related."Gio-2.0"]
name = "Gio"
description = "GObject Interfaces and Objects, Networking, IPC, and I/O"
docs_url = "https://docs.gtk.org/gio/"
[related."Gst-1.0"]
name = "Gst"
description = "GStreamer core library"
docs_url = "https://gstreamer.freedesktop.org/documentation/gstreamer/gi-index.html"
[theme]
name = "basic"
show_index_summary = true
show_class_hierarchy = true
[source-location]
base_url = "https://github.com/Rafostar/clapper/tree/master/"
[extra]
# The same order will be used when generating the index
content_files = [
]
content_images = [
"images/clapper-logo.svg",
]
urlmap_file = "urlmap.js"

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -0,0 +1,30 @@
clappergtk_toml = configure_file(
input: 'clapper-gtk.toml.in',
output: 'clapper-gtk.toml',
configuration: doc_version_conf,
install: true,
install_dir: join_paths(datadir, 'doc', 'clapper-gtk'),
)
custom_target('clapper-gtk-doc',
input: [
clappergtk_toml,
clappergtk_gir[0],
],
output: 'clapper-gtk',
command: [
gi_docgen,
'generate',
gi_docgen_common_args,
'--add-include-path=@0@'.format(join_paths(meson.project_build_root(), 'src', 'lib', 'clapper')),
'--add-include-path=@0@'.format(join_paths(meson.project_build_root(), 'src', 'lib', 'clapper-gtk')),
'--config=@INPUT0@',
'--output-dir=@OUTPUT@',
'--content-dir=@0@'.format(meson.current_build_dir()),
'--content-dir=@0@'.format(meson.current_source_dir()),
'@INPUT1@',
],
build_by_default: true,
install: true,
install_dir: join_paths(datadir, 'doc'),
)

View File

@@ -0,0 +1,8 @@
baseURLs = [
['GLib', 'https://docs.gtk.org/glib/'],
['GObject', 'https://docs.gtk.org/gobject/'],
['Gio', 'https://docs.gtk.org/gio/'],
['Gtk', 'https://docs.gtk.org/gtk4/'],
['Gst', 'https://gstreamer.freedesktop.org/documentation/gstreamer/gi-index.html?'],
['Clapper', 'https://rafostar.github.io/clapper/doc/clapper/'],
]

View File

@@ -0,0 +1,73 @@
[library]
version = "@CLAPPER_VERSION@"
browse_url = "https://github.com/Rafostar/clapper/"
repository_url = "https://github.com/Rafostar/clapper.git"
website_url = "https://rafostar.github.io/clapper/"
docs_url = "https://rafostar.github.io/clapper/doc/clapper/"
authors = "Rafał Dzięgiel"
logo_url = "clapper-logo.svg"
license = "LGPL-2.1-or-later"
description = "Clapper playback library"
devhelp = true
search_index = true
dependencies = ["GLib-2.0", "GObject-2.0", "Gio-2.0", "Gst-1.0", "GstBase-1.0", "GstAudio-1.0", "GstTag-1.0", "GstPbutils-1.0"]
[dependencies."GLib-2.0"]
name = "GLib"
description = "A general-purpose, portable utility library"
docs_url = "https://docs.gtk.org/glib/"
[dependencies."GObject-2.0"]
name = "GObject"
description = "The base type system library"
docs_url = "https://docs.gtk.org/gobject/"
[dependencies."Gio-2.0"]
name = "Gio"
description = "GObject Interfaces and Objects, Networking, IPC, and I/O"
docs_url = "https://docs.gtk.org/gio/"
[dependencies."Gst-1.0"]
name = "Gst"
description = "GStreamer core library"
docs_url = "https://gstreamer.freedesktop.org/documentation/gstreamer/gi-index.html"
[dependencies."GstBase-1.0"]
name = "GstBase"
description = "GStreamer base and utility classes"
docs_url = "https://gstreamer.freedesktop.org/documentation/base/"
[dependencies."GstAudio-1.0"]
name = "GstAudio"
description = "GStreamer audio library"
docs_url = "https://gstreamer.freedesktop.org/documentation/audio/"
[dependencies."GstTag-1.0"]
name = "GstTag"
description = "GStreamer tag support library"
docs_url = "https://gstreamer.freedesktop.org/documentation/tag/"
[dependencies."GstPbutils-1.0"]
name = "GstPbutils"
description = "GStreamer base utils library"
docs_url = "https://gstreamer.freedesktop.org/documentation/pbutils/"
related = []
[theme]
name = "basic"
show_index_summary = true
show_class_hierarchy = true
[source-location]
base_url = "https://github.com/Rafostar/clapper/tree/master/"
[extra]
# The same order will be used when generating the index
content_files = [
]
content_images = [
"images/clapper-logo.svg",
]
urlmap_file = "urlmap.js"

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 256 256" width="256" height="256">
<defs>
<path id="b1nGq5BrLC" d="M27.2 243.52C27.2 236.16 27.2 199.83 27.2 134.22C47.64 134.22 211.12 134.22 231.56 134.22C231.56 199.83 231.56 236.16 231.56 243.52C231.56 250.4 225.96 256 218.92 256C183.07 256 57.77 256 39.84 256C32.8 256 27.2 250.4 27.2 243.52Z"></path>
<path id="a3jkaoNn4k" d="M24.32 103.65C24.32 106.22 24.32 127.02 24.32 129.58C24.32 132.78 26.72 135.18 29.92 135.18C50.41 135.18 215.08 135.18 235.72 135.18C238.76 135.18 241.32 132.78 241.32 129.58C241.32 127.02 241.32 106.22 241.32 103.65C241.32 100.45 238.76 98.05 235.72 98.05C194.59 98.05 50.41 98.05 29.92 98.05C26.72 98.05 24.32 100.45 24.32 103.65Z"></path>
<path id="atpVQ8mnd" d="M174.59 135.18L211.87 98.05L171.07 98.05L133.78 135.18L174.59 135.18Z"></path>
<path id="bMtYoNHu0" d="M76.81 135.18L114.1 98.05L73.13 98.05L35.84 135.18L76.81 135.18Z"></path>
<path id="b5oP0Glp4" d="M19.04 69.41C19.84 71.97 25.92 91.97 26.72 94.37C27.68 97.41 30.72 99.01 33.76 98.05C54.09 91.81 216.68 42.04 237 35.8C240.04 35 241.64 31.8 240.84 28.92C240.04 26.36 233.96 6.36 233.16 3.96C232.2 0.92 229.16 -0.68 226.12 0.28C185.47 12.6 43.21 56.29 22.88 62.53C19.84 63.33 18.24 66.53 19.04 69.41Z"></path>
<path id="lwBgev6DR" d="M176.51 54.37L129.94 29.4L169.15 17.56L215.72 42.52L176.51 54.37Z"></path>
<path id="cUsjEMRUu" d="M81.61 83.49L35.04 58.69L74.25 46.69L120.82 71.49L81.61 83.49Z"></path>
<path id="c1bcHZGXe" d="M14.72 66.69C14.72 72.93 14.72 123.02 14.72 129.26C14.72 132.62 17.44 135.18 20.64 135.18C26.56 135.18 74.09 135.18 80.01 135.18C84.33 135.18 87.21 130.86 85.61 127.02C82.89 120.78 61.45 70.53 58.73 64.29C57.77 62.05 55.69 60.77 53.29 60.77C46.73 60.77 24 60.77 20.64 60.77C17.44 60.77 14.72 63.33 14.72 66.69Z"></path>
<path id="f2PtH0V1vC" d="M32.64 60.61C31.52 60.61 21.92 60.61 20.64 60.61C17.44 60.61 14.72 63.33 14.72 66.53C14.72 72.77 14.72 123.02 14.72 129.26C14.72 132.46 17.44 135.18 20.64 135.18C21.92 135.18 31.52 135.18 32.64 135.18C29.44 135.18 26.72 132.46 26.72 129.26C26.72 116.62 26.72 72.77 26.72 66.53C26.72 63.33 29.44 60.61 32.64 60.61Z"></path>
<path id="a1SvrrkqVm" d="M231.56 135.18C231.56 143.82 231.56 148.46 231.56 149.42C231.56 149.42 231.56 149.42 231.56 149.42C108.98 149.42 40.8 149.42 27.2 149.42C27.2 149.42 27.2 149.42 27.2 149.42C27.2 140.94 27.2 136.14 27.2 135.18C27.2 135.18 27.2 135.18 27.2 135.18C149.78 135.18 217.96 135.18 231.56 135.18C231.56 135.18 231.56 135.18 231.56 135.18Z"></path>
<path id="agXcvKqh8" d="M104.22 162.46L104.22 234.46L163.22 198.54L104.22 162.46Z"></path>
</defs>
<g>
<g><use xlink:href="#b1nGq5BrLC" fill="#4747d1" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
<g><use xlink:href="#a3jkaoNn4k" fill="#4747d1" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
<g><use xlink:href="#atpVQ8mnd" fill="#f1f1f1" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
<g><use xlink:href="#bMtYoNHu0" fill="#f1f1f1" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
<g><use xlink:href="#b5oP0Glp4" fill="#4747d1" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
<g><use xlink:href="#lwBgev6DR" fill="#f1f1f1" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
<g><use xlink:href="#cUsjEMRUu" fill="#f1f1f1" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
<g><use xlink:href="#c1bcHZGXe" fill="#a9a9a9" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
<g><use xlink:href="#f2PtH0V1vC" opacity="0.2" fill="#000000" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
<g><use xlink:href="#a1SvrrkqVm" opacity="0.2" fill="#000000" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
<g><use xlink:href="#agXcvKqh8" fill="#f1f1f1" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -0,0 +1,29 @@
clapper_toml = configure_file(
input: 'clapper.toml.in',
output: 'clapper.toml',
configuration: doc_version_conf,
install: true,
install_dir: join_paths(datadir, 'doc', 'clapper'),
)
custom_target('clapper-doc',
input: [
clapper_toml,
clapper_gir[0],
],
output: 'clapper',
command: [
gi_docgen,
'generate',
gi_docgen_common_args,
'--add-include-path=@0@'.format(join_paths(meson.project_build_root(), 'src', 'lib', 'clapper')),
'--config=@INPUT0@',
'--output-dir=@OUTPUT@',
'--content-dir=@0@'.format(meson.current_build_dir()),
'--content-dir=@0@'.format(meson.current_source_dir()),
'@INPUT1@',
],
build_by_default: true,
install: true,
install_dir: join_paths(datadir, 'doc'),
)

View File

@@ -0,0 +1,10 @@
baseURLs = [
['GLib', 'https://docs.gtk.org/glib/'],
['GObject', 'https://docs.gtk.org/gobject/'],
['Gio', 'https://docs.gtk.org/gio/'],
['Gst', 'https://gstreamer.freedesktop.org/documentation/gstreamer/gi-index.html?'],
['GstBase', 'https://gstreamer.freedesktop.org/documentation/base/?'],
['GstAudio', 'https://gstreamer.freedesktop.org/documentation/audio/?'],
['GstTag', 'https://gstreamer.freedesktop.org/documentation/tag/?'],
['GstPbutils', 'https://gstreamer.freedesktop.org/documentation/pbutils/?'],
]

18
doc/reference/meson.build Normal file
View File

@@ -0,0 +1,18 @@
doc_version_conf = configuration_data()
doc_version_conf.set('CLAPPER_VERSION', meson.project_version())
doc_version_conf.set('CLAPPER_VERSION_SUFFIX', clapper_version_suffix)
gi_docgen_common_args = [
'--quiet',
'--no-namespace-dir',
]
if get_option('werror')
gi_docgen_common_args += ['--fatal-warnings']
endif
if build_clapper
subdir('clapper')
endif
if build_clappergtk
subdir('clapper-gtk')
endif

View File

@@ -0,0 +1,57 @@
#!/usr/bin/env python3
import gi
gi.require_version('Adw', '1')
gi.require_version('Clapper', '0.0')
gi.require_version('ClapperGtk', '0.0')
gi.require_version('GLib', '2.0')
gi.require_version('Gtk', '4.0')
from gi.repository import Adw, Clapper, ClapperGtk, GLib, Gtk
import shutil
Clapper.init(None)
download_dir = GLib.build_filenamev([GLib.get_user_cache_dir(), "example_download_dir", None])
print('Using cache directory: {0}'.format(download_dir))
def on_download_complete(player, item, location):
# Media downloaded. Data from this file is still used for current playback (including seeking).
print('Download complete: {0} => {1}'.format(item.props.uri, location))
def on_activate(app):
win = Gtk.ApplicationWindow(application=app, default_width=640, default_height=396)
video = ClapperGtk.Video()
controls = ClapperGtk.SimpleControls(fullscreenable=False)
# Enable local storage caching and monitor it
video.props.player.set_download_dir(download_dir)
video.props.player.set_download_enabled(True)
video.props.player.connect('download-complete', on_download_complete)
# Configure playback
video.props.player.props.queue.set_progression_mode(Clapper.QueueProgressionMode.CAROUSEL)
video.props.player.set_autoplay(True)
# Assemble window
video.add_fading_overlay(controls)
win.set_child(video)
win.present()
# Create and add media for playback
item_1 = Clapper.MediaItem(uri='http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4')
item_2 = Clapper.MediaItem(uri='http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4')
video.props.player.props.queue.add_item(item_1)
video.props.player.props.queue.add_item(item_2)
# Create a new application
app = Adw.Application(application_id='com.example.ClapperDownloadCache')
app.connect('activate', on_activate)
# Run the application
app.run(None)
# Finally app should cleanup before exit. Possibly moving data to
# another dir if it wants to use it on next run and deleting what's
# left (so any unfinished downloads will also be removed).
print('Cleanup')
shutil.rmtree(download_dir)

View File

@@ -0,0 +1,45 @@
#!/usr/bin/env python3
import gi
gi.require_version('Adw', '1')
gi.require_version('Clapper', '0.0')
gi.require_version('ClapperGtk', '0.0')
gi.require_version('Gtk', '4.0')
from gi.repository import Adw, Clapper, ClapperGtk, Gtk
Clapper.init(None)
def on_toggle_fullscreen(video, win):
# Since this example uses only video inside normal window, all we
# need to toggle fullscreen is to invert its fullscreened property
win.props.fullscreened ^= True
def on_activate(app):
win = Gtk.ApplicationWindow(application=app, default_width=640, default_height=396)
video = ClapperGtk.Video()
controls = ClapperGtk.SimpleControls()
# This signal will be emitted when user requests fullscreen state change.
# It is app job to fullscreen video only (which might require something
# more than simply inverting fullscreen on the whole window).
video.connect('toggle-fullscreen', on_toggle_fullscreen, win)
# Create and add media for playback. First added media item to empty
# playback queue will be automatically selected.
item = Clapper.MediaItem(uri='http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4')
video.props.player.props.queue.add_item(item)
# Assemble window
video.add_fading_overlay(controls)
win.set_child(video)
win.present()
# Start playback
video.props.player.play()
# Create a new application
app = Adw.Application(application_id='com.example.ClapperSimple')
app.connect('activate', on_activate)
# Run the application
app.run(None)

View File

@@ -1,183 +0,0 @@
const { GLib } = imports.gi;
let ink = { Ink: null };
try {
ink = imports.ink;
} catch(e) {}
const { Ink } = ink;
const DEBUG_ENV = GLib.getenv('DEBUG');
var Debugger = class
{
constructor(name, opts)
{
opts = (opts && typeof opts === 'object')
? opts : {};
this.name = (name && typeof name === 'string')
? name : 'GJS';
this.print_state = (opts.print_state)
? true : false;
this.json_space = (typeof opts.json_space === 'number')
? opts.json_space : 2;
this.name_printer = opts.name_printer || this._getInkPrinter(true);
this.message_printer = opts.message_printer || this._getDefaultPrinter();
this.time_printer = opts.time_printer || this._getInkPrinter();
this.high_precision = opts.high_precision || false;
if(typeof opts.color !== 'undefined')
this.color = opts.color;
this._isEnabled = false;
this._lastDebug = GLib.get_monotonic_time();
this.enabled = (typeof opts.enabled !== 'undefined')
? opts.enabled : this._enabledAtStart;
}
get enabled()
{
return this._isEnabled;
}
set enabled(value)
{
if(this._isEnabled === value)
return;
this._isEnabled = (value) ? true : false;
if(!this.print_state)
return;
let state = (this.enabled) ? 'en' : 'dis';
this._runDebug(`debug ${state}abled`);
}
get color()
{
return this.name_printer.color;
}
set color(value)
{
this.name_printer.color = value;
this.time_printer.color = this.name_printer.color;
}
get debug()
{
return message => this._debug(message);
}
get _enabledAtStart()
{
if(!DEBUG_ENV)
return false;
let envArr = DEBUG_ENV.split(',');
return envArr.some(el => {
if(el === this.name || el === '*')
return true;
let searchType;
let offset = 0;
if(el.startsWith('*')) {
searchType = 'ends';
} else if(el.endsWith('*')) {
searchType = 'starts';
offset = 1;
}
if(!searchType)
return false;
return this.name[searchType + 'With'](
el.substring(1 - offset, el.length - offset)
);
});
}
_getInkPrinter(isBold)
{
if(!Ink)
return this._getDefaultPrinter();
let printer = new Ink.Printer({
color: Ink.colorFromText(this.name)
});
if(isBold)
printer.font = Ink.Font.BOLD;
return printer;
}
_getDefaultPrinter()
{
return {
getPainted: function() {
return Object.values(arguments);
}
};
}
_debug(message)
{
if(!this.enabled)
return;
this._runDebug(message);
}
_runDebug(message)
{
switch(typeof message) {
case 'string':
break;
case 'object':
if(
message !== null
&& (message.constructor === Object
|| message.constructor === Array)
) {
message = JSON.stringify(message, null, this.json_space);
break;
}
default:
message = String(message);
break;
}
let time = GLib.get_monotonic_time() - this._lastDebug;
if(!this.high_precision) {
time = (time < 1000)
? '+0ms'
: (time < 1000000)
? '+' + Math.floor(time / 1000) + 'ms'
: '+' + Math.floor(time / 1000000) + 's';
}
else {
time = (time < 1000)
? '+' + time + 'µs'
: (time < 1000000)
? '+' + (time / 1000).toFixed(3) + 'ms'
: '+' + (time / 1000000).toFixed(3) + 's';
}
printerr(
this.name_printer.getPainted(this.name),
this.message_printer.getPainted(message),
this.time_printer.getPainted(time)
);
this._lastDebug = GLib.get_monotonic_time();
}
}

View File

@@ -1,322 +0,0 @@
const TERM_ESC = '\x1B[';
const TERM_RESET = '0m';
var maxTransparency = 128;
var Font = {
VARIOUS: null,
REGULAR: 0,
BOLD: 1,
DIM: 2,
ITALIC: 3,
UNDERLINE: 4,
BLINK: 5,
REVERSE: 7,
HIDDEN: 8,
STRIKEOUT: 9,
};
var Color = {
VARIOUS: null,
DEFAULT: 39,
BLACK: 30,
RED: 31,
GREEN: 32,
YELLOW: 33,
BLUE: 34,
MAGENTA: 35,
CYAN: 36,
LIGHT_GRAY: 37,
DARK_GRAY: 90,
LIGHT_RED: 91,
LIGHT_GREEN: 92,
LIGHT_YELLOW: 93,
LIGHT_BLUE: 94,
LIGHT_MAGENTA: 95,
LIGHT_CYAN: 96,
WHITE: 97,
BROWN: colorFrom256(52),
LIGHT_BROWN: colorFrom256(130),
PINK: colorFrom256(205),
LIGHT_PINK: colorFrom256(211),
ORANGE: colorFrom256(208),
LIGHT_ORANGE: colorFrom256(214),
SALMON: colorFrom256(209),
LIGHT_SALMON: colorFrom256(216),
};
function colorFrom256(number)
{
if(typeof number === 'undefined')
number = Math.floor(Math.random() * 256) + 1;
return `38;5;${number || 0}`;
}
function colorFromRGB(R, G, B, A)
{
if(typeof R === 'undefined') {
R = Math.floor(Math.random() * 256);
G = Math.floor(Math.random() * 256);
B = Math.floor(Math.random() * 256);
}
else if(typeof G === 'undefined' && Array.isArray(R)) {
A = (R.length > 3) ? R[3] : 255;
B = (R.length > 2) ? R[2] : 0;
G = (R.length > 1) ? R[1] : 0;
R = (R.length > 0) ? R[0] : 0;
}
if(_getIsTransparent(A))
return Color.DEFAULT;
R = R || 0;
G = G || 0;
B = B || 0;
return `38;2;${R};${G};${B}`;
}
function colorFromHex(R, G, B, A)
{
if((Array.isArray(R)))
R = R.join('');
let str = (typeof G === 'undefined')
? String(R)
: (typeof A !== 'undefined')
? String(R) + String(G) + String(B) + String(A)
: (typeof B !== 'undefined')
? String(R) + String(G) + String(B)
: String(R) + String(G);
let offset = (str[0] === '#') ? 1 : 0;
let alphaIndex = 6 + offset;
while(str.length < alphaIndex)
str += '0';
A = (str.length > alphaIndex)
? parseInt(str.substring(alphaIndex, alphaIndex + 2), 16)
: 255;
str = str.substring(offset, alphaIndex);
let colorInt = parseInt(str, 16);
let u8arr = new Uint8Array(3);
u8arr[2] = colorInt;
u8arr[1] = colorInt >> 8;
u8arr[0] = colorInt >> 16;
return colorFromRGB(u8arr[0], u8arr[1], u8arr[2], A);
}
function colorFromText(text)
{
let value = _stringToDec(text);
/* Returns color from 1 to 221 every 10 */
return colorFrom256((value % 23) * 10 + 1);
}
function fontFromText(text)
{
let arr = Object.keys(Font);
let value = _stringToDec(text);
/* Return a font excluding first (null) */
return Font[arr[value % (arr.length - 1) + 1]];
}
function _getIsImage(args)
{
if(args.length !== 1)
return false;
let arg = args[0];
let argType = (typeof arg);
if(argType === 'string' || argType === 'number')
return false;
if(!Array.isArray(arg))
return false;
let depth = 2;
while(depth--) {
arg = arg[0];
if(!Array.isArray(arg))
return false;
}
return arg.some(val => val !== 'number');
}
function _getIsTransparent(A)
{
return (typeof A !== 'undefined' && A <= maxTransparency);
}
function _stringToDec(str)
{
str = str || '';
let len = str.length;
let total = 0;
while(len--)
total += Number(str.charCodeAt(len).toString(10));
return total;
}
var Printer = class
{
constructor(opts)
{
opts = opts || {};
const defaults = {
font: Font.REGULAR,
color: Color.DEFAULT,
background: Color.DEFAULT
};
for(let def in defaults) {
this[def] = (typeof opts[def] !== 'undefined')
? opts[def] : defaults[def];
}
}
print()
{
(_getIsImage(arguments))
? this._printImage(arguments[0], 'stdout')
: print(this._getPaintedArgs(arguments));
}
printerr()
{
(_getIsImage(arguments))
? this._printImage(arguments[0], 'stderr')
: printerr(this._getPaintedArgs(arguments));
}
getPainted()
{
return (_getIsImage(arguments))
? this._printImage(arguments[0], 'return')
: this._getPaintedArgs(arguments);
}
get background()
{
return this._background;
}
set background(value)
{
let valueType = (typeof value);
if(valueType === 'string') {
value = (value[2] === ';')
? '4' + value.substring(1)
: Number(value);
}
this._background = (valueType === 'object')
? null
: (value < 40 || value >= 90 && value < 100)
? value + 10
: value;
}
_getPaintedArgs(args)
{
let str = '';
for(let arg of args) {
if(Array.isArray(arg))
arg = arg.join(',');
let painted = this._getPaintedString(arg);
str += (str.length) ? ' ' + painted : painted;
}
return str;
}
_getPaintedString(text, noReset)
{
let str = TERM_ESC;
for(let option of ['font', 'color', '_background']) {
let optionType = (typeof this[option]);
str += (optionType === 'number' || optionType === 'string')
? this[option]
: (option === 'font' && Array.isArray(this[option]))
? this[option].join(';')
: (option === 'font')
? fontFromText(text)
: colorFromText(text);
str += (option !== '_background') ? ';' : 'm';
}
str += text;
return (noReset)
? str
: (str + TERM_ESC + TERM_RESET);
}
_printImage(pixelsArr, output)
{
let total = '';
let prevColor = this.color;
let prevBackground = this._background;
for(let row of pixelsArr) {
let paintedLine = '';
let block = ' ';
for(let i = 0; i < row.length; i++) {
let pixel = row[i];
let nextPixel = (i < row.length - 1) ? row[i + 1] : null;
if(nextPixel && pixel.every((value, index) =>
value === nextPixel[index]
)) {
block += ' ';
continue;
}
/* Do not use predefined functions here (it would impact performance) */
let isTransparent = (pixel.length >= 3) ? _getIsTransparent(pixel[3]) : false;
this.color = (isTransparent)
? Color.DEFAULT
: `38;2;${pixel[0]};${pixel[1]};${pixel[2]}`;
this._background = (isTransparent)
? Color.DEFAULT
: `48;2;${pixel[0]};${pixel[1]};${pixel[2]}`;
paintedLine += `${TERM_ESC}0;${this.color};${this._background}m${block}`;
block = ' ';
}
paintedLine += TERM_ESC + TERM_RESET;
switch(output) {
case 'stderr':
printerr(paintedLine);
break;
case 'return':
total += paintedLine + '\n';
break;
default:
print(paintedLine);
break;
}
}
this.color = prevColor;
this._background = prevBackground;
return total;
}
}

View File

@@ -1,42 +0,0 @@
/* GStreamer
* Copyright (C) 2018 GStreamer developers
* Copyright (C) 2021 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.
*/
#ifndef __GST_CLAPPER_PRELUDE_H__
#define __GST_CLAPPER_PRELUDE_H__
#include <gst/gst.h>
#ifndef GST_CLAPPER_API
# ifdef BUILDING_GST_CLAPPER
# define GST_CLAPPER_API GST_API_EXPORT /* from config.h */
# else
# define GST_CLAPPER_API GST_API_IMPORT
# endif
#endif
#ifndef GST_DISABLE_DEPRECATED
#define GST_CLAPPER_DEPRECATED GST_CLAPPER_API
#define GST_CLAPPER_DEPRECATED_FOR(f) GST_CLAPPER_API
#else
#define GST_CLAPPER_DEPRECATED G_DEPRECATED GST_CLAPPER_API
#define GST_CLAPPER_DEPRECATED_FOR(f) G_DEPRECATED_FOR(f) GST_CLAPPER_API
#endif
#endif /* __GST_CLAPPER_PRELUDE_H__ */

View File

@@ -1,34 +0,0 @@
/* GStreamer
*
* Copyright (C) 2014 Sebastian Dröge <sebastian@centricular.com>
* Copyright (C) 2021 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.
*/
#ifndef __CLAPPER_H__
#define __CLAPPER_H__
#include <gst/clapper/clapper-prelude.h>
#include <gst/clapper/gstclapper.h>
#include <gst/clapper/gstclapper-media-info.h>
#include <gst/clapper/gstclapper-g-main-context-signal-dispatcher.h>
#include <gst/clapper/gstclapper-video-overlay-video-renderer.h>
#include <gst/clapper/gstclapper-visualization.h>
#include <gst/clapper/gstclapper-mpris.h>
#include <gst/clapper/gstclapper-gtk4-plugin.h>
#endif /* __CLAPPER_H__ */

View File

@@ -1,214 +0,0 @@
/* GStreamer
*
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
* Copyright (C) 2021 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.
*/
/**
* SECTION:gstclapper-gmaincontextsignaldispatcher
* @title: GstClapperGMainContextSignalDispatcher
* @short_description: Clapper GLib MainContext dispatcher
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstclapper-g-main-context-signal-dispatcher.h"
struct _GstClapperGMainContextSignalDispatcher
{
GObject parent;
GMainContext *application_context;
};
struct _GstClapperGMainContextSignalDispatcherClass
{
GObjectClass parent_class;
};
static void
gst_clapper_g_main_context_signal_dispatcher_interface_init
(GstClapperSignalDispatcherInterface * iface);
enum
{
G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_0,
G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_APPLICATION_CONTEXT,
G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_LAST
};
G_DEFINE_TYPE_WITH_CODE (GstClapperGMainContextSignalDispatcher,
gst_clapper_g_main_context_signal_dispatcher, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GST_TYPE_CLAPPER_SIGNAL_DISPATCHER,
gst_clapper_g_main_context_signal_dispatcher_interface_init));
static GParamSpec
* g_main_context_signal_dispatcher_param_specs
[G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_LAST] = { NULL, };
static void
gst_clapper_g_main_context_signal_dispatcher_finalize (GObject * object)
{
GstClapperGMainContextSignalDispatcher *self =
GST_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER (object);
if (self->application_context)
g_main_context_unref (self->application_context);
G_OBJECT_CLASS
(gst_clapper_g_main_context_signal_dispatcher_parent_class)->finalize
(object);
}
static void
gst_clapper_g_main_context_signal_dispatcher_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec)
{
GstClapperGMainContextSignalDispatcher *self =
GST_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER (object);
switch (prop_id) {
case G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_APPLICATION_CONTEXT:
self->application_context = g_value_dup_boxed (value);
if (!self->application_context)
self->application_context = g_main_context_ref_thread_default ();
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_clapper_g_main_context_signal_dispatcher_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec)
{
GstClapperGMainContextSignalDispatcher *self =
GST_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER (object);
switch (prop_id) {
case G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_APPLICATION_CONTEXT:
g_value_set_boxed (value, self->application_context);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_clapper_g_main_context_signal_dispatcher_class_init
(GstClapperGMainContextSignalDispatcherClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize =
gst_clapper_g_main_context_signal_dispatcher_finalize;
gobject_class->set_property =
gst_clapper_g_main_context_signal_dispatcher_set_property;
gobject_class->get_property =
gst_clapper_g_main_context_signal_dispatcher_get_property;
g_main_context_signal_dispatcher_param_specs
[G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_APPLICATION_CONTEXT] =
g_param_spec_boxed ("application-context", "Application Context",
"Application GMainContext to dispatch signals to", G_TYPE_MAIN_CONTEXT,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class,
G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_LAST,
g_main_context_signal_dispatcher_param_specs);
}
static void
gst_clapper_g_main_context_signal_dispatcher_init
(G_GNUC_UNUSED GstClapperGMainContextSignalDispatcher * self)
{
}
typedef struct
{
void (*emitter) (gpointer data);
gpointer data;
GDestroyNotify destroy;
} GMainContextSignalDispatcherData;
static gboolean
g_main_context_signal_dispatcher_dispatch_gsourcefunc (gpointer user_data)
{
GMainContextSignalDispatcherData *data = user_data;
data->emitter (data->data);
return G_SOURCE_REMOVE;
}
static void
g_main_context_signal_dispatcher_dispatch_destroy (gpointer user_data)
{
GMainContextSignalDispatcherData *data = user_data;
if (data->destroy)
data->destroy (data->data);
g_free (data);
}
static void
gst_clapper_g_main_context_signal_dispatcher_dispatch (GstClapperSignalDispatcher
* iface, G_GNUC_UNUSED GstClapper * clapper, void (*emitter) (gpointer data),
gpointer data, GDestroyNotify destroy)
{
GstClapperGMainContextSignalDispatcher *self =
GST_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER (iface);
GMainContextSignalDispatcherData *gsourcefunc_data =
g_new (GMainContextSignalDispatcherData, 1);
gsourcefunc_data->emitter = emitter;
gsourcefunc_data->data = data;
gsourcefunc_data->destroy = destroy;
g_main_context_invoke_full (self->application_context,
G_PRIORITY_DEFAULT, g_main_context_signal_dispatcher_dispatch_gsourcefunc,
gsourcefunc_data, g_main_context_signal_dispatcher_dispatch_destroy);
}
static void
gst_clapper_g_main_context_signal_dispatcher_interface_init
(GstClapperSignalDispatcherInterface * iface)
{
iface->dispatch = gst_clapper_g_main_context_signal_dispatcher_dispatch;
}
/**
* gst_clapper_g_main_context_signal_dispatcher_new:
* @application_context: (allow-none): GMainContext to use or %NULL
*
* Creates a new GstClapperSignalDispatcher that uses @application_context,
* or the thread default one if %NULL is used. See gst_clapper_new().
*
* Returns: (transfer full): the new GstClapperSignalDispatcher
*/
GstClapperSignalDispatcher *
gst_clapper_g_main_context_signal_dispatcher_new (GMainContext *
application_context)
{
return g_object_new (GST_TYPE_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER,
"application-context", application_context, NULL);
}

View File

@@ -1,51 +0,0 @@
/* GStreamer
*
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
* Copyright (C) 2021 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.
*/
#ifndef __GST_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER_H__
#define __GST_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER_H__
#include <gst/clapper/gstclapper-types.h>
#include <gst/clapper/gstclapper-signal-dispatcher.h>
G_BEGIN_DECLS
typedef struct _GstClapperGMainContextSignalDispatcher
GstClapperGMainContextSignalDispatcher;
typedef struct _GstClapperGMainContextSignalDispatcherClass
GstClapperGMainContextSignalDispatcherClass;
#define GST_TYPE_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER (gst_clapper_g_main_context_signal_dispatcher_get_type ())
#define GST_IS_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER))
#define GST_IS_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER))
#define GST_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER, GstClapperGMainContextSignalDispatcherClass))
#define GST_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER, GstClapperGMainContextSignalDispatcher))
#define GST_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER, GstClapperGMainContextSignalDispatcherClass))
#define GST_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER_CAST(obj) ((GstClapperGMainContextSignalDispatcher*)(obj))
GST_CLAPPER_API
GType gst_clapper_g_main_context_signal_dispatcher_get_type (void);
GST_CLAPPER_API
GstClapperSignalDispatcher * gst_clapper_g_main_context_signal_dispatcher_new (GMainContext * application_context);
G_END_DECLS
#endif /* __GST_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER_H__ */

View File

@@ -1,123 +0,0 @@
/* GStreamer
*
* Copyright (C) 2021 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.
*/
/**
* SECTION:gstclapper-gtk4plugin
* @title: GstClapperGtk4Plugin
* @short_description: Clapper GTK4 plugin
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstclapper-gtk4-plugin.h"
#include "gtk4/gstclapperglsink.h"
enum
{
PROP_0,
PROP_VIDEO_SINK,
PROP_LAST
};
#define parent_class gst_clapper_gtk4_plugin_parent_class
G_DEFINE_TYPE_WITH_CODE (GstClapperGtk4Plugin, gst_clapper_gtk4_plugin,
G_TYPE_OBJECT, NULL);
static GParamSpec *param_specs[PROP_LAST] = { NULL, };
static void gst_clapper_gtk4_plugin_constructed (GObject * object);
static void gst_clapper_gtk4_plugin_finalize (GObject * object);
static void gst_clapper_gtk4_plugin_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_clapper_gtk4_plugin_init
(G_GNUC_UNUSED GstClapperGtk4Plugin * self)
{
}
static void gst_clapper_gtk4_plugin_class_init
(G_GNUC_UNUSED GstClapperGtk4PluginClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
gobject_class->constructed = gst_clapper_gtk4_plugin_constructed;
gobject_class->get_property = gst_clapper_gtk4_plugin_get_property;
gobject_class->finalize = gst_clapper_gtk4_plugin_finalize;
param_specs[PROP_VIDEO_SINK] =
g_param_spec_object ("video-sink",
"Video Sink", "Video sink to use with video renderer",
GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, PROP_LAST, param_specs);
}
static void
gst_clapper_gtk4_plugin_constructed (GObject * object)
{
GstClapperGtk4Plugin *self = GST_CLAPPER_GTK4_PLUGIN (object);
self->video_sink = g_object_new (GST_TYPE_CLAPPER_GL_SINK, NULL);
gst_object_ref_sink (self->video_sink);
G_OBJECT_CLASS (parent_class)->constructed (object);
}
static void
gst_clapper_gtk4_plugin_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstClapperGtk4Plugin *self = GST_CLAPPER_GTK4_PLUGIN (object);
switch (prop_id) {
case PROP_VIDEO_SINK:
g_value_set_object (value, self->video_sink);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_clapper_gtk4_plugin_finalize (GObject * object)
{
GstClapperGtk4Plugin *self = GST_CLAPPER_GTK4_PLUGIN (object);
gst_object_unref (self->video_sink);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
/**
* gst_clapper_gtk4_plugin_new:
*
* Creates a new GTK4 plugin.
*
* Returns: (transfer full): the new GstClapperGtk4Plugin
*/
GstClapperGtk4Plugin *
gst_clapper_gtk4_plugin_new (void)
{
return g_object_new (GST_TYPE_CLAPPER_GTK4_PLUGIN, NULL);
}

View File

@@ -1,72 +0,0 @@
/* GStreamer
*
* Copyright (C) 2021 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.
*/
#ifndef __GST_CLAPPER_GTK4_PLUGIN_H__
#define __GST_CLAPPER_GTK4_PLUGIN_H__
#include <gst/gst.h>
#include <gst/clapper/clapper-prelude.h>
G_BEGIN_DECLS
#define GST_TYPE_CLAPPER_GTK4_PLUGIN (gst_clapper_gtk4_plugin_get_type ())
#define GST_IS_CLAPPER_GTK4_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CLAPPER_GTK4_PLUGIN))
#define GST_IS_CLAPPER_GTK4_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CLAPPER_GTK4_PLUGIN))
#define GST_CLAPPER_GTK4_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CLAPPER_GTK4_PLUGIN, GstClapperGtk4PluginClass))
#define GST_CLAPPER_GTK4_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CLAPPER_GTK4_PLUGIN, GstClapperGtk4Plugin))
#define GST_CLAPPER_GTK4_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_CLAPPER_GTK4_PLUGIN, GstClapperGtk4PluginClass))
#define GST_CLAPPER_GTK4_PLUGIN_CAST(obj) ((GstClapperGtk4Plugin*)(obj))
typedef struct _GstClapperGtk4Plugin GstClapperGtk4Plugin;
typedef struct _GstClapperGtk4PluginClass GstClapperGtk4PluginClass;
/**
* GstClapperGtk4Plugin:
*
* Opaque #GstClapperGtk4Plugin object
*/
struct _GstClapperGtk4Plugin
{
/* <private> */
GObject parent;
GstElement *video_sink;
};
/**
* GstClapperGtk4PluginClass:
*
* The #GstClapperGtk4PluginClass struct only contains private data
*/
struct _GstClapperGtk4PluginClass
{
/* <private> */
GstElementClass parent_class;
};
GST_CLAPPER_API
GType gst_clapper_gtk4_plugin_get_type (void);
GST_CLAPPER_API
GstClapperGtk4Plugin * gst_clapper_gtk4_plugin_new (void);
G_END_DECLS
#endif /* __GST_CLAPPER_GTK4_PLUGIN__ */

View File

@@ -1,125 +0,0 @@
/* GStreamer
*
* Copyright (C) 2015 Brijesh Singh <brijesh.ksingh@gmail.com>
* Copyright (C) 2021 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 "gstclapper-media-info.h"
#ifndef __GST_CLAPPER_MEDIA_INFO_PRIVATE_H__
#define __GST_CLAPPER_MEDIA_INFO_PRIVATE_H__
struct _GstClapperStreamInfo
{
GObject parent;
gchar *codec;
GstCaps *caps;
gint stream_index;
GstTagList *tags;
gchar *stream_id;
};
struct _GstClapperStreamInfoClass
{
GObjectClass parent_class;
};
struct _GstClapperSubtitleInfo
{
GstClapperStreamInfo parent;
gchar *title;
gchar *language;
};
struct _GstClapperSubtitleInfoClass
{
GstClapperStreamInfoClass parent_class;
};
struct _GstClapperAudioInfo
{
GstClapperStreamInfo parent;
gint channels;
gint sample_rate;
guint bitrate;
guint max_bitrate;
gchar *language;
};
struct _GstClapperAudioInfoClass
{
GstClapperStreamInfoClass parent_class;
};
struct _GstClapperVideoInfo
{
GstClapperStreamInfo parent;
gint width;
gint height;
gint framerate_num;
gint framerate_denom;
gint par_num;
gint par_denom;
guint bitrate;
guint max_bitrate;
};
struct _GstClapperVideoInfoClass
{
GstClapperStreamInfoClass parent_class;
};
struct _GstClapperMediaInfo
{
GObject parent;
gchar *uri;
gchar *title;
gchar *container;
gboolean seekable, is_live;
GstTagList *tags;
GstToc *toc;
GstSample *image_sample;
GList *stream_list;
GList *audio_stream_list;
GList *video_stream_list;
GList *subtitle_stream_list;
GstClockTime duration;
};
struct _GstClapperMediaInfoClass
{
GObjectClass parent_class;
};
G_GNUC_INTERNAL GstClapperMediaInfo * gst_clapper_media_info_new (const gchar *uri);
G_GNUC_INTERNAL GstClapperMediaInfo * gst_clapper_media_info_copy (GstClapperMediaInfo *ref);
G_GNUC_INTERNAL GstClapperStreamInfo * gst_clapper_stream_info_new (gint stream_index, GType type);
G_GNUC_INTERNAL GstClapperStreamInfo * gst_clapper_stream_info_copy (GstClapperStreamInfo *ref);
#endif /* __GST_CLAPPER_MEDIA_INFO_PRIVATE_H__ */

View File

@@ -1,885 +0,0 @@
/* GStreamer
*
* Copyright (C) 2015 Brijesh Singh <brijesh.ksingh@gmail.com>
* Copyright (C) 2021 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.
*/
/**
* SECTION:gstclapper-mediainfo
* @title: GstClapperMediaInfo
* @short_description: Clapper Media Information
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstclapper-media-info.h"
#include "gstclapper-media-info-private.h"
/* Per-stream information */
G_DEFINE_ABSTRACT_TYPE (GstClapperStreamInfo, gst_clapper_stream_info,
G_TYPE_OBJECT);
static void
gst_clapper_stream_info_init (GstClapperStreamInfo * sinfo)
{
sinfo->stream_index = -1;
}
static void
gst_clapper_stream_info_finalize (GObject * object)
{
GstClapperStreamInfo *sinfo = GST_CLAPPER_STREAM_INFO (object);
g_free (sinfo->codec);
g_free (sinfo->stream_id);
if (sinfo->caps)
gst_caps_unref (sinfo->caps);
if (sinfo->tags)
gst_tag_list_unref (sinfo->tags);
G_OBJECT_CLASS (gst_clapper_stream_info_parent_class)->finalize (object);
}
static void
gst_clapper_stream_info_class_init (GstClapperStreamInfoClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
gobject_class->finalize = gst_clapper_stream_info_finalize;
}
/**
* gst_clapper_stream_info_get_index:
* @info: a #GstClapperStreamInfo
*
* Function to get stream index from #GstClapperStreamInfo instance.
*
* Returns: the stream index of this stream.
*/
gint
gst_clapper_stream_info_get_index (const GstClapperStreamInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_STREAM_INFO (info), -1);
return info->stream_index;
}
/**
* gst_clapper_stream_info_get_stream_type:
* @info: a #GstClapperStreamInfo
*
* Function to return human readable name for the stream type
* of the given @info (ex: "audio", "video", "subtitle")
*
* Returns: a human readable name
*/
const gchar *
gst_clapper_stream_info_get_stream_type (const GstClapperStreamInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_STREAM_INFO (info), NULL);
if (GST_IS_CLAPPER_VIDEO_INFO (info))
return "video";
else if (GST_IS_CLAPPER_AUDIO_INFO (info))
return "audio";
else
return "subtitle";
}
/**
* gst_clapper_stream_info_get_tags:
* @info: a #GstClapperStreamInfo
*
* Returns: (transfer none): the tags contained in this stream.
*/
GstTagList *
gst_clapper_stream_info_get_tags (const GstClapperStreamInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_STREAM_INFO (info), NULL);
return info->tags;
}
/**
* gst_clapper_stream_info_get_codec:
* @info: a #GstClapperStreamInfo
*
* A string describing codec used in #GstClapperStreamInfo.
*
* Returns: codec string or NULL on unknown.
*/
const gchar *
gst_clapper_stream_info_get_codec (const GstClapperStreamInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_STREAM_INFO (info), NULL);
return info->codec;
}
/**
* gst_clapper_stream_info_get_caps:
* @info: a #GstClapperStreamInfo
*
* Returns: (transfer none): the #GstCaps of the stream.
*/
GstCaps *
gst_clapper_stream_info_get_caps (const GstClapperStreamInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_STREAM_INFO (info), NULL);
return info->caps;
}
/* Video information */
G_DEFINE_TYPE (GstClapperVideoInfo, gst_clapper_video_info,
GST_TYPE_CLAPPER_STREAM_INFO);
static void
gst_clapper_video_info_init (GstClapperVideoInfo * info)
{
info->width = -1;
info->height = -1;
info->framerate_num = 0;
info->framerate_denom = 1;
info->par_num = 1;
info->par_denom = 1;
}
static void
gst_clapper_video_info_class_init (G_GNUC_UNUSED GstClapperVideoInfoClass * klass)
{
/* nothing to do here */
}
/**
* gst_clapper_video_info_get_width:
* @info: a #GstClapperVideoInfo
*
* Returns: the width of video in #GstClapperVideoInfo.
*/
gint
gst_clapper_video_info_get_width (const GstClapperVideoInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_VIDEO_INFO (info), -1);
return info->width;
}
/**
* gst_clapper_video_info_get_height:
* @info: a #GstClapperVideoInfo
*
* Returns: the height of video in #GstClapperVideoInfo.
*/
gint
gst_clapper_video_info_get_height (const GstClapperVideoInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_VIDEO_INFO (info), -1);
return info->height;
}
/**
* gst_clapper_video_info_get_framerate:
* @info: a #GstClapperVideoInfo
* @fps_n: (out): Numerator of frame rate
* @fps_d: (out): Denominator of frame rate
*
*/
void
gst_clapper_video_info_get_framerate (const GstClapperVideoInfo * info,
gint * fps_n, gint * fps_d)
{
g_return_if_fail (GST_IS_CLAPPER_VIDEO_INFO (info));
*fps_n = info->framerate_num;
*fps_d = info->framerate_denom;
}
/**
* gst_clapper_video_info_get_pixel_aspect_ratio:
* @info: a #GstClapperVideoInfo
* @par_n: (out): numerator
* @par_d: (out): denominator
*
* Returns the pixel aspect ratio in @par_n and @par_d
*
*/
void
gst_clapper_video_info_get_pixel_aspect_ratio (const GstClapperVideoInfo * info,
guint * par_n, guint * par_d)
{
g_return_if_fail (GST_IS_CLAPPER_VIDEO_INFO (info));
*par_n = info->par_num;
*par_d = info->par_denom;
}
/**
* gst_clapper_video_info_get_bitrate:
* @info: a #GstClapperVideoInfo
*
* Returns: the current bitrate of video in #GstClapperVideoInfo.
*/
gint
gst_clapper_video_info_get_bitrate (const GstClapperVideoInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_VIDEO_INFO (info), -1);
return info->bitrate;
}
/**
* gst_clapper_video_info_get_max_bitrate:
* @info: a #GstClapperVideoInfo
*
* Returns: the maximum bitrate of video in #GstClapperVideoInfo.
*/
gint
gst_clapper_video_info_get_max_bitrate (const GstClapperVideoInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_VIDEO_INFO (info), -1);
return info->max_bitrate;
}
/* Audio information */
G_DEFINE_TYPE (GstClapperAudioInfo, gst_clapper_audio_info,
GST_TYPE_CLAPPER_STREAM_INFO);
static void
gst_clapper_audio_info_init (GstClapperAudioInfo * info)
{
info->channels = 0;
info->sample_rate = 0;
info->bitrate = -1;
info->max_bitrate = -1;
}
static void
gst_clapper_audio_info_finalize (GObject * object)
{
GstClapperAudioInfo *info = GST_CLAPPER_AUDIO_INFO (object);
g_free (info->language);
G_OBJECT_CLASS (gst_clapper_audio_info_parent_class)->finalize (object);
}
static void
gst_clapper_audio_info_class_init (GstClapperAudioInfoClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
gobject_class->finalize = gst_clapper_audio_info_finalize;
}
/**
* gst_clapper_audio_info_get_language:
* @info: a #GstClapperAudioInfo
*
* Returns: the language of the stream, or NULL if unknown.
*/
const gchar *
gst_clapper_audio_info_get_language (const GstClapperAudioInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_AUDIO_INFO (info), NULL);
return info->language;
}
/**
* gst_clapper_audio_info_get_channels:
* @info: a #GstClapperAudioInfo
*
* Returns: the number of audio channels in #GstClapperAudioInfo.
*/
gint
gst_clapper_audio_info_get_channels (const GstClapperAudioInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_AUDIO_INFO (info), 0);
return info->channels;
}
/**
* gst_clapper_audio_info_get_sample_rate:
* @info: a #GstClapperAudioInfo
*
* Returns: the audio sample rate in #GstClapperAudioInfo.
*/
gint
gst_clapper_audio_info_get_sample_rate (const GstClapperAudioInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_AUDIO_INFO (info), 0);
return info->sample_rate;
}
/**
* gst_clapper_audio_info_get_bitrate:
* @info: a #GstClapperAudioInfo
*
* Returns: the audio bitrate in #GstClapperAudioInfo.
*/
gint
gst_clapper_audio_info_get_bitrate (const GstClapperAudioInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_AUDIO_INFO (info), -1);
return info->bitrate;
}
/**
* gst_clapper_audio_info_get_max_bitrate:
* @info: a #GstClapperAudioInfo
*
* Returns: the audio maximum bitrate in #GstClapperAudioInfo.
*/
gint
gst_clapper_audio_info_get_max_bitrate (const GstClapperAudioInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_AUDIO_INFO (info), -1);
return info->max_bitrate;
}
/* Subtitle information */
G_DEFINE_TYPE (GstClapperSubtitleInfo, gst_clapper_subtitle_info,
GST_TYPE_CLAPPER_STREAM_INFO);
static void
gst_clapper_subtitle_info_init (G_GNUC_UNUSED GstClapperSubtitleInfo * info)
{
/* nothing to do */
}
static void
gst_clapper_subtitle_info_finalize (GObject * object)
{
GstClapperSubtitleInfo *info = GST_CLAPPER_SUBTITLE_INFO (object);
g_free (info->title);
g_free (info->language);
G_OBJECT_CLASS (gst_clapper_subtitle_info_parent_class)->finalize (object);
}
static void
gst_clapper_subtitle_info_class_init (GstClapperSubtitleInfoClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
gobject_class->finalize = gst_clapper_subtitle_info_finalize;
}
/**
* gst_clapper_subtitle_info_get_title:
* @info: a #GstClapperSubtitleInfo
*
* Returns: the title of the stream, or NULL if unknown.
*/
const gchar *
gst_clapper_subtitle_info_get_title (const GstClapperSubtitleInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_SUBTITLE_INFO (info), NULL);
return info->title;
}
/**
* gst_clapper_subtitle_info_get_language:
* @info: a #GstClapperSubtitleInfo
*
* Returns: the language of the stream, or NULL if unknown.
*/
const gchar *
gst_clapper_subtitle_info_get_language (const GstClapperSubtitleInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_SUBTITLE_INFO (info), NULL);
return info->language;
}
/* Global media information */
G_DEFINE_TYPE (GstClapperMediaInfo, gst_clapper_media_info, G_TYPE_OBJECT);
static void
gst_clapper_media_info_init (GstClapperMediaInfo * info)
{
info->duration = -1;
info->is_live = FALSE;
info->seekable = FALSE;
}
static void
gst_clapper_media_info_finalize (GObject * object)
{
GstClapperMediaInfo *info = GST_CLAPPER_MEDIA_INFO (object);
g_free (info->uri);
g_free (info->title);
g_free (info->container);
if (info->tags)
gst_tag_list_unref (info->tags);
if (info->toc)
gst_toc_unref (info->toc);
if (info->image_sample)
gst_sample_unref (info->image_sample);
if (info->audio_stream_list)
g_list_free (info->audio_stream_list);
if (info->video_stream_list)
g_list_free (info->video_stream_list);
if (info->subtitle_stream_list)
g_list_free (info->subtitle_stream_list);
if (info->stream_list)
g_list_free_full (info->stream_list, g_object_unref);
G_OBJECT_CLASS (gst_clapper_media_info_parent_class)->finalize (object);
}
static void
gst_clapper_media_info_class_init (GstClapperMediaInfoClass * klass)
{
GObjectClass *oclass = (GObjectClass *) klass;
oclass->finalize = gst_clapper_media_info_finalize;
}
static GstClapperVideoInfo *
gst_clapper_video_info_new (void)
{
return g_object_new (GST_TYPE_CLAPPER_VIDEO_INFO, NULL);
}
static GstClapperAudioInfo *
gst_clapper_audio_info_new (void)
{
return g_object_new (GST_TYPE_CLAPPER_AUDIO_INFO, NULL);
}
static GstClapperSubtitleInfo *
gst_clapper_subtitle_info_new (void)
{
return g_object_new (GST_TYPE_CLAPPER_SUBTITLE_INFO, NULL);
}
static GstClapperStreamInfo *
gst_clapper_video_info_copy (GstClapperVideoInfo * ref)
{
GstClapperVideoInfo *ret;
ret = gst_clapper_video_info_new ();
ret->width = ref->width;
ret->height = ref->height;
ret->framerate_num = ref->framerate_num;
ret->framerate_denom = ref->framerate_denom;
ret->par_num = ref->par_num;
ret->par_denom = ref->par_denom;
ret->bitrate = ref->bitrate;
ret->max_bitrate = ref->max_bitrate;
return (GstClapperStreamInfo *) ret;
}
static GstClapperStreamInfo *
gst_clapper_audio_info_copy (GstClapperAudioInfo * ref)
{
GstClapperAudioInfo *ret;
ret = gst_clapper_audio_info_new ();
ret->sample_rate = ref->sample_rate;
ret->channels = ref->channels;
ret->bitrate = ref->bitrate;
ret->max_bitrate = ref->max_bitrate;
if (ref->language)
ret->language = g_strdup (ref->language);
return (GstClapperStreamInfo *) ret;
}
static GstClapperStreamInfo *
gst_clapper_subtitle_info_copy (GstClapperSubtitleInfo * ref)
{
GstClapperSubtitleInfo *ret;
ret = gst_clapper_subtitle_info_new ();
if (ref->title)
ret->title = g_strdup (ref->title);
if (ref->language)
ret->language = g_strdup (ref->language);
return (GstClapperStreamInfo *) ret;
}
GstClapperStreamInfo *
gst_clapper_stream_info_copy (GstClapperStreamInfo * ref)
{
GstClapperStreamInfo *info = NULL;
if (!ref)
return NULL;
if (GST_IS_CLAPPER_VIDEO_INFO (ref))
info = gst_clapper_video_info_copy ((GstClapperVideoInfo *) ref);
else if (GST_IS_CLAPPER_AUDIO_INFO (ref))
info = gst_clapper_audio_info_copy ((GstClapperAudioInfo *) ref);
else
info = gst_clapper_subtitle_info_copy ((GstClapperSubtitleInfo *) ref);
info->stream_index = ref->stream_index;
if (ref->tags)
info->tags = gst_tag_list_ref (ref->tags);
if (ref->caps)
info->caps = gst_caps_copy (ref->caps);
if (ref->codec)
info->codec = g_strdup (ref->codec);
if (ref->stream_id)
info->stream_id = g_strdup (ref->stream_id);
return info;
}
GstClapperMediaInfo *
gst_clapper_media_info_copy (GstClapperMediaInfo * ref)
{
GList *l;
GstClapperMediaInfo *info;
if (!ref)
return NULL;
info = gst_clapper_media_info_new (ref->uri);
info->duration = ref->duration;
info->seekable = ref->seekable;
info->is_live = ref->is_live;
if (ref->tags)
info->tags = gst_tag_list_ref (ref->tags);
if (ref->toc)
info->toc = gst_toc_ref (ref->toc);
if (ref->title)
info->title = g_strdup (ref->title);
if (ref->container)
info->container = g_strdup (ref->container);
if (ref->image_sample)
info->image_sample = gst_sample_ref (ref->image_sample);
for (l = ref->stream_list; l != NULL; l = l->next) {
GstClapperStreamInfo *s;
s = gst_clapper_stream_info_copy ((GstClapperStreamInfo *) l->data);
info->stream_list = g_list_append (info->stream_list, s);
if (GST_IS_CLAPPER_AUDIO_INFO (s))
info->audio_stream_list = g_list_append (info->audio_stream_list, s);
else if (GST_IS_CLAPPER_VIDEO_INFO (s))
info->video_stream_list = g_list_append (info->video_stream_list, s);
else
info->subtitle_stream_list =
g_list_append (info->subtitle_stream_list, s);
}
return info;
}
GstClapperStreamInfo *
gst_clapper_stream_info_new (gint stream_index, GType type)
{
GstClapperStreamInfo *info = NULL;
if (type == GST_TYPE_CLAPPER_AUDIO_INFO)
info = (GstClapperStreamInfo *) gst_clapper_audio_info_new ();
else if (type == GST_TYPE_CLAPPER_VIDEO_INFO)
info = (GstClapperStreamInfo *) gst_clapper_video_info_new ();
else
info = (GstClapperStreamInfo *) gst_clapper_subtitle_info_new ();
info->stream_index = stream_index;
return info;
}
GstClapperMediaInfo *
gst_clapper_media_info_new (const gchar * uri)
{
GstClapperMediaInfo *info;
g_return_val_if_fail (uri != NULL, NULL);
info = g_object_new (GST_TYPE_CLAPPER_MEDIA_INFO, NULL);
info->uri = g_strdup (uri);
return info;
}
/**
* gst_clapper_media_info_get_uri:
* @info: a #GstClapperMediaInfo
*
* Returns: the URI associated with #GstClapperMediaInfo.
*/
const gchar *
gst_clapper_media_info_get_uri (const GstClapperMediaInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), NULL);
return info->uri;
}
/**
* gst_clapper_media_info_is_seekable:
* @info: a #GstClapperMediaInfo
*
* Returns: %TRUE if the media is seekable.
*/
gboolean
gst_clapper_media_info_is_seekable (const GstClapperMediaInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), FALSE);
return info->seekable;
}
/**
* gst_clapper_media_info_is_live:
* @info: a #GstClapperMediaInfo
*
* Returns: %TRUE if the media is live.
*/
gboolean
gst_clapper_media_info_is_live (const GstClapperMediaInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), FALSE);
return info->is_live;
}
/**
* gst_clapper_media_info_get_stream_list:
* @info: a #GstClapperMediaInfo
*
* Returns: (transfer none) (element-type GstClapperStreamInfo): A #GList of
* matching #GstClapperStreamInfo.
*/
GList *
gst_clapper_media_info_get_stream_list (const GstClapperMediaInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), NULL);
return info->stream_list;
}
/**
* gst_clapper_media_info_get_video_streams:
* @info: a #GstClapperMediaInfo
*
* Returns: (transfer none) (element-type GstClapperVideoInfo): A #GList of
* matching #GstClapperVideoInfo.
*/
GList *
gst_clapper_media_info_get_video_streams (const GstClapperMediaInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), NULL);
return info->video_stream_list;
}
/**
* gst_clapper_media_info_get_subtitle_streams:
* @info: a #GstClapperMediaInfo
*
* Returns: (transfer none) (element-type GstClapperSubtitleInfo): A #GList of
* matching #GstClapperSubtitleInfo.
*/
GList *
gst_clapper_media_info_get_subtitle_streams (const GstClapperMediaInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), NULL);
return info->subtitle_stream_list;
}
/**
* gst_clapper_media_info_get_audio_streams:
* @info: a #GstClapperMediaInfo
*
* Returns: (transfer none) (element-type GstClapperAudioInfo): A #GList of
* matching #GstClapperAudioInfo.
*/
GList *
gst_clapper_media_info_get_audio_streams (const GstClapperMediaInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), NULL);
return info->audio_stream_list;
}
/**
* gst_clapper_media_info_get_duration:
* @info: a #GstClapperMediaInfo
*
* Returns: duration of the media.
*/
GstClockTime
gst_clapper_media_info_get_duration (const GstClapperMediaInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), -1);
return info->duration;
}
/**
* gst_clapper_media_info_get_tags:
* @info: a #GstClapperMediaInfo
*
* Returns: (transfer none): the tags contained in media info.
*/
GstTagList *
gst_clapper_media_info_get_tags (const GstClapperMediaInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), NULL);
return info->tags;
}
/**
* gst_clapper_media_info_get_toc:
* @info: a #GstClapperMediaInfo
*
* Returns: (transfer none): the toc contained in media info.
*/
GstToc *
gst_clapper_media_info_get_toc (const GstClapperMediaInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), NULL);
return info->toc;
}
/**
* gst_clapper_media_info_get_title:
* @info: a #GstClapperMediaInfo
*
* Returns: the media title. When metadata does not contain title,
* returns title parsed from URI.
*/
const gchar *
gst_clapper_media_info_get_title (const GstClapperMediaInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), NULL);
return info->title;
}
/**
* gst_clapper_media_info_get_container_format:
* @info: a #GstClapperMediaInfo
*
* Returns: the container format.
*/
const gchar *
gst_clapper_media_info_get_container_format (const GstClapperMediaInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), NULL);
return info->container;
}
/**
* gst_clapper_media_info_get_image_sample:
* @info: a #GstClapperMediaInfo
*
* Function to get the image (or preview-image) stored in taglist.
* Application can use `gst_sample_*_()` API's to get caps, buffer etc.
*
* Returns: (transfer none): GstSample or NULL.
*/
GstSample *
gst_clapper_media_info_get_image_sample (const GstClapperMediaInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), NULL);
return info->image_sample;
}
/**
* gst_clapper_media_info_get_number_of_streams:
* @info: a #GstClapperMediaInfo
*
* Returns: number of total streams.
*/
guint
gst_clapper_media_info_get_number_of_streams (const GstClapperMediaInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), 0);
return g_list_length (info->stream_list);
}
/**
* gst_clapper_media_info_get_number_of_video_streams:
* @info: a #GstClapperMediaInfo
*
* Returns: number of video streams.
*/
guint
gst_clapper_media_info_get_number_of_video_streams (const GstClapperMediaInfo *
info)
{
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), 0);
return g_list_length (info->video_stream_list);
}
/**
* gst_clapper_media_info_get_number_of_audio_streams:
* @info: a #GstClapperMediaInfo
*
* Returns: number of audio streams.
*/
guint
gst_clapper_media_info_get_number_of_audio_streams (const GstClapperMediaInfo *
info)
{
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), 0);
return g_list_length (info->audio_stream_list);
}
/**
* gst_clapper_media_info_get_number_of_subtitle_streams:
* @info: a #GstClapperMediaInfo
*
* Returns: number of subtitle streams.
*/
guint gst_clapper_media_info_get_number_of_subtitle_streams
(const GstClapperMediaInfo * info)
{
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), 0);
return g_list_length (info->subtitle_stream_list);
}

View File

@@ -1,253 +0,0 @@
/* GStreamer
*
* Copyright (C) 2015 Brijesh Singh <brijesh.ksingh@gmail.com>
* Copyright (C) 2021 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.
*/
#ifndef __GST_CLAPPER_MEDIA_INFO_H__
#define __GST_CLAPPER_MEDIA_INFO_H__
#include <gst/gst.h>
#include <gst/clapper/clapper-prelude.h>
G_BEGIN_DECLS
#define GST_TYPE_CLAPPER_STREAM_INFO \
(gst_clapper_stream_info_get_type ())
#define GST_CLAPPER_STREAM_INFO(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CLAPPER_STREAM_INFO,GstClapperStreamInfo))
#define GST_CLAPPER_STREAM_INFO_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CLAPPER_STREAM_INFO,GstClapperStreamInfo))
#define GST_IS_CLAPPER_STREAM_INFO(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CLAPPER_STREAM_INFO))
#define GST_IS_CLAPPER_STREAM_INFO_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CLAPPER_STREAM_INFO))
/**
* GstClapperStreamInfo:
*
* Base structure for information concerning a media stream. Depending on
* the stream type, one can find more media-specific information in
* #GstClapperVideoInfo, #GstClapperAudioInfo, #GstClapperSubtitleInfo.
*/
typedef struct _GstClapperStreamInfo GstClapperStreamInfo;
typedef struct _GstClapperStreamInfoClass GstClapperStreamInfoClass;
GST_CLAPPER_API
GType gst_clapper_stream_info_get_type (void);
GST_CLAPPER_API
gint gst_clapper_stream_info_get_index (const GstClapperStreamInfo *info);
GST_CLAPPER_API
const gchar* gst_clapper_stream_info_get_stream_type (const GstClapperStreamInfo *info);
GST_CLAPPER_API
GstTagList* gst_clapper_stream_info_get_tags (const GstClapperStreamInfo *info);
GST_CLAPPER_API
GstCaps* gst_clapper_stream_info_get_caps (const GstClapperStreamInfo *info);
GST_CLAPPER_API
const gchar* gst_clapper_stream_info_get_codec (const GstClapperStreamInfo *info);
#define GST_TYPE_CLAPPER_VIDEO_INFO \
(gst_clapper_video_info_get_type ())
#define GST_CLAPPER_VIDEO_INFO(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CLAPPER_VIDEO_INFO, GstClapperVideoInfo))
#define GST_CLAPPER_VIDEO_INFO_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((obj),GST_TYPE_CLAPPER_VIDEO_INFO, GstClapperVideoInfoClass))
#define GST_IS_CLAPPER_VIDEO_INFO(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CLAPPER_VIDEO_INFO))
#define GST_IS_CLAPPER_VIDEO_INFO_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((obj),GST_TYPE_CLAPPER_VIDEO_INFO))
/**
* GstClapperVideoInfo:
*
* #GstClapperStreamInfo specific to video streams.
*/
typedef struct _GstClapperVideoInfo GstClapperVideoInfo;
typedef struct _GstClapperVideoInfoClass GstClapperVideoInfoClass;
GST_CLAPPER_API
GType gst_clapper_video_info_get_type (void);
GST_CLAPPER_API
gint gst_clapper_video_info_get_bitrate (const GstClapperVideoInfo * info);
GST_CLAPPER_API
gint gst_clapper_video_info_get_max_bitrate (const GstClapperVideoInfo * info);
GST_CLAPPER_API
gint gst_clapper_video_info_get_width (const GstClapperVideoInfo * info);
GST_CLAPPER_API
gint gst_clapper_video_info_get_height (const GstClapperVideoInfo * info);
GST_CLAPPER_API
void gst_clapper_video_info_get_framerate (const GstClapperVideoInfo * info,
gint * fps_n,
gint * fps_d);
GST_CLAPPER_API
void gst_clapper_video_info_get_pixel_aspect_ratio (const GstClapperVideoInfo * info,
guint * par_n,
guint * par_d);
#define GST_TYPE_CLAPPER_AUDIO_INFO \
(gst_clapper_audio_info_get_type ())
#define GST_CLAPPER_AUDIO_INFO(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CLAPPER_AUDIO_INFO, GstClapperAudioInfo))
#define GST_CLAPPER_AUDIO_INFO_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CLAPPER_AUDIO_INFO, GstClapperAudioInfoClass))
#define GST_IS_CLAPPER_AUDIO_INFO(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CLAPPER_AUDIO_INFO))
#define GST_IS_CLAPPER_AUDIO_INFO_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CLAPPER_AUDIO_INFO))
/**
* GstClapperAudioInfo:
*
* #GstClapperStreamInfo specific to audio streams.
*/
typedef struct _GstClapperAudioInfo GstClapperAudioInfo;
typedef struct _GstClapperAudioInfoClass GstClapperAudioInfoClass;
GST_CLAPPER_API
GType gst_clapper_audio_info_get_type (void);
GST_CLAPPER_API
gint gst_clapper_audio_info_get_channels (const GstClapperAudioInfo* info);
GST_CLAPPER_API
gint gst_clapper_audio_info_get_sample_rate (const GstClapperAudioInfo* info);
GST_CLAPPER_API
gint gst_clapper_audio_info_get_bitrate (const GstClapperAudioInfo* info);
GST_CLAPPER_API
gint gst_clapper_audio_info_get_max_bitrate (const GstClapperAudioInfo* info);
GST_CLAPPER_API
const gchar* gst_clapper_audio_info_get_language (const GstClapperAudioInfo* info);
#define GST_TYPE_CLAPPER_SUBTITLE_INFO \
(gst_clapper_subtitle_info_get_type ())
#define GST_CLAPPER_SUBTITLE_INFO(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CLAPPER_SUBTITLE_INFO, GstClapperSubtitleInfo))
#define GST_CLAPPER_SUBTITLE_INFO_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CLAPPER_SUBTITLE_INFO,GstClapperSubtitleInfoClass))
#define GST_IS_CLAPPER_SUBTITLE_INFO(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CLAPPER_SUBTITLE_INFO))
#define GST_IS_CLAPPER_SUBTITLE_INFO_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CLAPPER_SUBTITLE_INFO))
/**
* GstClapperSubtitleInfo:
*
* #GstClapperStreamInfo specific to subtitle streams.
*/
typedef struct _GstClapperSubtitleInfo GstClapperSubtitleInfo;
typedef struct _GstClapperSubtitleInfoClass GstClapperSubtitleInfoClass;
GST_CLAPPER_API
GType gst_clapper_subtitle_info_get_type (void);
GST_CLAPPER_API
const gchar * gst_clapper_subtitle_info_get_title (const GstClapperSubtitleInfo *info);
GST_CLAPPER_API
const gchar * gst_clapper_subtitle_info_get_language (const GstClapperSubtitleInfo *info);
#define GST_TYPE_CLAPPER_MEDIA_INFO \
(gst_clapper_media_info_get_type())
#define GST_CLAPPER_MEDIA_INFO(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CLAPPER_MEDIA_INFO,GstClapperMediaInfo))
#define GST_CLAPPER_MEDIA_INFO_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CLAPPER_MEDIA_INFO,GstClapperMediaInfoClass))
#define GST_IS_CLAPPER_MEDIA_INFO(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CLAPPER_MEDIA_INFO))
#define GST_IS_CLAPPER_MEDIA_INFO_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CLAPPER_MEDIA_INFO))
/**
* GstClapperMediaInfo:
*
* Structure containing the media information of a URI.
*/
typedef struct _GstClapperMediaInfo GstClapperMediaInfo;
typedef struct _GstClapperMediaInfoClass GstClapperMediaInfoClass;
GST_CLAPPER_API
GType gst_clapper_media_info_get_type (void);
GST_CLAPPER_API
const gchar * gst_clapper_media_info_get_uri (const GstClapperMediaInfo *info);
GST_CLAPPER_API
gboolean gst_clapper_media_info_is_seekable (const GstClapperMediaInfo *info);
GST_CLAPPER_API
gboolean gst_clapper_media_info_is_live (const GstClapperMediaInfo *info);
GST_CLAPPER_API
GstClockTime gst_clapper_media_info_get_duration (const GstClapperMediaInfo *info);
GST_CLAPPER_API
GList * gst_clapper_media_info_get_stream_list (const GstClapperMediaInfo *info);
GST_CLAPPER_API
guint gst_clapper_media_info_get_number_of_streams (const GstClapperMediaInfo *info);
GST_CLAPPER_API
GList * gst_clapper_media_info_get_video_streams (const GstClapperMediaInfo *info);
GST_CLAPPER_API
guint gst_clapper_media_info_get_number_of_video_streams (const GstClapperMediaInfo *info);
GST_CLAPPER_API
GList * gst_clapper_media_info_get_audio_streams (const GstClapperMediaInfo *info);
GST_CLAPPER_API
guint gst_clapper_media_info_get_number_of_audio_streams (const GstClapperMediaInfo *info);
GST_CLAPPER_API
GList * gst_clapper_media_info_get_subtitle_streams (const GstClapperMediaInfo *info);
GST_CLAPPER_API
guint gst_clapper_media_info_get_number_of_subtitle_streams (const GstClapperMediaInfo *info);
GST_CLAPPER_API
GstTagList * gst_clapper_media_info_get_tags (const GstClapperMediaInfo *info);
GST_CLAPPER_API
GstToc * gst_clapper_media_info_get_toc (const GstClapperMediaInfo *info);
GST_CLAPPER_API
const gchar * gst_clapper_media_info_get_title (const GstClapperMediaInfo *info);
GST_CLAPPER_API
const gchar * gst_clapper_media_info_get_container_format (const GstClapperMediaInfo *info);
GST_CLAPPER_API
GstSample * gst_clapper_media_info_get_image_sample (const GstClapperMediaInfo *info);
G_END_DECLS
#endif /* __GST_CLAPPER_MEDIA_INFO_H */

View File

@@ -1,43 +0,0 @@
/*
* Copyright (C) 2021 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.
*/
#ifndef __GST_CLAPPER_MPRIS_PRIVATE_H__
#define __GST_CLAPPER_MPRIS_PRIVATE_H__
#include <gst/clapper/gstclapper-mpris.h>
#include <gst/clapper/gstclapper.h>
G_BEGIN_DECLS
G_GNUC_INTERNAL
void gst_clapper_mpris_set_clapper (GstClapperMpris *self, GstClapper *clapper,
GstClapperSignalDispatcher *signal_dispatcher);
G_GNUC_INTERNAL
void gst_clapper_mpris_set_media_info (GstClapperMpris *self, GstClapperMediaInfo *info);
G_GNUC_INTERNAL
void gst_clapper_mpris_set_playback_status (GstClapperMpris *self, const gchar *status);
G_GNUC_INTERNAL
void gst_clapper_mpris_set_position (GstClapperMpris *self, gint64 position);
G_END_DECLS
#endif /* __GST_CLAPPER_MPRIS_PRIVATE_H__ */

View File

@@ -1,793 +0,0 @@
/*
* Copyright (C) 2021 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 "gstclapper-mpris-gdbus.h"
#include "gstclapper-mpris.h"
#include "gstclapper-mpris-private.h"
#include "gstclapper-signal-dispatcher-private.h"
GST_DEBUG_CATEGORY_STATIC (gst_clapper_mpris_debug);
#define GST_CAT_DEFAULT gst_clapper_mpris_debug
#define MPRIS_DEFAULT_VOLUME 1.0
enum
{
PROP_0,
PROP_OWN_NAME,
PROP_ID_PATH,
PROP_IDENTITY,
PROP_DESKTOP_ENTRY,
PROP_DEFAULT_ART_URL,
PROP_VOLUME,
PROP_LAST
};
struct _GstClapperMpris
{
GObject parent;
GstClapperMprisMediaPlayer2 *base_skeleton;
GstClapperMprisMediaPlayer2Player *player_skeleton;
GstClapperSignalDispatcher *signal_dispatcher;
GstClapperMediaInfo *media_info;
guint name_id;
/* Properties */
gchar *own_name;
gchar *id_path;
gchar *identity;
gchar *desktop_entry;
gchar *default_art_url;
gboolean parse_media_info;
/* Current status */
gchar *playback_status;
gboolean can_play;
guint64 position;
GThread *thread;
GMutex lock;
GCond cond;
GMainContext *context;
GMainLoop *loop;
};
struct _GstClapperMprisClass
{
GObjectClass parent_class;
};
#define parent_class gst_clapper_mpris_parent_class
G_DEFINE_TYPE (GstClapperMpris, gst_clapper_mpris, G_TYPE_OBJECT);
static GParamSpec *param_specs[PROP_LAST] = { NULL, };
static void gst_clapper_mpris_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_clapper_mpris_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_clapper_mpris_dispose (GObject * object);
static void gst_clapper_mpris_finalize (GObject * object);
static void gst_clapper_mpris_constructed (GObject * object);
static gpointer gst_clapper_mpris_main (gpointer data);
static void unregister (GstClapperMpris * self);
static void
gst_clapper_mpris_init (GstClapperMpris * self)
{
GST_DEBUG_CATEGORY_INIT (gst_clapper_mpris_debug, "ClapperMpris", 0,
"GstClapperMpris");
GST_TRACE_OBJECT (self, "Initializing");
self = gst_clapper_mpris_get_instance_private (self);
g_mutex_init (&self->lock);
g_cond_init (&self->cond);
self->context = g_main_context_new ();
self->loop = g_main_loop_new (self->context, FALSE);
self->base_skeleton = gst_clapper_mpris_media_player2_skeleton_new ();
self->player_skeleton = gst_clapper_mpris_media_player2_player_skeleton_new ();
self->name_id = 0;
self->own_name = NULL;
self->id_path = NULL;
self->identity = NULL;
self->desktop_entry = NULL;
self->default_art_url = NULL;
self->signal_dispatcher = NULL;
self->media_info = NULL;
self->parse_media_info = FALSE;
self->playback_status = g_strdup ("Stopped");
self->can_play = FALSE;
self->position = 0;
GST_TRACE_OBJECT (self, "Initialized");
}
static void
gst_clapper_mpris_class_init (GstClapperMprisClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
gobject_class->set_property = gst_clapper_mpris_set_property;
gobject_class->get_property = gst_clapper_mpris_get_property;
gobject_class->dispose = gst_clapper_mpris_dispose;
gobject_class->finalize = gst_clapper_mpris_finalize;
gobject_class->constructed = gst_clapper_mpris_constructed;
param_specs[PROP_OWN_NAME] =
g_param_spec_string ("own-name", "DBus own name",
"DBus name to own on connection",
NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
param_specs[PROP_ID_PATH] =
g_param_spec_string ("id-path", "DBus id path",
"A valid D-Bus path describing this player",
NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
param_specs[PROP_IDENTITY] =
g_param_spec_string ("identity", "Player name",
"A friendly name to identify the media player",
NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
param_specs[PROP_DESKTOP_ENTRY] =
g_param_spec_string ("desktop-entry", "Desktop entry filename",
"The basename of an installed .desktop file",
NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
param_specs[PROP_DEFAULT_ART_URL] =
g_param_spec_string ("default-art-url", "Default Art URL",
"Default art to show when media does not provide one",
NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
param_specs[PROP_VOLUME] =
g_param_spec_double ("volume", "Volume", "Volume",
0, 1.5, MPRIS_DEFAULT_VOLUME, G_PARAM_READWRITE |
G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, PROP_LAST, param_specs);
}
static void
gst_clapper_mpris_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstClapperMpris *self = GST_CLAPPER_MPRIS (object);
switch (prop_id) {
case PROP_OWN_NAME:
self->own_name = g_value_dup_string (value);
break;
case PROP_ID_PATH:
self->id_path = g_value_dup_string (value);
break;
case PROP_IDENTITY:
self->identity = g_value_dup_string (value);
break;
case PROP_DESKTOP_ENTRY:
self->desktop_entry = g_value_dup_string (value);
break;
case PROP_DEFAULT_ART_URL:
self->default_art_url = g_value_dup_string (value);
break;
case PROP_VOLUME:
g_object_set_property (G_OBJECT (self->player_skeleton), "volume", value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_clapper_mpris_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstClapperMpris *self = GST_CLAPPER_MPRIS (object);
switch (prop_id) {
case PROP_OWN_NAME:
g_value_set_string (value, self->own_name);
break;
case PROP_ID_PATH:
g_value_set_string (value, self->id_path);
break;
case PROP_IDENTITY:
g_value_set_string (value, self->identity);
break;
case PROP_DESKTOP_ENTRY:
g_value_set_string (value, self->desktop_entry);
break;
case PROP_DEFAULT_ART_URL:
g_value_set_string (value, self->default_art_url);
break;
case PROP_VOLUME:
g_object_get_property (G_OBJECT (self->player_skeleton), "volume", value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_clapper_mpris_dispose (GObject * object)
{
GstClapperMpris *self = GST_CLAPPER_MPRIS (object);
GST_TRACE_OBJECT (self, "Stopping main thread");
if (self->loop) {
g_main_loop_quit (self->loop);
if (self->thread != g_thread_self ())
g_thread_join (self->thread);
else
g_thread_unref (self->thread);
self->thread = NULL;
g_main_loop_unref (self->loop);
self->loop = NULL;
g_main_context_unref (self->context);
self->context = NULL;
}
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
gst_clapper_mpris_finalize (GObject * object)
{
GstClapperMpris *self = GST_CLAPPER_MPRIS (object);
GST_TRACE_OBJECT (self, "Finalize");
g_free (self->own_name);
g_free (self->id_path);
g_free (self->identity);
g_free (self->desktop_entry);
g_free (self->default_art_url);
g_free (self->playback_status);
if (self->base_skeleton)
g_object_unref (self->base_skeleton);
if (self->player_skeleton)
g_object_unref (self->player_skeleton);
if (self->signal_dispatcher)
g_object_unref (self->signal_dispatcher);
if (self->media_info)
g_object_unref (self->media_info);
g_mutex_clear (&self->lock);
g_cond_clear (&self->cond);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gst_clapper_mpris_constructed (GObject * object)
{
GstClapperMpris *self = GST_CLAPPER_MPRIS (object);
GST_TRACE_OBJECT (self, "Constructed");
g_mutex_lock (&self->lock);
self->thread = g_thread_new ("GstClapperMpris",
gst_clapper_mpris_main, self);
while (!self->loop || !g_main_loop_is_running (self->loop))
g_cond_wait (&self->cond, &self->lock);
g_mutex_unlock (&self->lock);
G_OBJECT_CLASS (parent_class)->constructed (object);
}
static gboolean
main_loop_running_cb (gpointer user_data)
{
GstClapperMpris *self = GST_CLAPPER_MPRIS (user_data);
GST_TRACE_OBJECT (self, "Main loop running now");
g_mutex_lock (&self->lock);
g_cond_signal (&self->cond);
g_mutex_unlock (&self->lock);
return G_SOURCE_REMOVE;
}
static gboolean
handle_play_cb (GstClapperMprisMediaPlayer2Player * player_skeleton,
GDBusMethodInvocation * invocation, gpointer user_data)
{
GstClapper *clapper = GST_CLAPPER (user_data);
GST_DEBUG ("Handle Play");
gst_clapper_play (clapper);
gst_clapper_mpris_media_player2_player_complete_play (player_skeleton, invocation);
return TRUE;
}
static gboolean
handle_pause_cb (GstClapperMprisMediaPlayer2Player * player_skeleton,
GDBusMethodInvocation * invocation, gpointer user_data)
{
GstClapper *clapper = GST_CLAPPER (user_data);
GST_DEBUG ("Handle Pause");
gst_clapper_pause (clapper);
gst_clapper_mpris_media_player2_player_complete_pause (player_skeleton, invocation);
return TRUE;
}
static gboolean
handle_play_pause_cb (GstClapperMprisMediaPlayer2Player * player_skeleton,
GDBusMethodInvocation * invocation, gpointer user_data)
{
GstClapper *clapper = GST_CLAPPER (user_data);
GST_DEBUG ("Handle PlayPause");
gst_clapper_toggle_play (clapper);
gst_clapper_mpris_media_player2_player_complete_play_pause (player_skeleton, invocation);
return TRUE;
}
static gboolean
handle_seek_cb (GstClapperMprisMediaPlayer2Player * player_skeleton,
GDBusMethodInvocation * invocation, gint64 offset, gpointer user_data)
{
GstClapper *clapper = GST_CLAPPER (user_data);
GST_DEBUG ("Handle Seek");
gst_clapper_seek_offset (clapper, offset * GST_USECOND);
gst_clapper_mpris_media_player2_player_complete_seek (player_skeleton, invocation);
return TRUE;
}
static gboolean
handle_set_position_cb (GstClapperMprisMediaPlayer2Player * player_skeleton,
GDBusMethodInvocation * invocation, const gchar * track_id,
gint64 position, gpointer user_data)
{
GstClapper *clapper = GST_CLAPPER (user_data);
GST_DEBUG ("Handle SetPosition");
gst_clapper_seek (clapper, position * GST_USECOND);
gst_clapper_mpris_media_player2_player_complete_set_position (player_skeleton, invocation);
return TRUE;
}
static gboolean
handle_open_uri_cb (GstClapperMprisMediaPlayer2Player * player_skeleton,
GDBusMethodInvocation * invocation, const gchar * uri,
gpointer user_data)
{
GstClapper *clapper = GST_CLAPPER (user_data);
GST_DEBUG ("Handle OpenUri");
/* FIXME: set one item playlist instead */
gst_clapper_set_uri (clapper, uri);
gst_clapper_mpris_media_player2_player_complete_open_uri (player_skeleton, invocation);
return TRUE;
}
static void
volume_notify_dispatch (gpointer user_data)
{
GstClapperMpris *self = user_data;
g_object_notify_by_pspec (G_OBJECT (self), param_specs[PROP_VOLUME]);
}
static void
handle_volume_notify_cb (G_GNUC_UNUSED GObject * obj,
G_GNUC_UNUSED GParamSpec * pspec, GstClapperMpris * self)
{
gst_clapper_signal_dispatcher_dispatch (self->signal_dispatcher, NULL,
volume_notify_dispatch, g_object_ref (self),
(GDestroyNotify) g_object_unref);
}
static void
unregister (GstClapperMpris * self)
{
if (!self->name_id)
return;
GST_DEBUG_OBJECT (self, "Unregister");
g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self->base_skeleton));
g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self->player_skeleton));
g_bus_unown_name (self->name_id);
self->name_id = 0;
}
static const gchar *
_get_mpris_trackid (GstClapperMpris * self)
{
/* TODO: Support more tracks */
return g_strdup_printf ("%s%s%i", self->id_path, "/Track/", 0);
}
static void
_set_supported_uri_schemes (GstClapperMpris * self)
{
const gchar *uri_schemes[96] = {};
GList *elements, *el;
guint index = 0;
elements = gst_element_factory_list_get_elements (
GST_ELEMENT_FACTORY_TYPE_SRC, GST_RANK_NONE);
for (el = elements; el != NULL; el = el->next) {
const gchar *const *protocols;
GstElementFactory *factory = GST_ELEMENT_FACTORY (el->data);
if (gst_element_factory_get_uri_type (factory) != GST_URI_SRC)
continue;
protocols = gst_element_factory_get_uri_protocols (factory);
if (protocols == NULL || *protocols == NULL)
continue;
while (*protocols != NULL) {
guint j = index;
while (j--) {
if (strcmp (uri_schemes[j], *protocols) == 0)
goto next;
}
uri_schemes[index] = *protocols;
GST_DEBUG_OBJECT (self, "Added supported URI scheme: %s", *protocols);
++index;
next:
++protocols;
}
}
gst_plugin_feature_list_free (elements);
gst_clapper_mpris_media_player2_set_supported_uri_schemes (
self->base_skeleton, uri_schemes);
}
static void
name_acquired_cb (GDBusConnection * connection,
const gchar *name, gpointer user_data)
{
GstClapperMpris *self = GST_CLAPPER_MPRIS (user_data);
GVariantBuilder builder;
g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self->base_skeleton),
connection, "/org/mpris/MediaPlayer2", NULL);
g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self->player_skeleton),
connection, "/org/mpris/MediaPlayer2", NULL);
if (self->identity)
gst_clapper_mpris_media_player2_set_identity (self->base_skeleton, self->identity);
if (self->desktop_entry)
gst_clapper_mpris_media_player2_set_desktop_entry (self->base_skeleton, self->desktop_entry);
_set_supported_uri_schemes (self);
gst_clapper_mpris_media_player2_player_set_playback_status (self->player_skeleton, "Stopped");
gst_clapper_mpris_media_player2_player_set_minimum_rate (self->player_skeleton, 0.01);
gst_clapper_mpris_media_player2_player_set_maximum_rate (self->player_skeleton, 2.0);
gst_clapper_mpris_media_player2_player_set_can_seek (self->player_skeleton, TRUE);
gst_clapper_mpris_media_player2_player_set_can_control (self->player_skeleton, TRUE);
g_object_bind_property (self->player_skeleton, "can-play",
self->player_skeleton, "can-pause", G_BINDING_DEFAULT);
g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
g_variant_builder_add (&builder, "{sv}", "mpris:trackid", g_variant_new_string (_get_mpris_trackid (self)));
g_variant_builder_add (&builder, "{sv}", "mpris:length", g_variant_new_uint64 (0));
if (self->default_art_url)
g_variant_builder_add (&builder, "{sv}", "mpris:artUrl", g_variant_new_string (self->default_art_url));
gst_clapper_mpris_media_player2_player_set_metadata (self->player_skeleton, g_variant_builder_end (&builder));
GST_DEBUG_OBJECT (self, "Ready");
}
static void
name_lost_cb (GDBusConnection * connection,
const gchar * name, gpointer user_data)
{
GstClapperMpris *self = GST_CLAPPER_MPRIS (user_data);
unregister (self);
}
static gboolean
mpris_update_props_dispatch (gpointer user_data)
{
GstClapperMpris *self = GST_CLAPPER_MPRIS (user_data);
GST_DEBUG_OBJECT (self, "Updating MPRIS props");
g_mutex_lock (&self->lock);
if (self->parse_media_info) {
GVariantBuilder builder;
guint64 duration;
const gchar *track_id, *uri, *title;
GST_DEBUG_OBJECT (self, "Parsing media info");
g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
track_id = _get_mpris_trackid (self);
uri = gst_clapper_media_info_get_uri (self->media_info);
title = gst_clapper_media_info_get_title (self->media_info);
if (track_id) {
g_variant_builder_add (&builder, "{sv}", "mpris:trackid",
g_variant_new_string (track_id));
GST_DEBUG_OBJECT (self, "mpris:trackid: %s", track_id);
}
if (uri) {
g_variant_builder_add (&builder, "{sv}", "xesam:url",
g_variant_new_string (uri));
GST_DEBUG_OBJECT (self, "xesam:url: %s", uri);
}
if (title) {
g_variant_builder_add (&builder, "{sv}", "xesam:title",
g_variant_new_string (title));
GST_DEBUG_OBJECT (self, "xesam:title: %s", title);
}
duration = gst_clapper_media_info_get_duration (self->media_info);
duration = (duration != GST_CLOCK_TIME_NONE) ? duration / GST_USECOND : 0;
g_variant_builder_add (&builder, "{sv}", "mpris:length", g_variant_new_uint64 (duration));
GST_DEBUG_OBJECT (self, "mpris:length: %ld", duration);
/* TODO: Check for image sample */
if (self->default_art_url) {
g_variant_builder_add (&builder, "{sv}", "mpris:artUrl", g_variant_new_string (self->default_art_url));
GST_DEBUG_OBJECT (self, "mpris:artUrl: %s", self->default_art_url);
}
GST_DEBUG_OBJECT (self, "Media info parsed");
self->parse_media_info = FALSE;
gst_clapper_mpris_media_player2_player_set_metadata (
self->player_skeleton, g_variant_builder_end (&builder));
}
if (gst_clapper_mpris_media_player2_player_get_can_play (
self->player_skeleton) != self->can_play) {
/* "can-play" is bound with "can-pause" */
gst_clapper_mpris_media_player2_player_set_can_play (
self->player_skeleton, self->can_play);
GST_DEBUG_OBJECT (self, "CanPlay/CanPause: %s", self->can_play ? "yes" : "no");
}
if (strcmp (gst_clapper_mpris_media_player2_player_get_playback_status (
self->player_skeleton), self->playback_status) != 0) {
gst_clapper_mpris_media_player2_player_set_playback_status (
self->player_skeleton, self->playback_status);
GST_DEBUG_OBJECT (self, "PlaybackStatus: %s", self->playback_status);
}
if (gst_clapper_mpris_media_player2_player_get_position (
self->player_skeleton) != self->position) {
gst_clapper_mpris_media_player2_player_set_position (
self->player_skeleton, self->position);
GST_DEBUG_OBJECT (self, "Position: %ld", self->position);
}
g_mutex_unlock (&self->lock);
GST_DEBUG_OBJECT (self, "MPRIS props updated");
return G_SOURCE_REMOVE;
}
static void
mpris_dispatcher_update_dispatch (GstClapperMpris * self)
{
if (!self->name_id)
return;
GST_DEBUG_OBJECT (self, "Queued update props dispatch");
g_main_context_invoke_full (self->context,
G_PRIORITY_DEFAULT, mpris_update_props_dispatch,
g_object_ref (self), g_object_unref);
}
static gpointer
gst_clapper_mpris_main (gpointer data)
{
GstClapperMpris *self = GST_CLAPPER_MPRIS (data);
GDBusConnectionFlags flags;
GDBusConnection *connection;
GSource *source;
gchar *address;
GST_TRACE_OBJECT (self, "Starting main thread");
g_main_context_push_thread_default (self->context);
source = g_idle_source_new ();
g_source_set_callback (source, (GSourceFunc) main_loop_running_cb, self,
NULL);
g_source_attach (source, self->context);
g_source_unref (source);
address = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION, NULL, NULL);
if (!address) {
GST_WARNING_OBJECT (self, "No MPRIS bus address");
goto no_mpris;
}
GST_DEBUG_OBJECT (self, "Obtained MPRIS DBus address");
flags = G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION;
connection = g_dbus_connection_new_for_address_sync (address,
flags, NULL, NULL, NULL);
g_free (address);
if (!connection) {
GST_WARNING_OBJECT (self, "No MPRIS bus connection");
goto no_mpris;
}
GST_DEBUG_OBJECT (self, "Obtained MPRIS DBus connection");
self->name_id = g_bus_own_name_on_connection (connection, self->own_name,
G_BUS_NAME_OWNER_FLAGS_NONE,
(GBusNameAcquiredCallback) name_acquired_cb,
(GBusNameLostCallback) name_lost_cb,
self, NULL);
g_object_unref (connection);
goto done;
no_mpris:
g_warning ("GstClapperMpris: failed to create DBus connection");
done:
GST_TRACE_OBJECT (self, "Starting main loop");
g_main_loop_run (self->loop);
GST_TRACE_OBJECT (self, "Stopped main loop");
unregister (self);
g_main_context_pop_thread_default (self->context);
GST_TRACE_OBJECT (self, "Stopped main thread");
return NULL;
}
void
gst_clapper_mpris_set_clapper (GstClapperMpris * self, GstClapper * clapper,
GstClapperSignalDispatcher * signal_dispatcher)
{
if (signal_dispatcher)
self->signal_dispatcher = g_object_ref (signal_dispatcher);
g_signal_connect (self->player_skeleton, "handle-play",
G_CALLBACK (handle_play_cb), clapper);
g_signal_connect (self->player_skeleton, "handle-pause",
G_CALLBACK (handle_pause_cb), clapper);
g_signal_connect (self->player_skeleton, "handle-play-pause",
G_CALLBACK (handle_play_pause_cb), clapper);
g_signal_connect (self->player_skeleton, "handle-seek",
G_CALLBACK (handle_seek_cb), clapper);
g_signal_connect (self->player_skeleton, "handle-set-position",
G_CALLBACK (handle_set_position_cb), clapper);
g_signal_connect (self->player_skeleton, "handle-open-uri",
G_CALLBACK (handle_open_uri_cb), clapper);
g_object_bind_property (clapper, "volume", self, "volume", G_BINDING_BIDIRECTIONAL);
g_signal_connect (self->player_skeleton, "notify::volume",
G_CALLBACK (handle_volume_notify_cb), self);
}
void
gst_clapper_mpris_set_playback_status (GstClapperMpris * self, const gchar * status)
{
g_mutex_lock (&self->lock);
if (strcmp (self->playback_status, status) == 0) {
g_mutex_unlock (&self->lock);
return;
}
g_free (self->playback_status);
self->playback_status = g_strdup (status);
self->can_play = strcmp (status, "Stopped") != 0;
g_mutex_unlock (&self->lock);
mpris_dispatcher_update_dispatch (self);
}
void
gst_clapper_mpris_set_position (GstClapperMpris * self, gint64 position)
{
position /= GST_USECOND;
g_mutex_lock (&self->lock);
if (self->position == position) {
g_mutex_unlock (&self->lock);
return;
}
self->position = position;
g_mutex_unlock (&self->lock);
mpris_dispatcher_update_dispatch (self);
}
void
gst_clapper_mpris_set_media_info (GstClapperMpris *self, GstClapperMediaInfo *info)
{
g_mutex_lock (&self->lock);
if (self->media_info)
g_object_unref (self->media_info);
self->media_info = info;
self->parse_media_info = TRUE;
g_mutex_unlock (&self->lock);
mpris_dispatcher_update_dispatch (self);
}
/**
* gst_clapper_mpris_new:
* @own_name: DBus own name
* @id_path: DBus id path used for prefix
* @identity: (allow-none): friendly name
* @desktop_entry: (allow-none): Desktop entry filename
* @default_art_url: (allow-none): filepath to default art
*
* Creates a new #GstClapperMpris instance.
*
* Returns: (transfer full): a new #GstClapperMpris instance
*/
GstClapperMpris *
gst_clapper_mpris_new (const gchar * own_name, const gchar * id_path,
const gchar * identity, const gchar * desktop_entry,
const gchar * default_art_url)
{
return g_object_new (GST_TYPE_CLAPPER_MPRIS,
"own-name", own_name, "id_path", id_path,
"identity", identity, "desktop-entry", desktop_entry,
"default-art-url", default_art_url, NULL);
}

View File

@@ -1,54 +0,0 @@
/*
* Copyright (C) 2021 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.
*/
#ifndef __GST_CLAPPER_MPRIS_H__
#define __GST_CLAPPER_MPRIS_H__
#include <glib.h>
#include <gio/gio.h>
#include <gst/clapper/clapper-prelude.h>
G_BEGIN_DECLS
typedef struct _GstClapperMpris GstClapperMpris;
typedef struct _GstClapperMprisClass GstClapperMprisClass;
#define GST_TYPE_CLAPPER_MPRIS (gst_clapper_mpris_get_type ())
#define GST_IS_CLAPPER_MPRIS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CLAPPER_MPRIS))
#define GST_IS_CLAPPER_MPRIS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CLAPPER_MPRIS))
#define GST_CLAPPER_MPRIS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CLAPPER_MPRIS, GstClapperMprisClass))
#define GST_CLAPPER_MPRIS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CLAPPER_MPRIS, GstClapperMpris))
#define GST_CLAPPER_MPRIS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_CLAPPER_MPRIS, GstClapperMprisClass))
#define GST_CLAPPER_MPRIS_CAST(obj) ((GstClapperMpris*)(obj))
#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstClapperMpris, g_object_unref)
#endif
GST_CLAPPER_API
GType gst_clapper_mpris_get_type (void);
GST_CLAPPER_API
GstClapperMpris * gst_clapper_mpris_new (const gchar *own_name, const gchar *id_path, const gchar *identity,
const gchar *desktop_entry, const gchar *default_art_url);
G_END_DECLS
#endif /* __GST_CLAPPER_MPRIS_H__ */

View File

@@ -1,35 +0,0 @@
/* GStreamer
*
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
* Copyright (C) 2021 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.
*/
#ifndef __GST_CLAPPER_SIGNAL_DISPATCHER_PRIVATE_H__
#define __GST_CLAPPER_SIGNAL_DISPATCHER_PRIVATE_H__
#include <gst/clapper/gstclapper-signal-dispatcher.h>
G_BEGIN_DECLS
G_GNUC_INTERNAL void gst_clapper_signal_dispatcher_dispatch (GstClapperSignalDispatcher * self,
GstClapper * clapper, GstClapperSignalDispatcherFunc emitter, gpointer data,
GDestroyNotify destroy);
G_END_DECLS
#endif /* __GST_CLAPPER_SIGNAL_DISPATCHER_PRIVATE_H__ */

View File

@@ -1,58 +0,0 @@
/* GStreamer
*
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
* Copyright (C) 2021 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 "gstclapper-signal-dispatcher.h"
#include "gstclapper-signal-dispatcher-private.h"
G_DEFINE_INTERFACE (GstClapperSignalDispatcher, gst_clapper_signal_dispatcher,
G_TYPE_OBJECT);
static void
gst_clapper_signal_dispatcher_default_init (G_GNUC_UNUSED
GstClapperSignalDispatcherInterface * iface)
{
}
void
gst_clapper_signal_dispatcher_dispatch (GstClapperSignalDispatcher * self,
GstClapper * clapper, GstClapperSignalDispatcherFunc emitter, gpointer data,
GDestroyNotify destroy)
{
GstClapperSignalDispatcherInterface *iface;
if (!self) {
emitter (data);
if (destroy)
destroy (data);
return;
}
g_return_if_fail (GST_IS_CLAPPER_SIGNAL_DISPATCHER (self));
iface = GST_CLAPPER_SIGNAL_DISPATCHER_GET_INTERFACE (self);
g_return_if_fail (iface->dispatch != NULL);
iface->dispatch (self, clapper, emitter, data, destroy);
}

View File

@@ -1,53 +0,0 @@
/* GStreamer
*
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
* Copyright (C) 2021 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.
*/
#ifndef __GST_CLAPPER_SIGNAL_DISPATCHER_H__
#define __GST_CLAPPER_SIGNAL_DISPATCHER_H__
#include <gst/gst.h>
#include <gst/clapper/gstclapper-types.h>
G_BEGIN_DECLS
typedef struct _GstClapperSignalDispatcher GstClapperSignalDispatcher;
typedef struct _GstClapperSignalDispatcherInterface GstClapperSignalDispatcherInterface;
#define GST_TYPE_CLAPPER_SIGNAL_DISPATCHER (gst_clapper_signal_dispatcher_get_type ())
#define GST_CLAPPER_SIGNAL_DISPATCHER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CLAPPER_SIGNAL_DISPATCHER, GstClapperSignalDispatcher))
#define GST_IS_CLAPPER_SIGNAL_DISPATCHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CLAPPER_SIGNAL_DISPATCHER))
#define GST_CLAPPER_SIGNAL_DISPATCHER_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_CLAPPER_SIGNAL_DISPATCHER, GstClapperSignalDispatcherInterface))
typedef void (*GstClapperSignalDispatcherFunc) (gpointer data);
struct _GstClapperSignalDispatcherInterface {
GTypeInterface parent_iface;
void (*dispatch) (GstClapperSignalDispatcher * self, GstClapper * clapper,
GstClapperSignalDispatcherFunc emitter, gpointer data,
GDestroyNotify destroy);
};
GST_CLAPPER_API
GType gst_clapper_signal_dispatcher_get_type (void);
G_END_DECLS
#endif /* __GST_CLAPPER_SIGNAL_DISPATCHER_H__ */

View File

@@ -1,345 +0,0 @@
/* GStreamer
*
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
* Copyright (C) 2021 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.
*/
/**
* SECTION:gstclapper-videooverlayvideorenderer
* @title: GstClapperVideoOverlayVideoRenderer
* @short_description: Clapper Video Overlay Video Renderer
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstclapper-video-overlay-video-renderer.h"
#include "gstclapper.h"
#include <gst/video/video.h>
struct _GstClapperVideoOverlayVideoRenderer
{
GObject parent;
GstVideoOverlay *video_overlay;
gpointer window_handle;
gint x, y, width, height;
GstElement *video_sink; /* configured video sink, or NULL */
};
struct _GstClapperVideoOverlayVideoRendererClass
{
GObjectClass parent_class;
};
static void
gst_clapper_video_overlay_video_renderer_interface_init
(GstClapperVideoRendererInterface * iface);
enum
{
VIDEO_OVERLAY_VIDEO_RENDERER_PROP_0,
VIDEO_OVERLAY_VIDEO_RENDERER_PROP_WINDOW_HANDLE,
VIDEO_OVERLAY_VIDEO_RENDERER_PROP_VIDEO_SINK,
VIDEO_OVERLAY_VIDEO_RENDERER_PROP_LAST
};
G_DEFINE_TYPE_WITH_CODE (GstClapperVideoOverlayVideoRenderer,
gst_clapper_video_overlay_video_renderer, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GST_TYPE_CLAPPER_VIDEO_RENDERER,
gst_clapper_video_overlay_video_renderer_interface_init));
static GParamSpec
* video_overlay_video_renderer_param_specs
[VIDEO_OVERLAY_VIDEO_RENDERER_PROP_LAST] = { NULL, };
static void
gst_clapper_video_overlay_video_renderer_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec)
{
GstClapperVideoOverlayVideoRenderer *self =
GST_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER (object);
switch (prop_id) {
case VIDEO_OVERLAY_VIDEO_RENDERER_PROP_WINDOW_HANDLE:
self->window_handle = g_value_get_pointer (value);
if (self->video_overlay)
gst_video_overlay_set_window_handle (self->video_overlay,
(guintptr) self->window_handle);
break;
case VIDEO_OVERLAY_VIDEO_RENDERER_PROP_VIDEO_SINK:
self->video_sink = gst_object_ref_sink (g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_clapper_video_overlay_video_renderer_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec)
{
GstClapperVideoOverlayVideoRenderer *self =
GST_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER (object);
switch (prop_id) {
case VIDEO_OVERLAY_VIDEO_RENDERER_PROP_WINDOW_HANDLE:
g_value_set_pointer (value, self->window_handle);
break;
case VIDEO_OVERLAY_VIDEO_RENDERER_PROP_VIDEO_SINK:
g_value_set_object (value, self->video_sink);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_clapper_video_overlay_video_renderer_finalize (GObject * object)
{
GstClapperVideoOverlayVideoRenderer *self =
GST_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER (object);
if (self->video_overlay)
gst_object_unref (self->video_overlay);
if (self->video_sink)
gst_object_unref (self->video_sink);
G_OBJECT_CLASS
(gst_clapper_video_overlay_video_renderer_parent_class)->finalize (object);
}
static void
gst_clapper_video_overlay_video_renderer_class_init
(GstClapperVideoOverlayVideoRendererClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->set_property =
gst_clapper_video_overlay_video_renderer_set_property;
gobject_class->get_property =
gst_clapper_video_overlay_video_renderer_get_property;
gobject_class->finalize = gst_clapper_video_overlay_video_renderer_finalize;
video_overlay_video_renderer_param_specs
[VIDEO_OVERLAY_VIDEO_RENDERER_PROP_WINDOW_HANDLE] =
g_param_spec_pointer ("window-handle", "Window Handle",
"Window handle to embed the video into",
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
video_overlay_video_renderer_param_specs
[VIDEO_OVERLAY_VIDEO_RENDERER_PROP_VIDEO_SINK] =
g_param_spec_object ("video-sink", "Video Sink",
"the video output element to use (NULL = default sink)",
GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class,
VIDEO_OVERLAY_VIDEO_RENDERER_PROP_LAST,
video_overlay_video_renderer_param_specs);
}
static void
gst_clapper_video_overlay_video_renderer_init
(GstClapperVideoOverlayVideoRenderer * self)
{
self->x = self->y = self->width = self->height = -1;
self->video_sink = NULL;
}
static GstElement *gst_clapper_video_overlay_video_renderer_create_video_sink
(GstClapperVideoRenderer * iface, GstClapper * clapper)
{
GstElement *video_overlay;
GstClapperVideoOverlayVideoRenderer *self =
GST_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER (iface);
if (self->video_overlay)
gst_object_unref (self->video_overlay);
video_overlay = gst_clapper_get_pipeline (clapper);
g_return_val_if_fail (GST_IS_VIDEO_OVERLAY (video_overlay), NULL);
self->video_overlay = GST_VIDEO_OVERLAY (video_overlay);
gst_video_overlay_set_window_handle (self->video_overlay,
(guintptr) self->window_handle);
if (self->width != -1 || self->height != -1)
gst_video_overlay_set_render_rectangle (self->video_overlay, self->x,
self->y, self->width, self->height);
return self->video_sink;
}
static void
gst_clapper_video_overlay_video_renderer_interface_init
(GstClapperVideoRendererInterface * iface)
{
iface->create_video_sink =
gst_clapper_video_overlay_video_renderer_create_video_sink;
}
/**
* gst_clapper_video_overlay_video_renderer_new:
* @window_handle: (allow-none): Window handle to use or %NULL
*
* Returns: (transfer full):
*/
GstClapperVideoRenderer *
gst_clapper_video_overlay_video_renderer_new (gpointer window_handle)
{
return g_object_new (GST_TYPE_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER,
"window-handle", window_handle, NULL);
}
/**
* gst_clapper_video_overlay_video_renderer_new_with_sink:
* @window_handle: (allow-none): Window handle to use or %NULL
* @video_sink: (transfer floating): the custom video_sink element to be set for the video renderer
*
* Returns: (transfer full): clapper video renderer
*/
GstClapperVideoRenderer *
gst_clapper_video_overlay_video_renderer_new_with_sink (gpointer window_handle,
GstElement * video_sink)
{
return g_object_new (GST_TYPE_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER,
"window-handle", window_handle, "video-sink", video_sink, NULL);
}
/**
* gst_clapper_video_overlay_video_renderer_set_window_handle:
* @self: #GstClapperVideoRenderer instance
* @window_handle: handle referencing to the platform specific window
*
* Sets the platform specific window handle into which the video
* should be rendered
**/
void gst_clapper_video_overlay_video_renderer_set_window_handle
(GstClapperVideoOverlayVideoRenderer * self, gpointer window_handle)
{
g_return_if_fail (GST_IS_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER (self));
g_object_set (self, "window-handle", window_handle, NULL);
}
/**
* gst_clapper_video_overlay_video_renderer_get_window_handle:
* @self: #GstClapperVideoRenderer instance
*
* Returns: (transfer none): The currently set, platform specific window
* handle
*/
gpointer
gst_clapper_video_overlay_video_renderer_get_window_handle
(GstClapperVideoOverlayVideoRenderer * self) {
gpointer window_handle;
g_return_val_if_fail (GST_IS_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER (self),
NULL);
g_object_get (self, "window-handle", &window_handle, NULL);
return window_handle;
}
/**
* gst_clapper_video_overlay_video_renderer_expose:
* @self: a #GstClapperVideoOverlayVideoRenderer instance.
*
* Tell an overlay that it has been exposed. This will redraw the current frame
* in the drawable even if the pipeline is PAUSED.
*/
void gst_clapper_video_overlay_video_renderer_expose
(GstClapperVideoOverlayVideoRenderer * self)
{
g_return_if_fail (GST_IS_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER (self));
if (self->video_overlay)
gst_video_overlay_expose (self->video_overlay);
}
/**
* gst_clapper_video_overlay_video_renderer_set_render_rectangle:
* @self: a #GstClapperVideoOverlayVideoRenderer instance
* @x: the horizontal offset of the render area inside the window
* @y: the vertical offset of the render area inside the window
* @width: the width of the render area inside the window
* @height: the height of the render area inside the window
*
* Configure a subregion as a video target within the window set by
* gst_clapper_video_overlay_video_renderer_set_window_handle(). If this is not
* used or not supported the video will fill the area of the window set as the
* overlay to 100%. By specifying the rectangle, the video can be overlaid to
* a specific region of that window only. After setting the new rectangle one
* should call gst_clapper_video_overlay_video_renderer_expose() to force a
* redraw. To unset the region pass -1 for the @width and @height parameters.
*
* This method is needed for non fullscreen video overlay in UI toolkits that
* do not support subwindows.
*
*/
void gst_clapper_video_overlay_video_renderer_set_render_rectangle
(GstClapperVideoOverlayVideoRenderer * self, gint x, gint y, gint width,
gint height)
{
g_return_if_fail (GST_IS_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER (self));
self->x = x;
self->y = y;
self->width = width;
self->height = height;
if (self->video_overlay)
gst_video_overlay_set_render_rectangle (self->video_overlay,
x, y, width, height);
}
/**
* gst_clapper_video_overlay_video_renderer_get_render_rectangle:
* @self: a #GstClapperVideoOverlayVideoRenderer instance
* @x: (out) (allow-none): the horizontal offset of the render area inside the window
* @y: (out) (allow-none): the vertical offset of the render area inside the window
* @width: (out) (allow-none): the width of the render area inside the window
* @height: (out) (allow-none): the height of the render area inside the window
*
* Return the currently configured render rectangle. See gst_clapper_video_overlay_video_renderer_set_render_rectangle()
* for details.
*
*/
void gst_clapper_video_overlay_video_renderer_get_render_rectangle
(GstClapperVideoOverlayVideoRenderer * self, gint * x, gint * y,
gint * width, gint * height)
{
g_return_if_fail (GST_IS_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER (self));
if (x)
*x = self->x;
if (y)
*y = self->y;
if (width)
*width = self->width;
if (height)
*height = self->height;
}

View File

@@ -1,71 +0,0 @@
/* GStreamer
*
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
* Copyright (C) 2021 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.
*/
#ifndef __GST_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER_H__
#define __GST_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER_H__
#include <gst/clapper/gstclapper-types.h>
#include <gst/clapper/gstclapper-video-renderer.h>
G_BEGIN_DECLS
typedef struct _GstClapperVideoOverlayVideoRenderer
GstClapperVideoOverlayVideoRenderer;
typedef struct _GstClapperVideoOverlayVideoRendererClass
GstClapperVideoOverlayVideoRendererClass;
#define GST_TYPE_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER (gst_clapper_video_overlay_video_renderer_get_type ())
#define GST_IS_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER))
#define GST_IS_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER))
#define GST_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER, GstClapperVideoOverlayVideoRendererClass))
#define GST_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER, GstClapperVideoOverlayVideoRenderer))
#define GST_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER, GstClapperVideoOverlayVideoRendererClass))
#define GST_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER_CAST(obj) ((GstClapperVideoOverlayVideoRenderer*)(obj))
GST_CLAPPER_API
GType gst_clapper_video_overlay_video_renderer_get_type (void);
GST_CLAPPER_API
GstClapperVideoRenderer *
gst_clapper_video_overlay_video_renderer_new (gpointer window_handle);
GST_CLAPPER_API
GstClapperVideoRenderer *
gst_clapper_video_overlay_video_renderer_new_with_sink (gpointer window_handle, GstElement *video_sink);
GST_CLAPPER_API
void gst_clapper_video_overlay_video_renderer_set_window_handle (GstClapperVideoOverlayVideoRenderer *self, gpointer window_handle);
GST_CLAPPER_API
gpointer gst_clapper_video_overlay_video_renderer_get_window_handle (GstClapperVideoOverlayVideoRenderer *self);
GST_CLAPPER_API
void gst_clapper_video_overlay_video_renderer_expose (GstClapperVideoOverlayVideoRenderer *self);
GST_CLAPPER_API
void gst_clapper_video_overlay_video_renderer_set_render_rectangle (GstClapperVideoOverlayVideoRenderer *self, gint x, gint y, gint width, gint height);
GST_CLAPPER_API
void gst_clapper_video_overlay_video_renderer_get_render_rectangle (GstClapperVideoOverlayVideoRenderer *self, gint *x, gint *y, gint *width, gint *height);
G_END_DECLS
#endif /* __GST_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER_H__ */

View File

@@ -1,50 +0,0 @@
/* GStreamer
*
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
* Copyright (C) 2021 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 "gstclapper-video-renderer.h"
#include "gstclapper-video-renderer-private.h"
G_DEFINE_INTERFACE (GstClapperVideoRenderer, gst_clapper_video_renderer,
G_TYPE_OBJECT);
static void
gst_clapper_video_renderer_default_init (G_GNUC_UNUSED
GstClapperVideoRendererInterface * iface)
{
}
GstElement *
gst_clapper_video_renderer_create_video_sink (GstClapperVideoRenderer * self,
GstClapper * clapper)
{
GstClapperVideoRendererInterface *iface;
g_return_val_if_fail (GST_IS_CLAPPER_VIDEO_RENDERER (self), NULL);
iface = GST_CLAPPER_VIDEO_RENDERER_GET_INTERFACE (self);
g_return_val_if_fail (iface->create_video_sink != NULL, NULL);
return iface->create_video_sink (self, clapper);
}

View File

@@ -1,49 +0,0 @@
/* GStreamer
*
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
* Copyright (C) 2021 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.
*/
#ifndef __GST_CLAPPER_VIDEO_RENDERER_H__
#define __GST_CLAPPER_VIDEO_RENDERER_H__
#include <gst/gst.h>
#include <gst/clapper/gstclapper-types.h>
G_BEGIN_DECLS
typedef struct _GstClapperVideoRenderer GstClapperVideoRenderer;
typedef struct _GstClapperVideoRendererInterface GstClapperVideoRendererInterface;
#define GST_TYPE_CLAPPER_VIDEO_RENDERER (gst_clapper_video_renderer_get_type ())
#define GST_CLAPPER_VIDEO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CLAPPER_VIDEO_RENDERER, GstClapperVideoRenderer))
#define GST_IS_CLAPPER_VIDEO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CLAPPER_VIDEO_RENDERER))
#define GST_CLAPPER_VIDEO_RENDERER_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_CLAPPER_VIDEO_RENDERER, GstClapperVideoRendererInterface))
struct _GstClapperVideoRendererInterface {
GTypeInterface parent_iface;
GstElement * (*create_video_sink) (GstClapperVideoRenderer * self, GstClapper * clapper);
};
GST_CLAPPER_API
GType gst_clapper_video_renderer_get_type (void);
G_END_DECLS
#endif /* __GST_CLAPPER_VIDEO_RENDERER_H__ */

View File

@@ -1,180 +0,0 @@
/* GStreamer
*
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
* Copyright (C) 2015 Brijesh Singh <brijesh.ksingh@gmail.com>
* Copyright (C) 2021 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.
*/
/**
* SECTION:gstclapper-visualization
* @title: GstClapperVisualization
* @short_description: Clapper Visualization
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstclapper-visualization.h"
#include <string.h>
static GMutex vis_lock;
static GQueue vis_list = G_QUEUE_INIT;
static guint32 vis_cookie;
G_DEFINE_BOXED_TYPE (GstClapperVisualization, gst_clapper_visualization,
(GBoxedCopyFunc) gst_clapper_visualization_copy,
(GBoxedFreeFunc) gst_clapper_visualization_free);
/**
* gst_clapper_visualization_free:
* @vis: #GstClapperVisualization instance
*
* Frees a #GstClapperVisualization.
*/
void
gst_clapper_visualization_free (GstClapperVisualization * vis)
{
g_return_if_fail (vis != NULL);
g_free (vis->name);
g_free (vis->description);
g_free (vis);
}
/**
* gst_clapper_visualization_copy:
* @vis: #GstClapperVisualization instance
*
* Makes a copy of the #GstClapperVisualization. The result must be
* freed using gst_clapper_visualization_free().
*
* Returns: (transfer full): an allocated copy of @vis.
*/
GstClapperVisualization *
gst_clapper_visualization_copy (const GstClapperVisualization * vis)
{
GstClapperVisualization *ret;
g_return_val_if_fail (vis != NULL, NULL);
ret = g_new0 (GstClapperVisualization, 1);
ret->name = vis->name ? g_strdup (vis->name) : NULL;
ret->description = vis->description ? g_strdup (vis->description) : NULL;
return ret;
}
/**
* gst_clapper_visualizations_free:
* @viss: a %NULL terminated array of #GstClapperVisualization to free
*
* Frees a %NULL terminated array of #GstClapperVisualization.
*/
void
gst_clapper_visualizations_free (GstClapperVisualization ** viss)
{
GstClapperVisualization **p;
g_return_if_fail (viss != NULL);
p = viss;
while (*p) {
g_free ((*p)->name);
g_free ((*p)->description);
g_free (*p);
p++;
}
g_free (viss);
}
static void
gst_clapper_update_visualization_list (void)
{
GList *features;
GList *l;
guint32 cookie;
GstClapperVisualization *vis;
g_mutex_lock (&vis_lock);
/* check if we need to update the list */
cookie = gst_registry_get_feature_list_cookie (gst_registry_get ());
if (vis_cookie == cookie) {
g_mutex_unlock (&vis_lock);
return;
}
/* if update is needed then first free the existing list */
while ((vis = g_queue_pop_head (&vis_list)))
gst_clapper_visualization_free (vis);
features = gst_registry_get_feature_list (gst_registry_get (),
GST_TYPE_ELEMENT_FACTORY);
for (l = features; l; l = l->next) {
GstPluginFeature *feature = l->data;
const gchar *klass;
klass = gst_element_factory_get_metadata (GST_ELEMENT_FACTORY (feature),
GST_ELEMENT_METADATA_KLASS);
if (strstr (klass, "Visualization")) {
vis = g_new0 (GstClapperVisualization, 1);
vis->name = g_strdup (gst_plugin_feature_get_name (feature));
vis->description =
g_strdup (gst_element_factory_get_metadata (GST_ELEMENT_FACTORY
(feature), GST_ELEMENT_METADATA_DESCRIPTION));
g_queue_push_tail (&vis_list, vis);
}
}
gst_plugin_feature_list_free (features);
vis_cookie = cookie;
g_mutex_unlock (&vis_lock);
}
/**
* gst_clapper_visualizations_get:
*
* Returns: (transfer full) (array zero-terminated=1) (element-type GstClapperVisualization):
* a %NULL terminated array containing all available
* visualizations. Use gst_clapper_visualizations_free() after
* usage.
*/
GstClapperVisualization **
gst_clapper_visualizations_get (void)
{
gint i = 0;
GList *l;
GstClapperVisualization **ret;
gst_clapper_update_visualization_list ();
g_mutex_lock (&vis_lock);
ret = g_new0 (GstClapperVisualization *, g_queue_get_length (&vis_list) + 1);
for (l = vis_list.head; l; l = l->next)
ret[i++] = gst_clapper_visualization_copy (l->data);
g_mutex_unlock (&vis_lock);
return ret;
}

View File

@@ -1,61 +0,0 @@
/* GStreamer
*
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
* Copyright (C) 2015 Brijesh Singh <brijesh.ksingh@gmail.com>
* Copyright (C) 2021 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.
*/
#ifndef __GST_CLAPPER_VISUALIZATION_H__
#define __GST_CLAPPER_VISUALIZATION_H__
#include <gst/gst.h>
#include <gst/clapper/clapper-prelude.h>
G_BEGIN_DECLS
typedef struct _GstClapperVisualization GstClapperVisualization;
/**
* GstClapperVisualization:
* @name: name of the visualization.
* @description: description of the visualization.
*
* A #GstClapperVisualization descriptor.
*/
struct _GstClapperVisualization {
gchar *name;
gchar *description;
};
GST_CLAPPER_API
GType gst_clapper_visualization_get_type (void);
GST_CLAPPER_API
GstClapperVisualization * gst_clapper_visualization_copy (const GstClapperVisualization *vis);
GST_CLAPPER_API
void gst_clapper_visualization_free (GstClapperVisualization *vis);
GST_CLAPPER_API
GstClapperVisualization ** gst_clapper_visualizations_get (void);
GST_CLAPPER_API
void gst_clapper_visualizations_free (GstClapperVisualization **viss);
G_END_DECLS
#endif /* __GST_CLAPPER_VISUALIZATION_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -1,318 +0,0 @@
/* GStreamer
*
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
* Copyright (C) 2021 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.
*/
#ifndef __GST_CLAPPER_H__
#define __GST_CLAPPER_H__
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/clapper/clapper-prelude.h>
#include <gst/clapper/gstclapper-types.h>
#include <gst/clapper/gstclapper-signal-dispatcher.h>
#include <gst/clapper/gstclapper-video-renderer.h>
#include <gst/clapper/gstclapper-media-info.h>
#include <gst/clapper/gstclapper-mpris.h>
G_BEGIN_DECLS
/* ClapperState */
GST_CLAPPER_API
GType gst_clapper_state_get_type (void);
#define GST_TYPE_CLAPPER_STATE (gst_clapper_state_get_type ())
/**
* GstClapperState:
* @GST_CLAPPER_STATE_STOPPED: clapper is stopped.
* @GST_CLAPPER_STATE_BUFFERING: clapper is buffering.
* @GST_CLAPPER_STATE_PAUSED: clapper is paused.
* @GST_CLAPPER_STATE_PLAYING: clapper is currently playing a stream.
*/
typedef enum
{
GST_CLAPPER_STATE_STOPPED,
GST_CLAPPER_STATE_BUFFERING,
GST_CLAPPER_STATE_PAUSED,
GST_CLAPPER_STATE_PLAYING
} GstClapperState;
GST_CLAPPER_API
const gchar * gst_clapper_state_get_name (GstClapperState state);
/* ClapperSeekMode */
GST_CLAPPER_API
GType gst_clapper_seek_mode_get_type (void);
#define GST_TYPE_CLAPPER_SEEK_MODE (gst_clapper_seek_mode_get_type ())
/**
* GstClapperSeekMode:
* @GST_CLAPPER_SEEK_MODE_DEFAULT: default seek method (flush only).
* @GST_CLAPPER_SEEK_MODE_ACCURATE: accurate seek method.
* @GST_CLAPPER_SEEK_MODE_FAST: fast seek method (next keyframe).
*/
typedef enum
{
GST_CLAPPER_SEEK_MODE_DEFAULT,
GST_CLAPPER_SEEK_MODE_ACCURATE,
GST_CLAPPER_SEEK_MODE_FAST,
} GstClapperSeekMode;
/* ClapperError */
GST_CLAPPER_API
GQuark gst_clapper_error_quark (void);
GST_CLAPPER_API
GType gst_clapper_error_get_type (void);
#define GST_CLAPPER_ERROR (gst_clapper_error_quark ())
#define GST_TYPE_CLAPPER_ERROR (gst_clapper_error_get_type ())
/**
* GstClapperError:
* @GST_CLAPPER_ERROR_FAILED: generic error.
*/
typedef enum {
GST_CLAPPER_ERROR_FAILED = 0
} GstClapperError;
GST_CLAPPER_API
const gchar * gst_clapper_error_get_name (GstClapperError error);
/* ClapperColorBalanceType */
GST_CLAPPER_API
GType gst_clapper_color_balance_type_get_type (void);
#define GST_TYPE_CLAPPER_COLOR_BALANCE_TYPE (gst_clapper_color_balance_type_get_type ())
/**
* GstClapperColorBalanceType:
* @GST_CLAPPER_COLOR_BALANCE_BRIGHTNESS: brightness or black level.
* @GST_CLAPPER_COLOR_BALANCE_CONTRAST: contrast or luma gain.
* @GST_CLAPPER_COLOR_BALANCE_SATURATION: color saturation or chroma
* gain.
* @GST_CLAPPER_COLOR_BALANCE_HUE: hue or color balance.
*/
typedef enum
{
GST_CLAPPER_COLOR_BALANCE_BRIGHTNESS,
GST_CLAPPER_COLOR_BALANCE_CONTRAST,
GST_CLAPPER_COLOR_BALANCE_SATURATION,
GST_CLAPPER_COLOR_BALANCE_HUE,
} GstClapperColorBalanceType;
GST_CLAPPER_API
const gchar * gst_clapper_color_balance_type_get_name (GstClapperColorBalanceType type);
/* ClapperSnapshotFormat */
/**
* GstClapperSnapshotFormat:
* @GST_CLAPPER_THUMBNAIL_RAW_NATIVE: RAW Native.
* @GST_CLAPPER_THUMBNAIL_RAW_xRGB: RAW xRGB.
* @GST_CLAPPER_THUMBNAIL_RAW_BGRx: RAW BGRx.
* @GST_CLAPPER_THUMBNAIL_JPG: JPG.
* @GST_CLAPPER_THUMBNAIL_PNG: PNG.
*/
typedef enum
{
GST_CLAPPER_THUMBNAIL_RAW_NATIVE = 0,
GST_CLAPPER_THUMBNAIL_RAW_xRGB,
GST_CLAPPER_THUMBNAIL_RAW_BGRx,
GST_CLAPPER_THUMBNAIL_JPG,
GST_CLAPPER_THUMBNAIL_PNG
} GstClapperSnapshotFormat;
#define GST_TYPE_CLAPPER (gst_clapper_get_type ())
#define GST_IS_CLAPPER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CLAPPER))
#define GST_IS_CLAPPER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CLAPPER))
#define GST_CLAPPER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CLAPPER, GstClapperClass))
#define GST_CLAPPER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CLAPPER, GstClapper))
#define GST_CLAPPER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_CLAPPER, GstClapperClass))
#define GST_CLAPPER_CAST(obj) ((GstClapper*)(obj))
#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstClapper, gst_object_unref)
#endif
GST_CLAPPER_API
GType gst_clapper_get_type (void);
GST_CLAPPER_API
void gst_clapper_gst_init (int *argc, char **argv[]);
GST_CLAPPER_API
GstClapper * gst_clapper_new (GstClapperVideoRenderer *video_renderer, GstClapperSignalDispatcher *signal_dispatcher,
GstClapperMpris *mpris);
GST_CLAPPER_API
void gst_clapper_play (GstClapper *clapper);
GST_CLAPPER_API
void gst_clapper_pause (GstClapper *clapper);
GST_CLAPPER_API
void gst_clapper_toggle_play (GstClapper *clapper);
GST_CLAPPER_API
void gst_clapper_stop (GstClapper *clapper);
GST_CLAPPER_API
void gst_clapper_seek (GstClapper *clapper, GstClockTime position);
GST_CLAPPER_API
void gst_clapper_seek_offset (GstClapper *clapper, GstClockTime offset);
GST_CLAPPER_API
GstClapperState
gst_clapper_get_state (GstClapper *clapper);
GST_CLAPPER_API
GstClapperSeekMode
gst_clapper_get_seek_mode (GstClapper *clapper);
GST_CLAPPER_API
void gst_clapper_set_seek_mode (GstClapper *clapper, GstClapperSeekMode mode);
GST_CLAPPER_API
void gst_clapper_set_rate (GstClapper *clapper, gdouble rate);
GST_CLAPPER_API
gdouble gst_clapper_get_rate (GstClapper *clapper);
GST_CLAPPER_API
gchar * gst_clapper_get_uri (GstClapper *clapper);
GST_CLAPPER_API
void gst_clapper_set_uri (GstClapper *clapper, const gchar *uri);
GST_CLAPPER_API
gchar * gst_clapper_get_subtitle_uri (GstClapper *clapper);
GST_CLAPPER_API
void gst_clapper_set_subtitle_uri (GstClapper *clapper, const gchar *uri);
GST_CLAPPER_API
GstClockTime gst_clapper_get_position (GstClapper *clapper);
GST_CLAPPER_API
GstClockTime gst_clapper_get_duration (GstClapper *clapper);
GST_CLAPPER_API
gdouble gst_clapper_get_volume (GstClapper *clapper);
GST_CLAPPER_API
void gst_clapper_set_volume (GstClapper *clapper, gdouble val);
GST_CLAPPER_API
gboolean gst_clapper_get_mute (GstClapper *clapper);
GST_CLAPPER_API
void gst_clapper_set_mute (GstClapper *clapper, gboolean val);
GST_CLAPPER_API
GstElement * gst_clapper_get_pipeline (GstClapper *clapper);
GST_CLAPPER_API
GstClapperMpris *
gst_clapper_get_mpris (GstClapper *clapper);
GST_CLAPPER_API
void gst_clapper_set_video_track_enabled (GstClapper *clapper, gboolean enabled);
GST_CLAPPER_API
void gst_clapper_set_audio_track_enabled (GstClapper *clapper, gboolean enabled);
GST_CLAPPER_API
void gst_clapper_set_subtitle_track_enabled (GstClapper *clapper, gboolean enabled);
GST_CLAPPER_API
gboolean gst_clapper_set_audio_track (GstClapper *clapper, gint stream_index);
GST_CLAPPER_API
gboolean gst_clapper_set_video_track (GstClapper *clapper, gint stream_index);
GST_CLAPPER_API
gboolean gst_clapper_set_subtitle_track (GstClapper *clapper, gint stream_index);
GST_CLAPPER_API
GstClapperMediaInfo *
gst_clapper_get_media_info (GstClapper *clapper);
GST_CLAPPER_API
GstClapperAudioInfo *
gst_clapper_get_current_audio_track (GstClapper *clapper);
GST_CLAPPER_API
GstClapperVideoInfo *
gst_clapper_get_current_video_track (GstClapper *clapper);
GST_CLAPPER_API
GstClapperSubtitleInfo *
gst_clapper_get_current_subtitle_track (GstClapper *clapper);
GST_CLAPPER_API
gboolean gst_clapper_set_visualization (GstClapper *clapper, const gchar *name);
GST_CLAPPER_API
void gst_clapper_set_visualization_enabled (GstClapper *clapper, gboolean enabled);
GST_CLAPPER_API
gchar * gst_clapper_get_current_visualization (GstClapper *clapper);
GST_CLAPPER_API
gboolean gst_clapper_has_color_balance (GstClapper *clapper);
GST_CLAPPER_API
void gst_clapper_set_color_balance (GstClapper *clapper, GstClapperColorBalanceType type, gdouble value);
GST_CLAPPER_API
gdouble gst_clapper_get_color_balance (GstClapper *clapper, GstClapperColorBalanceType type);
GST_CLAPPER_API
GstVideoMultiviewFramePacking
gst_clapper_get_multiview_mode (GstClapper *clapper);
GST_CLAPPER_API
void gst_clapper_set_multiview_mode (GstClapper *clapper, GstVideoMultiviewFramePacking mode);
GST_CLAPPER_API
GstVideoMultiviewFlags
gst_clapper_get_multiview_flags (GstClapper *clapper);
GST_CLAPPER_API
void gst_clapper_set_multiview_flags (GstClapper *clapper, GstVideoMultiviewFlags flags);
GST_CLAPPER_API
gint64 gst_clapper_get_audio_video_offset (GstClapper *clapper);
GST_CLAPPER_API
void gst_clapper_set_audio_video_offset (GstClapper *clapper, gint64 offset);
GST_CLAPPER_API
gint64 gst_clapper_get_subtitle_video_offset (GstClapper *clapper);
GST_CLAPPER_API
void gst_clapper_set_subtitle_video_offset (GstClapper *clapper, gint64 offset);
GST_CLAPPER_API
GstSample * gst_clapper_get_video_snapshot (GstClapper *clapper, GstClapperSnapshotFormat format, const GstStructure *config);
G_END_DECLS
#endif /* __GST_CLAPPER_H__ */

View File

@@ -1,759 +0,0 @@
/*
* GStreamer
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
* Copyright (C) 2020 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.
*/
/**
* SECTION:gstclapperglsink
* @title: GstClapperGLSink
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gl/gstglfuncs.h>
#include "gstclapperglsink.h"
#include "gstgtkutils.h"
GST_DEBUG_CATEGORY (gst_debug_clapper_gl_sink);
#define GST_CAT_DEFAULT gst_debug_clapper_gl_sink
#define GST_CLAPPER_GL_SINK_CAPS \
"video/x-raw(" GST_CAPS_FEATURE_MEMORY_GL_MEMORY "), " \
"format = (string) RGBA, " \
"width = " GST_VIDEO_SIZE_RANGE ", " \
"height = " GST_VIDEO_SIZE_RANGE ", " \
"framerate = " GST_VIDEO_FPS_RANGE ", " \
"texture-target = (string) { 2D, external-oes } " \
" ; " \
"video/x-raw(" GST_CAPS_FEATURE_MEMORY_GL_MEMORY "," \
GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION "), " \
"format = (string) RGBA, " \
"width = " GST_VIDEO_SIZE_RANGE ", " \
"height = " GST_VIDEO_SIZE_RANGE ", " \
"framerate = " GST_VIDEO_FPS_RANGE ", " \
"texture-target = (string) { 2D, external-oes } "
static GstStaticPadTemplate gst_clapper_gl_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_CLAPPER_GL_SINK_CAPS));
static void gst_clapper_gl_sink_finalize (GObject * object);
static void gst_clapper_gl_sink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * param_spec);
static void gst_clapper_gl_sink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * param_spec);
static gboolean gst_clapper_gl_sink_propose_allocation (GstBaseSink * bsink,
GstQuery * query);
static gboolean gst_clapper_gl_sink_query (GstBaseSink * bsink, GstQuery * query);
static gboolean gst_clapper_gl_sink_start (GstBaseSink * bsink);
static gboolean gst_clapper_gl_sink_stop (GstBaseSink * bsink);
static GstFlowReturn gst_clapper_gl_sink_wait_event (GstBaseSink * bsink, GstEvent * event);
static GstStateChangeReturn
gst_clapper_gl_sink_change_state (GstElement * element,
GstStateChange transition);
static void gst_clapper_gl_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
GstClockTime * start, GstClockTime * end);
static GstCaps *gst_clapper_gl_sink_get_caps (GstBaseSink * bsink,
GstCaps * filter);
static gboolean gst_clapper_gl_sink_set_caps (GstBaseSink * bsink,
GstCaps * caps);
static GstFlowReturn gst_clapper_gl_sink_show_frame (GstVideoSink * bsink,
GstBuffer * buf);
static void
gst_clapper_gl_sink_navigation_interface_init (GstNavigationInterface * iface);
#define gst_clapper_gl_sink_parent_class parent_class
G_DEFINE_TYPE_WITH_CODE (GstClapperGLSink, gst_clapper_gl_sink,
GST_TYPE_VIDEO_SINK,
G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION,
gst_clapper_gl_sink_navigation_interface_init);
GST_DEBUG_CATEGORY_INIT (gst_debug_clapper_gl_sink,
"clapperglsink", 0, "Clapper GL Sink"));
static void
gst_clapper_gl_sink_class_init (GstClapperGLSinkClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GstBaseSinkClass *gstbasesink_class;
GstVideoSinkClass *gstvideosink_class;
GstClapperGLSinkClass *gstclapperglsink_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gstbasesink_class = (GstBaseSinkClass *) klass;
gstvideosink_class = (GstVideoSinkClass *) klass;
gstclapperglsink_class = (GstClapperGLSinkClass *) klass;
gobject_class->set_property = gst_clapper_gl_sink_set_property;
gobject_class->get_property = gst_clapper_gl_sink_get_property;
gobject_class->finalize = gst_clapper_gl_sink_finalize;
g_object_class_install_property (gobject_class, PROP_WIDGET,
g_param_spec_object ("widget", "GTK Widget",
"The GtkWidget to place in the widget hierarchy "
"(must only be get from the GTK main thread)",
GTK_TYPE_WIDGET, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
gst_gtk_install_shared_properties (gobject_class);
gstelement_class->change_state = gst_clapper_gl_sink_change_state;
gstbasesink_class->get_caps = gst_clapper_gl_sink_get_caps;
gstbasesink_class->set_caps = gst_clapper_gl_sink_set_caps;
gstbasesink_class->get_times = gst_clapper_gl_sink_get_times;
gstbasesink_class->propose_allocation = gst_clapper_gl_sink_propose_allocation;
gstbasesink_class->query = gst_clapper_gl_sink_query;
gstbasesink_class->start = gst_clapper_gl_sink_start;
gstbasesink_class->stop = gst_clapper_gl_sink_stop;
gstbasesink_class->wait_event = gst_clapper_gl_sink_wait_event;
gstvideosink_class->show_frame = gst_clapper_gl_sink_show_frame;
gstclapperglsink_class->create_widget = gtk_clapper_gl_widget_new;
gstclapperglsink_class->window_title = "GTK4 GL Renderer";
gst_element_class_set_metadata (gstelement_class,
"GTK4 GL Video Sink",
"Sink/Video", "A video sink that renders to a GtkWidget using OpenGL",
"Matthew Waters <matthew@centricular.com>, "
"Rafał Dzięgiel <rafostar.github@gmail.com>");
gst_element_class_add_static_pad_template (gstelement_class,
&gst_clapper_gl_sink_template);
gst_type_mark_as_plugin_api (GST_TYPE_CLAPPER_GL_SINK, 0);
}
static void
gst_clapper_gl_sink_init (GstClapperGLSink * clapper_sink)
{
clapper_sink->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO;
clapper_sink->par_n = DEFAULT_PAR_N;
clapper_sink->par_d = DEFAULT_PAR_D;
clapper_sink->keep_last_frame = DEFAULT_KEEP_LAST_FRAME;
clapper_sink->had_eos = FALSE;
}
static void
gst_clapper_gl_sink_finalize (GObject * object)
{
GstClapperGLSink *clapper_sink = GST_CLAPPER_GL_SINK (object);
GST_DEBUG ("Finalizing Clapper GL sink");
GST_OBJECT_LOCK (clapper_sink);
if (clapper_sink->window && clapper_sink->window_destroy_id)
g_signal_handler_disconnect (clapper_sink->window, clapper_sink->window_destroy_id);
if (clapper_sink->widget && clapper_sink->widget_destroy_id)
g_signal_handler_disconnect (clapper_sink->widget, clapper_sink->widget_destroy_id);
g_clear_object (&clapper_sink->widget);
GST_OBJECT_UNLOCK (clapper_sink);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
widget_destroy_cb (GtkWidget * widget, GstClapperGLSink * clapper_sink)
{
GST_OBJECT_LOCK (clapper_sink);
g_clear_object (&clapper_sink->widget);
GST_OBJECT_UNLOCK (clapper_sink);
}
static void
window_destroy_cb (GtkWidget * widget, GstClapperGLSink * clapper_sink)
{
GST_OBJECT_LOCK (clapper_sink);
if (clapper_sink->widget) {
if (clapper_sink->widget_destroy_id) {
g_signal_handler_disconnect (clapper_sink->widget,
clapper_sink->widget_destroy_id);
clapper_sink->widget_destroy_id = 0;
}
g_clear_object (&clapper_sink->widget);
}
clapper_sink->window = NULL;
GST_OBJECT_UNLOCK (clapper_sink);
}
static GtkClapperGLWidget *
gst_clapper_gl_sink_get_widget (GstClapperGLSink * clapper_sink)
{
if (clapper_sink->widget != NULL)
return clapper_sink->widget;
/* Ensure GTK is initialized, this has no side effect if it was already
* initialized. Also, we do that lazily, so the application can be first */
if (!gtk_init_check ()) {
GST_ERROR_OBJECT (clapper_sink, "Could not ensure GTK initialization.");
return NULL;
}
g_assert (GST_CLAPPER_GL_SINK_GET_CLASS (clapper_sink)->create_widget);
clapper_sink->widget = (GtkClapperGLWidget *)
GST_CLAPPER_GL_SINK_GET_CLASS (clapper_sink)->create_widget ();
g_object_bind_property (clapper_sink, "force-aspect-ratio", clapper_sink->widget,
"force-aspect-ratio", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
g_object_bind_property (clapper_sink, "pixel-aspect-ratio", clapper_sink->widget,
"pixel-aspect-ratio", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
g_object_bind_property (clapper_sink, "keep-last-frame", clapper_sink->widget,
"keep-last-frame", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
/* Take the floating ref, other wise the destruction of the container will
* make this widget disappear possibly before we are done. */
gst_object_ref_sink (clapper_sink->widget);
clapper_sink->widget_destroy_id = g_signal_connect (clapper_sink->widget, "destroy",
G_CALLBACK (widget_destroy_cb), clapper_sink);
/* back pointer */
gtk_clapper_gl_widget_set_element (GTK_CLAPPER_GL_WIDGET (clapper_sink->widget),
GST_ELEMENT (clapper_sink));
return clapper_sink->widget;
}
static void
gst_clapper_gl_sink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstClapperGLSink *clapper_sink = GST_CLAPPER_GL_SINK (object);
switch (prop_id) {
case PROP_WIDGET:
{
GObject *widget = NULL;
GST_OBJECT_LOCK (clapper_sink);
if (clapper_sink->widget != NULL)
widget = G_OBJECT (clapper_sink->widget);
GST_OBJECT_UNLOCK (clapper_sink);
if (!widget)
widget =
gst_gtk_invoke_on_main ((GThreadFunc) gst_clapper_gl_sink_get_widget,
clapper_sink);
g_value_set_object (value, widget);
break;
}
case PROP_FORCE_ASPECT_RATIO:
g_value_set_boolean (value, clapper_sink->force_aspect_ratio);
break;
case PROP_PIXEL_ASPECT_RATIO:
gst_value_set_fraction (value, clapper_sink->par_n, clapper_sink->par_d);
break;
case PROP_KEEP_LAST_FRAME:
g_value_set_boolean (value, clapper_sink->keep_last_frame);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_clapper_gl_sink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstClapperGLSink *clapper_sink = GST_CLAPPER_GL_SINK (object);
switch (prop_id) {
case PROP_FORCE_ASPECT_RATIO:
clapper_sink->force_aspect_ratio = g_value_get_boolean (value);
break;
case PROP_PIXEL_ASPECT_RATIO:
clapper_sink->par_n = gst_value_get_fraction_numerator (value);
clapper_sink->par_d = gst_value_get_fraction_denominator (value);
break;
case PROP_KEEP_LAST_FRAME:
clapper_sink->keep_last_frame = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_clapper_gl_sink_navigation_send_event (GstNavigation * navigation,
GstStructure * structure)
{
GstClapperGLSink *sink = GST_CLAPPER_GL_SINK (navigation);
GstEvent *event;
GstPad *pad;
event = gst_event_new_navigation (structure);
pad = gst_pad_get_peer (GST_VIDEO_SINK_PAD (sink));
GST_TRACE_OBJECT (sink, "navigation event %" GST_PTR_FORMAT, structure);
if (GST_IS_PAD (pad) && GST_IS_EVENT (event)) {
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_event_unref (event);
gst_object_unref (pad);
}
}
static void
gst_clapper_gl_sink_navigation_interface_init (GstNavigationInterface * iface)
{
iface->send_event = gst_clapper_gl_sink_navigation_send_event;
}
static gboolean
gst_clapper_gl_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
{
GstClapperGLSink *clapper_sink = GST_CLAPPER_GL_SINK (bsink);
GstBufferPool *pool = NULL;
GstStructure *config;
GstCaps *caps;
GstVideoInfo info;
guint size;
gboolean need_pool;
GstStructure *allocation_meta = NULL;
gint display_width, display_height;
if (!clapper_sink->display || !clapper_sink->context)
return FALSE;
gst_query_parse_allocation (query, &caps, &need_pool);
if (caps == NULL)
goto no_caps;
if (!gst_video_info_from_caps (&info, caps))
goto invalid_caps;
/* the normal size of a frame */
size = info.size;
if (need_pool) {
GST_DEBUG_OBJECT (clapper_sink, "create new pool");
pool = gst_gl_buffer_pool_new (clapper_sink->context);
config = gst_buffer_pool_get_config (pool);
gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
gst_buffer_pool_config_add_option (config,
GST_BUFFER_POOL_OPTION_GL_SYNC_META);
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 */
gst_query_add_allocation_pool (query, pool, size, 2, 0);
if (pool)
gst_object_unref (pool);
GST_OBJECT_LOCK (clapper_sink);
display_width = clapper_sink->display_width;
display_height = clapper_sink->display_height;
GST_OBJECT_UNLOCK (clapper_sink);
if (display_width != 0 && display_height != 0) {
GST_DEBUG_OBJECT (clapper_sink, "sending alloc query with size %dx%d",
display_width, display_height);
allocation_meta = gst_structure_new ("GstVideoOverlayCompositionMeta",
"width", G_TYPE_UINT, display_width,
"height", G_TYPE_UINT, display_height, NULL);
}
gst_query_add_allocation_meta (query,
GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, allocation_meta);
if (allocation_meta)
gst_structure_free (allocation_meta);
/* we also support various metadata */
gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, 0);
if (clapper_sink->context->gl_vtable->FenceSync)
gst_query_add_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, 0);
return TRUE;
/* ERRORS */
no_caps:
{
GST_DEBUG_OBJECT (bsink, "no caps specified");
return FALSE;
}
invalid_caps:
{
GST_DEBUG_OBJECT (bsink, "invalid caps specified");
return FALSE;
}
config_failed:
{
GST_DEBUG_OBJECT (bsink, "failed setting config");
return FALSE;
}
}
static gboolean
gst_clapper_gl_sink_query (GstBaseSink * bsink, GstQuery * query)
{
GstClapperGLSink *clapper_sink = GST_CLAPPER_GL_SINK (bsink);
gboolean res = FALSE;
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_CONTEXT:
res = gst_gl_handle_context_query ((GstElement *) clapper_sink, query,
clapper_sink->display, clapper_sink->context, clapper_sink->gtk_context);
break;
default:
res = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query);
break;
}
return res;
}
static gboolean
gst_clapper_gl_sink_start_on_main (GstBaseSink * bsink)
{
GstClapperGLSink *gst_sink = GST_CLAPPER_GL_SINK (bsink);
GstClapperGLSinkClass *klass = GST_CLAPPER_GL_SINK_GET_CLASS (bsink);
GtkWidget *toplevel;
GtkRoot *root;
if (gst_clapper_gl_sink_get_widget (gst_sink) == NULL)
return FALSE;
/* After this point, clapper_sink->widget will always be set */
root = gtk_widget_get_root (GTK_WIDGET (gst_sink->widget));
if (!GTK_IS_ROOT (root)) {
GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (gst_sink->widget));
if (parent) {
GtkWidget *temp_parent;
while ((temp_parent = gtk_widget_get_parent (parent)))
parent = temp_parent;
}
toplevel = (parent) ? parent : GTK_WIDGET (gst_sink->widget);
/* sanity check */
g_assert (klass->window_title);
/* User did not add widget its own UI, let's popup a new GtkWindow to
* make gst-launch-1.0 work. */
gst_sink->window = gtk_window_new ();
gtk_window_set_default_size (GTK_WINDOW (gst_sink->window), 640, 480);
gtk_window_set_title (GTK_WINDOW (gst_sink->window), klass->window_title);
gtk_window_set_child (GTK_WINDOW (gst_sink->window), toplevel);
gst_sink->window_destroy_id = g_signal_connect (
GTK_WINDOW (gst_sink->window),
"destroy", G_CALLBACK (window_destroy_cb), gst_sink);
}
return TRUE;
}
static gboolean
gst_clapper_gl_sink_start (GstBaseSink * bsink)
{
GstClapperGLSink *clapper_sink = GST_CLAPPER_GL_SINK (bsink);
GtkClapperGLWidget *clapper_widget;
if (!(! !gst_gtk_invoke_on_main ((GThreadFunc) (GCallback)
gst_clapper_gl_sink_start_on_main, bsink)))
return FALSE;
/* After this point, clapper_sink->widget will always be set */
clapper_widget = GTK_CLAPPER_GL_WIDGET (clapper_sink->widget);
if (!gtk_clapper_gl_widget_init_winsys (clapper_widget)) {
GST_ELEMENT_ERROR (bsink, RESOURCE, NOT_FOUND, ("%s",
"Failed to initialize OpenGL with GTK"), (NULL));
return FALSE;
}
if (!clapper_sink->display)
clapper_sink->display = gtk_clapper_gl_widget_get_display (clapper_widget);
if (!clapper_sink->context)
clapper_sink->context = gtk_clapper_gl_widget_get_context (clapper_widget);
if (!clapper_sink->gtk_context)
clapper_sink->gtk_context = gtk_clapper_gl_widget_get_gtk_context (clapper_widget);
if (!clapper_sink->display || !clapper_sink->context || !clapper_sink->gtk_context) {
GST_ELEMENT_ERROR (bsink, RESOURCE, NOT_FOUND, ("%s",
"Failed to retrieve OpenGL context from GTK"), (NULL));
return FALSE;
}
gst_gl_element_propagate_display_context (GST_ELEMENT (bsink),
clapper_sink->display);
return TRUE;
}
static gboolean
gst_clapper_gl_sink_stop_on_main (GstBaseSink * bsink)
{
GstClapperGLSink *gst_sink = GST_CLAPPER_GL_SINK (bsink);
if (gst_sink->window) {
gtk_window_destroy (GTK_WINDOW (gst_sink->window));
gst_sink->window = NULL;
gst_sink->widget = NULL;
}
return TRUE;
}
static gboolean
gst_clapper_gl_sink_stop (GstBaseSink * bsink)
{
GstClapperGLSink *clapper_sink = GST_CLAPPER_GL_SINK (bsink);
if (clapper_sink->display) {
gst_object_unref (clapper_sink->display);
clapper_sink->display = NULL;
}
if (clapper_sink->context) {
gst_object_unref (clapper_sink->context);
clapper_sink->context = NULL;
}
if (clapper_sink->gtk_context) {
gst_object_unref (clapper_sink->gtk_context);
clapper_sink->gtk_context = NULL;
}
if (clapper_sink->window)
return ! !gst_gtk_invoke_on_main ((GThreadFunc) (GCallback)
gst_clapper_gl_sink_stop_on_main, bsink);
return TRUE;
}
static void
gst_gtk_window_show_all_and_unref (GtkWidget * window)
{
gtk_window_present (GTK_WINDOW (window));
g_object_unref (window);
}
static GstStateChangeReturn
gst_clapper_gl_sink_change_state (GstElement * element, GstStateChange transition)
{
GstClapperGLSink *clapper_sink = GST_CLAPPER_GL_SINK (element);
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
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)));
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:
GST_OBJECT_LOCK (clapper_sink);
clapper_sink->had_eos = FALSE;
if (clapper_sink->widget) {
GTK_CLAPPER_GL_WIDGET_LOCK (clapper_sink->widget);
clapper_sink->widget->ignore_buffers = FALSE;
GTK_CLAPPER_GL_WIDGET_UNLOCK (clapper_sink->widget);
}
GST_OBJECT_UNLOCK (clapper_sink);
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:{
GtkWindow *window = NULL;
GST_OBJECT_LOCK (clapper_sink);
if (clapper_sink->window)
window = g_object_ref (GTK_WINDOW (clapper_sink->window));
GST_OBJECT_UNLOCK (clapper_sink);
if (window) {
gst_gtk_invoke_on_main ((GThreadFunc) (GCallback)
gst_gtk_window_show_all_and_unref, window);
}
break;
}
case GST_STATE_CHANGE_READY_TO_NULL:
GST_OBJECT_LOCK (clapper_sink);
if (clapper_sink->widget) {
GTK_CLAPPER_GL_WIDGET_LOCK (clapper_sink->widget);
clapper_sink->widget->ignore_buffers =
!clapper_sink->had_eos || !clapper_sink->keep_last_frame;
GTK_CLAPPER_GL_WIDGET_UNLOCK (clapper_sink->widget);
}
GST_OBJECT_UNLOCK (clapper_sink);
/* Fall through to render black bg */
case GST_STATE_CHANGE_PAUSED_TO_READY:
GST_OBJECT_LOCK (clapper_sink);
if (clapper_sink->widget)
gtk_clapper_gl_widget_set_buffer (clapper_sink->widget, NULL);
GST_OBJECT_UNLOCK (clapper_sink);
break;
default:
break;
}
return ret;
}
static void
gst_clapper_gl_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
GstClockTime * start, GstClockTime * end)
{
GstClapperGLSink *clapper_sink = GST_CLAPPER_GL_SINK (bsink);
if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
*start = GST_BUFFER_TIMESTAMP (buf);
if (GST_BUFFER_DURATION_IS_VALID (buf))
*end = *start + GST_BUFFER_DURATION (buf);
else {
if (GST_VIDEO_INFO_FPS_N (&clapper_sink->v_info) > 0) {
*end = *start +
gst_util_uint64_scale_int (GST_SECOND,
GST_VIDEO_INFO_FPS_D (&clapper_sink->v_info),
GST_VIDEO_INFO_FPS_N (&clapper_sink->v_info));
}
}
}
}
static GstCaps *
gst_clapper_gl_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
{
GstCaps *tmp = NULL;
GstCaps *result = NULL;
tmp = gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink));
if (filter) {
GST_DEBUG_OBJECT (bsink, "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;
}
result = gst_gl_overlay_compositor_add_caps (result);
GST_DEBUG_OBJECT (bsink, "returning caps: %" GST_PTR_FORMAT, result);
return result;
}
static gboolean
gst_clapper_gl_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
{
GstClapperGLSink *clapper_sink = GST_CLAPPER_GL_SINK (bsink);
gboolean res = FALSE;
GST_DEBUG ("set caps with %" GST_PTR_FORMAT, caps);
if (!gst_video_info_from_caps (&clapper_sink->v_info, caps))
return FALSE;
GST_OBJECT_LOCK (clapper_sink);
if (clapper_sink->widget == NULL) {
GST_OBJECT_UNLOCK (clapper_sink);
GST_ELEMENT_ERROR (clapper_sink, RESOURCE, NOT_FOUND,
("%s", "Output widget was destroyed"), (NULL));
return FALSE;
}
if (!gtk_clapper_gl_widget_set_format (clapper_sink->widget, &clapper_sink->v_info)) {
GST_OBJECT_UNLOCK (clapper_sink);
return FALSE;
}
res = gtk_clapper_gl_widget_update_output_format (clapper_sink->widget, caps);
GST_OBJECT_UNLOCK (clapper_sink);
return res;
}
static GstFlowReturn
gst_clapper_gl_sink_wait_event (GstBaseSink * bsink, GstEvent * event)
{
GstClapperGLSink *clapper_sink = GST_CLAPPER_GL_SINK (bsink);
GstFlowReturn ret;
ret = GST_BASE_SINK_CLASS (parent_class)->wait_event (bsink, event);
switch (event->type) {
case GST_EVENT_EOS:
if (ret == GST_FLOW_OK) {
GST_OBJECT_LOCK (clapper_sink);
clapper_sink->had_eos = TRUE;
GST_OBJECT_UNLOCK (clapper_sink);
}
break;
default:
break;
}
return ret;
}
static GstFlowReturn
gst_clapper_gl_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
{
GstClapperGLSink *clapper_sink;
GST_TRACE ("rendering buffer:%p", buf);
clapper_sink = GST_CLAPPER_GL_SINK (vsink);
GST_OBJECT_LOCK (clapper_sink);
if (clapper_sink->widget == NULL) {
GST_OBJECT_UNLOCK (clapper_sink);
GST_ELEMENT_ERROR (clapper_sink, RESOURCE, NOT_FOUND,
("%s", "Output widget was destroyed"), (NULL));
return GST_FLOW_ERROR;
}
gtk_clapper_gl_widget_set_buffer (clapper_sink->widget, buf);
GST_OBJECT_UNLOCK (clapper_sink);
return GST_FLOW_OK;
}

View File

@@ -1,105 +0,0 @@
/*
* GStreamer
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
* Copyright (C) 2020 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.
*/
#ifndef __GST_CLAPPER_GL_SINK_H__
#define __GST_CLAPPER_GL_SINK_H__
#include <gtk/gtk.h>
#include <gst/gst.h>
#include <gst/video/gstvideosink.h>
#include <gst/video/video.h>
#include <gst/gl/gl.h>
#include "gtkclapperglwidget.h"
#define GST_TYPE_CLAPPER_GL_SINK (gst_clapper_gl_sink_get_type())
#define GST_CLAPPER_GL_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CLAPPER_GL_SINK,GstClapperGLSink))
#define GST_CLAPPER_GL_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CLAPPER_GL_SINK,GstClapperGLClass))
#define GST_CLAPPER_GL_SINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CLAPPER_GL_SINK, GstClapperGLSinkClass))
#define GST_IS_CLAPPER_GL_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CLAPPER_GL_SINK))
#define GST_IS_CLAPPER_GL_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CLAPPER_GL_SINK))
#define GST_CLAPPER_GL_SINK_CAST(obj) ((GstClapperGLSink*)(obj))
G_BEGIN_DECLS
typedef struct _GstClapperGLSink GstClapperGLSink;
typedef struct _GstClapperGLSinkClass GstClapperGLSinkClass;
GType gst_clapper_gl_sink_get_type (void);
/**
* GstClapperGLSink:
*
* Opaque #GstClapperGLSink object
*/
struct _GstClapperGLSink
{
/* <private> */
GstVideoSink parent;
GstVideoInfo v_info;
GtkClapperGLWidget *widget;
gboolean had_eos;
/* properties */
gboolean force_aspect_ratio;
gint par_n, par_d;
gboolean keep_last_frame;
gboolean ignore_textures;
GtkWidget *window;
gulong widget_destroy_id;
gulong window_destroy_id;
GstGLDisplay *display;
GstGLContext *context;
GstGLContext *gtk_context;
GstGLUpload *upload;
GstBuffer *uploaded_buffer;
/* read/write with object lock */
gint display_width, display_height;
};
/**
* GstClapperGLSinkClass:
*
* The #GstClapperGLSinkClass struct only contains private data
*/
struct _GstClapperGLSinkClass
{
GstVideoSinkClass object_class;
/* metadata */
const gchar *window_title;
/* virtuals */
GtkWidget* (*create_widget) (void);
};
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GstClapperGLSink, gst_object_unref)
G_END_DECLS
#endif /* __GST_CLAPPER_GL_SINK_H__ */

View File

@@ -1,103 +0,0 @@
/*
* GStreamer
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
* Copyright (C) 2015 Thibault Saunier <tsaunier@gnome.org>
* Copyright (C) 2021 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.
*/
/* FIXME: remove these once their headers are public in gstreamer:
* https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/merge_requests/804
*/
#include "gstclapperglutils.h"
static const gfloat identity_matrix[] = {
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0,
};
static const gfloat from_ndc_matrix[] = {
0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0,
};
static const gfloat to_ndc_matrix[] = {
2.0, 0.0, 0.0, 0.0,
0.0, 2.0, 0.0, 0.0,
0.0, 0.0, 2.0, 0.0,
-1.0, -1.0, -1.0, 1.0,
};
/* multiplies two 4x4 matrices, @a X @b, and stores the result in @result
* https://en.wikipedia.org/wiki/Matrix_multiplication
*/
static void
gst_gl_multiply_matrix4 (const gfloat * a, const gfloat * b, gfloat * result)
{
int i, j, k;
gfloat tmp[16] = { 0.0f };
if (!a || !b || !result)
return;
for (i = 0; i < 4; i++) { /* column */
for (j = 0; j < 4; j++) { /* row */
for (k = 0; k < 4; k++) {
tmp[j + (i * 4)] += a[k + (i * 4)] * b[j + (k * 4)];
}
}
}
for (i = 0; i < 16; i++)
result[i] = tmp[i];
}
/*
* gst_clapper_gl_get_affine_transformation_meta_as_ndc:
* @meta: (nullable): a #GstVideoAffineTransformationMeta
* @matrix: (out): result of the 4x4 matrix
*
* Retrieves the stored 4x4 affine transformation matrix stored in @meta in
* NDC coordinates. if @meta is NULL, an identity matrix is returned.
*
* NDC is a left-handed coordinate system
* - x - [-1, 1] - +ve X moves right
* - y - [-1, 1] - +ve Y moves up
* - z - [-1, 1] - +ve Z moves into
*/
void
gst_clapper_gl_get_affine_transformation_meta_as_ndc (GstVideoAffineTransformationMeta *
meta, gfloat * matrix)
{
if (!meta) {
int i;
for (i = 0; i < 16; i++) {
matrix[i] = identity_matrix[i];
}
} else {
float tmp[16];
/* change of basis multiplications */
gst_gl_multiply_matrix4 (from_ndc_matrix, meta->matrix, tmp);
gst_gl_multiply_matrix4 (tmp, to_ndc_matrix, matrix);
}
}

View File

@@ -1,29 +0,0 @@
/*
* GStreamer
* Copyright (C) 2016 Matthew Waters <matthew@centricular.com>
* Copyright (C) 2021 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.
*/
#ifndef __GST_CLAPPER_GL_UTILS_H__
#define __GST_CLAPPER_GL_UTILS_H__
#include <gst/video/gstvideoaffinetransformationmeta.h>
void gst_clapper_gl_get_affine_transformation_meta_as_ndc (GstVideoAffineTransformationMeta *meta, gfloat *matrix);
#endif /* __GST_CLAPPER_GL_UTILS_H__ */

View File

@@ -1,95 +0,0 @@
/*
* GStreamer
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
* Copyright (C) 2015 Thibault Saunier <tsaunier@gnome.org>
*
* 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 <gst/gst.h>
#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;
}
void
gst_gtk_install_shared_properties (GObjectClass *gobject_class)
{
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));
}

View File

@@ -1,46 +0,0 @@
/*
* GStreamer
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
* Copyright (C) 2015 Thibault Saunier <tsaunier@gnome.org>
*
* 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.
*/
#ifndef __GST_GTK_UTILS_H__
#define __GST_GTK_UTILS_H__
#define DEFAULT_FORCE_ASPECT_RATIO TRUE
#define DEFAULT_PAR_N 0
#define DEFAULT_PAR_D 1
#define DEFAULT_KEEP_LAST_FRAME FALSE
#include <glib.h>
#include <glib-object.h>
enum
{
PROP_0,
PROP_WIDGET,
PROP_FORCE_ASPECT_RATIO,
PROP_PIXEL_ASPECT_RATIO,
PROP_KEEP_LAST_FRAME
};
gpointer gst_gtk_invoke_on_main (GThreadFunc func, gpointer data);
void gst_gtk_install_shared_properties (GObjectClass *gobject_class);
#endif /* __GST_GTK_UTILS_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -1,113 +0,0 @@
/*
* GStreamer
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
* Copyright (C) 2020 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.
*/
#ifndef __GTK_CLAPPER_GL_WIDGET_H__
#define __GTK_CLAPPER_GL_WIDGET_H__
#include <gtk/gtk.h>
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/gl/gl.h>
G_BEGIN_DECLS
GType gtk_clapper_gl_widget_get_type (void);
#define GTK_TYPE_CLAPPER_GL_WIDGET (gtk_clapper_gl_widget_get_type())
#define GTK_CLAPPER_GL_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GTK_TYPE_CLAPPER_GL_WIDGET,GtkClapperGLWidget))
#define GTK_CLAPPER_GL_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GTK_TYPE_CLAPPER_GL_WIDGET,GtkClapperGLWidgetClass))
#define GTK_IS_CLAPPER_GL_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GTK_TYPE_CLAPPER_GL_WIDGET))
#define GTK_IS_CLAPPER_GL_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GTK_TYPE_CLAPPER_GL_WIDGET))
#define GTK_CLAPPER_GL_WIDGET_CAST(obj) ((GtkClapperGLWidget*)(obj))
#define GTK_CLAPPER_GL_WIDGET_LOCK(w) g_mutex_lock(&((GtkClapperGLWidget*)(w))->lock)
#define GTK_CLAPPER_GL_WIDGET_UNLOCK(w) g_mutex_unlock(&((GtkClapperGLWidget*)(w))->lock)
typedef struct _GtkClapperGLWidget GtkClapperGLWidget;
typedef struct _GtkClapperGLWidgetClass GtkClapperGLWidgetClass;
typedef struct _GtkClapperGLWidgetPrivate GtkClapperGLWidgetPrivate;
struct _GtkClapperGLWidget
{
/* <private> */
GtkGLArea parent;
GtkClapperGLWidgetPrivate *priv;
/* properties */
gboolean force_aspect_ratio;
gint par_n, par_d;
gboolean keep_last_frame;
gint display_width;
gint display_height;
/* Widget dimensions */
gint scaled_width;
gint scaled_height;
/* Position coords */
gdouble last_pos_x;
gdouble last_pos_y;
gboolean negotiated;
gboolean ignore_buffers;
GstBuffer *pending_buffer;
GstBuffer *buffer;
GstVideoInfo v_info;
/* resize */
gboolean pending_resize;
GstVideoInfo pending_v_info;
guint display_ratio_num;
guint display_ratio_den;
/*< private >*/
GMutex lock;
GWeakRef element;
/* event controllers */
GtkEventController *key_controller;
GtkEventController *motion_controller;
GtkGesture *click_gesture;
/* Pending draw idles callback */
guint draw_id;
};
struct _GtkClapperGLWidgetClass
{
GtkGLAreaClass parent_class;
};
/* API */
gboolean gtk_clapper_gl_widget_set_format (GtkClapperGLWidget * widget, GstVideoInfo * v_info);
void gtk_clapper_gl_widget_set_buffer (GtkClapperGLWidget * widget, GstBuffer * buffer);
void gtk_clapper_gl_widget_set_element (GtkClapperGLWidget * widget, GstElement * element);
GtkWidget * gtk_clapper_gl_widget_new (void);
gboolean gtk_clapper_gl_widget_init_winsys (GtkClapperGLWidget * widget);
GstGLDisplay * gtk_clapper_gl_widget_get_display (GtkClapperGLWidget * widget);
GstGLContext * gtk_clapper_gl_widget_get_context (GtkClapperGLWidget * widget);
GstGLContext * gtk_clapper_gl_widget_get_gtk_context (GtkClapperGLWidget * widget);
gboolean gtk_clapper_gl_widget_update_output_format (GtkClapperGLWidget * widget, GstCaps * caps);
G_END_DECLS
#endif /* __GTK_CLAPPER_GL_WIDGET_H__ */

View File

@@ -1,83 +0,0 @@
gstclapper_sources = [
'gstclapper.c',
'gstclapper-signal-dispatcher.c',
'gstclapper-video-renderer.c',
'gstclapper-media-info.c',
'gstclapper-g-main-context-signal-dispatcher.c',
'gstclapper-video-overlay-video-renderer.c',
'gstclapper-visualization.c',
'gstclapper-mpris.c',
'gstclapper-gtk4-plugin.c',
'gtk4/gstclapperglsink.c',
'gtk4/gstgtkutils.c',
'gtk4/gtkclapperglwidget.c',
'gtk4/gstclapperglutils.c',
]
gstclapper_headers = [
'clapper.h',
'clapper-prelude.h',
'gstclapper.h',
'gstclapper-types.h',
'gstclapper-signal-dispatcher.h',
'gstclapper-video-renderer.h',
'gstclapper-media-info.h',
'gstclapper-g-main-context-signal-dispatcher.h',
'gstclapper-video-overlay-video-renderer.h',
'gstclapper-visualization.h',
'gstclapper-mpris.h',
'gstclapper-gtk4-plugin.h',
]
gstclapper_defines = [
'-DHAVE_CONFIG_H',
'-DBUILDING_GST_CLAPPER',
'-DGST_USE_UNSTABLE_API',
'-DHAVE_GTK_GL',
]
if not get_option('lib')
subdir_done()
endif
if not gir.found()
error('Clapper lib requires GI bindings to be compiled')
endif
if not have_gtk_gl_windowing
error('GTK4 widget requires GL windowing')
endif
gstclapper_mpris_gdbus = gnome.gdbus_codegen('gstclapper-mpris-gdbus',
sources: '../../../data/gstclapper-mpris-gdbus.xml',
interface_prefix: 'org.mpris.',
namespace: 'GstClapperMpris'
)
gstclapper = library('gstclapper-' + api_version,
gstclapper_sources + gstclapper_mpris_gdbus,
c_args: gstclapper_defines,
link_args: noseh_link_args,
include_directories: [configinc, libsinc],
version: libversion,
install: true,
install_dir: pkglibdir,
dependencies: [gtk4_dep, glib_dep, gio_dep, giounix_dep,
gstbase_dep, gstvideo_dep, gstaudio_dep,
gsttag_dep, gstpbutils_dep, libm] + gtk_deps,
)
clapper_gir = gnome.generate_gir(gstclapper,
sources: gstclapper_sources + gstclapper_headers,
namespace: 'GstClapper',
nsversion: api_version,
identifier_prefix: 'Gst',
symbol_prefix: 'gst',
export_packages: 'gstreamer-clapper-1.0',
includes: ['Gst-1.0', 'GstPbutils-1.0', 'GstBase-1.0', 'GstVideo-1.0',
'GstAudio-1.0', 'GstTag-1.0'],
install: true,
install_dir_typelib: join_paths(pkglibdir, 'girepository-1.0'),
extra_args: gir_init_section + ['-DGST_USE_UNSTABLE_API'],
dependencies: [gstbase_dep, gstvideo_dep, gstaudio_dep,
gsttag_dep, gstpbutils_dep]
)

View File

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

View File

@@ -1,681 +0,0 @@
/*
* GStreamer
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
* Copyright (C) 2020-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 "gstgtkutils.h"
#define DEFAULT_FORCE_ASPECT_RATIO TRUE
#define DEFAULT_PAR_N 0
#define DEFAULT_PAR_D 1
#define SINK_FORMATS \
"{ BGR, RGB, BGRA, RGBA, ABGR, ARGB, RGBx, BGRx, RGBA64_LE, RGBA64_BE, NV12 }"
#define GST_CLAPPER_GL_SINK_CAPS \
"video/x-raw(" GST_CAPS_FEATURE_MEMORY_GL_MEMORY "), " \
"format = (string)" SINK_FORMATS ", " \
"width = " GST_VIDEO_SIZE_RANGE ", " \
"height = " GST_VIDEO_SIZE_RANGE ", " \
"framerate = " GST_VIDEO_FPS_RANGE ", " \
"texture-target = (string) { 2D, external-oes } " \
" ; " \
"video/x-raw(" GST_CAPS_FEATURE_MEMORY_GL_MEMORY "," \
GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION "), " \
"format = (string)" SINK_FORMATS ", " \
"width = " GST_VIDEO_SIZE_RANGE ", " \
"height = " GST_VIDEO_SIZE_RANGE ", " \
"framerate = " GST_VIDEO_FPS_RANGE ", " \
"texture-target = (string) { 2D, external-oes } "
enum
{
PROP_0,
PROP_WIDGET,
PROP_FORCE_ASPECT_RATIO,
PROP_PIXEL_ASPECT_RATIO,
PROP_LAST
};
GST_DEBUG_CATEGORY (gst_debug_clapper_sink);
#define GST_CAT_DEFAULT gst_debug_clapper_sink
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 ("memory:DMABuf", SINK_FORMATS) ";"
GST_CLAPPER_GL_SINK_CAPS ";"
GST_VIDEO_CAPS_MAKE (SINK_FORMATS)));
static void gst_clapper_sink_navigation_interface_init (
GstNavigationInterface *iface);
#define gst_clapper_sink_parent_class 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_DEBUG_CATEGORY_INIT (gst_debug_clapper_sink,
"clappersink", 0, "Clapper Sink"));
GST_ELEMENT_REGISTER_DEFINE (clappersink, "clappersink", GST_RANK_NONE,
GST_TYPE_CLAPPER_SINK);
static void gst_clapper_sink_finalize (GObject *object);
static void gst_clapper_sink_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *param_spec);
static void gst_clapper_sink_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *param_spec);
static gboolean gst_clapper_sink_propose_allocation (GstBaseSink *bsink,
GstQuery *query);
static gboolean gst_clapper_sink_start (GstBaseSink *bsink);
static gboolean gst_clapper_sink_stop (GstBaseSink *bsink);
static GstStateChangeReturn
gst_clapper_sink_change_state (GstElement *element, GstStateChange transition);
static void gst_clapper_sink_get_times (GstBaseSink *bsink, GstBuffer *buffer,
GstClockTime *start, GstClockTime *end);
static GstCaps * gst_clapper_sink_get_caps (GstBaseSink *bsink,
GstCaps *filter);
static gboolean gst_clapper_sink_set_caps (GstBaseSink *bsink,
GstCaps *caps);
static GstFlowReturn gst_clapper_sink_show_frame (GstVideoSink *bsink,
GstBuffer *buffer);
static void
gst_clapper_sink_class_init (GstClapperSinkClass *klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GstBaseSinkClass *gstbasesink_class;
GstVideoSinkClass *gstvideosink_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gstbasesink_class = (GstBaseSinkClass *) klass;
gstvideosink_class = (GstVideoSinkClass *) klass;
gobject_class->set_property = gst_clapper_sink_set_property;
gobject_class->get_property = gst_clapper_sink_get_property;
gobject_class->finalize = gst_clapper_sink_finalize;
//gst_gtk_install_shared_properties (gobject_class);
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);
}
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 "
"(must only be get from the GTK main thread)",
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;
}
static void
gst_clapper_sink_finalize (GObject *object)
{
GstClapperSink *self = GST_CLAPPER_SINK (object);
GST_TRACE ("Finalize");
GST_OBJECT_LOCK (self);
if (self->window && self->window_destroy_id)
g_signal_handler_disconnect (self->window, self->window_destroy_id);
//if (self->widget && self->widget_destroy_id)
// g_signal_handler_disconnect (self->widget, self->widget_destroy_id);
g_clear_object (&self->obj);
GST_OBJECT_UNLOCK (self);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
widget_destroy_cb (GtkWidget *widget, GstClapperSink *self)
{
GST_OBJECT_LOCK (self);
g_clear_object (&self->obj);
GST_OBJECT_UNLOCK (self);
}
static void
window_destroy_cb (GtkWidget *window, GstClapperSink *self)
{
GST_OBJECT_LOCK (self);
if (self->obj) {
if (self->widget_destroy_id) {
GtkWidget *widget;
widget = gtk_clapper_object_get_widget (self->obj);
g_signal_handler_disconnect (widget, self->widget_destroy_id);
self->widget_destroy_id = 0;
}
g_clear_object (&self->obj);
}
self->window = NULL;
GST_OBJECT_UNLOCK (self);
}
static GtkWidget *
gst_clapper_sink_get_widget (GstClapperSink *self)
{
if (G_UNLIKELY (self->obj == NULL)) {
/* Ensure GTK is initialized */
if (!gtk_init_check ()) {
GST_ERROR_OBJECT (self, "Could not ensure GTK initialization");
return NULL;
}
self->obj = gtk_clapper_object_new ();
/* Take the floating ref, otherwise the destruction of the container will
* make this widget disappear possibly before we are done. */
//g_object_ref_sink (self->obj);
//self->widget_destroy_id = g_signal_connect (widget,
// "destroy", G_CALLBACK (widget_destroy_cb), self);
/* Back pointer */
gtk_clapper_object_set_element (
GTK_CLAPPER_OBJECT (self->obj), GST_ELEMENT (self));
}
return gtk_clapper_object_get_widget (self->obj);
}
static void
gst_clapper_sink_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
GstClapperSink *self = GST_CLAPPER_SINK (object);
switch (prop_id) {
case PROP_WIDGET:{
GObject *widget = NULL;
GST_OBJECT_LOCK (self);
if (G_LIKELY (self->obj != NULL))
widget = G_OBJECT (gtk_clapper_object_get_widget (self->obj));
GST_OBJECT_UNLOCK (self);
if (G_UNLIKELY (widget == NULL)) {
widget = gst_gtk_invoke_on_main (
(GThreadFunc) gst_clapper_sink_get_widget, self);
}
g_value_set_object (value, 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;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_clapper_sink_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
GstClapperSink *self = GST_CLAPPER_SINK (object);
switch (prop_id) {
case PROP_FORCE_ASPECT_RATIO:
self->force_aspect_ratio = g_value_get_boolean (value);
break;
case PROP_PIXEL_ASPECT_RATIO:
self->par_n = gst_value_get_fraction_numerator (value);
self->par_d = gst_value_get_fraction_denominator (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
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 (GST_IS_EVENT (event))) {
GstPad *pad;
pad = gst_pad_get_peer (GST_VIDEO_SINK_PAD (sink));
if (G_LIKELY (GST_IS_PAD (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 void
gst_clapper_sink_navigation_interface_init (GstNavigationInterface *iface)
{
iface->send_event = gst_clapper_sink_navigation_send_event;
}
static gboolean
gst_clapper_sink_propose_allocation (GstBaseSink *bsink, GstQuery *query)
{
GstClapperSink *self = GST_CLAPPER_SINK (bsink);
GstBufferPool *pool = NULL;
GstStructure *config;
GstCaps *caps;
GstVideoInfo info;
guint size;
gboolean need_pool;
GstStructure *allocation_meta = NULL;
gint display_width, display_height;
//if (!self->display || !self->context)
// return FALSE;
gst_query_parse_allocation (query, &caps, &need_pool);
if (!caps)
goto no_caps;
if (!gst_video_info_from_caps (&info, caps))
goto invalid_caps;
/* Normal size of a frame */
size = GST_VIDEO_INFO_SIZE (&info);
if (need_pool) {
GST_DEBUG_OBJECT (self, "Creating new pool");
pool = gst_buffer_pool_new ();
config = gst_buffer_pool_get_config (pool);
gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
if (!gst_buffer_pool_set_config (pool, config)) {
gst_object_unref (pool);
goto config_failed;
}
}
/* We need at least 3 buffers because we keep around the current one
* for memory to stay valid during resizing and hold on to the pending one */
gst_query_add_allocation_pool (query, pool, size, 3, 0);
if (pool)
gst_object_unref (pool);
/* FIXME: Read calculated display sizes from widget */
display_width = GST_VIDEO_INFO_WIDTH (&info);
display_height = GST_VIDEO_INFO_HEIGHT (&info);
if (display_width != 0 && display_height != 0) {
GST_DEBUG_OBJECT (self, "Sending alloc query with size %dx%d",
display_width, display_height);
allocation_meta = gst_structure_new ("GstVideoOverlayCompositionMeta",
"width", G_TYPE_UINT, display_width,
"height", G_TYPE_UINT, display_height, NULL);
}
gst_query_add_allocation_meta (query,
GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, allocation_meta);
if (allocation_meta)
gst_structure_free (allocation_meta);
/* We also support various metadata */
gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
return TRUE;
/* ERRORS */
no_caps:
GST_DEBUG_OBJECT (bsink, "No caps specified");
return FALSE;
invalid_caps:
GST_DEBUG_OBJECT (bsink, "Invalid caps specified");
return FALSE;
config_failed:
GST_DEBUG_OBJECT (bsink, "Failed to set config");
return FALSE;
}
static gboolean
gst_clapper_sink_start_on_main (GstClapperSink *self)
{
GtkWidget *widget;
/* Make sure widget is created */
if (!(widget = gst_clapper_sink_get_widget (self)))
return FALSE;
/* After this point, self->obj will always be set */
if (!GTK_IS_ROOT (gtk_widget_get_root (widget))) {
GtkWidget *toplevel, *parent;
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;
/* User did not add widget its own UI, let's popup a new GtkWindow to
* make "gst-launch-1.0" work. */
self->window = (GtkWindow *) gtk_window_new ();
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);
}
return TRUE;
}
static gboolean
gst_clapper_sink_start (GstBaseSink *bsink)
{
GstClapperSink *self = GST_CLAPPER_SINK (bsink);
GtkClapperObject *obj = NULL;
if (!(! !gst_gtk_invoke_on_main ((GThreadFunc) (GCallback)
gst_clapper_sink_start_on_main, self)))
return FALSE;
//widget = GTK_CLAPPER_WIDGET (self->widget);
GST_OBJECT_LOCK (self);
if (self->obj)
obj = g_object_ref (self->obj);
GST_OBJECT_UNLOCK (self);
if (G_UNLIKELY (obj == NULL)) {
GST_ELEMENT_ERROR (bsink, RESOURCE, NOT_FOUND, ("%s",
"Clapper widget does not exist"), (NULL));
return FALSE;
}
if (!gtk_clapper_object_init_winsys (obj)) {
GST_ELEMENT_ERROR (bsink, RESOURCE, NOT_FOUND, ("%s",
"Failed to initialize OpenGL with GTK"), (NULL));
return FALSE;
}
/*
if (!clapper_sink->display)
clapper_sink->display = gtk_clapper_gl_widget_get_display (clapper_widget);
if (!clapper_sink->context)
clapper_sink->context = gtk_clapper_gl_widget_get_context (clapper_widget);
if (!clapper_sink->gtk_context)
clapper_sink->gtk_context = gtk_clapper_gl_widget_get_gtk_context (clapper_widget);
if (!clapper_sink->display || !clapper_sink->context || !clapper_sink->gtk_context) {
GST_ELEMENT_ERROR (bsink, RESOURCE, NOT_FOUND, ("%s",
"Failed to retrieve OpenGL context from GTK"), (NULL));
return FALSE;
}
gst_gl_element_propagate_display_context (GST_ELEMENT (bsink),
clapper_sink->display);
*/
return TRUE;
}
static gboolean
gst_clapper_sink_stop_on_main (GstClapperSink *self)
{
if (self->window) {
gtk_window_destroy (self->window);
self->window = NULL;
//self->widget = NULL;
}
return TRUE;
}
static gboolean
gst_clapper_sink_stop (GstBaseSink *bsink)
{
GstClapperSink *self = GST_CLAPPER_SINK_CAST (bsink);
if (G_UNLIKELY (self->window != NULL)) {
return ! !gst_gtk_invoke_on_main ((GThreadFunc) (GCallback)
gst_clapper_sink_stop_on_main, self);
}
return TRUE;
}
static void
gst_gtk_window_show_all_and_unref (GtkWindow *window)
{
gtk_window_present (window);
g_object_unref (window);
}
static GstStateChangeReturn
gst_clapper_sink_change_state (GstElement *element, GstStateChange transition)
{
GstClapperSink *self = GST_CLAPPER_SINK_CAST (element);
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
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)));
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
if (G_UNLIKELY (ret == GST_STATE_CHANGE_FAILURE))
return ret;
switch (transition) {
case GST_STATE_CHANGE_READY_TO_PAUSED:{
GtkWindow *window = NULL;
GST_OBJECT_LOCK (self);
if (self->window)
window = g_object_ref (self->window);
GST_OBJECT_UNLOCK (self);
if (window) {
gst_gtk_invoke_on_main ((GThreadFunc) (GCallback)
gst_gtk_window_show_all_and_unref, window);
}
break;
}
case GST_STATE_CHANGE_PAUSED_TO_READY:
GST_OBJECT_LOCK (self);
if (G_LIKELY (self->obj != NULL))
gtk_clapper_object_set_buffer (self->obj, NULL);
GST_OBJECT_UNLOCK (self);
break;
default:
break;
}
return ret;
}
static void
gst_clapper_sink_get_times (GstBaseSink *bsink, GstBuffer *buffer,
GstClockTime *start, GstClockTime *end)
{
if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) {
*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);
if (GST_VIDEO_INFO_FPS_N (&self->v_info) > 0) {
*end = *start + gst_util_uint64_scale_int (GST_SECOND,
GST_VIDEO_INFO_FPS_D (&self->v_info),
GST_VIDEO_INFO_FPS_N (&self->v_info));
}
}
}
}
static GstCaps *
gst_clapper_sink_get_caps (GstBaseSink *bsink, GstCaps *filter)
{
GstCaps *tmp = NULL;
GstCaps *result = NULL;
tmp = gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink));
if (filter) {
GST_DEBUG_OBJECT (bsink, "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;
}
//result = gst_gl_overlay_compositor_add_caps (result);
GST_DEBUG_OBJECT (bsink, "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);
GST_DEBUG ("Set caps: %" GST_PTR_FORMAT, caps);
GST_OBJECT_LOCK (self);
if (!gst_video_info_from_caps (&self->v_info, caps)) {
GST_OBJECT_UNLOCK (self);
return FALSE;
}
if (G_UNLIKELY (self->obj == NULL)) {
GST_OBJECT_UNLOCK (self);
GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
("%s", "Output widget was destroyed"), (NULL));
return FALSE;
}
if (!gtk_clapper_object_set_format (self->obj, &self->v_info)) {
GST_OBJECT_UNLOCK (self);
return FALSE;
}
GST_OBJECT_UNLOCK (self);
return TRUE;
}
static GstFlowReturn
gst_clapper_sink_show_frame (GstVideoSink *vsink, GstBuffer *buffer)
{
GstClapperSink *self = GST_CLAPPER_SINK_CAST (vsink);
GST_TRACE ("Rendering buffer: %p", buffer);
GST_OBJECT_LOCK (self);
if (G_UNLIKELY (self->obj == NULL)) {
GST_OBJECT_UNLOCK (self);
GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
("%s", "Output widget was destroyed"), (NULL));
return GST_FLOW_ERROR;
}
gtk_clapper_object_set_buffer (self->obj, buffer);
GST_OBJECT_UNLOCK (self);
return GST_FLOW_OK;
}

View File

@@ -1,74 +0,0 @@
/*
* GStreamer
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
* Copyright (C) 2020-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 "gtkclapperobject.h"
G_BEGIN_DECLS
#define GST_TYPE_CLAPPER_SINK (gst_clapper_sink_get_type ())
#define GST_IS_CLAPPER_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CLAPPER_SINK))
#define GST_IS_CLAPPER_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CLAPPER_SINK))
#define GST_CLAPPER_SINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CLAPPER_SINK, GstClapperSinkClass))
#define GST_CLAPPER_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_CLAPPER_SINK, GstClapperSinkClass))
#define GST_CLAPPER_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CLAPPER_SINK, GstClapperSink))
#define GST_CLAPPER_SINK_CAST(obj) ((GstClapperSink*)(obj))
typedef struct _GstClapperSink GstClapperSink;
typedef struct _GstClapperSinkClass GstClapperSinkClass;
#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GstClapperSink, gst_object_unref)
#endif
struct _GstClapperSink
{
GstVideoSink parent;
GstVideoInfo v_info;
GtkClapperObject *obj;
GtkWindow *window;
/* properties */
gboolean force_aspect_ratio;
gint par_n, par_d;
gint display_width, display_height;
gulong widget_destroy_id, window_destroy_id;
};
struct _GstClapperSinkClass
{
GstVideoSinkClass parent_class;
};
GST_ELEMENT_REGISTER_DECLARE (clappersink);
GType gst_clapper_sink_get_type (void);
G_END_DECLS

View File

@@ -1,71 +0,0 @@
/*
* GStreamer
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
* Copyright (C) 2015 Thibault Saunier <tsaunier@gnome.org>
*
* 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;
}

View File

@@ -1,960 +0,0 @@
/*
* GStreamer
* 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 <gst/gl/gstglfuncs.h>
#include <gst/allocators/gstdmabuf.h>
#include "gtkclapperobject.h"
#include "gstgtkutils.h"
#if GST_GL_HAVE_WINDOW_X11 && defined (GDK_WINDOWING_X11)
#include <gdk/x11/gdkx.h>
#if GST_GL_HAVE_PLATFORM_EGL
#include <gst/gl/egl/gstgldisplay_egl.h>
#endif
#endif
#if GST_GL_HAVE_WINDOW_WAYLAND && defined (GDK_WINDOWING_WAYLAND)
#include <gdk/wayland/gdkwayland.h>
#include <gst/gl/wayland/gstgldisplay_wayland.h>
#endif
#if GST_GL_HAVE_PLATFORM_EGL
#include <gst/gl/egl/gsteglimage.h>
#endif
GST_DEBUG_CATEGORY (gst_debug_clapper_object);
#define GST_CAT_DEFAULT gst_debug_clapper_object
static void gtk_clapper_object_paintable_iface_init (GdkPaintableInterface *iface);
static void gtk_clapper_object_finalize (GObject *object);
static const GLfloat vertices[] = {
1.0f, 1.0f, 0.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 0.0f, 0.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 1.0f
};
static const GLushort indices[] = {
0, 1, 2, 0, 2, 3
};
/* GTK4 renders things upside down ¯\_(ツ)_/¯ */
static const gfloat vertical_flip_matrix[] = {
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
#define gtk_clapper_object_parent_class parent_class
G_DEFINE_TYPE_WITH_CODE (GtkClapperObject, gtk_clapper_object, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
gtk_clapper_object_paintable_iface_init)
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "gtkclapperobject", 0,
"GTK Clapper Object"));
static void
gtk_clapper_object_class_init (GtkClapperObjectClass *klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
gobject_class->finalize = gtk_clapper_object_finalize;
}
static void
gtk_clapper_object_init (GtkClapperObject *self)
{
self->last_pos_x = 0;
self->last_pos_y = 0;
self->picture = (GtkPicture *) gtk_picture_new ();
/* We cannot do textures of 0x0px size */
gtk_widget_set_size_request (GTK_WIDGET (self->picture), 1, 1);
/* Center instead of fill to not draw empty space into framebuffer */
gtk_widget_set_halign (GTK_WIDGET (self->picture), GTK_ALIGN_CENTER);
gtk_widget_set_valign (GTK_WIDGET (self->picture), GTK_ALIGN_CENTER);
gtk_picture_set_paintable (self->picture, GDK_PAINTABLE (self));
gst_video_info_init (&self->v_info);
gst_video_info_init (&self->pending_v_info);
g_weak_ref_init (&self->element, NULL);
g_mutex_init (&self->lock);
self->gst_tex_target = GST_GL_TEXTURE_TARGET_EXTERNAL_OES;
self->gl_tex_target = gst_gl_texture_target_to_gl (self->gst_tex_target);
}
static void
gtk_clapper_object_finalize (GObject *object)
{
GtkClapperObject *self = GTK_CLAPPER_OBJECT (object);
if (self->draw_id)
g_source_remove (self->draw_id);
gst_buffer_replace (&self->pending_buffer, NULL);
gst_buffer_replace (&self->buffer, NULL);
g_mutex_clear (&self->lock);
g_weak_ref_clear (&self->element);
GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
}
static void
_gdk_gl_context_set_active (GtkClapperObject *self, gboolean activate)
{
/* We wrap around a GDK context, so we need to make
* both GTK and GStreamer aware of its active state */
if (activate) {
gdk_gl_context_make_current (self->gdk_context);
gst_gl_context_activate (self->wrapped_context, TRUE);
} else {
gst_gl_context_activate (self->wrapped_context, FALSE);
gdk_gl_context_clear_current ();
}
}
static GdkMemoryFormat
video_format_to_gdk_memory_format (GstVideoFormat format)
{
switch (format) {
case GST_VIDEO_FORMAT_BGR:
return GDK_MEMORY_B8G8R8;
case GST_VIDEO_FORMAT_RGB:
return GDK_MEMORY_R8G8B8;
case GST_VIDEO_FORMAT_BGRA:
return GDK_MEMORY_B8G8R8A8;
case GST_VIDEO_FORMAT_RGBA:
return GDK_MEMORY_R8G8B8A8;
case GST_VIDEO_FORMAT_ABGR:
return GDK_MEMORY_A8B8G8R8;
case GST_VIDEO_FORMAT_ARGB:
return GDK_MEMORY_A8R8G8B8;
case GST_VIDEO_FORMAT_BGRx:
return GDK_MEMORY_B8G8R8A8_PREMULTIPLIED;
case GST_VIDEO_FORMAT_RGBx:
return GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
case GST_VIDEO_FORMAT_RGBA64_LE:
case GST_VIDEO_FORMAT_RGBA64_BE:
return GDK_MEMORY_R16G16B16A16_PREMULTIPLIED;
default:
g_assert_not_reached ();
}
/* Number not belonging to any format */
return GDK_MEMORY_N_FORMATS;
}
static void
gtk_clapper_object_bind_buffer (GtkClapperObject *self)
{
const GstGLFuncs *gl = self->wrapped_context->gl_vtable;
gl->BindBuffer (GL_ARRAY_BUFFER, self->vertex_buffer);
/* Load the vertex position */
gl->VertexAttribPointer (self->attr_position, 3, GL_FLOAT, GL_FALSE,
5 * sizeof (GLfloat), (void *) 0);
/* Load the texture coordinate */
gl->VertexAttribPointer (self->attr_texture, 2, GL_FLOAT, GL_FALSE,
5 * sizeof (GLfloat), (void *) (3 * sizeof (GLfloat)));
gl->EnableVertexAttribArray (self->attr_position);
gl->EnableVertexAttribArray (self->attr_texture);
}
static void
gtk_clapper_object_unbind_buffer (GtkClapperObject *self)
{
const GstGLFuncs *gl = self->wrapped_context->gl_vtable;
gl->BindBuffer (GL_ARRAY_BUFFER, 0);
gl->DisableVertexAttribArray (self->attr_position);
gl->DisableVertexAttribArray (self->attr_texture);
}
static void
gtk_clapper_object_init_redisplay (GtkClapperObject *self)
{
GstGLSLStage *frag_stage, *vert_stage;
GError *error = NULL;
gchar *frag_str;
const GstGLFuncs *gl;
if (self->gst_tex_target != GST_GL_TEXTURE_TARGET_EXTERNAL_OES)
return;
if (!((vert_stage = gst_glsl_stage_new_with_string (self->wrapped_context,
GL_VERTEX_SHADER, GST_GLSL_VERSION_NONE,
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
gst_gl_shader_string_vertex_mat4_vertex_transform)))) {
GST_ERROR ("Failed to retrieve vertex shader for texture target");
return;
}
frag_str = gst_gl_shader_string_fragment_external_oes_get_default (
self->wrapped_context, GST_GLSL_VERSION_NONE,
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY);
frag_stage = gst_glsl_stage_new_with_string (self->wrapped_context,
GL_FRAGMENT_SHADER, GST_GLSL_VERSION_NONE,
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY, frag_str);
g_free (frag_str);
if (!frag_stage) {
GST_ERROR ("Failed to retrieve fragment shader for texture target");
return;
}
if (!((self->shader = gst_gl_shader_new_link_with_stages (self->wrapped_context,
&error, vert_stage, frag_stage, NULL)))) {
GST_ERROR ("Failed to initialize shader: %s", error->message);
g_clear_error (&error);
gst_object_unref (vert_stage);
gst_object_unref (frag_stage);
return;
}
self->attr_position =
gst_gl_shader_get_attribute_location (self->shader, "a_position");
self->attr_texture =
gst_gl_shader_get_attribute_location (self->shader, "a_texcoord");
gl = self->wrapped_context->gl_vtable;
if (gl->GenVertexArrays) {
gl->GenVertexArrays (1, &self->vao);
gl->BindVertexArray (self->vao);
}
gl->GenBuffers (1, &self->vertex_buffer);
gl->BindBuffer (GL_ARRAY_BUFFER, self->vertex_buffer);
gl->BufferData (GL_ARRAY_BUFFER, 4 * 5 * sizeof (GLfloat), vertices, GL_STATIC_DRAW);
if (gl->GenVertexArrays) {
gtk_clapper_object_bind_buffer (self);
gl->BindVertexArray (0);
}
gl->BindBuffer (GL_ARRAY_BUFFER, 0);
self->initiated = TRUE;
}
static gboolean
_dmabuf_into_texture (GtkClapperObject *self, gint *fds, gsize *offsets)
{
GstEGLImage *image;
const GstGLFuncs *gl;
image = gst_egl_image_from_dmabuf_direct_target (self->wrapped_context,
fds, offsets, &self->v_info, self->gst_tex_target);
/* If HW colorspace conversion failed and there is only one
* plane, we can just make it into single EGLImage as is */
if (!image && GST_VIDEO_INFO_N_PLANES (&self->v_info) == 1)
image = gst_egl_image_from_dmabuf (self->wrapped_context,
fds[0], &self->v_info, 0, offsets[0]);
/* Still no image? Give up then */
if (!image)
return FALSE;
gl = self->wrapped_context->gl_vtable;
if (!self->texture_id)
gl->GenTextures (1, &self->texture_id);
gl->BindTexture (self->gl_tex_target, self->texture_id);
gl->TexParameteri (self->gl_tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
gl->TexParameteri (self->gl_tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gl->TexParameteri (self->gl_tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl->TexParameteri (self->gl_tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
gl->EGLImageTargetTexture2D (self->gl_tex_target, gst_egl_image_get_image (image));
gl->BindTexture (GL_TEXTURE_2D, 0);
gst_egl_image_unref (image);
return TRUE;
}
static gboolean
_ext_texture_into_2d (GtkClapperObject *self, guint tex_width, guint tex_height)
{
GLuint framebuffer, new_texture_id;
GLenum status;
const GstGLFuncs *gl;
if (!self->initiated)
gtk_clapper_object_init_redisplay (self);
gl = self->wrapped_context->gl_vtable;
gl->GenFramebuffers (1, &framebuffer);
gl->BindFramebuffer (GL_FRAMEBUFFER, framebuffer);
gl->GenTextures (1, &new_texture_id);
gl->BindTexture (GL_TEXTURE_2D, new_texture_id);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, tex_width, tex_height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, NULL);
gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, new_texture_id, 0);
status = gl->CheckFramebufferStatus (GL_FRAMEBUFFER);
if (G_UNLIKELY (status != GL_FRAMEBUFFER_COMPLETE)) {
GST_ERROR ("Invalid framebuffer status: %u", status);
gl->BindTexture (GL_TEXTURE_2D, 0);
gl->DeleteTextures (1, &new_texture_id);
gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
gl->DeleteFramebuffers (1, &framebuffer);
return FALSE;
}
gl->Viewport (0, 0, tex_width, tex_height);
gst_gl_shader_use (self->shader);
if (gl->BindVertexArray)
gl->BindVertexArray (self->vao);
gtk_clapper_object_bind_buffer (self);
gl->ActiveTexture (GL_TEXTURE0);
gl->BindTexture (self->gl_tex_target, self->texture_id);
gst_gl_shader_set_uniform_1i (self->shader, "tex", 0);
gst_gl_shader_set_uniform_matrix_4fv (self->shader,
"u_transformation", 1, FALSE, vertical_flip_matrix);
gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
if (gl->BindVertexArray)
gl->BindVertexArray (0);
else
gtk_clapper_object_unbind_buffer (self);
gl->BindTexture (self->gl_tex_target, 0);
/* Replace external OES texture with new 2D one */
gl->DeleteTextures (1, &self->texture_id);
self->texture_id = new_texture_id;
gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
gl->DeleteFramebuffers (1, &framebuffer);
return TRUE;
}
static GdkTexture *
gtk_clapper_object_import_dmabuf (GtkClapperObject *self, gint *fds, gsize *offsets)
{
GdkTexture *texture;
guint tex_width, tex_height;
_gdk_gl_context_set_active (self, TRUE);
if (!_dmabuf_into_texture (self, fds, offsets)) {
_gdk_gl_context_set_active (self, FALSE);
return NULL;
}
switch (self->gst_tex_target) {
case GST_GL_TEXTURE_TARGET_2D:
tex_width = GST_VIDEO_INFO_WIDTH (&self->v_info);
tex_height = GST_VIDEO_INFO_HEIGHT (&self->v_info);
break;
case GST_GL_TEXTURE_TARGET_EXTERNAL_OES:{
GtkWidget *widget = (GtkWidget *) self->picture;
gint scale;
scale = gtk_widget_get_scale_factor (widget);
tex_width = gtk_widget_get_width (widget) * scale;
tex_height = gtk_widget_get_height (widget) * scale;
if (G_LIKELY (_ext_texture_into_2d (self, tex_width, tex_height)))
break;
return NULL;
}
default:
g_assert_not_reached ();
return NULL;
}
texture = gdk_gl_texture_new (self->gdk_context,
self->texture_id, tex_width, tex_height, NULL, NULL);
_gdk_gl_context_set_active (self, FALSE);
return texture;
}
typedef gboolean (*MemTypeCheckFunc) (gpointer data);
static gboolean
buffer_memory_type_check (GstBuffer *buffer, MemTypeCheckFunc func)
{
guint i, n_mems;
n_mems = gst_buffer_n_memory (buffer);
for (i = 0; i < n_mems; i++) {
if (!func (gst_buffer_peek_memory (buffer, i)))
return FALSE;
}
return n_mems > 0;
}
static gboolean
verify_dmabuf_memory (GtkClapperObject *self, guint n_planes,
gint *fds, gsize *offsets)
{
guint i;
for (i = 0; i < n_planes; i++) {
GstMemory *memory;
gsize plane_size, mem_skip;
guint mem_idx, length;
plane_size = gst_gl_get_plane_data_size (&self->v_info, NULL, i);
if (!gst_buffer_find_memory (self->buffer,
GST_VIDEO_INFO_PLANE_OFFSET (&self->v_info, i),
plane_size, &mem_idx, &length, &mem_skip)) {
GST_DEBUG_OBJECT (self, "Could not find memory %u", i);
return FALSE;
}
/* We can't have more then one DMABuf per plane */
if (length != 1) {
GST_DEBUG_OBJECT (self, "Data for plane %u spans %u memories",
i, length);
return FALSE;
}
memory = gst_buffer_peek_memory (self->buffer, mem_idx);
offsets[i] = memory->offset + mem_skip;
fds[i] = gst_dmabuf_memory_get_fd (memory);
}
return TRUE;
}
static GdkTexture *
obtain_texture_from_current_buffer (GtkClapperObject *self)
{
GdkTexture *texture = NULL;
GstVideoFrame frame;
/* DMABuf */
if (buffer_memory_type_check (self->buffer, (MemTypeCheckFunc) gst_is_dmabuf_memory)) {
gsize offsets[GST_VIDEO_MAX_PLANES];
gint fds[GST_VIDEO_MAX_PLANES];
guint n_planes;
n_planes = GST_VIDEO_INFO_N_PLANES (&self->v_info);
if (!verify_dmabuf_memory (self, n_planes, fds, offsets)) {
GST_ERROR ("DMABuf memory is invalid");
return NULL;
}
if (!((texture = gtk_clapper_object_import_dmabuf (self, fds, offsets))))
GST_ERROR ("Could not create texture from DMABuf");
return texture;
}
/* GL Memory */
if (buffer_memory_type_check (self->buffer, (MemTypeCheckFunc) gst_is_gl_memory)) {
if (gst_video_frame_map (&frame, &self->v_info, self->buffer, GST_MAP_READ | GST_MAP_GL)) {
GST_FIXME_OBJECT (self, "Handle GstGLMemory");
texture = gdk_gl_texture_new (
self->gdk_context,
*(guint *) GST_VIDEO_FRAME_PLANE_DATA (&frame, 0),
GST_VIDEO_FRAME_WIDTH (&frame),
GST_VIDEO_FRAME_HEIGHT (&frame),
NULL, NULL);
gst_video_frame_unmap (&frame);
}
return texture;
}
/* RAW */
if (gst_video_frame_map (&frame, &self->v_info, self->buffer, GST_MAP_READ)) {
GBytes *bytes;
/* Our ref on a buffer together with 2 buffers pool ensures that
* current buffer will not be freed while another one is prepared */
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),
NULL, NULL);
texture = gdk_memory_texture_new (
GST_VIDEO_FRAME_WIDTH (&frame),
GST_VIDEO_FRAME_HEIGHT (&frame),
video_format_to_gdk_memory_format (GST_VIDEO_FRAME_FORMAT (&frame)),
bytes,
GST_VIDEO_FRAME_PLANE_STRIDE (&frame, 0));
g_bytes_unref (bytes);
gst_video_frame_unmap (&frame);
}
return texture;
}
static gboolean
calculate_display_par (GtkClapperObject *self, GstVideoInfo *info)
{
gboolean success;
gint width, height;
gint par_n, par_d;
gint display_par_n, display_par_d;
width = GST_VIDEO_INFO_WIDTH (info);
height = GST_VIDEO_INFO_HEIGHT (info);
par_n = GST_VIDEO_INFO_PAR_N (info);
par_d = GST_VIDEO_INFO_PAR_D (info);
if (!par_n)
par_n = 1;
/* User set props */
if (self->par_n != 0 && self->par_d != 0) {
display_par_n = self->par_n;
display_par_d = self->par_d;
} else {
display_par_n = 1;
display_par_d = 1;
}
if ((success = gst_video_calculate_display_ratio (&self->display_ratio_num,
&self->display_ratio_den, width, height, par_n, par_d, display_par_n,
display_par_d))) {
GST_LOG ("PAR: %u/%u, DAR: %u/%u", par_n, par_d, display_par_n, display_par_d);
}
return success;
}
static void
update_display_size (GtkClapperObject *self)
{
guint display_ratio_num, display_ratio_den;
gint width, height;
display_ratio_num = self->display_ratio_num;
display_ratio_den = self->display_ratio_den;
width = GST_VIDEO_INFO_WIDTH (&self->v_info);
height = GST_VIDEO_INFO_HEIGHT (&self->v_info);
if (height % display_ratio_den == 0) {
GST_DEBUG ("Keeping video height");
self->display_width = (guint)
gst_util_uint64_scale_int (height, display_ratio_num, display_ratio_den);
self->display_height = height;
} else if (width % display_ratio_num == 0) {
GST_DEBUG ("Keeping video width");
self->display_width = width;
self->display_height = (guint)
gst_util_uint64_scale_int (width, display_ratio_den, display_ratio_num);
} else {
GST_DEBUG ("Approximating while keeping video height");
self->display_width = (guint)
gst_util_uint64_scale_int (height, display_ratio_num, display_ratio_den);
self->display_height = height;
}
self->display_aspect_ratio = ((gdouble) self->display_width
/ (gdouble) self->display_height);
GST_DEBUG ("Scaling to %dx%d", self->display_width, self->display_height);
}
static void
update_paintable (GtkClapperObject *self, GdkPaintable *paintable)
{
/* No change, so discard the new one */
if (self->paintable == paintable) {
if (paintable)
g_object_unref (paintable);
return;
}
if (self->paintable)
g_object_unref (self->paintable);
self->paintable = paintable;
if (self->pending_resize) {
update_display_size (self);
gdk_paintable_invalidate_size ((GdkPaintable *) self);
self->pending_resize = FALSE;
}
gdk_paintable_invalidate_contents ((GdkPaintable *) self);
}
static gboolean
draw_on_main_cb (GtkClapperObject *self)
{
GdkTexture *texture;
GTK_CLAPPER_OBJECT_LOCK (self);
/* Replace used buffer and set matching v_info */
gst_buffer_replace (&self->buffer, self->pending_buffer);
self->v_info = self->pending_v_info;
texture = obtain_texture_from_current_buffer (self);
if (texture)
update_paintable (self, (GdkPaintable *) texture);
self->draw_id = 0;
GTK_CLAPPER_OBJECT_UNLOCK (self);
return G_SOURCE_REMOVE;
}
void
gtk_clapper_object_set_element (GtkClapperObject *self, GstElement *element)
{
g_weak_ref_set (&self->element, element);
}
gboolean
gtk_clapper_object_set_format (GtkClapperObject *self, GstVideoInfo *v_info)
{
GTK_CLAPPER_OBJECT_LOCK (self);
if (gst_video_info_is_equal (&self->pending_v_info, v_info)) {
GTK_CLAPPER_OBJECT_UNLOCK (self);
return TRUE;
}
if (!calculate_display_par (self, v_info)) {
GTK_CLAPPER_OBJECT_UNLOCK (self);
return FALSE;
}
self->pending_resize = TRUE;
self->pending_v_info = *v_info;
GTK_CLAPPER_OBJECT_UNLOCK (self);
return TRUE;
}
void
gtk_clapper_object_set_buffer (GtkClapperObject *self, GstBuffer *buffer)
{
GstVideoMeta *meta = NULL;
GTK_CLAPPER_OBJECT_LOCK (self);
gst_buffer_replace (&self->pending_buffer, buffer);
if (self->draw_id) {
GTK_CLAPPER_OBJECT_UNLOCK (self);
return;
}
if (self->pending_buffer)
meta = gst_buffer_get_video_meta (self->pending_buffer);
/* Update pending info from video meta */
if (meta) {
guint i;
GST_VIDEO_INFO_WIDTH (&self->pending_v_info) = meta->width;
GST_VIDEO_INFO_HEIGHT (&self->pending_v_info) = meta->height;
for (i = 0; i < meta->n_planes; i++) {
GST_VIDEO_INFO_PLANE_OFFSET (&self->pending_v_info, i) = meta->offset[i];
GST_VIDEO_INFO_PLANE_STRIDE (&self->pending_v_info, i) = meta->stride[i];
}
}
self->draw_id = g_idle_add_full (G_PRIORITY_DEFAULT,
(GSourceFunc) draw_on_main_cb, self, NULL);
GTK_CLAPPER_OBJECT_UNLOCK (self);
}
GtkClapperObject *
gtk_clapper_object_new (void)
{
return g_object_new (GTK_TYPE_CLAPPER_OBJECT, NULL);
}
GtkWidget *
gtk_clapper_object_get_widget (GtkClapperObject *self)
{
return (GtkWidget *) self->picture;
}
static gboolean
wrap_current_gl (GstGLDisplay *display, GstGLPlatform platform, GstGLContext **context)
{
GstGLAPI gl_api = GST_GL_API_NONE;
guint gl_major = 0, gl_minor = 0;
gl_api = gst_gl_context_get_current_gl_api (platform, &gl_major, &gl_minor);
if (gl_api) {
const gboolean is_es = gl_api & (GST_GL_API_GLES1 | GST_GL_API_GLES2);
gchar *gl_api_str = gst_gl_api_to_string (gl_api);
guintptr gl_handle = 0;
GST_INFO ("Using GL API: %s, ver: %d.%d", gl_api_str, gl_major, gl_minor);
g_free (gl_api_str);
if (is_es && platform == GST_GL_PLATFORM_EGL && !g_getenv ("GST_GL_API")) {
GST_DEBUG ("No GST_GL_API env and GTK is using EGL GLES2, enforcing it");
gst_gl_display_filter_gl_api (display, GST_GL_API_GLES2);
}
gl_handle = gst_gl_context_get_current_gl_context (platform);
if (gl_handle) {
if ((*context = gst_gl_context_new_wrapped (display,
gl_handle, platform, gl_api)))
return TRUE;
}
}
return FALSE;
}
static void
retrieve_gl_context_on_main (GtkClapperObject *self)
{
GdkDisplay *gdk_display;
GstGLPlatform platform = GST_GL_PLATFORM_NONE;
GError *error = NULL;
gst_clear_object (&self->wrapped_context);
g_clear_object (&self->gdk_context);
gtk_widget_realize (GTK_WIDGET (self->picture));
if (!((self->gdk_context = gdk_surface_create_gl_context (gtk_native_get_surface (
gtk_widget_get_native (GTK_WIDGET (self->picture))), &error)))) {
GST_ERROR_OBJECT (self, "Error creating Gdk GL context: %s",
error ? error->message : "No error set by Gdk");
g_clear_error (&error);
return;
}
//gdk_gl_context_set_use_es (self->gdk_context, TRUE);
//gdk_gl_context_realize (self->gdk_context, &error);
gdk_display = gdk_gl_context_get_display (self->gdk_context);
#if GST_GL_HAVE_WINDOW_X11 && defined (GDK_WINDOWING_X11)
if (GDK_IS_X11_DISPLAY (gdk_display)) {
gpointer display_ptr;
#if GST_GL_HAVE_PLATFORM_EGL && GTK_CHECK_VERSION(4,3,1)
display_ptr = gdk_x11_display_get_egl_display (gdk_display);
if (display_ptr)
self->display = (GstGLDisplay *)
gst_gl_display_egl_new_with_egl_display (display_ptr);
#endif
}
#endif
#if GST_GL_HAVE_WINDOW_WAYLAND && defined (GDK_WINDOWING_WAYLAND)
if (GDK_IS_WAYLAND_DISPLAY (gdk_display)) {
struct wl_display *wayland_display =
gdk_wayland_display_get_wl_display (gdk_display);
self->display = (GstGLDisplay *)
gst_gl_display_wayland_new_with_display (wayland_display);
}
#endif
if (G_UNLIKELY (!self->display)) {
GST_WARNING_OBJECT (self, "Unknown Gdk display!");
self->display = gst_gl_display_new ();
}
#if GST_GL_HAVE_PLATFORM_EGL
#if GST_GL_HAVE_WINDOW_WAYLAND && defined (GDK_WINDOWING_WAYLAND)
if (GST_IS_GL_DISPLAY_WAYLAND (self->display)) {
platform = GST_GL_PLATFORM_EGL;
GST_DEBUG ("Using EGL on Wayland");
goto have_platform;
}
#endif
#if GST_GL_HAVE_WINDOW_X11 && defined (GDK_WINDOWING_X11)
if (GST_IS_GL_DISPLAY_EGL (self->display)) {
platform = GST_GL_PLATFORM_EGL;
GST_DEBUG ("Using EGL on x11");
goto have_platform;
}
#endif
#endif /* GST_GL_HAVE_PLATFORM_EGL */
GST_ERROR ("Unsupported GL platform");
return;
have_platform:
g_object_ref (self->gdk_context);
gdk_gl_context_make_current (self->gdk_context);
if (!wrap_current_gl (self->display, platform, &self->wrapped_context)) {
GST_WARNING ("Could not retrieve Gdk OpenGL context");
return;
}
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 retrieve Gdk context info: %s", error->message);
g_clear_error (&error);
g_clear_object (&self->wrapped_context);
}
/* Deactivate in both places */
_gdk_gl_context_set_active (self, FALSE);
}
gboolean
gtk_clapper_object_init_winsys (GtkClapperObject *self)
{
GError *error = NULL;
GTK_CLAPPER_OBJECT_LOCK (self);
if (self->display && self->gdk_context && self->wrapped_context) {
GST_TRACE ("Have already initialized contexts");
GTK_CLAPPER_OBJECT_UNLOCK (self);
return TRUE;
}
if (!self->wrapped_context) {
GTK_CLAPPER_OBJECT_UNLOCK (self);
gst_gtk_invoke_on_main ((GThreadFunc) (GCallback) retrieve_gl_context_on_main, self);
GTK_CLAPPER_OBJECT_LOCK (self);
}
if (!GST_IS_GL_CONTEXT (self->wrapped_context)) {
GST_FIXME ("Could not retrieve Gdk GL context");
GTK_CLAPPER_OBJECT_UNLOCK (self);
return FALSE;
}
GTK_CLAPPER_OBJECT_UNLOCK (self);
return TRUE;
}
/*
* GdkPaintableInterface
*/
static void
gtk_clapper_object_paintable_snapshot (GdkPaintable *paintable,
GdkSnapshot *snapshot, gdouble width, gdouble height)
{
GtkClapperObject *self = GTK_CLAPPER_OBJECT_CAST (paintable);
if (self->paintable)
gdk_paintable_snapshot (self->paintable, snapshot, width, height);
}
static GdkPaintable *
gtk_clapper_object_paintable_get_current_image (GdkPaintable *paintable)
{
GtkClapperObject *self = GTK_CLAPPER_OBJECT_CAST (paintable);
return (self->paintable)
? g_object_ref (self->paintable)
: gdk_paintable_new_empty (0, 0);
}
static gint
gtk_clapper_object_paintable_get_intrinsic_width (GdkPaintable *paintable)
{
GtkClapperObject *self = GTK_CLAPPER_OBJECT_CAST (paintable);
return self->display_width;
}
static gint
gtk_clapper_object_paintable_get_intrinsic_height (GdkPaintable *paintable)
{
GtkClapperObject *self = GTK_CLAPPER_OBJECT_CAST (paintable);
return self->display_height;
}
static gdouble
gtk_clapper_object_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable)
{
GtkClapperObject *self = GTK_CLAPPER_OBJECT_CAST (paintable);
return self->display_aspect_ratio;
}
static void
gtk_clapper_object_paintable_iface_init (GdkPaintableInterface *iface)
{
iface->snapshot = gtk_clapper_object_paintable_snapshot;
iface->get_current_image = gtk_clapper_object_paintable_get_current_image;
iface->get_intrinsic_width = gtk_clapper_object_paintable_get_intrinsic_width;
iface->get_intrinsic_height = gtk_clapper_object_paintable_get_intrinsic_height;
iface->get_intrinsic_aspect_ratio = gtk_clapper_object_paintable_get_intrinsic_aspect_ratio;
}

View File

@@ -1,139 +0,0 @@
/*
* GStreamer
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
* Copyright (C) 2020-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>
#include <gst/gl/gl.h>
#include <gst/gl/gstglfuncs.h>
G_BEGIN_DECLS
#define GTK_TYPE_CLAPPER_OBJECT (gtk_clapper_object_get_type ())
#define GTK_IS_CLAPPER_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_CLAPPER_OBJECT))
#define GTK_IS_CLAPPER_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_CLAPPER_OBJECT))
#define GTK_CLAPPER_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CLAPPER_OBJECT, GtkClapperObjectClass))
#define GTK_CLAPPER_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_CLAPPER_OBJECT, GtkClapperObjectClass))
#define GTK_CLAPPER_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_CLAPPER_OBJECT, GtkClapperObject))
#define GTK_CLAPPER_OBJECT_CAST(obj) ((GtkClapperObject*)(obj))
#define GTK_CLAPPER_OBJECT_LOCK(w) g_mutex_lock(&((GtkClapperObject*)(w))->lock)
#define GTK_CLAPPER_OBJECT_UNLOCK(w) g_mutex_unlock(&((GtkClapperObject*)(w))->lock)
typedef struct _GtkClapperObject GtkClapperObject;
typedef struct _GtkClapperObjectClass GtkClapperObjectClass;
struct _GtkClapperObject
{
GObject parent;
GtkPicture *picture;
GdkPaintable *paintable;
GstGLDisplay *display;
GdkGLContext *gdk_context;
GstGLContext *wrapped_context;
GstGLContext *gst_context;
/* properties */
gboolean force_aspect_ratio;
gint par_n, par_d;
gboolean keep_last_frame;
gint display_width;
gint display_height;
gdouble display_aspect_ratio;
/* Object dimensions */
gint scaled_width;
gint scaled_height;
/* Position coords */
gdouble last_pos_x;
gdouble last_pos_y;
gboolean negotiated;
gboolean ignore_buffers;
GstBuffer *pending_buffer;
GstBuffer *buffer;
GstVideoInfo pending_v_info;
GstVideoInfo v_info;
guint texture_id, oes_texture_id, next_texture_id;
/* resize */
gboolean pending_resize;
guint display_ratio_num;
guint display_ratio_den;
/*< private >*/
GMutex lock;
GWeakRef element;
/* event controllers */
GtkEventController *key_controller;
GtkEventController *motion_controller;
GtkGesture *click_gesture;
/* Pending draw idles callback */
guint draw_id;
GstGLTextureTarget gst_tex_target;
guint gl_tex_target;
GstGLShader *shader;
GLuint vao;
GLuint vertex_buffer;
GLint attr_position;
GLint attr_texture;
gboolean initiated;
guint frame_buffer;
};
struct _GtkClapperObjectClass
{
GObjectClass parent_class;
};
GType gtk_clapper_object_get_type (void);
GtkClapperObject * gtk_clapper_object_new (void);
GtkWidget * gtk_clapper_object_get_widget (GtkClapperObject *object);
gboolean gtk_clapper_object_init_winsys (GtkClapperObject *object);
gboolean gtk_clapper_object_set_format (GtkClapperObject *object, GstVideoInfo *v_info);
void gtk_clapper_object_set_buffer (GtkClapperObject *object, GstBuffer *buffer);
void gtk_clapper_object_set_element (GtkClapperObject *object, GstElement *element);
G_END_DECLS

View File

@@ -1,63 +0,0 @@
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 = [
'gstclappersink.c',
'gtkclapperobject.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,
)

View File

@@ -1,301 +0,0 @@
glib_req = '>= 2.56.0'
gst_req = '>= 1.19.1'
api_version = '1.0'
libversion = meson.project_version()
cc = meson.get_compiler('c')
cxx = meson.get_compiler('cpp')
cdata = configuration_data()
if cc.get_id() == 'msvc'
msvc_args = [
# Ignore several spurious warnings for things gstreamer does very commonly
# If a warning is completely useless and spammy, use '/wdXXXX' to suppress it
# If a warning is harmless but hard to fix, use '/woXXXX' so it's shown once
# NOTE: Only add warnings here if you are sure they're spurious
'/wd4018', # implicit signed/unsigned conversion
'/wd4146', # unary minus on unsigned (beware INT_MIN)
'/wd4244', # lossy type conversion (e.g. double -> int)
'/wd4305', # truncating type conversion (e.g. double -> float)
cc.get_supported_arguments(['/utf-8']), # set the input encoding to utf-8
# Enable some warnings on MSVC to match GCC/Clang behaviour
'/w14062', # enumerator 'identifier' in switch of enum 'enumeration' is not handled
'/w14101', # 'identifier' : unreferenced local variable
'/w14189', # 'identifier' : local variable is initialized but not referenced
]
add_project_arguments(msvc_args, language: ['c', 'cpp'])
noseh_link_args = ['/SAFESEH:NO']
else
if cxx.has_argument('-Wno-non-virtual-dtor')
add_project_arguments('-Wno-non-virtual-dtor', language: 'cpp')
endif
noseh_link_args = []
endif
if cc.has_link_argument('-Wl,-Bsymbolic-functions')
add_project_link_arguments('-Wl,-Bsymbolic-functions', language: 'c')
endif
# Symbol visibility
if cc.get_id() == 'msvc'
export_define = '__declspec(dllexport) extern'
elif cc.has_argument('-fvisibility=hidden')
add_project_arguments('-fvisibility=hidden', language: 'c')
add_project_arguments('-fvisibility=hidden', language: 'cpp')
export_define = 'extern __attribute__ ((visibility ("default")))'
else
export_define = 'extern'
endif
# Passing this through the command line would be too messy
cdata.set('GST_API_EXPORT', export_define)
# Disable strict aliasing
if cc.has_argument('-fno-strict-aliasing')
add_project_arguments('-fno-strict-aliasing', language: 'c')
endif
if cxx.has_argument('-fno-strict-aliasing')
add_project_arguments('-fno-strict-aliasing', language: 'cpp')
endif
if not get_option('deprecated-glib-api')
message('Disabling deprecated GLib API')
add_project_arguments('-DG_DISABLE_DEPRECATED', language: 'c')
endif
if not get_option('devel-checks')
message('Disabling GLib cast checks')
add_project_arguments('-DG_DISABLE_CAST_CHECKS', language: 'c')
message('Disabling GLib asserts')
add_project_arguments('-DG_DISABLE_ASSERT', language: 'c')
message('Disabling GLib checks')
add_project_arguments('-DG_DISABLE_CHECKS', language: 'c')
endif
check_headers = [
['HAVE_DLFCN_H', 'dlfcn.h'],
['HAVE_FCNTL_H', 'fcntl.h'],
['HAVE_INTTYPES_H', 'inttypes.h'],
['HAVE_MEMORY_H', 'memory.h'],
['HAVE_NETINET_IN_H', 'netinet/in.h'],
['HAVE_NETINET_IP_H', 'netinet/ip.h'],
['HAVE_NETINET_TCP_H', 'netinet/tcp.h'],
['HAVE_PTHREAD_H', 'pthread.h'],
['HAVE_STDINT_H', 'stdint.h'],
['HAVE_STDLIB_H', 'stdlib.h'],
['HAVE_STRINGS_H', 'strings.h'],
['HAVE_STRING_H', 'string.h'],
['HAVE_SYS_PARAM_H', 'sys/param.h'],
['HAVE_SYS_SOCKET_H', 'sys/socket.h'],
['HAVE_SYS_STAT_H', 'sys/stat.h'],
['HAVE_SYS_TIME_H', 'sys/time.h'],
['HAVE_SYS_TYPES_H', 'sys/types.h'],
['HAVE_SYS_UTSNAME_H', 'sys/utsname.h'],
['HAVE_UNISTD_H', 'unistd.h'],
]
foreach h : check_headers
if cc.has_header(h.get(1))
cdata.set(h.get(0), 1)
endif
endforeach
check_functions = [
['HAVE_DCGETTEXT', 'dcgettext'],
['HAVE_GETPAGESIZE', 'getpagesize'],
['HAVE_GMTIME_R', 'gmtime_r'],
['HAVE_MEMFD_CREATE', 'memfd_create'],
['HAVE_MMAP', 'mmap'],
['HAVE_PIPE2', 'pipe2'],
['HAVE_GETRUSAGE', 'getrusage', '#include<sys/resource.h>'],
]
foreach f : check_functions
prefix = ''
if f.length() == 3
prefix = f.get(2)
endif
if cc.has_function(f.get(1), prefix: prefix)
cdata.set(f.get(0), 1)
endif
endforeach
cdata.set('SIZEOF_CHAR', cc.sizeof('char'))
cdata.set('SIZEOF_INT', cc.sizeof('int'))
cdata.set('SIZEOF_LONG', cc.sizeof('long'))
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_VERSION', libversion)
cdata.set_quoted('PACKAGE_BUGREPORT', 'https://github.com/Rafostar/clapper/issues/new')
cdata.set_quoted('PACKAGE_NAME', 'GStreamer Clapper Libs')
cdata.set_quoted('GST_API_VERSION', api_version)
cdata.set_quoted('GST_LICENSE', 'LGPL')
cdata.set_quoted('LIBDIR', pkglibdir)
cdata.set_quoted('LOCALEDIR', join_paths(get_option('prefix'), get_option('localedir')))
warning_flags = [
'-Wmissing-declarations',
'-Wredundant-decls',
'-Wwrite-strings',
'-Wformat',
'-Wformat-security',
'-Winit-self',
'-Wmissing-include-dirs',
'-Waddress',
'-Wno-multichar',
'-Wvla',
'-Wpointer-arith',
]
warning_c_flags = [
'-Wmissing-prototypes',
'-Wdeclaration-after-statement',
'-Wold-style-definition',
]
warning_cxx_flags = [
'-Wformat-nonliteral',
]
foreach extra_arg : warning_c_flags
if cc.has_argument (extra_arg)
add_project_arguments([extra_arg], language: 'c')
endif
endforeach
foreach extra_arg : warning_cxx_flags
if cxx.has_argument (extra_arg)
add_project_arguments([extra_arg], language: 'cpp')
endif
endforeach
foreach extra_arg : warning_flags
if cc.has_argument (extra_arg)
add_project_arguments([extra_arg], language: 'c')
endif
if cxx.has_argument (extra_arg)
add_project_arguments([extra_arg], language: 'cpp')
endif
endforeach
cdata.set_quoted('GST_PACKAGE_NAME', 'GStreamer Plugins Clapper')
cdata.set_quoted('GST_PACKAGE_ORIGIN', 'https://github.com/Rafostar/clapper')
# Mandatory GST deps
gst_dep = dependency('gstreamer-1.0', version: gst_req,
fallback: ['gstreamer', 'gst_dep'])
gstbase_dep = dependency('gstreamer-base-1.0', version: gst_req,
fallback: ['gstreamer', 'gst_base_dep'])
gstpbutils_dep = dependency('gstreamer-pbutils-1.0', version: gst_req,
fallback: ['gst-plugins-base', 'pbutils_dep'])
gstaudio_dep = dependency('gstreamer-audio-1.0', version: gst_req,
fallback: ['gst-plugins-base', 'audio_dep'])
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,
fallback: ['gst-plugins-base', 'gstgl_dep'], required: true)
gstglx11_dep = dependency('', required: false)
gstglwayland_dep = dependency('', required: false)
gstglegl_dep = dependency('', required: false)
gst_gl_apis = gstgl_dep.get_pkgconfig_variable('gl_apis')
gst_gl_winsys = gstgl_dep.get_pkgconfig_variable('gl_winsys')
gst_gl_platforms = gstgl_dep.get_pkgconfig_variable('gl_platforms')
message('GStreamer OpenGL window systems: @0@'.format(gst_gl_winsys))
message('GStreamer OpenGL platforms: @0@'.format(gst_gl_platforms))
message('GStreamer OpenGL apis: @0@'.format(gst_gl_apis))
foreach ws : ['x11', 'wayland', 'android', 'cocoa', 'eagl', 'win32', 'dispmanx', 'viv_fb']
set_variable('gst_gl_have_window_@0@'.format(ws), gst_gl_winsys.contains(ws))
endforeach
foreach p : ['glx', 'egl', 'cgl', 'eagl', 'wgl']
set_variable('gst_gl_have_platform_@0@'.format(p), gst_gl_platforms.contains(p))
endforeach
foreach api : ['gl', 'gles2']
set_variable('gst_gl_have_api_@0@'.format(api), gst_gl_apis.contains(api))
endforeach
gstglproto_dep = dependency('gstreamer-gl-prototypes-1.0', version: gst_req,
fallback: ['gst-plugins-base', 'gstglproto_dep'], required: true)
if gst_gl_have_window_x11
gstglx11_dep = dependency('gstreamer-gl-x11-1.0', version: gst_req,
fallback: ['gst-plugins-base', 'gstglx11_dep'], required: true)
endif
if gst_gl_have_window_wayland
gstglwayland_dep = dependency('gstreamer-gl-wayland-1.0', version: gst_req,
fallback: ['gst-plugins-base', 'gstglwayland_dep'], required: true)
endif
if gst_gl_have_platform_egl
gstglegl_dep = dependency('gstreamer-gl-egl-1.0', version: gst_req,
fallback: ['gst-plugins-base', 'gstglegl_dep'], required: true)
endif
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'))
configinc = include_directories('.')
libsinc = include_directories('gst')
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,41 +1,173 @@
project('com.github.rafostar.Clapper', 'c', 'cpp',
version: '0.4.1',
meson_version: '>= 0.50.0',
license: 'GPL-3.0-or-later',
project('clapper', 'c',
version: '0.9.0',
meson_version: '>= 0.64.0',
license: 'LGPL-2.1-or-later AND GPL-3.0-or-later', # LGPL-2.1+ for libs and gst-plugin, GPL-3.0+ for app
default_options: [
'warning_level=1',
'buildtype=debugoptimized'
]
'buildtype=debugoptimized',
],
)
glib_req = '>= 2.76.0'
gst_req = '>= 1.24.0'
gtk4_req = '>= 4.10.0'
adw_req = '>= 1.4.0'
clapper_version = meson.project_version().split('-')[0]
version_array = clapper_version.split('.')
clapper_version_suffix = '-' + version_array[0] + '.0'
clapper_api_name = meson.project_name() + clapper_version_suffix
devenv = environment()
gnome = import('gnome')
pkgconfig = import('pkgconfig')
i18n = import('i18n')
python = import('python')
bindir = join_paths(get_option('prefix'), get_option('bindir'))
libdir = join_paths(get_option('prefix'), get_option('libdir'))
datadir = join_paths(get_option('prefix'), get_option('datadir'))
prefix = get_option('prefix')
bindir = get_option('bindir')
datadir = get_option('datadir')
libdir = get_option('libdir')
localedir = get_option('localedir')
includedir = get_option('includedir')
optimization = get_option('optimization')
pkglibdir = join_paths(libdir, meson.project_name())
pkgdatadir = join_paths(datadir, meson.project_name())
clapper_libdir = join_paths(prefix, libdir, clapper_api_name)
build_optimized = optimization in ['2', '3', 's']
if get_option('lib') or not get_option('gst-plugin').disabled()
subdir('lib')
endif
gst_dep = dependency('gstreamer-1.0',
version: gst_req,
required: false,
)
gst_base_dep = dependency('gstreamer-base-1.0',
version: gst_req,
required: false,
)
gst_video_dep = dependency('gstreamer-video-1.0',
version: gst_req,
required: false,
)
gst_audio_dep = dependency('gstreamer-audio-1.0',
version: gst_req,
required: false,
)
gst_pbutils_dep = dependency('gstreamer-pbutils-1.0',
version: gst_req,
required: false,
)
gst_tag_dep = dependency('gstreamer-tag-1.0',
version: gst_req,
required: false,
)
glib_dep = dependency('glib-2.0',
version: glib_req,
required: false,
)
gobject_dep = dependency('gobject-2.0',
version: glib_req,
required: false,
)
gio_dep = dependency('gio-2.0',
version: glib_req,
required: false,
)
gmodule_dep = dependency('gmodule-2.0',
version: glib_req,
required: false,
)
gtk4_dep = dependency('gtk4',
version: gtk4_req,
required: false,
)
libadwaita_dep = dependency('libadwaita-1',
version: adw_req,
required: false,
)
if get_option('player')
subdir('bin')
subdir('data')
subdir('po')
# Optional
peas_dep = dependency('libpeas-2',
required: false,
)
cgraph_dep = dependency('libcgraph',
required: false,
)
gvc_dep = dependency('libgvc',
required: false,
)
install_subdir('src', install_dir: pkgdatadir)
install_subdir('extras', install_dir: pkgdatadir)
install_subdir('css', install_dir: pkgdatadir)
install_subdir('ui', install_dir: pkgdatadir)
cc = meson.get_compiler('c')
libm = cc.find_library('m', required: false)
python_bin = python.find_installation('python3')
if not python_bin.found()
error('No valid python3 binary found')
warning_flags = [
'-Wmissing-declarations',
'-Wredundant-decls',
'-Wwrite-strings',
'-Wformat',
'-Wformat-security',
'-Winit-self',
'-Wmissing-include-dirs',
'-Waddress',
'-Wno-multichar',
'-Wvla',
'-Wpointer-arith',
'-Wmissing-prototypes',
'-Wdeclaration-after-statement',
'-Wold-style-definition',
'-Wsign-compare',
]
foreach extra_arg : warning_flags
if cc.has_argument (extra_arg)
add_project_arguments([extra_arg], language: 'c')
endif
meson.add_install_script('build-aux/meson/postinstall.py')
endforeach
if build_optimized
message('Disabling GLib cast checks')
add_project_arguments('-DG_DISABLE_CAST_CHECKS', language: 'c')
message('Disabling GLib asserts')
add_project_arguments('-DG_DISABLE_ASSERT', language: 'c')
message('Disabling GLib checks')
add_project_arguments('-DG_DISABLE_CHECKS', language: 'c')
endif
subdir('src')
subdir('doc')
subdir('pkgs')
meson.add_devenv(devenv)
summary({
'prefix': prefix,
'bindir': bindir,
'datadir': datadir,
'libdir': libdir,
'localedir': localedir,
'includedir': includedir,
'optimization': optimization,
}, section: 'Directories')
summary('clapper', build_clapper ? 'Yes' : 'No', section: 'Build')
summary('clapper-gtk', build_clappergtk ? 'Yes' : 'No', section: 'Build')
summary('clapper-app', build_clapperapp ? 'Yes' : 'No', section: 'Build')
summary('gst-plugin', build_gst_plugin ? 'Yes' : 'No', section: 'Build')
summary('introspection', build_gir ? 'Yes' : 'No', section: 'Build')
summary('vapi', build_vapi ? 'Yes' : 'No', section: 'Build')
summary('doc', build_doc ? 'Yes' : 'No', section: 'Build')
if build_clapper
foreach name : clapper_possible_functionalities
summary(name, clapper_available_functionalities.contains(name) ? 'Yes' : 'No', section: 'Functionalities')
endforeach
foreach name : clapper_possible_features
summary(name, clapper_available_features.contains(name) ? 'Yes' : 'No', section: 'Features')
endforeach
endif
if build_clapperapp
foreach name : clapperapp_possible_functionalities
summary(name, clapperapp_available_functionalities.contains(name) ? 'Yes' : 'No', section: 'Functionalities')
endforeach
endif

View File

@@ -1,25 +1,82 @@
option('player',
type: 'boolean',
value: true,
description: 'Build Clapper player'
# Build
option('clapper',
type: 'feature',
value: 'auto',
description: 'Build Clapper library'
)
option('lib',
type: 'boolean',
value: true,
description: 'Build GstClapper lib'
option('clapper-gtk',
type: 'feature',
value: 'auto',
description: 'Build Clapper GTK integration library'
)
option('clapper-app',
type: 'feature',
value: 'auto',
description: 'Build Clapper application'
)
option('gst-plugin',
type: 'feature',
value: 'enabled',
value: 'auto',
description: 'Build GStreamer plugin (includes GTK video sink element)'
)
option('devel-checks',
option('introspection',
type: 'feature',
value: 'auto',
description: 'Build GObject Introspection data'
)
option('vapi',
type: 'feature',
value: 'auto',
description: 'Build Vala bindings'
)
option('doc',
type: 'boolean',
value: false,
description: 'GStreamer GLib checks and asserts such as API guards (disable for stable releases)'
description: 'Build documentation'
)
option('deprecated-glib-api',
type: 'boolean',
value: true,
description: 'Allow using of deprecated GLib API'
# Functionalities
option('enhancers-loader',
type: 'feature',
value: 'enabled',
description: 'Ability to load libpeas based plugins that enhance capabilities'
)
option('pipeline-preview',
type: 'feature',
value: 'auto',
description: 'Ability to preview GStreamer pipeline in clapper-app'
)
# Features
option('discoverer',
type: 'feature',
value: 'auto',
description: 'Build Clapper Discoverer feature'
)
option('mpris',
type: 'feature',
value: 'auto',
description: 'Build Clapper MPRIS feature'
)
option('server',
type: 'feature',
value: 'auto',
description: 'Build Clapper Server feature'
)
# GStreamer plugin options
option('glimporter',
type: 'feature',
value: 'auto',
description: 'Build GL memory importer for clappersink'
)
option('gluploader',
type: 'feature',
value: 'auto',
description: 'Build GL uploader for clappersink'
)
option('rawimporter',
type: 'feature',
value: 'auto',
description: 'Build RAW system memory importer for clappersink'
)

View File

@@ -3,7 +3,28 @@
"runtime": "org.gnome.Platform",
"runtime-version": "master",
"sdk": "org.gnome.Sdk",
"command": "com.github.rafostar.Clapper",
"sdk-extensions": [
"org.freedesktop.Sdk.Extension.rust-stable",
"org.freedesktop.Sdk.Extension.llvm18"
],
"add-extensions": {
"org.freedesktop.Platform.ffmpeg-full": {
"version": "24.08",
"directory": "lib/ffmpeg",
"add-ld-path": ".",
"no-autodownload": false,
"autodelete": false
},
"com.github.rafostar.Clapper.Enhancers": {
"versions": "master;test;stable",
"directory": "extensions/clapper/enhancers",
"add-ld-path": "lib",
"no-autodownload": false,
"autodelete": false
}
},
"command": "clapper",
"separate-locales": false,
"finish-args": [
"--share=ipc",
"--socket=fallback-x11",
@@ -14,16 +35,25 @@
"--device=all",
"--filesystem=xdg-run/pipewire-0:ro",
"--filesystem=xdg-videos",
"--own-name=org.mpris.MediaPlayer2.Clapper",
"--talk-name=org.gnome.Shell",
"--filesystem=xdg-run/gvfsd",
"--own-name=org.mpris.MediaPlayer2.Clapper.*",
"--talk-name=org.gtk.vfs.*",
"--env=GST_PLUGIN_SYSTEM_PATH=/app/lib/gstreamer-1.0",
"--env=GST_VAAPI_ALL_DRIVERS=1"
"--env=CLAPPER_ENHANCERS_PATH=/app/extensions/clapper/enhancers/plugins",
"--env=PYTHONPATH=/app/extensions/clapper/enhancers/python/site-packages"
],
"build-options": {
"append-path": "/usr/lib/sdk/rust-stable/bin:/usr/lib/sdk/llvm18/bin",
"prepend-ld-library-path": "/usr/lib/sdk/llvm18/lib",
"env": {
"CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER": "clang",
"CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUSTFLAGS": "-C link-arg=-fuse-ld=/usr/lib/sdk/rust-stable/bin/mold",
"CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER": "clang",
"CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUSTFLAGS": "-C link-arg=-fuse-ld=/usr/lib/sdk/rust-stable/bin/mold"
}
},
"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,10 +61,12 @@
"flathub/lib/libdvdread.json",
"flathub/lib/libdvdnav.json",
"flathub/lib/libass.json",
"flathub/lib/ffmpeg.json",
"testing/libsoup3.json",
"flathub/lib/libmicrodns.json",
"flathub/lib/libpeas.json",
"testing/dav1d.json",
"testing/gstreamer.json",
"testing/gtuber.json",
"testing/gst-plugins-rs.json",
"testing/graphviz.json",
{
"name": "clapper",
"buildsystem": "meson",
@@ -47,6 +79,8 @@
}
],
"cleanup-commands": [
"mkdir -p /app/lib/ffmpeg",
"mkdir -p /app/extensions/clapper/enhancers",
"ln -s /lib/$FLATPAK_ARCH-linux-*/gstreamer-1.0/libgstpipewire.so /app/lib/gstreamer-1.0/"
]
}

View File

@@ -1,9 +1,26 @@
{
"app-id": "com.github.rafostar.Clapper",
"runtime": "org.gnome.Platform",
"runtime-version": "41",
"runtime-version": "47",
"sdk": "org.gnome.Sdk",
"command": "com.github.rafostar.Clapper",
"add-extensions": {
"org.freedesktop.Platform.ffmpeg-full": {
"version": "24.08",
"directory": "lib/ffmpeg",
"add-ld-path": ".",
"no-autodownload": false,
"autodelete": false
},
"com.github.rafostar.Clapper.Enhancers": {
"versions": "master;test;stable",
"directory": "extensions/clapper/enhancers",
"add-ld-path": "lib",
"no-autodownload": false,
"autodelete": false
}
},
"command": "clapper",
"separate-locales": false,
"finish-args": [
"--share=ipc",
"--socket=fallback-x11",
@@ -14,16 +31,15 @@
"--device=all",
"--filesystem=xdg-run/pipewire-0:ro",
"--filesystem=xdg-videos",
"--own-name=org.mpris.MediaPlayer2.Clapper",
"--talk-name=org.gnome.Shell",
"--filesystem=xdg-run/gvfsd",
"--own-name=org.mpris.MediaPlayer2.Clapper.*",
"--talk-name=org.gtk.vfs.*",
"--env=GST_PLUGIN_SYSTEM_PATH=/app/lib/gstreamer-1.0",
"--env=GST_VAAPI_ALL_DRIVERS=1"
"--env=CLAPPER_ENHANCERS_PATH=/app/extensions/clapper/enhancers/plugins",
"--env=PYTHONPATH=/app/extensions/clapper/enhancers/python/site-packages"
],
"modules": [
"flathub/shared-modules/gudev/gudev.json",
"flathub/lib/pango.json",
"flathub/lib/libsass.json",
"flathub/lib/sassc.json",
"flathub/lib/liba52.json",
"flathub/lib/libmpeg2.json",
"flathub/lib/libdv.json",
@@ -31,13 +47,11 @@
"flathub/lib/libdvdread.json",
"flathub/lib/libdvdnav.json",
"flathub/lib/libass.json",
"flathub/lib/ffmpeg.json",
"flathub/lib/uchardet.json",
"testing/libsoup3.json",
"flathub/lib/libmicrodns.json",
"flathub/lib/libpeas.json",
"flathub/gstreamer-1.0/gstreamer.json",
"flathub/lib/gtk4.json",
"flathub/lib/libadwaita.json",
"testing/gtuber.json",
"testing/graphviz.json",
{
"name": "clapper",
"buildsystem": "meson",
@@ -50,6 +64,8 @@
}
],
"cleanup-commands": [
"mkdir -p /app/lib/ffmpeg",
"mkdir -p /app/extensions/clapper/enhancers",
"ln -s /lib/$FLATPAK_ARCH-linux-*/gstreamer-1.0/libgstpipewire.so /app/lib/gstreamer-1.0/"
]
}

View File

@@ -0,0 +1,25 @@
{
"name": "dav1d",
"buildsystem": "meson",
"only-arches": [
"x86_64"
],
"config-opts": [
"-Denable_tools=false",
"-Denable_examples=false",
"-Denable_tests=false",
"-Denable_docs=false",
"-Dlogging=false"
],
"cleanup": [
"/include",
"/lib/pkgconfig"
],
"sources": [
{
"type": "git",
"url": "https://code.videolan.org/videolan/dav1d.git",
"branch": "master"
}
]
}

View File

@@ -0,0 +1,38 @@
{
"name": "graphviz",
"buildsystem": "autotools",
"config-opts": [
"--without-x",
"--without-gtk",
"--without-gtkgl",
"--without-gtkglext",
"--without-gdk",
"--without-gdk-pixbuf",
"--without-qt",
"--disable-static",
"--disable-sharp",
"--disable-go",
"--disable-guile",
"--disable-java",
"--disable-javascript",
"--disable-lua",
"--disable-perl",
"--disable-php",
"--disable-python",
"--disable-r",
"--disable-ruby",
"--disable-tcl"
],
"cleanup": [
"/bin",
"/share/man",
"/share/graphviz"
],
"sources": [
{
"type": "archive",
"url": "https://gitlab.com/api/v4/projects/4207231/packages/generic/graphviz-releases/12.2.1/graphviz-12.2.1.tar.gz",
"sha256": "242bc18942eebda6db4039f108f387ec97856fc91ba47f21e89341c34b554df8"
}
]
}

View File

@@ -0,0 +1,26 @@
{
"name": "gst-plugins-rs",
"buildsystem": "simple",
"only-arches": [
"x86_64"
],
"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

@@ -2,7 +2,7 @@
"name": "gstreamer",
"buildsystem": "meson",
"config-opts": [
"--wrap-mode=nofallback",
"--wrap-mode=nodownload",
"-Dbase=enabled",
"-Dgood=enabled",
@@ -26,26 +26,12 @@
"-Dgpl=enabled",
"-Dgstreamer:benchmarks=disabled",
"-Dgstreamer:gobject-cast-checks=disabled",
"-Dgstreamer:glib-asserts=disabled",
"-Dgstreamer:glib-checks=disabled",
"-Dgstreamer:extra-checks=disabled",
"-Dgst-plugins-base:gobject-cast-checks=disabled",
"-Dgst-plugins-base:glib-asserts=disabled",
"-Dgst-plugins-base:glib-checks=disabled",
"-Dgst-plugins-base:gl_api=opengl,gles2",
"-Dgst-plugins-base:gl_platform=egl,glx",
"-Dgst-plugins-good:gobject-cast-checks=disabled",
"-Dgst-plugins-good:glib-asserts=disabled",
"-Dgst-plugins-good:glib-checks=disabled",
"-Dgst-plugins-good:gtk3=disabled",
"-Dgst-plugins-bad:gobject-cast-checks=disabled",
"-Dgst-plugins-bad:glib-asserts=disabled",
"-Dgst-plugins-bad:glib-checks=disabled",
"-Dgst-plugins-bad:extra-checks=disabled",
"-Dgst-plugins-bad:vulkan=disabled",
"-Dgst-plugins-bad:webrtc=disabled",
"-Dgst-plugins-bad:wasapi=disabled",
@@ -57,16 +43,14 @@
"-Dgst-plugins-bad:v4l2codecs=enabled",
"-Dgst-plugins-bad:va=enabled",
"-Dgst-plugins-ugly:gobject-cast-checks=disabled",
"-Dgst-plugins-ugly:glib-asserts=disabled",
"-Dgst-plugins-ugly:glib-checks=disabled",
"-Dgst-plugins-ugly:mpeg2dec=enabled"
],
"sources": [
{
"type": "git",
"url": "https://gitlab.freedesktop.org/gstreamer/gstreamer.git",
"branch": "main"
"branch": "main",
"disable-submodules": true
}
]
}

View File

@@ -1,20 +0,0 @@
{
"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

@@ -0,0 +1,21 @@
{
"name": "libpeas",
"buildsystem": "meson",
"config-opts": [
"--wrap-mode=nodownload",
"-Dgjs=false",
"-Dlua51=false",
"-Dintrospection=false"
],
"sources": [
{
"type": "archive",
"url": "https://download.gnome.org/sources/libpeas/2.0/libpeas-2.0.5.tar.xz",
"sha256": "376f2f73d731b54e13ddbab1d91b6382cf6a980524def44df62add15489de6dd",
"x-checker-data": {
"type": "gnome",
"name": "libpeas"
}
}
]
}

View File

@@ -1,24 +0,0 @@
{
"name": "libsoup3",
"buildsystem": "meson",
"config-opts": [
"-Dintrospection=enabled",
"-Dvapi=disabled",
"-Dtests=false",
"-Dsysprof=disabled",
"-Dhttp2_tests=disabled",
"-Dpkcs11_tests=disabled"
],
"cleanup": [
"/include",
"/lib/pkgconfig"
],
"sources": [
{
"type": "git",
"url": "https://gitlab.gnome.org/GNOME/libsoup.git",
"tag": "3.0.4",
"commit": "25a728020c4b53b5db4c4c675070e92f947fbd4d"
}
]
}

5
pkgs/meson.build Normal file
View File

@@ -0,0 +1,5 @@
is_windows = ['windows'].contains(host_machine.system())
if is_windows
subdir('windows-installer')
endif

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,193 +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
%global soup_version 3.0.0
Name: clapper
Version: 0.4.1
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: libsoup-devel >= %{soup_version}
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: libsoup3-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
* Thu Feb 17 2022 Rafostar <rafostar.github@gmail.com> - 0.4.1-2
- Require libsoup3
* Mon Dec 20 2021 Rafostar <rafostar.github@gmail.com> - 0.4.1-1
- New version
* 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

@@ -0,0 +1,31 @@
[Setup]
AppName=Clapper
AppVersion=@CLAPPER_APP_VERSION@
AppVerName=Clapper @CLAPPER_APP_VERSION@
VersionInfoVersion=@CLAPPER_APP_VERSION@.0
ArchitecturesAllowed=x64compatible
ArchitecturesInstallIn64BitMode=x64compatible
WizardStyle=modern
DefaultDirName={autopf}\Clapper
DefaultGroupName=Clapper
DisableProgramGroupPage=yes
ChangesAssociations=yes
Compression=lzma2
SolidCompression=yes
OutputDir=InstallerOutput
OutputBaseFilename=Clapper_@CLAPPER_APP_VERSION@
SetupIconFile=@PROJECT_ROOT@\src\bin\clapper-app\windows\clapper.ico
LicenseFile=@PROJECT_ROOT@\COPYING-GPL
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
[Files]
Source: "@CLAPPER_APP_DEST@\*"; DestDir: "{app}"; Flags: recursesubdirs replacesameversion
[Icons]
Name: "{autoprograms}\Clapper"; Filename: "{app}\bin\clapper.exe"
Name: "{autodesktop}\Clapper"; Filename: "{app}\bin\clapper.exe"; Tasks: desktopicon
[Registry]
@CLAPPER_APP_REG_ENTRIES@

View File

@@ -0,0 +1,44 @@
# Same as "clapper-app-utils.c"
# FIXME: Have these in one place only
win_extensions = [
'avi', 'claps', 'm2ts', 'mkv', 'mov',
'mp4', 'webm', 'wmv'
]
reg_entries = []
foreach ext : win_extensions
ext_id = 'Clapper.' + ext
exe_path = '{app}\\bin\\clapper.exe'
subkey = 'Software\\Classes\\.' + ext + '\\OpenWithProgids'
reg_entries += 'Root: HKA; Subkey: "@0@"; ValueType: string; ValueName: "@1@"; ValueData: ""; Flags: uninsdeletevalue'.format(subkey, ext_id)
subkey = 'Software\\Classes\\' + ext_id
reg_entries += 'Root: HKA; Subkey: "@0@"; ValueType: string; ValueName: ""; ValueData: "@1@"; Flags: uninsdeletekey'.format(subkey, ext)
subkey = 'Software\\Classes\\' + ext_id + '\\DefaultIcon'
reg_entries += 'Root: HKA; Subkey: "@0@"; ValueType: string; ValueName: ""; ValueData: "@1@,0"'.format(subkey, exe_path)
subkey = 'Software\\Classes\\' + ext_id + '\\shell\\open\\command'
reg_entries += 'Root: HKA; Subkey: "@0@"; ValueType: string; ValueName: ""; ValueData: """@1@"" ""%1"""'.format(subkey, exe_path)
reg_entries += '' # Empty line for clarity
endforeach
# NOTE: In meson replacing "@@" vars after "\" sign does not work.
# For this reason we do not pass app name here.
iss_conf = configuration_data()
iss_conf.set('CLAPPER_APP_VERSION', meson.project_version())
iss_conf.set('CLAPPER_APP_REG_ENTRIES', '\n'.join(reg_entries))
iss_conf.set('PROJECT_ROOT', meson.project_source_root())
# NOTE: We also need to package other dependencies, hence using whole prefix.
# Workaround to reduce package size is to set prefix to some custom dir, install,
# then determine the rest with "ldd" and copy remaining files manually there.
iss_conf.set('CLAPPER_APP_DEST', prefix.replace('/', '\\'))
configure_file(
input: 'clapper.iss.in',
output: 'clapper.iss',
configuration: iss_conf,
)

View File

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

View File

@@ -1,10 +0,0 @@
ui/clapper.ui
ui/elapsed-time-button.ui
ui/help-overlay.ui
ui/preferences-plugin-ranking-subpage.ui
ui/preferences-window.ui
src/buttons.js
src/dialogs.js
src/revealers.js
src/widget.js

459
po/af.po
View File

@@ -1,459 +0,0 @@
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: 2021-09-14 15:25\n"
"Last-Translator: \n"
"Language-Team: Afrikaans\n"
"Language: af_ZA\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: af\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 ""

459
po/ar.po
View File

@@ -1,459 +0,0 @@
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: 2021-09-14 15:25\n"
"Last-Translator: \n"
"Language-Team: Arabic\n"
"Language: ar_SA\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=6; plural=(n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5);\n"
"X-Crowdin-Project: clapper\n"
"X-Crowdin-Project-ID: 473374\n"
"X-Crowdin-Language: ar\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 ""

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