Compare commits
352 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
2575b61cd0 | ||
|
9abf2fb11d | ||
|
167be4c37b | ||
|
74c4a079e6 | ||
|
8a597fffe7 | ||
|
159f96c984 | ||
|
96ad4fa3db | ||
|
b2e7bef8d4 | ||
|
40a1dc6960 | ||
|
c4bd604e17 | ||
|
83c0e3b598 | ||
|
54715023c0 | ||
|
95046ceba8 | ||
|
b189e24b5e | ||
|
cb9e2ac979 | ||
|
545d8826e0 | ||
|
c2160198b9 | ||
|
aa7eae2417 | ||
|
3192a32845 | ||
|
706c783498 | ||
|
8ba3ca4af6 | ||
|
38efa7ab9f | ||
|
d19ddbcaca | ||
|
615f1553fb | ||
|
09c9e7560b | ||
|
f40ce756ad | ||
|
23d51be185 | ||
|
0db2a4a045 | ||
|
469c06d22b | ||
|
3feaf225b5 | ||
|
fc8d881efd | ||
|
ac76836fd7 | ||
|
f6a1aaf1dc | ||
|
000dca82d9 | ||
|
7a508fef39 | ||
|
d465d9f150 | ||
|
5e4dfb322c | ||
|
0c561ab4b3 | ||
|
46ce261524 | ||
|
50aac8cdd8 | ||
|
810aea476f | ||
|
24905f1d60 | ||
|
82e3c9a52f | ||
|
654b8aaf60 | ||
|
3c0e33e4a4 | ||
|
d2df1c3bd8 | ||
|
af24073590 | ||
|
44cee14eb2 | ||
|
b853685dd4 | ||
|
15461dd38a | ||
|
1c1989bc32 | ||
|
e9c9ae073f | ||
|
22d2c40b0f | ||
|
5301c8b368 | ||
|
e910978590 | ||
|
3b99f0ee0c | ||
|
f93a0fed98 | ||
|
6b8c35b16e | ||
|
5fdb6e64be | ||
|
60d4b5aec1 | ||
|
f5258889cf | ||
|
31eddf5dd2 | ||
|
89f7304e0e | ||
|
3c918bda73 | ||
|
2a8ef2559f | ||
|
7676e18eee | ||
|
00b05b460d | ||
|
62f02cf2a3 | ||
|
9fc1d9b8c4 | ||
|
45a5ebb4b6 | ||
|
2500a42286 | ||
|
bafffa59b9 | ||
|
201cb6f64c | ||
|
636098182b | ||
|
5442b0b70a | ||
|
67d1b9f5bc | ||
|
a62483fda9 | ||
|
c825385a8f | ||
|
02a7419d66 | ||
|
e727b8fb50 | ||
|
3cbfd1a57c | ||
|
75b728457c | ||
|
b293a84df6 | ||
|
928244dc32 | ||
|
11caafe847 | ||
|
dbeb4cb0b7 | ||
|
3e04139288 | ||
|
c41b77a14b | ||
|
3c500e0be9 | ||
|
6cddb1a16d | ||
|
b5007d12a1 | ||
|
0d7274fb03 | ||
|
94be4c08c5 | ||
|
bfcc468528 | ||
|
98d2b80103 | ||
|
fa39c45773 | ||
|
b2a6e19fe1 | ||
|
e8c44dc400 | ||
|
5cc9c17632 | ||
|
35d359daf9 | ||
|
637fa75484 | ||
|
8733610a9b | ||
|
873e724bf2 | ||
|
7aa03f3e72 | ||
|
99acd36cc0 | ||
|
cd7d99606d | ||
|
574e084383 | ||
|
d49df86397 | ||
|
3483c94913 | ||
|
a99abc652a | ||
|
a9173bb481 | ||
|
a16444cefb | ||
|
65673dbf4f | ||
|
dea67e4712 | ||
|
3c765e9f17 | ||
|
a77eb5352e | ||
|
ca168f34ed | ||
|
d0304d4ded | ||
|
cd479f3bb4 | ||
|
70942ba419 | ||
|
ad0c6151a9 | ||
|
cccc584961 | ||
|
38e721be03 | ||
|
cf6d41b725 | ||
|
b68c1a62b2 | ||
|
dc25ec976a | ||
|
914292612b | ||
|
e34b164f5a | ||
|
2e0a455f92 | ||
|
3aab01d35c | ||
|
e264304c9d | ||
|
a145890f9d | ||
|
0323c816ad | ||
|
4f1d9be423 | ||
|
82557df7c4 | ||
|
c457158541 | ||
|
451711b9c6 | ||
|
bbada8fb4e | ||
|
04122d46a7 | ||
|
347d90b1ad | ||
|
27ffb65d8f | ||
|
9328a7af75 | ||
|
1f6e439632 | ||
|
97c1207b40 | ||
|
833559a208 | ||
|
9a8655b0a2 | ||
|
d2a03d40a3 | ||
|
66998ff6c6 | ||
|
7cdd905d73 | ||
|
10eb5102c1 | ||
|
9e8854c5e2 | ||
|
16a9546c97 | ||
|
2686c2ca03 | ||
|
ad563d16d0 | ||
|
12ce95b664 | ||
|
2dbabe52bb | ||
|
2c35ceb35a | ||
|
5eac1aa675 | ||
|
0e6a68665d | ||
|
86fe1628c3 | ||
|
a427817e53 | ||
|
7a767c34eb | ||
|
a7298e371e | ||
|
f6393a177d | ||
|
45decb8563 | ||
|
2e12e52730 | ||
|
ffbd8c35e1 | ||
|
01277f4a71 | ||
|
a54c3e4bcc | ||
|
17b2aec170 | ||
|
75bc0d6b69 | ||
|
edef26fc0e | ||
|
0edab83f86 | ||
|
9681d0eea1 | ||
|
b6559ee50f | ||
|
ce183595cd | ||
|
71f50ba414 | ||
|
0de8ee2d54 | ||
|
8be49f25b4 | ||
|
69bef3d174 | ||
|
d429e9105c | ||
|
a1ce04edfa | ||
|
8ca4c30beb | ||
|
9b53a3e387 | ||
|
f31682624f | ||
|
5874db45ea | ||
|
87a0dd473e | ||
|
c50df5f2a3 | ||
|
a72a8057e5 | ||
|
f29ec78b92 | ||
|
10f54c7c3d | ||
|
2b91056543 | ||
|
2656762cbc | ||
|
f5ff59f786 | ||
|
e4fe7844c4 | ||
|
b7d9a22d33 | ||
|
c8a5277908 | ||
|
62fab289b7 | ||
|
56ca13b370 | ||
|
ce46905319 | ||
|
5fe5f89e5d | ||
|
9ba6f5d09e | ||
|
4c0fc1dac2 | ||
|
13a792c0a9 | ||
|
02b0d5f03f | ||
|
b577dd762d | ||
|
d798539dce | ||
|
19e159d1bd | ||
|
c3cdabb050 | ||
|
c53cde4d78 | ||
|
b308ae367f | ||
|
b2005fd34f | ||
|
a6dfeeca37 | ||
|
90844e49ad | ||
|
eb60d036db | ||
|
6e20a5fa12 | ||
|
cf370961b4 | ||
|
6db36d6ac2 | ||
|
4738673f7f | ||
|
1004000ba2 | ||
|
e40f11def5 | ||
|
5378facb46 | ||
|
c6b252f261 | ||
|
0f1447b14e | ||
|
cfd6e1bd23 | ||
|
0cb89d3a84 | ||
|
3bf636d46b | ||
|
8f79a76a51 | ||
|
0efe9144d8 | ||
|
2e776ddf7b | ||
|
2eea3b05b1 | ||
|
e647cdc8c6 | ||
|
1f3ddab566 | ||
|
a38480c46b | ||
|
562587846a | ||
|
c6cd829e7b | ||
|
9b31581aac | ||
|
5018b3a28a | ||
|
bad836cc6d | ||
|
e1845a212f | ||
|
f86e32ed88 | ||
|
af2c74a4b1 | ||
|
1c414ef36b | ||
|
11e89dab26 | ||
|
37d2f7aebd | ||
|
f2ac3b20a3 | ||
|
ade60b93a4 | ||
|
48bc96f074 | ||
|
0d9cb91705 | ||
|
21ccab1cc2 | ||
|
bea3b1670d | ||
|
0d4d3f1a8c | ||
|
fc525ffcb1 | ||
|
6f1a5626bc | ||
|
fbe6a8804c | ||
|
c0b92c190b | ||
|
8fc64eaf73 | ||
|
0b7f31b7c2 | ||
|
2d4353aaec | ||
|
7062af472b | ||
|
1f4698448a | ||
|
95c8316af6 | ||
|
06d9f302c2 | ||
|
6246777f06 | ||
|
1f781716d7 | ||
|
0d7ef22c88 | ||
|
57664f32da | ||
|
f8a7abe195 | ||
|
5f259b28fe | ||
|
9f776e9ecb | ||
|
edb799bafa | ||
|
7535c4e598 | ||
|
f0475ee055 | ||
|
68d7205ead | ||
|
f08ffad178 | ||
|
c2de0b7b33 | ||
|
ac7be5956c | ||
|
76a1efab58 | ||
|
a2bbd2708d | ||
|
9e77660cac | ||
|
5ea22450c0 | ||
|
6ae38327ca | ||
|
9006e56534 | ||
|
af0e082c43 | ||
|
2f5d6d60ed | ||
|
9d537c7318 | ||
|
970b1487ac | ||
|
fc51fd857c | ||
|
b419ed7922 | ||
|
4f69183b85 | ||
|
98df55b231 | ||
|
6a4f5f2560 | ||
|
efe9439633 | ||
|
4179176ce8 | ||
|
a7288adf4c | ||
|
9bb3f999b1 | ||
|
0e6507682a | ||
|
2d8471dea0 | ||
|
68f49c1495 | ||
|
a8bb6c40f4 | ||
|
71db78a0f6 | ||
|
4133557086 | ||
|
d926e6b389 | ||
|
fd2de8b9b6 | ||
|
de65eee106 | ||
|
9b07ff7dc5 | ||
|
047dd12fbb | ||
|
3238270c0d | ||
|
997e47b93c | ||
|
ec1d4619a7 | ||
|
f4e48c9f8c | ||
|
1da6b94efc | ||
|
e4335721be | ||
|
45d2702e01 | ||
|
a8aca7b3c0 | ||
|
c6e8824e3b | ||
|
e92ad68220 | ||
|
a98ca53dfb | ||
|
32995fc6a6 | ||
|
6b5240ddbc | ||
|
46ef6bcd1d | ||
|
bd13a3c15a | ||
|
edfa85b5cc | ||
|
084f78a851 | ||
|
c9b2f25192 | ||
|
6f39b3939a | ||
|
ee78ffb1e4 | ||
|
bfbbc517d5 | ||
|
7559a61c9f | ||
|
deb273179f | ||
|
231af36ef6 | ||
|
2e892c923b | ||
|
0ab0b66825 | ||
|
d901eb4712 | ||
|
fe03719b38 | ||
|
f0ea7ae798 | ||
|
380236b8ba | ||
|
e721130a63 | ||
|
eaf090d2e2 | ||
|
87115f43d7 | ||
|
33a5ec18fa | ||
|
ab8cafa0b8 | ||
|
62b6de6db2 | ||
|
643c2029d0 | ||
|
9799783ee5 | ||
|
457cbde25e | ||
|
2fd94fdc70 | ||
|
3a998fb91e | ||
|
b02f54a3a6 | ||
|
ca7b44092e | ||
|
adbcfecb5e | ||
|
a717e481e8 |
2
.gitattributes
vendored
@@ -1,3 +1,5 @@
|
||||
extras/**/* linguist-vendored
|
||||
lib/**/* linguist-vendored
|
||||
lib/**/**/* linguist-vendored
|
||||
lib/gst/clapper/gstclapper-mpris* linguist-vendored=false
|
||||
lib/gst/clapper/gtk4/* linguist-vendored=false
|
||||
|
36
.github/workflows/flatpak-nightly.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
on:
|
||||
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]
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
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"
|
||||
with:
|
||||
bundle: com.github.rafostar.Clapper.flatpak
|
||||
manifest-path: pkgs/flatpak/com.github.rafostar.Clapper-nightly.json
|
||||
repository-name: gnome-nightly
|
||||
repository-url: https://nightly.gnome.org/gnome-nightly.flatpakrepo
|
||||
cache-key: flatpak-builder-${{ github.sha }}-testing-${{ github.run_number }}
|
||||
arch: ${{ matrix.arch }}
|
38
.github/workflows/flatpak.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
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]
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
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"
|
||||
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 }}
|
6
.gitmodules
vendored
@@ -1,3 +1,3 @@
|
||||
[submodule "pkgs/flatpak/shared-modules"]
|
||||
path = pkgs/flatpak/shared-modules
|
||||
url = https://github.com/flathub/shared-modules.git
|
||||
[submodule "pkgs/flatpak/flathub"]
|
||||
path = pkgs/flatpak/flathub
|
||||
url = https://github.com/flathub/com.github.rafostar.Clapper.git
|
||||
|
47
README.md
@@ -1,6 +1,10 @@
|
||||
# Clapper
|
||||
A GNOME media player build using [GJS](https://gitlab.gnome.org/GNOME/gjs) with [GTK4](https://www.gtk.org) toolkit.
|
||||
The media player is using [GStreamer](https://gstreamer.freedesktop.org/) as a media backend and renders everything via [OpenGL](https://www.opengl.org).
|
||||
[](https://github.com/Rafostar/clapper/actions/workflows/flatpak.yml)
|
||||
[](https://github.com/Rafostar/clapper/actions/workflows/flatpak-nightly.yml)
|
||||
[](https://crowdin.com/project/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).
|
||||
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/wiki/Rafostar/clapper/media/screenshot-windowed.png"><br>
|
||||
@@ -23,20 +27,21 @@ The media player is using [GStreamer](https://gstreamer.freedesktop.org/) as a m
|
||||
* [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
|
||||
|
||||
## 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). List of patches used in this version can be found [here](https://github.com/Rafostar/clapper/issues/35).
|
||||
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).
|
||||
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>
|
||||
|
||||
**Important:** If you have been using the flatpak package from my custom 3rd party repo, please remove it and replace your installation with version from Flathub. That repository will not be maintained any longer. Thank you for understanding.
|
||||
<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
|
||||
The [pkgs folder](https://github.com/Rafostar/clapper/tree/master/pkgs) in this repository contains build scripts for various package formats. You can use them to build package yourself or download one of pre-built packages:
|
||||
|
||||
#### Debian, 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))
|
||||
#### 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.
|
||||
|
||||
#### Arch Linux
|
||||
You can get Clapper from the AUR:
|
||||
@@ -49,23 +54,19 @@ meson builddir --prefix=/usr/local
|
||||
sudo meson install -C builddir
|
||||
```
|
||||
|
||||
## Q&A
|
||||
**Q:** Does using `GJS` negatively impact video performance?<br>
|
||||
**A:** Absolutely not. `GJS` here is used to put together the GUI during startup.
|
||||
It has nothing to do with video rendering. All used `GTK4` and `GStreamer` libraries are in C.
|
||||
Even the custom video widget that I prepared for this player (based on original `GTK3` implementation) is a compiled C code.
|
||||
All these libs are acting "on their own" and no function calls from `GJS` related to video decoding and rendering are performed during playback.
|
||||
## Questions?
|
||||
Feel free to ask me any questions. Come and talk on Matrix: [#clapper-player:matrix.org](https://matrix.to/#/#clapper-player:matrix.org)
|
||||
|
||||
**Q:** What settings should I set to maximize performance?<br>
|
||||
**A:** As of now, player works best on `Wayland` session. `Wayland` users can try enabling highly experimental `vah264dec` plugin for improved performance (this plugin does not work on `Xorg` right now) for standard (8-bit) `H.264` videos.
|
||||
It can be enabled from inside player preferences dialog inside `Advanced -> GStreamer` tab using customizable `Plugin Ranking` feature.
|
||||
Since the whole app is rendered using your GPU, users of VERY weak GPUs might want to disable the "render window shadows" option to have more GPU power available for non-fullscreen video rendering.
|
||||
## Translations
|
||||
Preferred translation method is to use [Clapper Crowdin](https://crowdin.com/project/clapper) web page.
|
||||
|
||||
## Other Questions?
|
||||
Feel free to ask me any questions.<br>
|
||||
Use either GitHub [discussions](https://github.com/Rafostar/clapper/discussions) or come and talk on Matrix: **#clapper-player:matrix.org**
|
||||
Crowdin does not require any additional tools and translating can be done through web browser.
|
||||
You can login using GitHub account or create a new one. Only I can add new languages to this project,
|
||||
so if your language is not available, please contact me first.
|
||||
|
||||
## Special Thanks
|
||||
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.
|
||||
|
||||
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.
|
||||
|
12
TODO.md
@@ -15,11 +15,11 @@
|
||||
- [X] Picture-in-Picture mode window (floating window)
|
||||
- [ ] Touch gestures/swipes support
|
||||
- Media playlists:
|
||||
- [ ] Add more items to playlist via GUI
|
||||
- [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)
|
||||
- [ ] Save to playlist file from GUI
|
||||
- [X] Save to playlist file from GUI
|
||||
- Seeking:
|
||||
- [X] Customizable seek time
|
||||
- [X] Set seek mode (default, accurate, fast)
|
||||
@@ -31,7 +31,7 @@
|
||||
- [X] Audio offset
|
||||
- [ ] MDNS and UPNP (discovering media in local network)
|
||||
- [X] DND files from Nautilus to play (ignore incompatible ones)
|
||||
- [ ] Support dropping whole folders
|
||||
- [X] Support dropping whole folders
|
||||
- [ ] Search for subtitles, download and activate (SMplayer)
|
||||
- [ ] Auto add subtitles from same folder
|
||||
- [ ] Set global subtitles folders
|
||||
@@ -40,7 +40,7 @@
|
||||
- [X] Remote playback controls via HTTP (VLC) + WebSockets
|
||||
- [ ] Expand available API
|
||||
- [ ] API documentation
|
||||
- [ ] Integration with the top bar
|
||||
- [ ] MPRIS support
|
||||
- [ ] Controls in the notifications panel
|
||||
- [X] Integration with the top bar
|
||||
- [X] MPRIS support
|
||||
- [X] Controls in the notifications panel
|
||||
- [ ] Progress bar in the notifications panel (maybe via extension)
|
||||
|
1
_service
@@ -4,7 +4,6 @@
|
||||
<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>
|
||||
<param name="extract">pkgs/deb/clapper.dsc</param>
|
||||
</service>
|
||||
<service name="tar" mode="buildtime"/>
|
||||
<service name="recompress" mode="buildtime">
|
||||
|
@@ -1,17 +0,0 @@
|
||||
#!@GJS@
|
||||
|
||||
/* pkg init enforces the imports path to the folder
|
||||
* named after the pkg name, but I would prefer to have
|
||||
* the bundled subprocess stored in the same directory */
|
||||
imports.searchPath.unshift('@datadir@/@PACKAGE_NAME@');
|
||||
|
||||
const Package = imports.package;
|
||||
|
||||
Package.init({
|
||||
name: '@PACKAGE_NAME@.@ID_POSTFIX@',
|
||||
version: '@PACKAGE_VERSION@',
|
||||
prefix: '@prefix@',
|
||||
libdir: '@libdir@',
|
||||
datadir: '@datadir@',
|
||||
});
|
||||
Package.run(imports.src.main@ID_POSTFIX@);
|
@@ -1,12 +1,9 @@
|
||||
#!@GJS@
|
||||
|
||||
const Package = imports.package;
|
||||
|
||||
Package.init({
|
||||
imports.package.init({
|
||||
name: '@PACKAGE_NAME@',
|
||||
version: '@PACKAGE_VERSION@',
|
||||
prefix: '@prefix@',
|
||||
libdir: '@libdir@',
|
||||
datadir: '@datadir@',
|
||||
});
|
||||
Package.run(imports.src.main);
|
||||
imports.package.run(imports.src.main);
|
||||
|
@@ -1,24 +1,22 @@
|
||||
clapper_apps = ['', 'Remote', 'Daemon']
|
||||
bin_conf = configuration_data()
|
||||
|
||||
foreach id_postfix : clapper_apps
|
||||
app_postfix = (id_postfix != '') ? '.' + id_postfix : ''
|
||||
template_type = (id_postfix != '') ? '.Subprocess' : ''
|
||||
bin_conf.set('GJS', find_program('gjs').path())
|
||||
bin_conf.set('PACKAGE_NAME', meson.project_name())
|
||||
bin_conf.set('PACKAGE_VERSION', meson.project_version())
|
||||
bin_conf.set('prefix', get_option('prefix'))
|
||||
bin_conf.set('libdir', libdir)
|
||||
|
||||
bin_conf = configuration_data()
|
||||
bin_conf.set('GJS', find_program('gjs').path())
|
||||
bin_conf.set('PACKAGE_NAME', meson.project_name())
|
||||
bin_conf.set('PACKAGE_VERSION', meson.project_version())
|
||||
bin_conf.set('ID_POSTFIX', id_postfix)
|
||||
bin_conf.set('prefix', get_option('prefix'))
|
||||
bin_conf.set('libdir', join_paths(get_option('prefix'), get_option('libdir')))
|
||||
bin_conf.set('datadir', join_paths(get_option('prefix'), get_option('datadir')))
|
||||
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'
|
||||
)
|
||||
|
||||
configure_file(
|
||||
input: 'com.github.rafostar.Clapper' + template_type + '.in',
|
||||
output: 'com.github.rafostar.Clapper' + app_postfix,
|
||||
configuration: bin_conf,
|
||||
install: true,
|
||||
install_dir: get_option('bindir'),
|
||||
install_mode: 'rwxr-xr-x'
|
||||
)
|
||||
endforeach
|
||||
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)
|
||||
|
3
crowdin.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
files:
|
||||
- source: /po/com.github.rafostar.Clapper.pot
|
||||
translation: /po/%osx_locale%.po
|
253
css/styles.css
@@ -5,19 +5,35 @@ scale marks {
|
||||
radio {
|
||||
margin-left: -2px;
|
||||
}
|
||||
scrolledwindow scrollbar.vertical slider {
|
||||
min-height: 16px;
|
||||
}
|
||||
|
||||
/* Adwaita is missing osd ListBox */
|
||||
.osd list {
|
||||
.clapperplaylist {
|
||||
background: none;
|
||||
}
|
||||
.osd list row image {
|
||||
.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;
|
||||
}
|
||||
.gtk402 trough highlight {
|
||||
border-color: transparent;
|
||||
}
|
||||
.gtk402 .osd trough highlight {
|
||||
border-color: inherit;
|
||||
}
|
||||
.osdheaderbar {
|
||||
background: transparent;
|
||||
}
|
||||
@@ -34,18 +50,18 @@ radio {
|
||||
.linkedright image {
|
||||
margin-right: 2px;
|
||||
}
|
||||
/* Non-osd style for popover menu */
|
||||
.menupopover label {
|
||||
color: @theme_text_color;
|
||||
|
||||
/* Flat popovers */
|
||||
popover arrow,
|
||||
popover contents {
|
||||
border-color: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
.menupopover arrow {
|
||||
background: @theme_base_color;
|
||||
border-color: @insensitive_base_color;
|
||||
}
|
||||
.menupopover contents {
|
||||
background: @theme_base_color;
|
||||
border-color: @insensitive_base_color;
|
||||
.popoverseparator separator {
|
||||
background-color: @insensitive_fg_color;
|
||||
}
|
||||
|
||||
/* Rounded corners */
|
||||
.adwrounded.csd {
|
||||
border-radius: 8px;
|
||||
}
|
||||
@@ -61,8 +77,15 @@ radio {
|
||||
.roundedcorners {
|
||||
border-radius: 8px;
|
||||
}
|
||||
.adwthemedark scale trough highlight {
|
||||
filter: brightness(120%);
|
||||
|
||||
/* Reduce sliders size */
|
||||
scale trough slider {
|
||||
min-height: 18px;
|
||||
min-width: 18px;
|
||||
}
|
||||
.fullscreen.tvmode scale trough slider {
|
||||
min-height: 20px;
|
||||
min-width: 20px;
|
||||
}
|
||||
|
||||
.videowidget {
|
||||
@@ -70,34 +93,39 @@ radio {
|
||||
min-height: 180px;
|
||||
}
|
||||
|
||||
.tvmode popover box {
|
||||
.fullscreen.tvmode popover box {
|
||||
text-shadow: none;
|
||||
font-size: 21px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.adwicons .playercontrols {
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
.playercontrols {
|
||||
.clappercontrols {
|
||||
margin-left: 2px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
.playercontrols button {
|
||||
.fullscreen.tvmode .clappercontrols {
|
||||
margin-left: 1px;
|
||||
margin-right: 1px;
|
||||
}
|
||||
.clappercontrolsbutton {
|
||||
margin: 3px;
|
||||
margin-left: 1px;
|
||||
margin-right: 1px;
|
||||
}
|
||||
.tvmode .playercontrols button {
|
||||
.fullscreen.tvmode .clappercontrolsbutton {
|
||||
min-width: 32px;
|
||||
min-height: 32px;
|
||||
margin: 5px;
|
||||
margin-left: 3px;
|
||||
margin-right: 3px;
|
||||
margin-left: 4px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
.tvmode button image {
|
||||
.clappercontrolsbutton.text-button {
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
}
|
||||
.fullscreen.tvmode button image {
|
||||
-gtk-icon-shadow: none;
|
||||
}
|
||||
.tvmode radio {
|
||||
.fullscreen.tvmode radio {
|
||||
margin-left: 0px;
|
||||
margin-right: 4px;
|
||||
border: 2px solid;
|
||||
@@ -105,38 +133,30 @@ radio {
|
||||
min-height: 17px;
|
||||
}
|
||||
|
||||
.tvmode .playercontrols button image {
|
||||
-gtk-icon-size: 24px;
|
||||
/* Also affects popover buttons */
|
||||
.fullscreen.tvmode .clappercontrols button image {
|
||||
-gtk-icon-size: 26px;
|
||||
}
|
||||
.adwicons .playbackicon {
|
||||
-gtk-icon-size: 20px;
|
||||
}
|
||||
.adwicons.tvmode .playbackicon {
|
||||
-gtk-icon-size: 28px;
|
||||
}
|
||||
.labelbuttonlabel {
|
||||
margin-left: -4px;
|
||||
margin-right: -4px;
|
||||
min-width: 8px;
|
||||
.clappercontrolsbutton.text-button label {
|
||||
font-family: 'Cantarell', sans-serif;
|
||||
font-variant-numeric: tabular-nums;
|
||||
font-weight: 600;
|
||||
}
|
||||
.tvmode .labelbuttonlabel {
|
||||
.fullscreen.tvmode .clappercontrolsbutton.text-button label {
|
||||
font-size: 22px;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
/* Top Revealer */
|
||||
.tvmode .revealertopgrid {
|
||||
.fullscreen.tvmode .revealertopgrid {
|
||||
font-family: 'Cantarell', sans-serif;
|
||||
}
|
||||
.tvmode .tvtitle {
|
||||
.fullscreen.tvmode .tvtitle {
|
||||
font-size: 28px;
|
||||
font-weight: 500;
|
||||
text-shadow: none;
|
||||
}
|
||||
.tvtime {
|
||||
.fullscreen.tvmode .tvtime {
|
||||
margin-top: -2px;
|
||||
margin-bottom: -2px;
|
||||
min-height: 4px;
|
||||
@@ -144,7 +164,7 @@ radio {
|
||||
font-weight: 700;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.tvendtime {
|
||||
.fullscreen.tvmode .tvendtime {
|
||||
margin-top: -4px;
|
||||
margin-bottom: 2px;
|
||||
min-height: 6px;
|
||||
@@ -153,29 +173,27 @@ radio {
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
/* Button Inside Popover */
|
||||
.popoverbutton {
|
||||
min-width: 24px;
|
||||
min-height: 24px;
|
||||
}
|
||||
|
||||
/* Position Scale */
|
||||
.positionscale {
|
||||
margin: -2px;
|
||||
margin-left: -4px;
|
||||
margin-right: -4px;
|
||||
}
|
||||
.positionscale trough highlight {
|
||||
min-height: 4px;
|
||||
}
|
||||
.osd .positionscale trough highlight {
|
||||
min-height: 6px;
|
||||
}
|
||||
.tvmode .positionscale trough slider {
|
||||
.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;
|
||||
@@ -183,11 +201,11 @@ radio {
|
||||
.positionscale.fine-tune mark indicator {
|
||||
min-height: 6px;
|
||||
}
|
||||
.tvmode .positionscale mark indicator {
|
||||
.fullscreen.tvmode .positionscale mark indicator {
|
||||
min-height: 7px;
|
||||
min-width: 2px;
|
||||
}
|
||||
.tvmode .positionscale.fine-tune mark indicator {
|
||||
.fullscreen.tvmode .positionscale.fine-tune mark indicator {
|
||||
min-height: 7px;
|
||||
min-width: 2px;
|
||||
}
|
||||
@@ -199,17 +217,20 @@ radio {
|
||||
margin-top: 4px;
|
||||
margin-bottom: -6px;
|
||||
}
|
||||
.tvmode .positionscale marks.top {
|
||||
.fullscreen.tvmode .positionscale marks.top {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.tvmode .positionscale marks.bottom {
|
||||
.fullscreen.tvmode .positionscale marks.bottom {
|
||||
margin-top: 2px;
|
||||
}
|
||||
.tvmode .positionscale trough highlight {
|
||||
.fullscreen.tvmode .positionscale trough {
|
||||
border-radius: 3px;
|
||||
}
|
||||
.fullscreen.tvmode .positionscale trough highlight {
|
||||
border-radius: 3px;
|
||||
min-height: 20px;
|
||||
}
|
||||
.tvmode .positionscale.fine-tune trough highlight {
|
||||
.fullscreen.tvmode .positionscale.fine-tune trough highlight {
|
||||
border-radius: 3px;
|
||||
min-height: 20px;
|
||||
}
|
||||
@@ -221,7 +242,7 @@ radio {
|
||||
margin-right: -6px;
|
||||
min-height: 180px;
|
||||
}
|
||||
.tvmode .volumescale {
|
||||
.fullscreen.tvmode .volumescale {
|
||||
margin: 2px;
|
||||
margin-left: -6px;
|
||||
margin-right: -4px;
|
||||
@@ -232,7 +253,10 @@ radio {
|
||||
margin-top: -4px;
|
||||
margin-bottom: -6px;
|
||||
}
|
||||
.tvmode .volumescale trough highlight {
|
||||
.volumescale trough highlight {
|
||||
min-width: 4px;
|
||||
}
|
||||
.fullscreen.tvmode .volumescale trough highlight {
|
||||
min-width: 6px;
|
||||
}
|
||||
.overamp trough highlight {
|
||||
@@ -240,16 +264,23 @@ radio {
|
||||
}
|
||||
|
||||
/* Elapsed Popover */
|
||||
.elapsedpopoverbox {
|
||||
min-width: 260px;
|
||||
.elapsedpopover {
|
||||
min-width: 326px;
|
||||
}
|
||||
.elapsedpopoverbox box separator {
|
||||
background: @insensitive_fg_color;
|
||||
.fullscreen.tvmode .elapsedpopover {
|
||||
min-width: 448px;
|
||||
}
|
||||
.tvmode .elapsedpopoverbox {
|
||||
min-width: 360px;
|
||||
.elapsedpopover contents {
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
.tvmode .speedscale trough highlight {
|
||||
.speedscale {
|
||||
margin-left: 4px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
.speedscale trough highlight {
|
||||
min-height: 4px;
|
||||
}
|
||||
.fullscreen.tvmode .speedscale trough highlight {
|
||||
min-height: 6px;
|
||||
}
|
||||
|
||||
@@ -272,33 +303,16 @@ radio {
|
||||
.chapterlabel {
|
||||
min-width: 32px;
|
||||
}
|
||||
.tvmode .chapterlabel {
|
||||
.fullscreen.tvmode .chapterlabel {
|
||||
min-width: 40px;
|
||||
text-shadow: none;
|
||||
font-size: 22px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Preferences */
|
||||
.prefsnotebook grid {
|
||||
margin: 10px;
|
||||
}
|
||||
.prefssubpage header {
|
||||
background: none;
|
||||
}
|
||||
.prefssubpage header tabs tab {
|
||||
box-shadow: none;
|
||||
margin: 0px;
|
||||
margin-right: 1px;
|
||||
}
|
||||
.prefssubpage header tabs tab:checked {
|
||||
color: initial;
|
||||
background: @theme_selected_bg_color;
|
||||
}
|
||||
|
||||
/* Open URI Dialog */
|
||||
.uridialogbox {
|
||||
margin: 12px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
/* Tweaks */
|
||||
@@ -314,7 +328,7 @@ radio {
|
||||
.gpufriendly {
|
||||
box-shadow: -8px -8px transparent, 8px 8px transparent;
|
||||
}
|
||||
.gpufriendlyfs {
|
||||
.fullscreen.gpufriendlyfs {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
@@ -322,3 +336,52 @@ radio {
|
||||
.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 */
|
||||
}
|
||||
|
115
data/com.github.rafostar.Clapper-symbolic.svg
Normal file
@@ -0,0 +1,115 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 4.2333333 4.2333334"
|
||||
version="1.1"
|
||||
id="svg5"
|
||||
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
|
||||
sodipodi:docname="com.github.rafostar.Clapper-symbolic.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview7"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:document-units="mm"
|
||||
showgrid="false"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true"
|
||||
inkscape:snap-bbox-midpoints="true"
|
||||
inkscape:object-paths="true"
|
||||
inkscape:snap-intersection-paths="true"
|
||||
inkscape:snap-smooth-nodes="true"
|
||||
inkscape:snap-midpoints="true"
|
||||
inkscape:snap-global="false"
|
||||
units="px"
|
||||
inkscape:zoom="32"
|
||||
inkscape:cx="6.078125"
|
||||
inkscape:cy="8.09375"
|
||||
inkscape:window-width="1680"
|
||||
inkscape:window-height="981"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs2">
|
||||
<inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect1853"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
satellites_param="F,0,0,1,0,1.8520833,0,1 @ F,0,0,1,0,1.8520833,0,1 @ F,0,0,1,0,1.8520833,0,1 @ F,0,0,1,0,1.8520833,0,1"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
radius="7"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" />
|
||||
<inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect1732"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
satellites_param="F,0,0,1,0,1.8520833,0,1 @ F,0,0,1,0,1.8520833,0,1 @ F,0,0,1,0,1.8520833,0,1 @ F,0,0,1,0,1.8520833,0,1"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
radius="7"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" />
|
||||
</defs>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<g
|
||||
id="g2022"
|
||||
transform="matrix(0.06169519,0,0,0.06168906,-4.7800087,-3.2713603)">
|
||||
<path
|
||||
id="rect973"
|
||||
style="fill:#000000;stroke-width:1.30776;stroke-linecap:round;stroke-linejoin:round;paint-order:stroke markers fill"
|
||||
d="m 88.193064,81.795006 c -0.699254,0 -1.342327,0.227875 -1.864484,0.609782 h 51.32503 c -0.52216,-0.381907 -1.16471,-0.609782 -1.86397,-0.609782 z m -3.157945,10.475846 v 26.225278 c 0,1.74939 1.40856,3.15743 3.157945,3.15743 h 47.596576 c 1.74939,0 3.15795,-1.40804 3.15795,-3.15743 V 92.270852 Z m 20.323311,4.964038 15.40009,9.27283 -15.5205,9.56634 z" />
|
||||
<path
|
||||
style="fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 83.974394,69.464471 7.344033,-0.06509 a 2.7923103,2.7923103 33.047712 0 1 2.587466,1.683384 l 7.009937,16.201526 a 1.2163248,1.2163248 123.30899 0 1 -1.116623,1.699322 l -15.720141,-0.004 a 1.862525,1.862525 44.853691 0 1 -1.862019,-1.852534 l -0.08473,-15.79409 a 1.8585738,1.8585738 134.59241 0 1 1.842075,-1.868472 z"
|
||||
id="path1422"
|
||||
inkscape:path-effect="#path-effect1732"
|
||||
inkscape:original-d="m 82.122383,69.480886 11.048055,-0.09792 8.480852,19.601124 -19.424307,-0.005 z" />
|
||||
<rect
|
||||
style="fill:#000000;stroke-width:1.3;stroke-linecap:round;stroke-linejoin:round;paint-order:stroke markers fill"
|
||||
id="rect1544"
|
||||
width="59.366463"
|
||||
height="9.8661175"
|
||||
x="82"
|
||||
y="79.292183"
|
||||
ry="1.2306831" />
|
||||
<path
|
||||
id="rect1847"
|
||||
style="fill:#000000;stroke-width:4.91339;stroke-linecap:round;stroke-linejoin:round;paint-order:stroke markers fill"
|
||||
d="m 522.12695,200.42773 c -0.45798,3.8e-4 -0.92335,0.0696 -1.38476,0.21289 l -172.88672,53.70313 5.28515,-0.0469 a 10.55362,10.55362 0 0 1 9.7793,6.36328 l 10.69922,24.72656 158.18359,-49.13477 c 2.46089,-0.7644 3.82691,-3.36137 3.0625,-5.82226 l -8.30078,-26.72657 c -0.62108,-1.99947 -2.4529,-3.277 -4.4375,-3.27539 z m -203.69531,63.05469 -3.08398,0.95899 c -2.46089,0.7644 -3.82691,3.35942 -3.0625,5.82031 l 6.29101,20.2539 z"
|
||||
transform="scale(0.26458333)" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.8 KiB |
9
data/com.github.rafostar.Clapper.data.gresource.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?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>
|
@@ -6,31 +6,31 @@
|
||||
<default>false</default>
|
||||
<summary>Automatically enter fullscreen when first file is loaded</summary>
|
||||
</key>
|
||||
<key name="volume-initial" type="s">
|
||||
<default>"restore"</default>
|
||||
<summary>Mode used for startup volume value</summary>
|
||||
<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="close-auto" type="b">
|
||||
<default>false</default>
|
||||
<summary>Automatically close the app after playback finishes</summary>
|
||||
<key name="after-playback" type="i">
|
||||
<default>0</default>
|
||||
<summary>What to do after playback finishes</summary>
|
||||
</key>
|
||||
|
||||
<!-- Behaviour -->
|
||||
<key name="seeking-mode" type="s">
|
||||
<default>"normal"</default>
|
||||
<!-- 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="s">
|
||||
<default>"second"</default>
|
||||
<summary>Unit to use with seeking value</summary>
|
||||
<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>
|
||||
@@ -46,16 +46,12 @@
|
||||
</key>
|
||||
|
||||
<!-- Audio -->
|
||||
<key name="audio-offset" type="d">
|
||||
<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-offset" type="d">
|
||||
<default>0</default>
|
||||
<summary>Offset time for subtitle tracks relative to video (milliseconds)</summary>
|
||||
</key>
|
||||
<key name="subtitle-font" type="s">
|
||||
<default>"Sans 12"</default>
|
||||
<summary>The subtitles font description</summary>
|
||||
@@ -91,20 +87,22 @@
|
||||
|
||||
<!-- GStreamer -->
|
||||
<key name="plugin-ranking" type="s">
|
||||
<default>'[{"apply":false,"name":"vah264dec","rank":300}]'</default>
|
||||
<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>
|
||||
|
||||
<!-- YouTube -->
|
||||
<key name="yt-adaptive-enabled" type="b">
|
||||
<default>false</default>
|
||||
<summary>Enable to use adaptive streaming</summary>
|
||||
</key>
|
||||
|
||||
<!-- Other -->
|
||||
<key name="window-size" type="s">
|
||||
<default>'[800, 490]'</default>
|
||||
|
@@ -9,24 +9,20 @@
|
||||
<launchable type="desktop-id">com.github.rafostar.Clapper.desktop</launchable>
|
||||
<description>
|
||||
<p>
|
||||
Clapper is a GNOME media player build using GJS with GTK4 toolkit.
|
||||
Clapper is a GNOME media player built using GJS with GTK4 toolkit.
|
||||
The media player is using GStreamer as a media backend and renders
|
||||
everything via OpenGL. Player works natively on both Xorg and Wayland.
|
||||
It also supports VA-API on AMD/Intel GPUs.
|
||||
It also supports hardware acceleration through VA-API on AMD/Intel GPUs,
|
||||
NVDEC on Nvidia and V4L2 on mobile devices.
|
||||
</p>
|
||||
<p>
|
||||
The media player has an adaptive GUI. When viewing videos in "Windowed Mode",
|
||||
Clapper will use mostly unmodified GTK widgets to match your OS look nicely.
|
||||
When player enters "Fullscreen Mode" all GUI elements will become darker, bigger
|
||||
and semi-transparent for your viewing comfort. It also has a "Floating Mode" which
|
||||
displays video only on top of all other windows for a PiP-like viewing experience.
|
||||
displays only video on top of all other windows for a PiP-like viewing experience.
|
||||
Mobile friendly transitions are also supported.
|
||||
</p>
|
||||
<p>
|
||||
For best stability Wayland session is recommended. Wayland users with AMD/Intel GPUs
|
||||
can try enabling HIGHLY EXPERIMENTAL "vah264dec" plugin inside player preferences
|
||||
for reduced CPU and GPU usage on standard (8-bit) H.264 videos.
|
||||
</p>
|
||||
</description>
|
||||
<developer_name>Rafał Dzięgiel</developer_name>
|
||||
<url type="homepage">https://rafostar.github.io/clapper</url>
|
||||
@@ -52,6 +48,109 @@
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<releases>
|
||||
<release version="0.4.1" date="2021-12-20">
|
||||
<description>
|
||||
<p>Fixes:</p>
|
||||
<ul>
|
||||
<li>Compatibility with more recent libadwaita versions</li>
|
||||
<li>Toggle mute with M button alone</li>
|
||||
<li>Allow handling YouTube with external GStreamer plugins</li>
|
||||
<li>Fix catching errors when reading clipboard</li>
|
||||
<li>Fix missing translator-credits</li>
|
||||
<li>Fix missing gio-unix-2.0 dep</li>
|
||||
<li>Fix playback pausing when entering fullscreen with touchscreen</li>
|
||||
<li>Fix GST_PLUGIN_FEATURE_RANK env usage</li>
|
||||
<li>Fix video/audio decoder change detection</li>
|
||||
<li>Merge global video tags instead replacing them</li>
|
||||
<li>Few other misc bug fixes</li>
|
||||
</ul>
|
||||
<p>New translations:</p>
|
||||
<ul>
|
||||
<li>Chinese Simplified</li>
|
||||
<li>Czech</li>
|
||||
<li>Hungarian</li>
|
||||
<li>Portuguese</li>
|
||||
<li>Portuguese, Brazilian</li>
|
||||
<li>Russian</li>
|
||||
<li>Spanish</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="0.4.0" date="2021-09-12">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Now uses libadwaita</li>
|
||||
<li>New and adaptive preferences window</li>
|
||||
<li>Improved open URI dialog</li>
|
||||
<li>Few small tweaks to fullscreen UI design</li>
|
||||
<li>Show current video and audio decoders in popovers (easy way to check if HW accel is used)</li>
|
||||
<li>Enabled NVDEC hardware acceleration by default (requires Nvidia proprietary drivers)</li>
|
||||
<li>Added option to use PipeWire for audio output (experimental)</li>
|
||||
<li>Added option to use playbin3 element (experimental)</li>
|
||||
<li>New PiP icon from icon development kit</li>
|
||||
<li>Improved performance on devices running OpenGL ES</li>
|
||||
<li>Translations support</li>
|
||||
<li>Various bug fixes</li>
|
||||
</ul>
|
||||
<p>New keyboard shortcuts:</p>
|
||||
<ul>
|
||||
<li>Leave fullscreen with Escape key</li>
|
||||
<li>Toggle mute with Ctrl+M</li>
|
||||
</ul>
|
||||
<p>More touchscreen gestures:</p>
|
||||
<ul>
|
||||
<li>Toggle playback with a long press</li>
|
||||
<li>Switch playlist items via double tap on screen side</li>
|
||||
</ul>
|
||||
<p>New translations:</p>
|
||||
<ul>
|
||||
<li>Catalan</li>
|
||||
<li>Dutch</li>
|
||||
<li>German</li>
|
||||
<li>Italian</li>
|
||||
<li>Polish</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="0.3.0" date="2021-06-18">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Added MPRIS support</li>
|
||||
<li>Added repeat modes: single video, whole playlist and shuffle</li>
|
||||
<li>Support opening folders with media files</li>
|
||||
<li>Append playlist items by holding Ctrl while doing Drag and Drop</li>
|
||||
<li>Improved handling of keyboard shortcuts</li>
|
||||
<li>Added more keyboard shortcuts</li>
|
||||
<li>Added window that shows available keyboard shortcuts</li>
|
||||
<li>Show black screen by default after playback (make showing last frame optional instead)</li>
|
||||
<li>Added ability to export playlist to file</li>
|
||||
<li>Improve handling of changing displays with different resolutions</li>
|
||||
<li>Added support for EGL under x11 with GTK 4.3.1 or later</li>
|
||||
<li>Added missing symbolic app icon</li>
|
||||
<li>Some misc bug fixes and code cleanups</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="0.2.1" date="2021-04-19">
|
||||
<description>
|
||||
<p>Player:</p>
|
||||
<ul>
|
||||
<li>Fix missing top left menu buttons on some system configurations</li>
|
||||
<li>Fix potential video sink deadlock</li>
|
||||
<li>Do not show mobile controls transition on launch</li>
|
||||
<li>Show tooltip with full playlist item text on hover</li>
|
||||
</ul>
|
||||
<p>YouTube:</p>
|
||||
<ul>
|
||||
<li>Auto select best matching resolution for used monitor</li>
|
||||
<li>Added some YouTube related preferences</li>
|
||||
<li>Added support for live HLS videos</li>
|
||||
<li>Added support for non-adaptive live HLS streaming</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="0.2.0" date="2021-04-13">
|
||||
<description>
|
||||
<p>New features:</p>
|
||||
@@ -84,6 +183,14 @@
|
||||
</release>
|
||||
</releases>
|
||||
<content_rating type="oars-1.1" />
|
||||
<recommends>
|
||||
<control>keyboard</control>
|
||||
<control>pointing</control>
|
||||
<control>touch</control>
|
||||
</recommends>
|
||||
<requires>
|
||||
<display_length compare="ge">small</display_length>
|
||||
</requires>
|
||||
<custom>
|
||||
<value key="Purism::form_factor">workstation</value>
|
||||
<value key="Purism::form_factor">mobile</value>
|
||||
|
@@ -1,29 +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 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" id="b1nGq5BrLC"></path>
|
||||
<path 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" id="a3jkaoNn4k"></path>
|
||||
<path d="M174.59 135.18L211.87 98.05L171.07 98.05L133.78 135.18L174.59 135.18Z" id="atpVQ8mnd"></path>
|
||||
<path d="M76.81 135.18L114.1 98.05L73.13 98.05L35.84 135.18L76.81 135.18Z" id="bMtYoNHu0"></path>
|
||||
<path 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" id="b5oP0Glp4"></path>
|
||||
<path d="M176.51 54.37L129.94 29.4L169.15 17.56L215.72 42.52L176.51 54.37Z" id="lwBgev6DR"></path>
|
||||
<path d="M81.61 83.49L35.04 58.69L74.25 46.69L120.82 71.49L81.61 83.49Z" id="cUsjEMRUu"></path>
|
||||
<path 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" id="c1bcHZGXe"></path>
|
||||
<path 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" id="f2PtH0V1vC"></path>
|
||||
<path 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" id="a1SvrrkqVm"></path>
|
||||
<path d="M104.22 162.46L104.22 234.46L163.22 198.54L104.22 162.46Z" id="agXcvKqh8"></path>
|
||||
<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"></use></g>
|
||||
<g><use xlink:href="#a3jkaoNn4k" fill="#4747d1"></use></g>
|
||||
<g><use xlink:href="#atpVQ8mnd" fill="#f1f1f1"></use></g>
|
||||
<g><use xlink:href="#bMtYoNHu0" fill="#f1f1f1"></use></g>
|
||||
<g><use xlink:href="#b5oP0Glp4" fill="#4747d1"></use></g>
|
||||
<g><use xlink:href="#lwBgev6DR" fill="#f1f1f1"></use></g>
|
||||
<g><use xlink:href="#cUsjEMRUu" fill="#f1f1f1"></use></g>
|
||||
<g><use xlink:href="#c1bcHZGXe" fill="#a9a9a9"></use></g>
|
||||
<g><use xlink:href="#f2PtH0V1vC" opacity="0.2" fill="#000000"></use></g>
|
||||
<g><use xlink:href="#a1SvrrkqVm" opacity="0.2" fill="#000000"></use></g>
|
||||
<g><use xlink:href="#agXcvKqh8" fill="#f1f1f1"></use></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>
|
||||
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.8 KiB |
52
data/gstclapper-mpris-gdbus.xml
Normal file
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<node>
|
||||
<interface name="org.mpris.MediaPlayer2">
|
||||
<method name="Raise"/>
|
||||
<method name="Quit"/>
|
||||
<property name="CanQuit" type="b" access="read"/>
|
||||
<property name="Fullscreen" type="b" access="readwrite"/>
|
||||
<property name="CanSetFullscreen" type="b" access="read"/>
|
||||
<property name="CanRaise" type="b" access="read"/>
|
||||
<property name="HasTrackList" type="b" access="read"/>
|
||||
<property name="Identity" type="s" access="read"/>
|
||||
<property name="DesktopEntry" type="s" access="read"/>
|
||||
<property name="SupportedUriSchemes" type="as" access="read"/>
|
||||
<property name="SupportedMimeTypes" type="as" access="read"/>
|
||||
</interface>
|
||||
<interface name="org.mpris.MediaPlayer2.Player">
|
||||
<method name="Next"/>
|
||||
<method name="Previous"/>
|
||||
<method name="Pause"/>
|
||||
<method name="PlayPause"/>
|
||||
<method name="Stop"/>
|
||||
<method name="Play"/>
|
||||
<method name="Seek">
|
||||
<arg name="Offset" type="x" direction="in"/>
|
||||
</method>
|
||||
<method name="SetPosition">
|
||||
<arg name="TrackId" type="o" direction="in"/>
|
||||
<arg name="Position" type="x" direction="in"/>
|
||||
</method>
|
||||
<method name="OpenUri">
|
||||
<arg name="Uri" type="s" direction="in"/>
|
||||
</method>
|
||||
<signal name="Seeked">
|
||||
<arg type="x" name="Position"/>
|
||||
</signal>
|
||||
<property name="PlaybackStatus" type="s" access="read"/>
|
||||
<property name="LoopStatus" type="s" access="readwrite"/>
|
||||
<property name="Rate" type="d" access="readwrite"/>
|
||||
<property name="Shuffle" type="b" access="readwrite"/>
|
||||
<property name="Metadata" type="a{sv}" access="read"/>
|
||||
<property name="Volume" type="d" access="readwrite"/>
|
||||
<property name="Position" type="x" access="read"/>
|
||||
<property name="MinimumRate" type="d" access="read"/>
|
||||
<property name="MaximumRate" type="d" access="read"/>
|
||||
<property name="CanGoNext" type="b" access="read"/>
|
||||
<property name="CanGoPrevious" type="b" access="read"/>
|
||||
<property name="CanPlay" type="b" access="read"/>
|
||||
<property name="CanPause" type="b" access="read"/>
|
||||
<property name="CanSeek" type="b" access="read"/>
|
||||
<property name="CanControl" type="b" access="read"/>
|
||||
</interface>
|
||||
</node>
|
7
data/icons/pause-symbolic.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<?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>
|
After Width: | Height: | Size: 262 B |
112
data/icons/pip-in-symbolic.svg
Normal file
@@ -0,0 +1,112 @@
|
||||
<?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>
|
After Width: | Height: | Size: 4.6 KiB |
112
data/icons/pip-out-symbolic.svg
Normal file
@@ -0,0 +1,112 @@
|
||||
<?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>
|
After Width: | Height: | Size: 4.7 KiB |
4
data/icons/play-symbolic.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<?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>
|
After Width: | Height: | Size: 480 B |
@@ -1,18 +1,34 @@
|
||||
sharedir = join_paths(get_option('prefix'), 'share')
|
||||
iconsdir = join_paths(sharedir, 'icons', 'hicolor')
|
||||
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(sharedir, 'glib-2.0', 'schemas')
|
||||
install_dir: join_paths(datadir, 'glib-2.0', 'schemas')
|
||||
)
|
||||
install_data('com.github.rafostar.Clapper.xml',
|
||||
install_dir: join_paths(sharedir, 'mime', 'packages')
|
||||
install_dir: join_paths(datadir, 'mime', 'packages')
|
||||
)
|
||||
install_data('com.github.rafostar.Clapper.desktop',
|
||||
install_dir: join_paths(sharedir, 'applications')
|
||||
install_dir: join_paths(datadir, 'applications')
|
||||
)
|
||||
install_data('com.github.rafostar.Clapper.metainfo.xml',
|
||||
install_dir: join_paths(sharedir, 'metainfo')
|
||||
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,
|
||||
)
|
||||
|
1
lib/gst/clapper/clapper.h
vendored
@@ -28,6 +28,7 @@
|
||||
#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__ */
|
||||
|
@@ -45,6 +45,7 @@ struct _GstClapperSubtitleInfo
|
||||
{
|
||||
GstClapperStreamInfo parent;
|
||||
|
||||
gchar *title;
|
||||
gchar *language;
|
||||
};
|
||||
|
||||
@@ -108,7 +109,7 @@ struct _GstClapperMediaInfo
|
||||
GList *video_stream_list;
|
||||
GList *subtitle_stream_list;
|
||||
|
||||
GstClockTime duration;
|
||||
GstClockTime duration;
|
||||
};
|
||||
|
||||
struct _GstClapperMediaInfoClass
|
||||
|
20
lib/gst/clapper/gstclapper-media-info.c
vendored
@@ -379,6 +379,7 @@ 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);
|
||||
@@ -392,6 +393,20 @@ gst_clapper_subtitle_info_class_init (GstClapperSubtitleInfoClass * 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
|
||||
@@ -513,6 +528,8 @@ 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);
|
||||
|
||||
@@ -767,7 +784,8 @@ gst_clapper_media_info_get_toc (const GstClapperMediaInfo * info)
|
||||
* gst_clapper_media_info_get_title:
|
||||
* @info: a #GstClapperMediaInfo
|
||||
*
|
||||
* Returns: the media title.
|
||||
* 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)
|
||||
|
5
lib/gst/clapper/gstclapper-media-info.h
vendored
@@ -170,7 +170,10 @@ GST_CLAPPER_API
|
||||
GType gst_clapper_subtitle_info_get_type (void);
|
||||
|
||||
GST_CLAPPER_API
|
||||
const gchar * gst_clapper_subtitle_info_get_language (const GstClapperSubtitleInfo* info);
|
||||
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())
|
||||
|
43
lib/gst/clapper/gstclapper-mpris-private.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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__ */
|
793
lib/gst/clapper/gstclapper-mpris.c
Normal file
@@ -0,0 +1,793 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
54
lib/gst/clapper/gstclapper-mpris.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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__ */
|
1020
lib/gst/clapper/gstclapper.c
vendored
21
lib/gst/clapper/gstclapper.h
vendored
@@ -30,6 +30,7 @@
|
||||
#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
|
||||
|
||||
@@ -153,7 +154,11 @@ GST_CLAPPER_API
|
||||
GType gst_clapper_get_type (void);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstClapper * gst_clapper_new (GstClapperVideoRenderer *video_renderer, GstClapperSignalDispatcher *signal_dispatcher);
|
||||
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);
|
||||
@@ -161,12 +166,22 @@ 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);
|
||||
@@ -213,6 +228,10 @@ void gst_clapper_set_mute (GstClapper *clapper
|
||||
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);
|
||||
|
||||
|
@@ -37,20 +37,27 @@
|
||||
GST_DEBUG_CATEGORY (gst_debug_clapper_gl_sink);
|
||||
#define GST_CAT_DEFAULT gst_debug_clapper_gl_sink
|
||||
|
||||
#define DEFAULT_FORCE_ASPECT_RATIO TRUE
|
||||
#define DEFAULT_PAR_N 0
|
||||
#define DEFAULT_PAR_D 1
|
||||
#define DEFAULT_IGNORE_TEXTURES FALSE
|
||||
#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_VIDEO_CAPS_MAKE_WITH_FEATURES
|
||||
(GST_CAPS_FEATURE_MEMORY_GL_MEMORY, "RGBA") "; "
|
||||
GST_VIDEO_CAPS_MAKE_WITH_FEATURES
|
||||
(GST_CAPS_FEATURE_MEMORY_GL_MEMORY ", "
|
||||
GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION, "RGBA")));
|
||||
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,
|
||||
@@ -63,6 +70,7 @@ static gboolean gst_clapper_gl_sink_propose_allocation (GstBaseSink * bsink,
|
||||
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,
|
||||
@@ -80,15 +88,6 @@ static GstFlowReturn gst_clapper_gl_sink_show_frame (GstVideoSink * bsink,
|
||||
static void
|
||||
gst_clapper_gl_sink_navigation_interface_init (GstNavigationInterface * iface);
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_WIDGET,
|
||||
PROP_FORCE_ASPECT_RATIO,
|
||||
PROP_PIXEL_ASPECT_RATIO,
|
||||
PROP_IGNORE_TEXTURES,
|
||||
};
|
||||
|
||||
#define gst_clapper_gl_sink_parent_class parent_class
|
||||
G_DEFINE_TYPE_WITH_CODE (GstClapperGLSink, gst_clapper_gl_sink,
|
||||
GST_TYPE_VIDEO_SINK,
|
||||
@@ -114,6 +113,7 @@ gst_clapper_gl_sink_class_init (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",
|
||||
@@ -121,24 +121,7 @@ gst_clapper_gl_sink_class_init (GstClapperGLSinkClass * klass)
|
||||
"(must only be get from the GTK main thread)",
|
||||
GTK_TYPE_WIDGET, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
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_IGNORE_TEXTURES,
|
||||
g_param_spec_boolean ("ignore-textures", "Ignore Textures",
|
||||
"When enabled, textures will be ignored and not drawn",
|
||||
DEFAULT_IGNORE_TEXTURES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
gobject_class->finalize = gst_clapper_gl_sink_finalize;
|
||||
gst_gtk_install_shared_properties (gobject_class);
|
||||
|
||||
gstelement_class->change_state = gst_clapper_gl_sink_change_state;
|
||||
|
||||
@@ -149,6 +132,7 @@ gst_clapper_gl_sink_class_init (GstClapperGLSinkClass * klass)
|
||||
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;
|
||||
|
||||
@@ -173,7 +157,9 @@ 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->ignore_textures = DEFAULT_IGNORE_TEXTURES;
|
||||
clapper_sink->keep_last_frame = DEFAULT_KEEP_LAST_FRAME;
|
||||
|
||||
clapper_sink->had_eos = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -236,15 +222,12 @@ gst_clapper_gl_sink_get_widget (GstClapperGLSink * clapper_sink)
|
||||
clapper_sink->widget = (GtkClapperGLWidget *)
|
||||
GST_CLAPPER_GL_SINK_GET_CLASS (clapper_sink)->create_widget ();
|
||||
|
||||
clapper_sink->bind_aspect_ratio =
|
||||
g_object_bind_property (clapper_sink, "force-aspect-ratio", clapper_sink->widget,
|
||||
g_object_bind_property (clapper_sink, "force-aspect-ratio", clapper_sink->widget,
|
||||
"force-aspect-ratio", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
clapper_sink->bind_pixel_aspect_ratio =
|
||||
g_object_bind_property (clapper_sink, "pixel-aspect-ratio", clapper_sink->widget,
|
||||
g_object_bind_property (clapper_sink, "pixel-aspect-ratio", clapper_sink->widget,
|
||||
"pixel-aspect-ratio", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
clapper_sink->bind_ignore_textures =
|
||||
g_object_bind_property (clapper_sink, "ignore-textures", clapper_sink->widget,
|
||||
"ignore-textures", 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. */
|
||||
@@ -290,8 +273,8 @@ gst_clapper_gl_sink_get_property (GObject * object, guint prop_id,
|
||||
case PROP_PIXEL_ASPECT_RATIO:
|
||||
gst_value_set_fraction (value, clapper_sink->par_n, clapper_sink->par_d);
|
||||
break;
|
||||
case PROP_IGNORE_TEXTURES:
|
||||
g_value_set_boolean (value, clapper_sink->ignore_textures);
|
||||
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);
|
||||
@@ -313,8 +296,8 @@ gst_clapper_gl_sink_set_property (GObject * object, guint prop_id,
|
||||
clapper_sink->par_n = gst_value_get_fraction_numerator (value);
|
||||
clapper_sink->par_d = gst_value_get_fraction_denominator (value);
|
||||
break;
|
||||
case PROP_IGNORE_TEXTURES:
|
||||
clapper_sink->ignore_textures = g_value_get_boolean (value);
|
||||
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);
|
||||
@@ -389,8 +372,10 @@ gst_clapper_gl_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
|
||||
gst_buffer_pool_config_add_option (config,
|
||||
GST_BUFFER_POOL_OPTION_GL_SYNC_META);
|
||||
|
||||
if (!gst_buffer_pool_set_config (pool, config))
|
||||
if (!gst_buffer_pool_set_config (pool, config)) {
|
||||
gst_object_unref (pool);
|
||||
goto config_failed;
|
||||
}
|
||||
}
|
||||
|
||||
/* we need at least 2 buffer because we hold on to the last one */
|
||||
@@ -451,12 +436,9 @@ gst_clapper_gl_sink_query (GstBaseSink * bsink, GstQuery * query)
|
||||
|
||||
switch (GST_QUERY_TYPE (query)) {
|
||||
case GST_QUERY_CONTEXT:
|
||||
{
|
||||
if (gst_gl_handle_context_query ((GstElement *) clapper_sink, query,
|
||||
clapper_sink->display, clapper_sink->context, clapper_sink->gtk_context))
|
||||
return TRUE;
|
||||
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;
|
||||
@@ -604,8 +586,17 @@ gst_clapper_gl_sink_change_state (GstElement * element, GstStateChange transitio
|
||||
return ret;
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||
{
|
||||
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);
|
||||
@@ -619,6 +610,16 @@ gst_clapper_gl_sink_change_state (GstElement * element, GstStateChange transitio
|
||||
}
|
||||
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)
|
||||
@@ -682,6 +683,7 @@ 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);
|
||||
|
||||
@@ -701,9 +703,34 @@ gst_clapper_gl_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
||||
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 TRUE;
|
||||
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
|
||||
|
@@ -58,15 +58,14 @@ struct _GstClapperGLSink
|
||||
|
||||
GtkClapperGLWidget *widget;
|
||||
|
||||
gboolean had_eos;
|
||||
|
||||
/* properties */
|
||||
gboolean force_aspect_ratio;
|
||||
GBinding *bind_aspect_ratio;
|
||||
|
||||
gint par_n, par_d;
|
||||
GBinding *bind_pixel_aspect_ratio;
|
||||
gboolean keep_last_frame;
|
||||
|
||||
gboolean ignore_textures;
|
||||
GBinding *bind_ignore_textures;
|
||||
|
||||
GtkWidget *window;
|
||||
gulong widget_destroy_id;
|
||||
|
103
lib/gst/clapper/gtk4/gstclapperglutils.c
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
29
lib/gst/clapper/gtk4/gstclapperglutils.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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__ */
|
@@ -19,6 +19,7 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include "gstgtkutils.h"
|
||||
|
||||
struct invoke_context
|
||||
@@ -69,3 +70,26 @@ gst_gtk_invoke_on_main (GThreadFunc func, gpointer data)
|
||||
|
||||
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));
|
||||
}
|
||||
|
@@ -22,8 +22,25 @@
|
||||
#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__ */
|
||||
|
@@ -26,14 +26,21 @@
|
||||
#include <stdio.h>
|
||||
#include <gst/gl/gstglfuncs.h>
|
||||
#include <gst/video/video.h>
|
||||
#include <gst/video/gstvideoaffinetransformationmeta.h>
|
||||
|
||||
#include "gtkclapperglwidget.h"
|
||||
#include "gstgtkutils.h"
|
||||
#include "gstclapperglutils.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
|
||||
#if GST_GL_HAVE_PLATFORM_GLX
|
||||
#include <gst/gl/x11/gstgldisplay_x11.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if GST_GL_HAVE_WINDOW_WAYLAND && defined (GDK_WINDOWING_WAYLAND)
|
||||
#include <gdk/wayland/gdkwayland.h>
|
||||
@@ -52,25 +59,27 @@
|
||||
GST_DEBUG_CATEGORY (gst_debug_clapper_gl_widget);
|
||||
#define GST_CAT_DEFAULT gst_debug_clapper_gl_widget
|
||||
|
||||
#define DEFAULT_FORCE_ASPECT_RATIO TRUE
|
||||
#define DEFAULT_PAR_N 0
|
||||
#define DEFAULT_PAR_D 1
|
||||
#define DEFAULT_IGNORE_TEXTURES FALSE
|
||||
|
||||
struct _GtkClapperGLWidgetPrivate
|
||||
{
|
||||
gboolean initiated;
|
||||
|
||||
GstGLDisplay *display;
|
||||
GdkGLContext *gdk_context;
|
||||
GstGLContext *other_context;
|
||||
GstGLContext *context;
|
||||
|
||||
GstGLTextureTarget texture_target;
|
||||
guint gl_target;
|
||||
|
||||
GstGLUpload *upload;
|
||||
GstGLShader *shader;
|
||||
|
||||
GLuint vao;
|
||||
GLuint vertex_buffer;
|
||||
GLint attr_position;
|
||||
GLint attr_texture;
|
||||
GLuint current_tex;
|
||||
|
||||
GstGLOverlayCompositor *overlay_compositor;
|
||||
};
|
||||
|
||||
@@ -90,14 +99,6 @@ G_DEFINE_TYPE_WITH_CODE (GtkClapperGLWidget, gtk_clapper_gl_widget, GTK_TYPE_GL_
|
||||
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "gtkclapperglwidget", 0,
|
||||
"GTK Clapper GL Widget"));
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_FORCE_ASPECT_RATIO,
|
||||
PROP_PIXEL_ASPECT_RATIO,
|
||||
PROP_IGNORE_TEXTURES,
|
||||
};
|
||||
|
||||
static void
|
||||
gtk_clapper_gl_widget_get_preferred_width (GtkWidget * widget, gint * min,
|
||||
gint * natural)
|
||||
@@ -151,13 +152,9 @@ gtk_clapper_gl_widget_size_allocate (GtkWidget * widget,
|
||||
GtkClapperGLWidget *clapper_widget = GTK_CLAPPER_GL_WIDGET (widget);
|
||||
gint scale_factor = gtk_widget_get_scale_factor (widget);
|
||||
|
||||
GTK_CLAPPER_GL_WIDGET_LOCK (clapper_widget);
|
||||
|
||||
clapper_widget->scaled_width = width * scale_factor;
|
||||
clapper_widget->scaled_height = height * scale_factor;
|
||||
|
||||
GTK_CLAPPER_GL_WIDGET_UNLOCK (clapper_widget);
|
||||
|
||||
gtk_gl_area_queue_render (GTK_GL_AREA (widget));
|
||||
}
|
||||
|
||||
@@ -175,8 +172,8 @@ gtk_clapper_gl_widget_set_property (GObject * object, guint prop_id,
|
||||
clapper_widget->par_n = gst_value_get_fraction_numerator (value);
|
||||
clapper_widget->par_d = gst_value_get_fraction_denominator (value);
|
||||
break;
|
||||
case PROP_IGNORE_TEXTURES:
|
||||
clapper_widget->ignore_textures = g_value_get_boolean (value);
|
||||
case PROP_KEEP_LAST_FRAME:
|
||||
clapper_widget->keep_last_frame = g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
@@ -197,8 +194,8 @@ gtk_clapper_gl_widget_get_property (GObject * object, guint prop_id,
|
||||
case PROP_PIXEL_ASPECT_RATIO:
|
||||
gst_value_set_fraction (value, clapper_widget->par_n, clapper_widget->par_d);
|
||||
break;
|
||||
case PROP_IGNORE_TEXTURES:
|
||||
g_value_set_boolean (value, clapper_widget->ignore_textures);
|
||||
case PROP_KEEP_LAST_FRAME:
|
||||
g_value_set_boolean (value, clapper_widget->keep_last_frame);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
@@ -323,6 +320,22 @@ _gdk_key_to_navigation_string (guint keyval)
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_get_is_navigation_allowed (GstElement * element, GstState min_state)
|
||||
{
|
||||
if (GST_IS_NAVIGATION (element)) {
|
||||
GstState nav_state;
|
||||
|
||||
GST_OBJECT_LOCK (element);
|
||||
nav_state = element->current_state;
|
||||
GST_OBJECT_UNLOCK (element);
|
||||
|
||||
return nav_state >= min_state;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_clapper_gl_widget_key_event (GtkEventControllerKey * key_controller,
|
||||
guint keyval, guint keycode, GdkModifierType state)
|
||||
@@ -333,7 +346,7 @@ gtk_clapper_gl_widget_key_event (GtkEventControllerKey * key_controller,
|
||||
GstElement *element;
|
||||
|
||||
if ((element = g_weak_ref_get (&clapper_widget->element))) {
|
||||
if (GST_IS_NAVIGATION (element)) {
|
||||
if (_get_is_navigation_allowed (element, GST_STATE_PAUSED)) {
|
||||
GdkEvent *event = gtk_event_controller_get_current_event (controller);
|
||||
const gchar *str = _gdk_key_to_navigation_string (keyval);
|
||||
|
||||
@@ -422,8 +435,11 @@ gtk_clapper_gl_widget_button_event (GtkGestureClick * gesture,
|
||||
GtkClapperGLWidget *clapper_widget = GTK_CLAPPER_GL_WIDGET (widget);
|
||||
GstElement *element;
|
||||
|
||||
if (clapper_widget->display_width == 0 || clapper_widget->display_height == 0)
|
||||
return FALSE;
|
||||
|
||||
if ((element = g_weak_ref_get (&clapper_widget->element))) {
|
||||
if (GST_IS_NAVIGATION (element)) {
|
||||
if (_get_is_navigation_allowed (element, GST_STATE_PLAYING)) {
|
||||
GdkEvent *event = gtk_event_controller_get_current_event (controller);
|
||||
const gchar *key_type =
|
||||
gdk_event_get_event_type (event) == GDK_BUTTON_PRESS
|
||||
@@ -452,10 +468,16 @@ gtk_clapper_gl_widget_motion_event (GtkEventControllerMotion * motion_controller
|
||||
GtkClapperGLWidget *clapper_widget = GTK_CLAPPER_GL_WIDGET (widget);
|
||||
GstElement *element;
|
||||
|
||||
if ((x == clapper_widget->last_pos_x && y == clapper_widget->last_pos_y) ||
|
||||
clapper_widget->display_width == 0 || clapper_widget->display_height == 0)
|
||||
return FALSE;
|
||||
|
||||
if ((element = g_weak_ref_get (&clapper_widget->element))) {
|
||||
if (GST_IS_NAVIGATION (element)) {
|
||||
if (_get_is_navigation_allowed (element, GST_STATE_PLAYING)) {
|
||||
gdouble stream_x, stream_y;
|
||||
|
||||
clapper_widget->last_pos_x = x;
|
||||
clapper_widget->last_pos_y = y;
|
||||
_display_size_to_stream_size (clapper_widget, x, y, &stream_x, &stream_y);
|
||||
|
||||
gst_navigation_send_mouse_event (GST_NAVIGATION (element), "mouse-move",
|
||||
@@ -467,6 +489,13 @@ gtk_clapper_gl_widget_motion_event (GtkEventControllerMotion * motion_controller
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_clapper_gl_widget_settings_changed (GtkGLArea * glarea)
|
||||
{
|
||||
GST_DEBUG ("GTK settings changed, queued render");
|
||||
gtk_gl_area_queue_render (glarea);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_clapper_gl_widget_bind_buffer (GtkClapperGLWidget * clapper_widget)
|
||||
{
|
||||
@@ -505,9 +534,42 @@ gtk_clapper_gl_widget_init_redisplay (GtkClapperGLWidget * clapper_widget)
|
||||
GtkClapperGLWidgetPrivate *priv = clapper_widget->priv;
|
||||
const GstGLFuncs *gl = priv->context->gl_vtable;
|
||||
GError *error = NULL;
|
||||
GstGLSLStage *frag_stage, *vert_stage;
|
||||
|
||||
gst_gl_insert_debug_marker (priv->other_context, "initializing redisplay");
|
||||
if (!(priv->shader = gst_gl_shader_new_default (priv->context, &error))) {
|
||||
|
||||
vert_stage = gst_glsl_stage_new_with_string (priv->context,
|
||||
GL_VERTEX_SHADER, GST_GLSL_VERSION_NONE,
|
||||
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
|
||||
gst_gl_shader_string_vertex_mat4_vertex_transform);
|
||||
if (priv->texture_target == GST_GL_TEXTURE_TARGET_EXTERNAL_OES) {
|
||||
gchar *frag_str;
|
||||
|
||||
frag_str =
|
||||
gst_gl_shader_string_fragment_external_oes_get_default
|
||||
(priv->context, GST_GLSL_VERSION_NONE,
|
||||
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY);
|
||||
frag_stage = gst_glsl_stage_new_with_string (priv->context,
|
||||
GL_FRAGMENT_SHADER, GST_GLSL_VERSION_NONE,
|
||||
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY, frag_str);
|
||||
|
||||
g_free (frag_str);
|
||||
} else {
|
||||
frag_stage = gst_glsl_stage_new_default_fragment (priv->context);
|
||||
}
|
||||
|
||||
if (!vert_stage || !frag_stage) {
|
||||
GST_ERROR ("Failed to retrieve fragment shader for texture target");
|
||||
if (vert_stage)
|
||||
gst_object_unref (vert_stage);
|
||||
if (frag_stage)
|
||||
gst_object_unref (frag_stage);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(priv->shader =
|
||||
gst_gl_shader_new_link_with_stages (priv->context, &error,
|
||||
vert_stage, frag_stage, NULL))) {
|
||||
GST_ERROR ("Failed to initialize shader: %s", error->message);
|
||||
return;
|
||||
}
|
||||
@@ -534,8 +596,9 @@ gtk_clapper_gl_widget_init_redisplay (GtkClapperGLWidget * clapper_widget)
|
||||
|
||||
gl->BindBuffer (GL_ARRAY_BUFFER, 0);
|
||||
|
||||
priv->overlay_compositor =
|
||||
gst_gl_overlay_compositor_new (priv->other_context);
|
||||
if (!priv->overlay_compositor)
|
||||
priv->overlay_compositor =
|
||||
gst_gl_overlay_compositor_new (priv->other_context);
|
||||
|
||||
priv->initiated = TRUE;
|
||||
}
|
||||
@@ -566,11 +629,14 @@ gtk_clapper_gl_widget_render (GtkGLArea * widget, GdkGLContext * context)
|
||||
GtkClapperGLWidgetPrivate *priv = clapper_widget->priv;
|
||||
const GstGLFuncs *gl;
|
||||
|
||||
GTK_CLAPPER_GL_WIDGET_LOCK (widget);
|
||||
GstVideoAffineTransformationMeta *af_meta;
|
||||
gfloat matrix[16];
|
||||
|
||||
GTK_CLAPPER_GL_WIDGET_LOCK (clapper_widget);
|
||||
|
||||
/* Draw black with GDK context when priv is not available yet.
|
||||
GTK calls render with GDK context already active. */
|
||||
if (!priv->context || !priv->other_context || clapper_widget->ignore_textures) {
|
||||
if (!priv->context || !priv->other_context || clapper_widget->ignore_buffers) {
|
||||
_draw_black_with_gdk (context);
|
||||
goto done;
|
||||
}
|
||||
@@ -653,9 +719,15 @@ gtk_clapper_gl_widget_render (GtkGLArea * widget, GdkGLContext * context)
|
||||
gtk_clapper_gl_widget_bind_buffer (clapper_widget);
|
||||
|
||||
gl->ActiveTexture (GL_TEXTURE0);
|
||||
gl->BindTexture (GL_TEXTURE_2D, priv->current_tex);
|
||||
gl->BindTexture (priv->gl_target, priv->current_tex);
|
||||
gst_gl_shader_set_uniform_1i (priv->shader, "tex", 0);
|
||||
|
||||
af_meta = gst_buffer_get_video_affine_transformation_meta (
|
||||
clapper_widget->buffer);
|
||||
gst_clapper_gl_get_affine_transformation_meta_as_ndc (af_meta, matrix);
|
||||
gst_gl_shader_set_uniform_matrix_4fv (priv->shader,
|
||||
"u_transformation", 1, FALSE, matrix);
|
||||
|
||||
gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
|
||||
|
||||
if (gl->BindVertexArray)
|
||||
@@ -663,7 +735,7 @@ gtk_clapper_gl_widget_render (GtkGLArea * widget, GdkGLContext * context)
|
||||
else
|
||||
gtk_clapper_gl_widget_unbind_buffer (clapper_widget);
|
||||
|
||||
gl->BindTexture (GL_TEXTURE_2D, 0);
|
||||
gl->BindTexture (priv->gl_target, 0);
|
||||
|
||||
/* Draw subtitles */
|
||||
gst_gl_overlay_compositor_draw_overlays (priv->overlay_compositor);
|
||||
@@ -672,15 +744,39 @@ done:
|
||||
if (priv->other_context)
|
||||
gst_gl_context_activate (priv->other_context, FALSE);
|
||||
|
||||
GTK_CLAPPER_GL_WIDGET_UNLOCK (widget);
|
||||
GTK_CLAPPER_GL_WIDGET_UNLOCK (clapper_widget);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
_reset_gl (GtkClapperGLWidget * clapper_widget)
|
||||
_cleanup_gl_private (GtkClapperGLWidgetPrivate * priv)
|
||||
{
|
||||
const GstGLFuncs *gl = priv->other_context->gl_vtable;
|
||||
|
||||
if (priv->vao) {
|
||||
gl->DeleteVertexArrays (1, &priv->vao);
|
||||
priv->vao = 0;
|
||||
}
|
||||
if (priv->vertex_buffer) {
|
||||
gl->DeleteBuffers (1, &priv->vertex_buffer);
|
||||
priv->vertex_buffer = 0;
|
||||
}
|
||||
if (priv->upload) {
|
||||
gst_object_unref (priv->upload);
|
||||
priv->upload = NULL;
|
||||
}
|
||||
if (priv->shader) {
|
||||
gst_object_unref (priv->shader);
|
||||
priv->shader = NULL;
|
||||
}
|
||||
if (priv->overlay_compositor)
|
||||
gst_gl_overlay_compositor_free_overlays (priv->overlay_compositor);
|
||||
}
|
||||
|
||||
static void
|
||||
_cleanup_gl_thread (GtkClapperGLWidget * clapper_widget)
|
||||
{
|
||||
GtkClapperGLWidgetPrivate *priv = clapper_widget->priv;
|
||||
const GstGLFuncs *gl = priv->other_context->gl_vtable;
|
||||
|
||||
if (!priv->gdk_context)
|
||||
priv->gdk_context = gtk_gl_area_get_context (GTK_GL_AREA (clapper_widget));
|
||||
@@ -691,25 +787,29 @@ _reset_gl (GtkClapperGLWidget * clapper_widget)
|
||||
gdk_gl_context_make_current (priv->gdk_context);
|
||||
gst_gl_context_activate (priv->other_context, TRUE);
|
||||
|
||||
if (priv->vao) {
|
||||
gl->DeleteVertexArrays (1, &priv->vao);
|
||||
priv->vao = 0;
|
||||
}
|
||||
_cleanup_gl_private (priv);
|
||||
|
||||
if (priv->vertex_buffer) {
|
||||
gl->DeleteBuffers (1, &priv->vertex_buffer);
|
||||
priv->vertex_buffer = 0;
|
||||
}
|
||||
gst_gl_context_activate (priv->other_context, FALSE);
|
||||
gdk_gl_context_clear_current ();
|
||||
|
||||
if (priv->upload) {
|
||||
gst_object_unref (priv->upload);
|
||||
priv->upload = NULL;
|
||||
}
|
||||
priv->initiated = FALSE;
|
||||
}
|
||||
|
||||
if (priv->shader) {
|
||||
gst_object_unref (priv->shader);
|
||||
priv->shader = NULL;
|
||||
}
|
||||
static void
|
||||
_reset_gl (GtkClapperGLWidget * clapper_widget)
|
||||
{
|
||||
GtkClapperGLWidgetPrivate *priv = clapper_widget->priv;
|
||||
|
||||
if (!priv->gdk_context)
|
||||
priv->gdk_context = gtk_gl_area_get_context (GTK_GL_AREA (clapper_widget));
|
||||
|
||||
if (priv->gdk_context == NULL)
|
||||
return;
|
||||
|
||||
gdk_gl_context_make_current (priv->gdk_context);
|
||||
gst_gl_context_activate (priv->other_context, TRUE);
|
||||
|
||||
_cleanup_gl_private (priv);
|
||||
|
||||
if (priv->overlay_compositor)
|
||||
gst_object_unref (priv->overlay_compositor);
|
||||
@@ -800,8 +900,9 @@ gtk_clapper_gl_widget_set_buffer (GtkClapperGLWidget * clapper_widget,
|
||||
GTK_CLAPPER_GL_WIDGET_UNLOCK (clapper_widget);
|
||||
}
|
||||
|
||||
static GstGLAPI
|
||||
_get_current_gl_api (GstGLPlatform platform)
|
||||
static gboolean
|
||||
_wrap_current_gl (GstGLDisplay * display, GstGLPlatform platform,
|
||||
GstGLContext ** other_context)
|
||||
{
|
||||
GstGLAPI gl_api = GST_GL_API_NONE;
|
||||
guint gl_major = 0, gl_minor = 0;
|
||||
@@ -810,11 +911,26 @@ _get_current_gl_api (GstGLPlatform platform)
|
||||
|
||||
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 OpenGL%s %d.%d", is_es ? " ES" : "", gl_major, gl_minor);
|
||||
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 ((*other_context = gst_gl_context_new_wrapped (display,
|
||||
gl_handle, platform, gl_api)))
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return gl_api;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -822,8 +938,6 @@ _get_gl_context (GtkClapperGLWidget * clapper_widget)
|
||||
{
|
||||
GtkClapperGLWidgetPrivate *priv = clapper_widget->priv;
|
||||
GstGLPlatform platform = GST_GL_PLATFORM_NONE;
|
||||
GstGLAPI gl_api = GST_GL_API_NONE;
|
||||
guintptr gl_handle = 0;
|
||||
|
||||
gtk_widget_realize (GTK_WIDGET (clapper_widget));
|
||||
|
||||
@@ -845,57 +959,45 @@ _get_gl_context (GtkClapperGLWidget * clapper_widget)
|
||||
}
|
||||
|
||||
g_object_ref (priv->gdk_context);
|
||||
|
||||
gdk_gl_context_make_current (priv->gdk_context);
|
||||
|
||||
#if GST_GL_HAVE_WINDOW_X11 && defined (GDK_WINDOWING_X11)
|
||||
if (GST_IS_GL_DISPLAY_X11 (priv->display)) {
|
||||
#if GST_GL_HAVE_PLATFORM_GLX
|
||||
if (!gl_handle) {
|
||||
platform = GST_GL_PLATFORM_GLX;
|
||||
gl_handle = gst_gl_context_get_current_gl_context (platform);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if GST_GL_HAVE_PLATFORM_EGL
|
||||
if (!gl_handle) {
|
||||
platform = GST_GL_PLATFORM_EGL;
|
||||
gl_handle = gst_gl_context_get_current_gl_context (platform);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (gl_handle) {
|
||||
gl_api = _get_current_gl_api (platform);
|
||||
priv->other_context =
|
||||
gst_gl_context_new_wrapped (priv->display, gl_handle,
|
||||
platform, gl_api);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if GST_GL_HAVE_WINDOW_WAYLAND && GST_GL_HAVE_PLATFORM_EGL && defined (GDK_WINDOWING_WAYLAND)
|
||||
if (GST_IS_GL_DISPLAY_WAYLAND (priv->display)) {
|
||||
platform = GST_GL_PLATFORM_EGL;
|
||||
gl_api = _get_current_gl_api (platform);
|
||||
gl_handle = gst_gl_context_get_current_gl_context (platform);
|
||||
if (gl_handle)
|
||||
priv->other_context =
|
||||
gst_gl_context_new_wrapped (priv->display, gl_handle,
|
||||
platform, gl_api);
|
||||
GST_DEBUG ("Using EGL on Wayland");
|
||||
goto have_platform;
|
||||
}
|
||||
#endif
|
||||
#if GST_GL_HAVE_WINDOW_X11 && defined (GDK_WINDOWING_X11)
|
||||
#if GST_GL_HAVE_PLATFORM_EGL
|
||||
if (GST_IS_GL_DISPLAY_EGL (priv->display)) {
|
||||
platform = GST_GL_PLATFORM_EGL;
|
||||
GST_DEBUG ("Using EGL on x11");
|
||||
goto have_platform;
|
||||
}
|
||||
#endif
|
||||
#if GST_GL_HAVE_PLATFORM_GLX
|
||||
if (GST_IS_GL_DISPLAY_X11 (priv->display)) {
|
||||
platform = GST_GL_PLATFORM_GLX;
|
||||
GST_DEBUG ("Using GLX on x11");
|
||||
goto have_platform;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
(void) platform;
|
||||
(void) gl_api;
|
||||
(void) gl_handle;
|
||||
GST_ERROR ("Unknown GL platform");
|
||||
return;
|
||||
|
||||
if (priv->other_context) {
|
||||
have_platform:
|
||||
|
||||
if (_wrap_current_gl (priv->display, platform, &priv->other_context)) {
|
||||
GError *error = NULL;
|
||||
|
||||
GST_INFO ("Retrieved Gdk OpenGL context %" GST_PTR_FORMAT,
|
||||
priv->other_context);
|
||||
gst_gl_context_activate (priv->other_context, TRUE);
|
||||
if (!gst_gl_context_fill_info (priv->other_context, &error)) {
|
||||
GST_ERROR ("failed to retrieve gdk context info: %s", error->message);
|
||||
GST_ERROR ("Failed to retrieve gdk context info: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
g_object_unref (priv->other_context);
|
||||
priv->other_context = NULL;
|
||||
@@ -910,35 +1012,20 @@ _get_gl_context (GtkClapperGLWidget * clapper_widget)
|
||||
static void
|
||||
gtk_clapper_gl_widget_class_init (GtkClapperGLWidgetClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_klass = (GObjectClass *) klass;
|
||||
GtkWidgetClass *widget_klass = (GtkWidgetClass *) klass;
|
||||
GtkGLAreaClass *gl_area_klass = (GtkGLAreaClass *) klass;
|
||||
GObjectClass *gobject_class = (GObjectClass *) klass;
|
||||
GtkWidgetClass *widget_class = (GtkWidgetClass *) klass;
|
||||
GtkGLAreaClass *gl_area_class = (GtkGLAreaClass *) klass;
|
||||
|
||||
gobject_klass->set_property = gtk_clapper_gl_widget_set_property;
|
||||
gobject_klass->get_property = gtk_clapper_gl_widget_get_property;
|
||||
gobject_klass->finalize = gtk_clapper_gl_widget_finalize;
|
||||
gobject_class->set_property = gtk_clapper_gl_widget_set_property;
|
||||
gobject_class->get_property = gtk_clapper_gl_widget_get_property;
|
||||
gobject_class->finalize = gtk_clapper_gl_widget_finalize;
|
||||
|
||||
g_object_class_install_property (gobject_klass, 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));
|
||||
gst_gtk_install_shared_properties (gobject_class);
|
||||
|
||||
g_object_class_install_property (gobject_klass, 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));
|
||||
widget_class->measure = gtk_clapper_gl_widget_measure;
|
||||
widget_class->size_allocate = gtk_clapper_gl_widget_size_allocate;
|
||||
|
||||
g_object_class_install_property (gobject_klass, PROP_IGNORE_TEXTURES,
|
||||
g_param_spec_boolean ("ignore-textures", "Ignore Textures",
|
||||
"When enabled, textures will be ignored and not drawn",
|
||||
DEFAULT_IGNORE_TEXTURES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
widget_klass->measure = gtk_clapper_gl_widget_measure;
|
||||
widget_klass->size_allocate = gtk_clapper_gl_widget_size_allocate;
|
||||
|
||||
gl_area_klass->render = gtk_clapper_gl_widget_render;
|
||||
gl_area_class->render = gtk_clapper_gl_widget_render;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -951,7 +1038,10 @@ gtk_clapper_gl_widget_init (GtkClapperGLWidget * clapper_widget)
|
||||
clapper_widget->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO;
|
||||
clapper_widget->par_n = DEFAULT_PAR_N;
|
||||
clapper_widget->par_d = DEFAULT_PAR_D;
|
||||
clapper_widget->ignore_textures = DEFAULT_IGNORE_TEXTURES;
|
||||
clapper_widget->keep_last_frame = DEFAULT_KEEP_LAST_FRAME;
|
||||
clapper_widget->ignore_buffers = FALSE;
|
||||
clapper_widget->last_pos_x = 0;
|
||||
clapper_widget->last_pos_y = 0;
|
||||
|
||||
gst_video_info_init (&clapper_widget->v_info);
|
||||
gst_video_info_init (&clapper_widget->pending_v_info);
|
||||
@@ -996,9 +1086,20 @@ gtk_clapper_gl_widget_init (GtkClapperGLWidget * clapper_widget)
|
||||
|
||||
#if GST_GL_HAVE_WINDOW_X11 && defined (GDK_WINDOWING_X11)
|
||||
if (GDK_IS_X11_DISPLAY (display)) {
|
||||
priv->display = (GstGLDisplay *)
|
||||
gst_gl_display_x11_new_with_display (gdk_x11_display_get_xdisplay
|
||||
(display));
|
||||
gpointer display_ptr;
|
||||
#if GST_GL_HAVE_PLATFORM_EGL && GTK_CHECK_VERSION(4,3,1)
|
||||
display_ptr = gdk_x11_display_get_egl_display (display);
|
||||
if (display_ptr)
|
||||
priv->display = (GstGLDisplay *)
|
||||
gst_gl_display_egl_new_with_egl_display (display_ptr);
|
||||
#endif
|
||||
#if GST_GL_HAVE_PLATFORM_GLX
|
||||
if (!priv->display) {
|
||||
display_ptr = gdk_x11_display_get_xdisplay (display);
|
||||
priv->display = (GstGLDisplay *)
|
||||
gst_gl_display_x11_new_with_display (display_ptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#if GST_GL_HAVE_WINDOW_WAYLAND && defined (GDK_WINDOWING_WAYLAND)
|
||||
@@ -1017,7 +1118,13 @@ gtk_clapper_gl_widget_init (GtkClapperGLWidget * clapper_widget)
|
||||
|
||||
GST_INFO ("Created %" GST_PTR_FORMAT, priv->display);
|
||||
|
||||
priv->texture_target = GST_GL_TEXTURE_TARGET_NONE;
|
||||
priv->gl_target = 0;
|
||||
|
||||
gtk_gl_area_set_auto_render (GTK_GL_AREA (widget), FALSE);
|
||||
|
||||
g_signal_connect_swapped (gtk_widget_get_settings (widget), "notify",
|
||||
G_CALLBACK (gtk_clapper_gl_widget_settings_changed), GTK_GL_AREA (widget));
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
@@ -1098,3 +1205,44 @@ gtk_clapper_gl_widget_get_display (GtkClapperGLWidget * clapper_widget)
|
||||
|
||||
return gst_object_ref (clapper_widget->priv->display);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_clapper_gl_widget_update_output_format (GtkClapperGLWidget * clapper_widget,
|
||||
GstCaps * caps)
|
||||
{
|
||||
GtkClapperGLWidgetPrivate *priv;
|
||||
GstGLTextureTarget previous_target;
|
||||
GstStructure *structure;
|
||||
const gchar *target_str;
|
||||
gboolean cleanup_gl;
|
||||
|
||||
GTK_CLAPPER_GL_WIDGET_LOCK (clapper_widget);
|
||||
priv = clapper_widget->priv;
|
||||
|
||||
previous_target = priv->texture_target;
|
||||
structure = gst_caps_get_structure (caps, 0);
|
||||
target_str = gst_structure_get_string (structure, "texture-target");
|
||||
|
||||
if (!target_str)
|
||||
target_str = GST_GL_TEXTURE_TARGET_2D_STR;
|
||||
|
||||
priv->texture_target = gst_gl_texture_target_from_string (target_str);
|
||||
if (!priv->texture_target)
|
||||
goto fail;
|
||||
|
||||
GST_DEBUG_OBJECT (clapper_widget, "Using texture-target: %s", target_str);
|
||||
priv->gl_target = gst_gl_texture_target_to_gl (priv->texture_target);
|
||||
|
||||
cleanup_gl = (previous_target != GST_GL_TEXTURE_TARGET_NONE &&
|
||||
priv->texture_target != previous_target);
|
||||
|
||||
GTK_CLAPPER_GL_WIDGET_UNLOCK (clapper_widget);
|
||||
if (cleanup_gl)
|
||||
gst_gtk_invoke_on_main ((GThreadFunc) (GCallback) _cleanup_gl_thread, clapper_widget);
|
||||
|
||||
return TRUE;
|
||||
|
||||
fail:
|
||||
GTK_CLAPPER_GL_WIDGET_UNLOCK (clapper_widget);
|
||||
return FALSE;
|
||||
}
|
||||
|
@@ -52,7 +52,7 @@ struct _GtkClapperGLWidget
|
||||
/* properties */
|
||||
gboolean force_aspect_ratio;
|
||||
gint par_n, par_d;
|
||||
gboolean ignore_textures;
|
||||
gboolean keep_last_frame;
|
||||
|
||||
gint display_width;
|
||||
gint display_height;
|
||||
@@ -61,7 +61,12 @@ struct _GtkClapperGLWidget
|
||||
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;
|
||||
@@ -95,12 +100,13 @@ gboolean gtk_clapper_gl_widget_set_format (GtkClapperGLWidget *
|
||||
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);
|
||||
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
|
||||
|
||||
|
72
lib/gst/clapper/meson.build
vendored
@@ -6,11 +6,13 @@ gstclapper_sources = [
|
||||
'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',
|
||||
@@ -23,6 +25,7 @@ gstclapper_headers = [
|
||||
'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 = [
|
||||
@@ -31,59 +34,50 @@ gstclapper_defines = [
|
||||
'-DGST_USE_UNSTABLE_API',
|
||||
'-DHAVE_GTK_GL',
|
||||
]
|
||||
gtk_deps = [gstgl_dep, gstglproto_dep]
|
||||
have_gtk_gl_windowing = false
|
||||
|
||||
gtk4_dep = dependency('gtk4', required : true)
|
||||
|
||||
if not gtk4_dep.version().version_compare('>=4.0.0')
|
||||
error('GTK4 version on this system is too old')
|
||||
if not get_option('lib')
|
||||
subdir_done()
|
||||
endif
|
||||
|
||||
if gst_gl_have_window_x11 and gst_gl_have_platform_glx
|
||||
gtk_x11_dep = dependency('gtk4-x11', required : false)
|
||||
if gtk_x11_dep.found()
|
||||
gtk_deps += [gtk_x11_dep, gstglx11_dep]
|
||||
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, gstglegl_dep, gstglwayland_dep]
|
||||
have_gtk_gl_windowing = true
|
||||
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,
|
||||
c_args : gstclapper_defines,
|
||||
link_args : noseh_link_args,
|
||||
include_directories : [configinc, libsinc],
|
||||
version : libversion,
|
||||
install : true,
|
||||
install_dir : clapper_libdir,
|
||||
dependencies : [gtk4_dep, gstbase_dep, gstvideo_dep, gstaudio_dep,
|
||||
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',
|
||||
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(clapper_libdir, 'girepository-1.0'),
|
||||
extra_args : gir_init_section + ['-DGST_USE_UNSTABLE_API'],
|
||||
dependencies : [gstbase_dep, gstvideo_dep, gstaudio_dep,
|
||||
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]
|
||||
)
|
||||
|
1
lib/gst/meson.build
vendored
@@ -1 +1,2 @@
|
||||
subdir('clapper')
|
||||
subdir('plugin')
|
||||
|
681
lib/gst/plugin/gstclappersink.c
vendored
Normal file
@@ -0,0 +1,681 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
74
lib/gst/plugin/gstclappersink.h
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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
|
71
lib/gst/plugin/gstgtkutils.c
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
26
lib/gst/plugin/gstgtkutils.h
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
gpointer gst_gtk_invoke_on_main (GThreadFunc func, gpointer data);
|
38
lib/gst/plugin/gstplugin.c
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gstclappersink.h"
|
||||
|
||||
static gboolean
|
||||
plugin_init (GstPlugin *plugin)
|
||||
{
|
||||
gboolean res = FALSE;
|
||||
|
||||
res |= GST_ELEMENT_REGISTER (clappersink, plugin);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
|
||||
clapper, "Clapper elements", plugin_init, VERSION, "LGPL",
|
||||
GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
|
960
lib/gst/plugin/gtkclapperobject.c
vendored
Normal file
@@ -0,0 +1,960 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
139
lib/gst/plugin/gtkclapperobject.h
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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
|
63
lib/gst/plugin/meson.build
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
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,
|
||||
)
|
119
lib/meson.build
vendored
@@ -1,5 +1,5 @@
|
||||
glib_req = '>= 2.56.0'
|
||||
gst_req = '>= 1.18.0'
|
||||
gst_req = '>= 1.19.1'
|
||||
|
||||
api_version = '1.0'
|
||||
libversion = meson.project_version()
|
||||
@@ -7,10 +7,6 @@ libversion = meson.project_version()
|
||||
cc = meson.get_compiler('c')
|
||||
cxx = meson.get_compiler('cpp')
|
||||
|
||||
clapper_libdir = join_paths(
|
||||
get_option('prefix'), get_option('libdir'), meson.project_name()
|
||||
)
|
||||
|
||||
cdata = configuration_data()
|
||||
|
||||
if cc.get_id() == 'msvc'
|
||||
@@ -40,7 +36,7 @@ else
|
||||
endif
|
||||
|
||||
if cc.has_link_argument('-Wl,-Bsymbolic-functions')
|
||||
add_project_link_arguments('-Wl,-Bsymbolic-functions', language : 'c')
|
||||
add_project_link_arguments('-Wl,-Bsymbolic-functions', language: 'c')
|
||||
endif
|
||||
|
||||
# Symbol visibility
|
||||
@@ -142,7 +138,7 @@ cdata.set_quoted('PACKAGE_BUGREPORT', 'https://github.com/Rafostar/clapper/issue
|
||||
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', clapper_libdir)
|
||||
cdata.set_quoted('LIBDIR', pkglibdir)
|
||||
cdata.set_quoted('LOCALEDIR', join_paths(get_option('prefix'), get_option('localedir')))
|
||||
|
||||
warning_flags = [
|
||||
@@ -192,25 +188,27 @@ 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'])
|
||||
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)
|
||||
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')
|
||||
@@ -232,53 +230,72 @@ 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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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'])
|
||||
libm = cc.find_library('m', required: false)
|
||||
glib_dep = dependency('glib-2.0', version: glib_req, fallback: ['glib', 'libglib_dep'])
|
||||
gmodule_dep = dependency('gmodule-2.0', fallback: ['glib', 'libgmodule_dep'])
|
||||
gio_dep = dependency('gio-2.0', fallback: ['glib', 'libgio_dep'])
|
||||
giounix_dep = dependency('gio-unix-2.0', version: glib_req, fallback: ['glib', 'libgiounix_dep'])
|
||||
|
||||
cdata.set('DISABLE_ORC', 1)
|
||||
cdata.set('GST_ENABLE_EXTRA_CHECKS', get_option('devel-checks'))
|
||||
cdata.set_quoted('GST_PACKAGE_RELEASE_DATETIME', 'Unknown')
|
||||
|
||||
message('GStreamer debug system is disabled')
|
||||
if cc.has_argument('-Wno-unused')
|
||||
add_project_arguments('-Wno-unused', language: 'c')
|
||||
endif
|
||||
if cxx.has_argument ('-Wno-unused')
|
||||
add_project_arguments('-Wno-unused', language: 'cpp')
|
||||
endif
|
||||
|
||||
configinc = include_directories('.')
|
||||
libsinc = include_directories('gst')
|
||||
|
||||
gnome = import('gnome')
|
||||
gir = find_program('g-ir-scanner', required : true)
|
||||
|
||||
if not gir.found()
|
||||
error('Clapper requires GI bindings to be compiled')
|
||||
endif
|
||||
|
||||
gir = find_program('g-ir-scanner')
|
||||
gir_init_section = ['--add-init-section=extern void gst_init(gint*,gchar**);' + \
|
||||
'g_setenv("GST_REGISTRY_1.0", "@0@", TRUE);'.format(meson.current_build_dir() + '/gir_empty_registry.reg') + \
|
||||
'g_setenv("GST_PLUGIN_PATH_1_0", "", TRUE);' + \
|
||||
'g_setenv("GST_PLUGIN_SYSTEM_PATH_1_0", "", TRUE);' + \
|
||||
'gst_init(NULL,NULL);', '--quiet'
|
||||
]
|
||||
|
||||
gtk_deps = [gstgl_dep, gstglproto_dep]
|
||||
have_gtk_gl_windowing = false
|
||||
|
||||
gtk4_dep = dependency('gtk4', required: true)
|
||||
|
||||
if not gtk4_dep.version().version_compare('>=4.0.0')
|
||||
error('GTK4 version on this system is too old')
|
||||
endif
|
||||
|
||||
if gst_gl_have_window_x11 and (gst_gl_have_platform_egl or gst_gl_have_platform_glx)
|
||||
gtk_x11_dep = dependency('gtk4-x11', required: false)
|
||||
if gtk_x11_dep.found()
|
||||
gtk_deps += gtk_x11_dep
|
||||
if gst_gl_have_platform_glx
|
||||
gtk_deps += gstglx11_dep
|
||||
endif
|
||||
have_gtk_gl_windowing = true
|
||||
endif
|
||||
endif
|
||||
|
||||
if gst_gl_have_window_wayland and gst_gl_have_platform_egl
|
||||
gtk_wayland_dep = dependency('gtk4-wayland', required: false)
|
||||
if gtk_wayland_dep.found()
|
||||
gtk_deps += [gtk_wayland_dep, gstglwayland_dep]
|
||||
have_gtk_gl_windowing = true
|
||||
endif
|
||||
endif
|
||||
|
||||
if gst_gl_have_platform_egl
|
||||
gtk_deps += gstglegl_dep
|
||||
endif
|
||||
|
||||
subdir('gst')
|
||||
configure_file(output : 'config.h', configuration : cdata)
|
||||
configure_file(output: 'config.h', configuration: cdata)
|
||||
|
34
meson.build
@@ -1,33 +1,41 @@
|
||||
project('com.github.rafostar.Clapper', 'c', 'cpp',
|
||||
version: '0.2.0',
|
||||
version: '0.4.1',
|
||||
meson_version: '>= 0.50.0',
|
||||
license: 'GPL3',
|
||||
license: 'GPL-3.0-or-later',
|
||||
default_options: [
|
||||
'warning_level=1',
|
||||
'buildtype=debugoptimized'
|
||||
]
|
||||
)
|
||||
|
||||
gnome = import('gnome')
|
||||
i18n = import('i18n')
|
||||
python = import('python')
|
||||
python_bin = python.find_installation('python3')
|
||||
|
||||
if not python_bin.found()
|
||||
error('No valid python3 binary found')
|
||||
endif
|
||||
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'))
|
||||
|
||||
if get_option('clapper-lib')
|
||||
pkglibdir = join_paths(libdir, meson.project_name())
|
||||
pkgdatadir = join_paths(datadir, meson.project_name())
|
||||
|
||||
if get_option('lib') or not get_option('gst-plugin').disabled()
|
||||
subdir('lib')
|
||||
endif
|
||||
|
||||
if get_option('clapper-player')
|
||||
if get_option('player')
|
||||
subdir('bin')
|
||||
subdir('data')
|
||||
subdir('po')
|
||||
|
||||
installdir = join_paths(get_option('prefix'), 'share', meson.project_name())
|
||||
install_subdir('src', install_dir : installdir)
|
||||
install_subdir('extras', install_dir : installdir)
|
||||
install_subdir('css', install_dir : installdir)
|
||||
install_subdir('ui', install_dir : installdir)
|
||||
install_subdir('src', install_dir: pkgdatadir)
|
||||
install_subdir('extras', install_dir: pkgdatadir)
|
||||
install_subdir('css', install_dir: pkgdatadir)
|
||||
install_subdir('ui', install_dir: pkgdatadir)
|
||||
|
||||
python_bin = python.find_installation('python3')
|
||||
if not python_bin.found()
|
||||
error('No valid python3 binary found')
|
||||
endif
|
||||
meson.add_install_script('build-aux/meson/postinstall.py')
|
||||
endif
|
||||
|
@@ -1,20 +1,25 @@
|
||||
option('clapper-player',
|
||||
type : 'boolean',
|
||||
value : true,
|
||||
option('player',
|
||||
type: 'boolean',
|
||||
value: true,
|
||||
description: 'Build Clapper player'
|
||||
)
|
||||
option('clapper-lib',
|
||||
type : 'boolean',
|
||||
value : true,
|
||||
description: 'Build Clapper libs (including API)'
|
||||
option('lib',
|
||||
type: 'boolean',
|
||||
value: true,
|
||||
description: 'Build GstClapper lib'
|
||||
)
|
||||
option('gst-plugin',
|
||||
type: 'feature',
|
||||
value: 'enabled',
|
||||
description: 'Build GStreamer plugin (includes GTK video sink element)'
|
||||
)
|
||||
option('devel-checks',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
type: 'boolean',
|
||||
value: false,
|
||||
description: 'GStreamer GLib checks and asserts such as API guards (disable for stable releases)'
|
||||
)
|
||||
option('deprecated-glib-api',
|
||||
type : 'boolean',
|
||||
value : true,
|
||||
type: 'boolean',
|
||||
value: true,
|
||||
description: 'Allow using of deprecated GLib API'
|
||||
)
|
||||
|
@@ -1,29 +0,0 @@
|
||||
pkgbase = clapper-git
|
||||
pkgdesc = A GNOME media player built using GJS with GTK4 toolkit and powered by GStreamer with OpenGL rendering.
|
||||
pkgver = r393.bf04af2
|
||||
pkgrel = 1
|
||||
url = https://github.com/Rafostar/clapper
|
||||
arch = any
|
||||
license = GPL-3.0
|
||||
makedepends = meson>=0.50
|
||||
makedepends = git
|
||||
depends = gtk4
|
||||
depends = gjs
|
||||
depends = glib2>=2.56.0
|
||||
depends = gobject-introspection
|
||||
depends = wayland-protocols
|
||||
depends = hicolor-icon-theme
|
||||
depends = gstreamer>=1.18.0
|
||||
depends = gst-plugins-base-libs>=1.18.0
|
||||
depends = gst-plugins-good>=1.18.0
|
||||
depends = gst-plugins-bad-libs>=1.18.0
|
||||
optdepends = gst-libav>=1.18.0: Popular video decoders
|
||||
optdepends = gstreamer-vaapi>=1.18.0: Intel/AMD video acceleration
|
||||
provides = clapper
|
||||
conflicts = clapper
|
||||
replaces = clapper
|
||||
source = clapper::git+https://github.com/Rafostar/clapper.git
|
||||
md5sums = SKIP
|
||||
|
||||
pkgname = clapper-git
|
||||
|
4
pkgs/arch/.gitignore
vendored
@@ -1,4 +0,0 @@
|
||||
clapper-*/
|
||||
clapper-*.pkg.tar.*
|
||||
pkg/
|
||||
src/
|
@@ -1,74 +0,0 @@
|
||||
#
|
||||
# PKGBUILD file for package clapper
|
||||
#
|
||||
# Copyright (C) 2020/21 sp1rit
|
||||
# Copyright (C) 2020 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/>.
|
||||
|
||||
# Maintainer: sp1rit <sp1ritCS@protonmail.com>
|
||||
|
||||
_basename=clapper
|
||||
pkgname="${_basename}-git"
|
||||
pkgver=r393.bf04af2
|
||||
pkgrel=1
|
||||
pkgdesc="A GNOME media player built using GJS with GTK4 toolkit and powered by GStreamer with OpenGL rendering."
|
||||
arch=(any)
|
||||
url="https://github.com/Rafostar/clapper"
|
||||
license=("GPL-3.0")
|
||||
depends=(
|
||||
"gtk4"
|
||||
"gjs"
|
||||
"glib2>=2.56.0" # glib-2.0, gmodule-2.0, gio-2.0
|
||||
"gobject-introspection" # /usr/sbin/g-ir-scanner
|
||||
"wayland-protocols" # gtk4 non-default runtime dep
|
||||
"hicolor-icon-theme"
|
||||
"gstreamer>=1.18.0" # gstreamer-1.0, gstreamer-base-1.0
|
||||
"gst-plugins-base-libs>=1.18.0" # gstreamer-pbutils-1.0, gstreamer-audio-1.0, gstreamer-tag-1.0, gstreamer-video-1.0, gstreamer-gl-1.0, gstreamer-gl-prototypes-1.0, gstreamer-gl-x11-1.0, gstreamer-gl-wayland-1.0, gstreamer-gl-egl-1.0,
|
||||
"gst-plugins-good>=1.18.0"
|
||||
"gst-plugins-bad-libs>=1.18.0"
|
||||
)
|
||||
makedepends=(
|
||||
"meson>=0.50"
|
||||
"git"
|
||||
)
|
||||
optdepends=(
|
||||
"gst-libav>=1.18.0: Popular video decoders"
|
||||
"gstreamer-vaapi>=1.18.0: Intel/AMD video acceleration"
|
||||
)
|
||||
source=("${_basename}::git+https://github.com/Rafostar/${_basename}.git")
|
||||
provides=("${_basename}")
|
||||
replaces=("${_basename}")
|
||||
conflicts=("${_basename}")
|
||||
md5sums=("SKIP")
|
||||
|
||||
pkgver() {
|
||||
cd "${srcdir}/${_basename}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${_basename}"
|
||||
arch-meson . _build
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${_basename}"
|
||||
ninja -C _build
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${_basename}"
|
||||
DESTDIR="$pkgdir" meson install -C _build/
|
||||
}
|
@@ -1,28 +0,0 @@
|
||||
Format: 3.0 (quilt)
|
||||
Source: clapper
|
||||
Binary: clapper
|
||||
Architecture: any
|
||||
Version: 0.2.0
|
||||
Maintainer: Rafostar <rafostar.github@gmail.com>
|
||||
Build-Depends: debhelper (>= 10),
|
||||
meson (>= 0.50),
|
||||
gjs,
|
||||
gobject-introspection,
|
||||
libgtk-4-dev (>= 4.0.0),
|
||||
libgstreamer1.0-dev (>= 1.18),
|
||||
libgstreamer-plugins-base1.0-dev (>= 1.18),
|
||||
libgstreamer-gl1.0-0 (>= 1.18),
|
||||
libgles-dev,
|
||||
libglib2.0-dev,
|
||||
libglib2.0-bin,
|
||||
desktop-file-utils,
|
||||
hicolor-icon-theme,
|
||||
brz,
|
||||
libfontconfig1-dev,
|
||||
libpam-systemd
|
||||
Package-List:
|
||||
clapper deb gnome optional arch=any
|
||||
Files:
|
||||
0 0 debian.tar.xz
|
||||
Description: Simple and modern GNOME media player
|
||||
A GNOME media player built using GJS with GTK4 toolkit and powered by GStreamer with OpenGL rendering.
|
@@ -1,5 +0,0 @@
|
||||
clapper (0.2.0) unstable; urgency=low
|
||||
|
||||
* New version
|
||||
|
||||
-- Rafostar <rafostar.github@gmail.com> Tue, 13 Apr 2021 09:39:00 +0100
|
@@ -1 +0,0 @@
|
||||
10
|
@@ -1,37 +0,0 @@
|
||||
Source: clapper
|
||||
Section: gnome
|
||||
Priority: optional
|
||||
Maintainer: Rafostar <rafostar.github@gmail.com>
|
||||
Standards-Version: 4.4.0
|
||||
Build-Depends: debhelper (>= 10),
|
||||
meson (>= 0.50),
|
||||
gjs,
|
||||
gobject-introspection,
|
||||
libgtk-4-dev (>= 4.0.0),
|
||||
libgstreamer1.0-dev (>= 1.18),
|
||||
libgstreamer-plugins-base1.0-dev (>= 1.18),
|
||||
libgstreamer-gl1.0-0 (>= 1.18),
|
||||
libgles-dev,
|
||||
libglib2.0-dev,
|
||||
libglib2.0-bin,
|
||||
desktop-file-utils,
|
||||
hicolor-icon-theme
|
||||
|
||||
Package: clapper
|
||||
Architecture: any
|
||||
Depends: gjs,
|
||||
gir1.2-gtk-4.0 (>= 4.0.0),
|
||||
hicolor-icon-theme,
|
||||
libgstreamer1.0-0 (>= 1.18),
|
||||
gstreamer1.0-plugins-base (>= 1.18),
|
||||
gstreamer1.0-plugins-good (>= 1.18),
|
||||
gstreamer1.0-plugins-bad (>= 1.18),
|
||||
gstreamer1.0-gl (>= 1.18)
|
||||
Recommends: gstreamer1.0-libav,
|
||||
gstreamer1.0-pulseaudio
|
||||
Suggests: gstreamer1.0-plugins-ugly,
|
||||
gstreamer1.0-vaapi
|
||||
Description: Simple and modern GNOME media player
|
||||
A GNOME media player built using GJS with GTK4 toolkit and powered by GStreamer with OpenGL rendering.
|
||||
.
|
||||
More codecs/features and video acceleration can be enabled by installing the suggested packages.
|
@@ -1,27 +0,0 @@
|
||||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: clapper
|
||||
Source: https://github.com/Rafostar/clapper
|
||||
|
||||
Files: *
|
||||
Copyright: 2020 Rafostar <rafostar.github@gmail.com>
|
||||
License: GPL-3.0+
|
||||
|
||||
Files: debian/*
|
||||
Copyright: 2020 Rafostar <rafostar.github@gmail.com>
|
||||
License: GPL-3.0+
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
.
|
||||
On Debian systems, the complete text of the GNU General Public License
|
||||
Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
|
@@ -1,4 +0,0 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
%:
|
||||
dh $@
|
@@ -1 +0,0 @@
|
||||
3.0 (quilt)
|
2
pkgs/flatpak/.gitignore
vendored
@@ -1,4 +1,6 @@
|
||||
build/
|
||||
builddir/
|
||||
repo/
|
||||
.flatpak-builder/
|
||||
com.github.rafostar.Clapper.flatpak
|
||||
flathub/com.github.rafostar.Clapper.json
|
||||
|
52
pkgs/flatpak/com.github.rafostar.Clapper-nightly.json
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"app-id": "com.github.rafostar.Clapper",
|
||||
"runtime": "org.gnome.Platform",
|
||||
"runtime-version": "master",
|
||||
"sdk": "org.gnome.Sdk",
|
||||
"command": "com.github.rafostar.Clapper",
|
||||
"finish-args": [
|
||||
"--share=ipc",
|
||||
"--socket=fallback-x11",
|
||||
"--socket=wayland",
|
||||
"--device=dri",
|
||||
"--socket=pulseaudio",
|
||||
"--share=network",
|
||||
"--device=all",
|
||||
"--filesystem=xdg-run/pipewire-0:ro",
|
||||
"--filesystem=xdg-videos",
|
||||
"--own-name=org.mpris.MediaPlayer2.Clapper",
|
||||
"--talk-name=org.gnome.Shell",
|
||||
"--env=GST_PLUGIN_SYSTEM_PATH=/app/lib/gstreamer-1.0",
|
||||
"--env=GST_VAAPI_ALL_DRIVERS=1"
|
||||
],
|
||||
"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",
|
||||
"flathub/lib/libdvdcss.json",
|
||||
"flathub/lib/libdvdread.json",
|
||||
"flathub/lib/libdvdnav.json",
|
||||
"flathub/lib/libass.json",
|
||||
"flathub/lib/ffmpeg.json",
|
||||
"testing/libsoup3.json",
|
||||
"testing/gstreamer.json",
|
||||
"testing/gtuber.json",
|
||||
{
|
||||
"name": "clapper",
|
||||
"buildsystem": "meson",
|
||||
"sources": [
|
||||
{
|
||||
"type": "dir",
|
||||
"path": "../../."
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"cleanup-commands": [
|
||||
"ln -s /lib/$FLATPAK_ARCH-linux-*/gstreamer-1.0/libgstpipewire.so /app/lib/gstreamer-1.0/"
|
||||
]
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"app-id": "com.github.rafostar.Clapper",
|
||||
"runtime": "org.gnome.Platform",
|
||||
"runtime-version": "40",
|
||||
"runtime-version": "41",
|
||||
"sdk": "org.gnome.Sdk",
|
||||
"command": "com.github.rafostar.Clapper",
|
||||
"finish-args": [
|
||||
@@ -12,41 +12,44 @@
|
||||
"--socket=pulseaudio",
|
||||
"--share=network",
|
||||
"--device=all",
|
||||
"--filesystem=xdg-run/pipewire-0:ro",
|
||||
"--filesystem=xdg-videos",
|
||||
"--own-name=org.mpris.MediaPlayer2.Clapper",
|
||||
"--talk-name=org.gnome.Shell",
|
||||
"--env=GST_PLUGIN_SYSTEM_PATH=/app/lib/gstreamer-1.0",
|
||||
"--env=GST_VAAPI_ALL_DRIVERS=1"
|
||||
],
|
||||
"modules": [
|
||||
"shared-modules/gudev/gudev.json",
|
||||
"lib/pango.json",
|
||||
"lib/libsass.json",
|
||||
"lib/sassc.json",
|
||||
"lib/gtk4.json",
|
||||
"lib/liba52.json",
|
||||
"lib/libmpeg2.json",
|
||||
"lib/libdvdcss.json",
|
||||
"lib/libdvdread.json",
|
||||
"lib/libdvdnav.json",
|
||||
"lib/libass.json",
|
||||
"lib/ffmpeg.json",
|
||||
"lib/uchardet.json",
|
||||
"gstreamer-1.0/gstreamer.json",
|
||||
"gstreamer-1.0/gst-plugins-base.json",
|
||||
"gstreamer-1.0/gst-plugins-good.json",
|
||||
"gstreamer-1.0/gst-plugins-bad.json",
|
||||
"gstreamer-1.0/gst-plugins-ugly.json",
|
||||
"gstreamer-1.0/gst-libav.json",
|
||||
"gstreamer-1.0/gstreamer-vaapi.json",
|
||||
"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",
|
||||
"flathub/lib/libdvdcss.json",
|
||||
"flathub/lib/libdvdread.json",
|
||||
"flathub/lib/libdvdnav.json",
|
||||
"flathub/lib/libass.json",
|
||||
"flathub/lib/ffmpeg.json",
|
||||
"flathub/lib/uchardet.json",
|
||||
"testing/libsoup3.json",
|
||||
"flathub/gstreamer-1.0/gstreamer.json",
|
||||
"flathub/lib/gtk4.json",
|
||||
"flathub/lib/libadwaita.json",
|
||||
"testing/gtuber.json",
|
||||
{
|
||||
"name": "clapper",
|
||||
"buildsystem": "meson",
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/Rafostar/clapper.git"
|
||||
"type": "dir",
|
||||
"path": "../../."
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"cleanup-commands": [
|
||||
"ln -s /lib/$FLATPAK_ARCH-linux-*/gstreamer-1.0/libgstpipewire.so /app/lib/gstreamer-1.0/"
|
||||
]
|
||||
}
|
||||
|
1
pkgs/flatpak/flathub
Submodule
@@ -1,30 +0,0 @@
|
||||
From 2c371f17af1695bd42f572d5ccdb837152b8b67a Mon Sep 17 00:00:00 2001
|
||||
From: Thomas Coldrick <othko97@gmail.com>
|
||||
Date: Thu, 8 Nov 2018 17:46:53 +0000
|
||||
Subject: [PATCH] gst-libav-stop-caching-codecs
|
||||
|
||||
---
|
||||
ext/libav/gstav.c | 16 ++++++++++++++++
|
||||
1 file changed, 16 insertions(+)
|
||||
|
||||
diff --git a/ext/libav/gstav.c b/ext/libav/gstav.c
|
||||
index 2a88230..bfd19a1 100644
|
||||
--- a/ext/libav/gstav.c
|
||||
+++ b/ext/libav/gstav.c
|
||||
@@ -155,6 +155,13 @@ plugin_init (GstPlugin * plugin)
|
||||
/* build global ffmpeg param/property info */
|
||||
gst_ffmpeg_cfg_init ();
|
||||
|
||||
+ gst_plugin_add_dependency_simple (plugin, NULL,
|
||||
+ "/app/lib",
|
||||
+ "libavcodec.so.58,"
|
||||
+ "libavformat.so.58,"
|
||||
+ "libswscale.so.5",
|
||||
+ GST_PLUGIN_DEPENDENCY_FLAG_NONE);
|
||||
+
|
||||
gst_ffmpegaudenc_register (plugin);
|
||||
gst_ffmpegvidenc_register (plugin);
|
||||
gst_ffmpegauddec_register (plugin);
|
||||
--
|
||||
2.19.1
|
||||
|
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"name": "gst-libav",
|
||||
"buildsystem": "meson",
|
||||
"config-opts": [
|
||||
"-Ddoc=disabled",
|
||||
"-Dtests=disabled"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://gitlab.freedesktop.org/gstreamer/gst-libav.git",
|
||||
"tag": "1.18.1",
|
||||
"commit": "097313530cae4a49437a779a9ded0ade8113c26b"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"path": "gst-libav-stop-caching-codecs.patch"
|
||||
}
|
||||
]
|
||||
}
|
@@ -1,89 +0,0 @@
|
||||
From ab9ceccc8b7f0591f580abfa6901d27c49812a94 Mon Sep 17 00:00:00 2001
|
||||
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
|
||||
Date: Sun, 10 Jan 2021 20:22:43 +0100
|
||||
Subject: [PATCH 1/2] assrender: fix mimetype detection
|
||||
|
||||
Previously gst_structure_has_name was used to get a string to compare with supported mimetypes.
|
||||
This is incorrect as above function returns a user defined structure name which is
|
||||
not the structure mimetype value.
|
||||
---
|
||||
ext/assrender/gstassrender.c | 21 ++++++++++++---------
|
||||
1 file changed, 12 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/ext/assrender/gstassrender.c b/ext/assrender/gstassrender.c
|
||||
index e6d31985b..a69d3fe78 100644
|
||||
--- a/ext/assrender/gstassrender.c
|
||||
+++ b/ext/assrender/gstassrender.c
|
||||
@@ -1557,7 +1557,7 @@ gst_ass_render_handle_tag_sample (GstAssRender * render, GstSample * sample)
|
||||
const GstStructure *structure;
|
||||
gboolean valid_mimetype, valid_extension;
|
||||
guint i;
|
||||
- const gchar *filename;
|
||||
+ const gchar *mimetype, *filename;
|
||||
|
||||
buf = gst_sample_get_buffer (sample);
|
||||
structure = gst_sample_get_info (sample);
|
||||
@@ -1565,20 +1565,23 @@ gst_ass_render_handle_tag_sample (GstAssRender * render, GstSample * sample)
|
||||
if (!buf || !structure)
|
||||
return;
|
||||
|
||||
+ filename = gst_structure_get_string (structure, "filename");
|
||||
+ if (!filename)
|
||||
+ return;
|
||||
+
|
||||
valid_mimetype = FALSE;
|
||||
valid_extension = FALSE;
|
||||
|
||||
- for (i = 0; i < G_N_ELEMENTS (mimetypes); i++) {
|
||||
- if (gst_structure_has_name (structure, mimetypes[i])) {
|
||||
- valid_mimetype = TRUE;
|
||||
- break;
|
||||
+ mimetype = gst_structure_get_string (structure, "mimetype");
|
||||
+ if (mimetype) {
|
||||
+ for (i = 0; i < G_N_ELEMENTS (mimetypes); i++) {
|
||||
+ if (strcmp (mimetype, mimetypes[i]) == 0) {
|
||||
+ valid_mimetype = TRUE;
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
- filename = gst_structure_get_string (structure, "filename");
|
||||
- if (!filename)
|
||||
- return;
|
||||
-
|
||||
if (!valid_mimetype) {
|
||||
guint len = strlen (filename);
|
||||
const gchar *extension = filename + len - 4;
|
||||
--
|
||||
2.28.0
|
||||
|
||||
|
||||
From fd7d46171b2abcd3ac247491f01a91444e7b95b2 Mon Sep 17 00:00:00 2001
|
||||
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
|
||||
Date: Sun, 10 Jan 2021 20:26:58 +0100
|
||||
Subject: [PATCH 2/2] assrender: add "vnd.ms-opentype" to supported mimetypes
|
||||
|
||||
The "application/vnd.ms-opentype" mimetype is commonly used mimetype
|
||||
for fonts with .otf extension, handle it without checking the file extension.
|
||||
---
|
||||
ext/assrender/gstassrender.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ext/assrender/gstassrender.c b/ext/assrender/gstassrender.c
|
||||
index a69d3fe78..96b062c50 100644
|
||||
--- a/ext/assrender/gstassrender.c
|
||||
+++ b/ext/assrender/gstassrender.c
|
||||
@@ -1546,7 +1546,8 @@ gst_ass_render_handle_tag_sample (GstAssRender * render, GstSample * sample)
|
||||
static const gchar *mimetypes[] = {
|
||||
"application/x-font-ttf",
|
||||
"application/x-font-otf",
|
||||
- "application/x-truetype-font"
|
||||
+ "application/x-truetype-font",
|
||||
+ "application/vnd.ms-opentype"
|
||||
};
|
||||
static const gchar *extensions[] = {
|
||||
".otf",
|
||||
--
|
||||
2.28.0
|
||||
|
@@ -1,30 +0,0 @@
|
||||
From 1c8538d8f8c2181106d626d67784af6db094036e Mon Sep 17 00:00:00 2001
|
||||
From: Rafostar <rafostar.github@gmail.com>
|
||||
Date: Thu, 19 Nov 2020 18:03:11 +0100
|
||||
Subject: [PATCH] assrender: fix smooth scaling by disabling hinting
|
||||
|
||||
When ass hinting value is set to anything other than NONE,
|
||||
subtitles cannot use smooth scaling, thus all animations will jitter.
|
||||
|
||||
The libass author warns about possibility of breaking some scripts when it is enabled,
|
||||
so lets do what is recommended and disable it to get the smooth scaling working.
|
||||
---
|
||||
ext/assrender/gstassrender.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ext/assrender/gstassrender.c b/ext/assrender/gstassrender.c
|
||||
index e99458bf29..111987b9d8 100644
|
||||
--- a/ext/assrender/gstassrender.c
|
||||
+++ b/ext/assrender/gstassrender.c
|
||||
@@ -916,7 +916,7 @@ gst_ass_render_negotiate (GstAssRender * render, GstCaps * caps)
|
||||
ass_set_pixel_aspect (render->ass_renderer,
|
||||
(gdouble) render->info.par_n / (gdouble) render->info.par_d);
|
||||
ass_set_font_scale (render->ass_renderer, 1.0);
|
||||
- ass_set_hinting (render->ass_renderer, ASS_HINTING_LIGHT);
|
||||
+ ass_set_hinting (render->ass_renderer, ASS_HINTING_NONE);
|
||||
|
||||
ass_set_fonts (render->ass_renderer, "Arial", "sans-serif", 1, NULL, 1);
|
||||
ass_set_fonts (render->ass_renderer, NULL, "Sans", 1, NULL, 1);
|
||||
--
|
||||
GitLab
|
||||
|
@@ -1,86 +0,0 @@
|
||||
From be0f4bc94fad9fe182c97eef389954b5f63f7092 Mon Sep 17 00:00:00 2001
|
||||
From: Jun Xie <jun.xie@samsung.com>
|
||||
Date: Sat, 4 Nov 2017 14:48:54 +0800
|
||||
Subject: [PATCH] dashdemux: fix segmentBase type with 'sidx' not using range
|
||||
download issue
|
||||
|
||||
1. for utilizing range download and enable bitrate switch
|
||||
* update fragment info after 'sidx' is downloaded and parsed,
|
||||
so that media segment's range is set by 'sidx' entry info.
|
||||
* while updating fragment info, setting range_end by 'sidx' entry size.
|
||||
|
||||
2. for singleSegmentBase type WITHOUT @indexRange explicitly presented in MPD file
|
||||
* set '*sidx_seek_needed' to true, early terminate currently no-range downloading whole file,
|
||||
then jump to the requested SIDX entry by using sidx info.
|
||||
|
||||
3. for 'ref type 1' 'sidx'
|
||||
* keep current behaviour for 'ref type 1', download as a whole file without range download
|
||||
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=788763
|
||||
|
||||
diff --git a/ext/dash/gstdashdemux.c b/ext/dash/gstdashdemux.c
|
||||
index e38240800..7554a44b2 100644
|
||||
--- a/ext/dash/gstdashdemux.c
|
||||
+++ b/ext/dash/gstdashdemux.c
|
||||
@@ -1356,7 +1356,7 @@ gst_dash_demux_stream_update_fragment_info (GstAdaptiveDemuxStream * stream)
|
||||
stream->fragment.range_start + entry->size - 1;
|
||||
dashstream->actual_position += entry->duration;
|
||||
} else {
|
||||
- stream->fragment.range_end = fragment.range_end;
|
||||
+ stream->fragment.range_end = stream->fragment.range_start + entry->size - 1;
|
||||
}
|
||||
} else {
|
||||
dashstream->actual_position = stream->fragment.timestamp =
|
||||
@@ -1572,7 +1572,7 @@ gst_dash_demux_stream_has_next_subfragment (GstAdaptiveDemuxStream * stream)
|
||||
|
||||
if (dashstream->sidx_parser.status == GST_ISOFF_SIDX_PARSER_FINISHED) {
|
||||
if (stream->demux->segment.rate > 0.0) {
|
||||
- if (sidx->entry_index + 1 < sidx->entries_count)
|
||||
+ if (sidx->entry_index < sidx->entries_count)
|
||||
return TRUE;
|
||||
} else {
|
||||
if (sidx->entry_index >= 1)
|
||||
@@ -2903,6 +2903,7 @@ gst_dash_demux_parse_isobmff (GstAdaptiveDemux * demux,
|
||||
GstByteReader sub_reader;
|
||||
GstIsoffParserResult res;
|
||||
guint dummy;
|
||||
+ gboolean ref_type1_found = FALSE;
|
||||
|
||||
dash_stream->sidx_base_offset =
|
||||
dash_stream->isobmff_parser.current_start_offset + size;
|
||||
@@ -2932,6 +2933,7 @@ gst_dash_demux_parse_isobmff (GstAdaptiveDemux * demux,
|
||||
GST_FIXME_OBJECT (stream->pad, "SIDX ref_type 1 not supported yet");
|
||||
dash_stream->sidx_position = GST_CLOCK_TIME_NONE;
|
||||
gst_isoff_sidx_parser_clear (&dash_stream->sidx_parser);
|
||||
+ ref_type1_found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2968,8 +2970,9 @@ gst_dash_demux_parse_isobmff (GstAdaptiveDemux * demux,
|
||||
}
|
||||
}
|
||||
|
||||
- if (dash_stream->sidx_parser.status == GST_ISOFF_SIDX_PARSER_FINISHED &&
|
||||
- SIDX (dash_stream)->entry_index != 0) {
|
||||
+ if ((dash_stream->sidx_parser.status == GST_ISOFF_SIDX_PARSER_FINISHED &&
|
||||
+ SIDX (dash_stream)->entry_index != 0) || (!stream->downloading_index &&
|
||||
+ !ref_type1_found)) {
|
||||
/* Need to jump to the requested SIDX entry. Push everything up to
|
||||
* the SIDX box below and let the caller handle everything else */
|
||||
*sidx_seek_needed = TRUE;
|
||||
diff --git a/gst-libs/gst/adaptivedemux/gstadaptivedemux.c b/gst-libs/gst/adaptivedemux/gstadaptivedemux.c
|
||||
index a495ec2e7..3a09a76b1 100644
|
||||
--- a/gst-libs/gst/adaptivedemux/gstadaptivedemux.c
|
||||
+++ b/gst-libs/gst/adaptivedemux/gstadaptivedemux.c
|
||||
@@ -3378,6 +3378,9 @@ gst_adaptive_demux_stream_download_header_fragment (GstAdaptiveDemuxStream *
|
||||
ret = gst_adaptive_demux_stream_download_uri (demux, stream,
|
||||
stream->fragment.index_uri, stream->fragment.index_range_start,
|
||||
stream->fragment.index_range_end, NULL);
|
||||
+
|
||||
+ gst_adaptive_demux_stream_update_fragment_info(stream->demux, stream);
|
||||
+
|
||||
stream->downloading_index = FALSE;
|
||||
}
|
||||
}
|
||||
--
|
||||
2.7.4
|
@@ -1,75 +0,0 @@
|
||||
From f9af93d841546ca7898350ae14ed57448b24a644 Mon Sep 17 00:00:00 2001
|
||||
From: Seungha Yang <seungha@centricular.com>
|
||||
Date: Sat, 14 Nov 2020 03:16:07 +0900
|
||||
Subject: [PATCH 1/2] codecs: h264decoder: Don't give up to decode due to
|
||||
missing reference picture
|
||||
|
||||
Missing reference picture is very common thing for broken/malformed stream.
|
||||
Decoder should be able to keep decoding if it's not a very critical error.
|
||||
|
||||
Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1809>
|
||||
---
|
||||
gst-libs/gst/codecs/gsth264decoder.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/gst-libs/gst/codecs/gsth264decoder.c b/gst-libs/gst/codecs/gsth264decoder.c
|
||||
index e6d20af208..40446d92df 100644
|
||||
--- a/gst-libs/gst/codecs/gsth264decoder.c
|
||||
+++ b/gst-libs/gst/codecs/gsth264decoder.c
|
||||
@@ -2354,7 +2354,7 @@ modify_ref_pic_list (GstH264Decoder * self, int list)
|
||||
if (!pic) {
|
||||
GST_WARNING_OBJECT (self, "Malformed stream, no pic num %d",
|
||||
pic_num_lx);
|
||||
- return FALSE;
|
||||
+ break;
|
||||
}
|
||||
shift_right_and_insert (ref_pic_listx, ref_idx_lx,
|
||||
num_ref_idx_lX_active_minus1, pic);
|
||||
@@ -2380,7 +2380,7 @@ modify_ref_pic_list (GstH264Decoder * self, int list)
|
||||
if (!pic) {
|
||||
GST_WARNING_OBJECT (self, "Malformed stream, no pic num %d",
|
||||
list_mod->value.long_term_pic_num);
|
||||
- return FALSE;
|
||||
+ break;
|
||||
}
|
||||
shift_right_and_insert (ref_pic_listx, ref_idx_lx,
|
||||
num_ref_idx_lX_active_minus1, pic);
|
||||
--
|
||||
GitLab
|
||||
|
||||
|
||||
From 9011a58491b089461762a8f550892de434af5c29 Mon Sep 17 00:00:00 2001
|
||||
From: Seungha Yang <seungha@centricular.com>
|
||||
Date: Sat, 14 Nov 2020 03:20:19 +0900
|
||||
Subject: [PATCH 2/2] vah264dec: Allow missing reference picture
|
||||
|
||||
baseclass might provide reference picture list with null picture.
|
||||
Ensure picture before filling picture information.
|
||||
|
||||
Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1809>
|
||||
---
|
||||
sys/va/gstvah264dec.c | 8 +++++++-
|
||||
1 file changed, 7 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/sys/va/gstvah264dec.c b/sys/va/gstvah264dec.c
|
||||
index e90f84bb44..184af430fa 100644
|
||||
--- a/sys/va/gstvah264dec.c
|
||||
+++ b/sys/va/gstvah264dec.c
|
||||
@@ -198,7 +198,13 @@ _fill_ref_pic_list (VAPictureH264 va_reflist[32], GArray * reflist)
|
||||
|
||||
for (i = 0; i < reflist->len; i++) {
|
||||
GstH264Picture *picture = g_array_index (reflist, GstH264Picture *, i);
|
||||
- _fill_vaapi_pic (&va_reflist[i], picture);
|
||||
+
|
||||
+ if (picture) {
|
||||
+ _fill_vaapi_pic (&va_reflist[i], picture);
|
||||
+ } else {
|
||||
+ /* list might include null picture if reference picture was missing */
|
||||
+ _init_vaapi_pic (&va_reflist[i]);
|
||||
+ }
|
||||
}
|
||||
|
||||
for (; i < 32; i++)
|
||||
--
|
||||
GitLab
|
||||
|
@@ -1,45 +0,0 @@
|
||||
{
|
||||
"name": "gst-plugins-bad",
|
||||
"buildsystem": "meson",
|
||||
"config-opts": [
|
||||
"-Ddoc=disabled",
|
||||
"-Dexamples=disabled",
|
||||
"-Dtests=disabled",
|
||||
"-Dnls=disabled",
|
||||
"-Dgobject-cast-checks=disabled",
|
||||
"-Dglib-asserts=disabled",
|
||||
"-Dglib-checks=disabled",
|
||||
"-Dextra-checks=disabled",
|
||||
|
||||
"-Dvulkan=disabled",
|
||||
"-Dwebrtc=disabled",
|
||||
"-Dwasapi=disabled",
|
||||
"-Dwasapi2=disabled",
|
||||
"-Dwinks=disabled",
|
||||
"-Dwinscreencap=disabled"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad.git",
|
||||
"tag": "1.18.1",
|
||||
"commit": "e5c3c106a2da607953fea36e3a253b382c939684"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"path": "gst-plugins-bad-vah264dec-fix-seeking-errors.patch"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"path": "gst-plugins-bad-assrender-smooth-scaling.patch"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"path": "gst-plugins-bad-assrender-fix-mimetype-detection.patch"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"path": "gst-plugins-bad-dashdemux-sdix-range-download.patch"
|
||||
}
|
||||
]
|
||||
}
|
@@ -1,142 +0,0 @@
|
||||
From 61a66babede5a587783a1d4eb28e950a755ff362 Mon Sep 17 00:00:00 2001
|
||||
From: Rafostar <rafostar.github@gmail.com>
|
||||
Date: Wed, 25 Nov 2020 14:44:21 +0100
|
||||
Subject: [PATCH] subparse: Autodetect subtitle text encoding
|
||||
|
||||
Use "uchardet" to guess the subtitle text encoding if it is not in UTF-8
|
||||
or manually specified instead of blindly guessing its "ISO-8859-15".
|
||||
The "uchardet" dependency is optional and when is not available at
|
||||
compile time, then old behaviour will be used.
|
||||
---
|
||||
gst/subparse/gstsubparse.c | 58 +++++++++++++++++++++++++++++++++-----
|
||||
gst/subparse/meson.build | 12 ++++++--
|
||||
2 files changed, 61 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/gst/subparse/gstsubparse.c b/gst/subparse/gstsubparse.c
|
||||
index 382e430f2..42283d2d1 100644
|
||||
--- a/gst/subparse/gstsubparse.c
|
||||
+++ b/gst/subparse/gstsubparse.c
|
||||
@@ -31,6 +31,10 @@
|
||||
#include <sys/types.h>
|
||||
#include <glib.h>
|
||||
|
||||
+#if defined(HAVE_UCHARDET)
|
||||
+#include <uchardet.h>
|
||||
+#endif
|
||||
+
|
||||
#include "gstsubparse.h"
|
||||
#include "gstssaparse.h"
|
||||
#include "samiparse.h"
|
||||
@@ -148,8 +152,9 @@ gst_sub_parse_class_init (GstSubParseClass * klass)
|
||||
"Encoding to assume if input subtitles are not in UTF-8 or any other "
|
||||
"Unicode encoding. If not set, the GST_SUBTITLE_ENCODING environment "
|
||||
"variable will be checked for an encoding to use. If that is not set "
|
||||
- "either, ISO-8859-15 will be assumed.", DEFAULT_ENCODING,
|
||||
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
+ "either, then if plugin was build with uchardet support it will be "
|
||||
+ "used to guess the encoding, otherwise ISO-8859-15 will be assumed.",
|
||||
+ DEFAULT_ENCODING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_VIDEOFPS,
|
||||
gst_param_spec_fraction ("video-fps", "Video framerate",
|
||||
@@ -439,6 +444,35 @@ detect_encoding (const gchar * str, gsize len)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+static gchar *
|
||||
+uchardet_detect_encoding (const gchar * str, gsize len)
|
||||
+{
|
||||
+ gchar *charset = NULL;
|
||||
+ gint retval;
|
||||
+
|
||||
+#if defined(HAVE_UCHARDET)
|
||||
+ uchardet_t handle = uchardet_new ();
|
||||
+ retval = uchardet_handle_data (handle, str, len);
|
||||
+
|
||||
+ GST_DEBUG ("detecting encoding with uchardet using %li characters", len);
|
||||
+
|
||||
+ if (retval != 0) {
|
||||
+ GST_WARNING ("could not handle data with uchardet");
|
||||
+ } else {
|
||||
+ uchardet_data_end (handle);
|
||||
+ charset = g_strdup (uchardet_get_charset (handle));
|
||||
+
|
||||
+ if (charset == NULL || *charset == '\0')
|
||||
+ GST_WARNING ("uchardet could not detect encoding");
|
||||
+ else
|
||||
+ GST_INFO ("uchardet detected encoding: %s", charset);
|
||||
+ }
|
||||
+ uchardet_delete (handle);
|
||||
+#endif
|
||||
+
|
||||
+ return charset;
|
||||
+}
|
||||
+
|
||||
static gchar *
|
||||
convert_encoding (GstSubParse * self, const gchar * str, gsize len,
|
||||
gsize * consumed)
|
||||
@@ -481,11 +515,18 @@ convert_encoding (GstSubParse * self, const gchar * str, gsize len,
|
||||
encoding = g_getenv ("GST_SUBTITLE_ENCODING");
|
||||
}
|
||||
if (encoding == NULL || *encoding == '\0') {
|
||||
- /* if local encoding is UTF-8 and no encoding specified
|
||||
- * via the environment variable, assume ISO-8859-15 */
|
||||
- if (g_get_charset (&encoding)) {
|
||||
+ /* no encoding specified via the environment variable either,
|
||||
+ * so try to autodetect with uchardet */
|
||||
+ encoding = uchardet_detect_encoding (str, len);
|
||||
+ }
|
||||
+
|
||||
+ /* if uchardet failed and local encoding is UTF-8, assume ISO-8859-15 */
|
||||
+ if (encoding == NULL || *encoding == '\0') {
|
||||
+ if (g_get_charset (&encoding))
|
||||
encoding = "ISO-8859-15";
|
||||
- }
|
||||
+ } else {
|
||||
+ /* reuse the detected encoding from now on */
|
||||
+ self->detected_encoding = g_strdup (encoding);
|
||||
}
|
||||
|
||||
ret = gst_convert_to_utf8 (str, len, encoding, consumed, &err);
|
||||
@@ -2159,7 +2200,10 @@ gst_subparse_type_find (GstTypeFind * tf, gpointer private)
|
||||
enc = g_getenv ("GST_SUBTITLE_ENCODING");
|
||||
if (enc == NULL || *enc == '\0') {
|
||||
/* if local encoding is UTF-8 and no encoding specified
|
||||
- * via the environment variable, assume ISO-8859-15 */
|
||||
+ * via the environment variable, assume ISO-8859-15
|
||||
+ *
|
||||
+ * Encoding here is only used for type find, so no need
|
||||
+ * to run through uchardet at this point */
|
||||
if (g_get_charset (&enc)) {
|
||||
enc = "ISO-8859-15";
|
||||
}
|
||||
diff --git a/gst/subparse/meson.build b/gst/subparse/meson.build
|
||||
index 9a76601f0..2dcf8830f 100644
|
||||
--- a/gst/subparse/meson.build
|
||||
+++ b/gst/subparse/meson.build
|
||||
@@ -6,12 +6,20 @@ subparse_sources = [
|
||||
'mpl2parse.c',
|
||||
'qttextparse.c',
|
||||
]
|
||||
+subparse_defines = []
|
||||
+subparse_optional_deps = []
|
||||
+
|
||||
+subparse_uchardet_dep = dependency('uchardet', required : false)
|
||||
+if subparse_uchardet_dep.found()
|
||||
+ subparse_defines += '-DHAVE_UCHARDET'
|
||||
+ subparse_optional_deps += subparse_uchardet_dep
|
||||
+endif
|
||||
|
||||
gstsubparse = library('gstsubparse',
|
||||
subparse_sources,
|
||||
- c_args : gst_plugins_base_args,
|
||||
+ c_args : gst_plugins_base_args + subparse_defines,
|
||||
include_directories: [configinc, libsinc],
|
||||
- dependencies : [gst_base_dep],
|
||||
+ dependencies : [gst_base_dep] + subparse_optional_deps,
|
||||
install : true,
|
||||
install_dir : plugins_install_dir,
|
||||
)
|
||||
--
|
||||
2.26.2
|
||||
|
@@ -1,34 +0,0 @@
|
||||
From d42546dda8fdb3d044e715d0a6a1a74cd411acbe Mon Sep 17 00:00:00 2001
|
||||
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
|
||||
Date: Mon, 5 Apr 2021 18:05:38 +0200
|
||||
Subject: [PATCH] GL: Do not set backbuffer on Wayland memory copy
|
||||
|
||||
This aims to workaround a Mesa bug that causes crash on Intel GPUs
|
||||
caused by calling "glDrawBuffer (GL_BACK)" on Wayland where
|
||||
there is no actual backbuffer in GStreamer OpenGL context.
|
||||
---
|
||||
gst-libs/gst/gl/gstglmemory.c | 8 +++++++-
|
||||
1 file changed, 7 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/gst-libs/gst/gl/gstglmemory.c b/gst-libs/gst/gl/gstglmemory.c
|
||||
index 76c04eb1b..cd3481847 100644
|
||||
--- a/gst-libs/gst/gl/gstglmemory.c
|
||||
+++ b/gst-libs/gst/gl/gstglmemory.c
|
||||
@@ -762,7 +762,13 @@ gst_gl_memory_copy_teximage (GstGLMemory * src, guint tex_id,
|
||||
gl->DeleteFramebuffers (n_fbos, &fbo[0]);
|
||||
|
||||
if (gl->DrawBuffer)
|
||||
- gl->DrawBuffer (GL_BACK);
|
||||
+ gl->DrawBuffer (
|
||||
+#if GST_GL_HAVE_WINDOW_WAYLAND
|
||||
+ GL_NONE
|
||||
+#else
|
||||
+ GL_BACK
|
||||
+#endif
|
||||
+ );
|
||||
}
|
||||
|
||||
gst_memory_unmap (GST_MEMORY_CAST (src), &sinfo);
|
||||
--
|
||||
2.28.0
|
||||
|
@@ -1,34 +0,0 @@
|
||||
{
|
||||
"name": "gst-plugins-base",
|
||||
"buildsystem": "meson",
|
||||
"config-opts": [
|
||||
"--wrap-mode=nofallback",
|
||||
|
||||
"-Ddoc=disabled",
|
||||
"-Dexamples=disabled",
|
||||
"-Dtests=disabled",
|
||||
"-Dnls=disabled",
|
||||
"-Dgobject-cast-checks=disabled",
|
||||
"-Dglib-asserts=disabled",
|
||||
"-Dglib-checks=disabled",
|
||||
|
||||
"-Dgl_api=opengl,gles2",
|
||||
"-Dgl_platform=egl,glx"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://gitlab.freedesktop.org/gstreamer/gst-plugins-base.git",
|
||||
"tag": "1.18.1",
|
||||
"commit": "4013b8003e78971dd01b055066c12f8aaadb8897"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"path": "gst-plugins-base-autodetect-subtitle-text-encoding.patch"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"path": "gst-plugins-base-do-not-set-backbuffer.patch"
|
||||
}
|
||||
]
|
||||
}
|
@@ -1,67 +0,0 @@
|
||||
From b2ad7c68c3478c433a0ede4aed6afb2f0b32702c Mon Sep 17 00:00:00 2001
|
||||
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
|
||||
Date: Sun, 10 Jan 2021 15:44:45 +0100
|
||||
Subject: [PATCH] matroska: fix attachments detection in large data blocks
|
||||
|
||||
Due to max block size limit being set to 15MB, large
|
||||
attachments (fonts of few MB in size) were undetected
|
||||
as attachments consist of single data block. Raise max
|
||||
data block limit to 30MB to fix that.
|
||||
---
|
||||
gst/matroska/matroska-demux.c | 34 ++++++++++++++++------------------
|
||||
1 file changed, 16 insertions(+), 18 deletions(-)
|
||||
|
||||
diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c
|
||||
index 4d0234743..ce906e5a3 100644
|
||||
--- a/gst/matroska/matroska-demux.c
|
||||
+++ b/gst/matroska/matroska-demux.c
|
||||
@@ -5115,30 +5115,28 @@ gst_matroska_demux_parse_contents (GstMatroskaDemux * demux, GstEbmlRead * ebml)
|
||||
}
|
||||
|
||||
#define GST_FLOW_OVERFLOW GST_FLOW_CUSTOM_ERROR
|
||||
-
|
||||
-#define MAX_BLOCK_SIZE (15 * 1024 * 1024)
|
||||
+#define MAX_BLOCK_SIZE (60 * 1024 * 1024)
|
||||
|
||||
static inline GstFlowReturn
|
||||
gst_matroska_demux_check_read_size (GstMatroskaDemux * demux, guint64 bytes)
|
||||
{
|
||||
- if (G_UNLIKELY (bytes > MAX_BLOCK_SIZE)) {
|
||||
- /* only a few blocks are expected/allowed to be large,
|
||||
- * and will be recursed into, whereas others will be read and must fit */
|
||||
- if (demux->streaming) {
|
||||
- /* fatal in streaming case, as we can't step over easily */
|
||||
- GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
|
||||
- ("reading large block of size %" G_GUINT64_FORMAT " not supported; "
|
||||
- "file might be corrupt.", bytes));
|
||||
- return GST_FLOW_ERROR;
|
||||
- } else {
|
||||
- /* indicate higher level to quietly give up */
|
||||
- GST_DEBUG_OBJECT (demux,
|
||||
- "too large block of size %" G_GUINT64_FORMAT, bytes);
|
||||
- return GST_FLOW_ERROR;
|
||||
- }
|
||||
- } else {
|
||||
+ if (G_LIKELY (bytes <= MAX_BLOCK_SIZE))
|
||||
return GST_FLOW_OK;
|
||||
+
|
||||
+ /* only a few blocks are expected/allowed to be large,
|
||||
+ * and will be recursed into, whereas others will be read and must fit */
|
||||
+ if (demux->streaming) {
|
||||
+ /* fatal in streaming case, as we can't step over easily */
|
||||
+ GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
|
||||
+ ("reading large block of size %" G_GUINT64_FORMAT " not supported; "
|
||||
+ "file might be corrupt.", bytes));
|
||||
+ } else {
|
||||
+ /* indicate higher level to quietly give up */
|
||||
+ GST_DEBUG_OBJECT (demux, "too large block of size %" G_GUINT64_FORMAT,
|
||||
+ bytes);
|
||||
}
|
||||
+
|
||||
+ return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
/* returns TRUE if we truly are in error state, and should give up */
|
||||
--
|
||||
2.29.2
|
||||
|
@@ -1,36 +0,0 @@
|
||||
From 4e5b2b0c3aeefffdd9613e33678cade25fac3fe4 Mon Sep 17 00:00:00 2001
|
||||
From: Rafostar <rafostar.github@gmail.com>
|
||||
Date: Sun, 10 Jan 2021 19:55:31 +0100
|
||||
Subject: [PATCH] matroska: treat non-image structure as attachment and set
|
||||
mimetype
|
||||
|
||||
Otherwise each structure is named as GstTagImageInfo even if it does not contain any images
|
||||
which is misleading. Also set the structure mimetype to fix assrender fonts detection.
|
||||
---
|
||||
gst/matroska/matroska-read-common.c | 9 ++++++---
|
||||
1 file changed, 6 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/gst/matroska/matroska-read-common.c b/gst/matroska/matroska-read-common.c
|
||||
index 90d6e38e1..628e19669 100644
|
||||
--- a/gst/matroska/matroska-read-common.c
|
||||
+++ b/gst/matroska/matroska-read-common.c
|
||||
@@ -851,10 +851,13 @@ gst_matroska_read_common_parse_attached_file (GstMatroskaReadCommon * common,
|
||||
}
|
||||
|
||||
/* Set filename and description in the info */
|
||||
- if (info == NULL)
|
||||
- info = gst_structure_new_empty ("GstTagImageInfo");
|
||||
-
|
||||
+ if (info == NULL) {
|
||||
+ const gchar *structure_name = (image_type != GST_TAG_IMAGE_TYPE_NONE) ?
|
||||
+ "GstTagImageInfo" : "GstTagAttachmentInfo";
|
||||
+ info = gst_structure_new_empty (structure_name);
|
||||
+ }
|
||||
gst_structure_set (info, "filename", G_TYPE_STRING, filename, NULL);
|
||||
+ gst_structure_set (info, "mimetype", G_TYPE_STRING, mimetype, NULL);
|
||||
if (description)
|
||||
gst_structure_set (info, "description", G_TYPE_STRING, description, NULL);
|
||||
|
||||
--
|
||||
2.28.0
|
||||
|
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"name": "gst-plugins-good",
|
||||
"buildsystem": "meson",
|
||||
"config-opts": [
|
||||
"-Ddoc=disabled",
|
||||
"-Dexamples=disabled",
|
||||
"-Dtests=disabled",
|
||||
"-Dnls=disabled",
|
||||
"-Dgobject-cast-checks=disabled",
|
||||
"-Dglib-asserts=disabled",
|
||||
"-Dglib-checks=disabled",
|
||||
|
||||
"-Dgtk3=disabled"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://gitlab.freedesktop.org/gstreamer/gst-plugins-good.git",
|
||||
"tag": "1.18.1",
|
||||
"commit": "7c44cdb0e00dd1c9932d8e5194b09fcf4e1e6fc1"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"path": "gst-plugins-good-matroska-fix-attachments-detection.patch"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"path": "gst-plugins-good-matroska-set-attachment-mimetype.patch"
|
||||
}
|
||||
]
|
||||
}
|
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"name": "gst-plugins-ugly",
|
||||
"buildsystem": "meson",
|
||||
"config-opts": [
|
||||
"-Ddoc=disabled",
|
||||
"-Dnls=disabled",
|
||||
"-Dtests=disabled",
|
||||
"-Dgobject-cast-checks=disabled",
|
||||
"-Dglib-asserts=disabled",
|
||||
"-Dglib-checks=disabled",
|
||||
|
||||
"-Dmpeg2dec=enabled"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://gitlab.freedesktop.org/gstreamer/gst-plugins-ugly.git",
|
||||
"tag": "1.18.1",
|
||||
"commit": "720672eed30b3be47b2f26d67554786c0d3693ad"
|
||||
}
|
||||
]
|
||||
}
|
@@ -1,83 +0,0 @@
|
||||
From 65fc08032a41ae8779d1845dce2c00b1efa2955c Mon Sep 17 00:00:00 2001
|
||||
From: Rafostar <rafostar.github@gmail.com>
|
||||
Date: Tue, 22 Dec 2020 15:08:21 +0100
|
||||
Subject: [PATCH] glx: Iterate over FBConfig and select 8 bit color size
|
||||
|
||||
---
|
||||
gst-libs/gst/vaapi/gstvaapiutils_glx.c | 40 ++++++++++++++++++++++++--
|
||||
1 file changed, 38 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/gst-libs/gst/vaapi/gstvaapiutils_glx.c b/gst-libs/gst/vaapi/gstvaapiutils_glx.c
|
||||
index ccd7832b..f73106c2 100644
|
||||
--- a/gst-libs/gst/vaapi/gstvaapiutils_glx.c
|
||||
+++ b/gst-libs/gst/vaapi/gstvaapiutils_glx.c
|
||||
@@ -301,9 +301,17 @@ gl_create_context (Display * dpy, int screen, GLContextState * parent)
|
||||
GLX_RED_SIZE, 8,
|
||||
GLX_GREEN_SIZE, 8,
|
||||
GLX_BLUE_SIZE, 8,
|
||||
+ GLX_ALPHA_SIZE, 8,
|
||||
None
|
||||
};
|
||||
|
||||
+ const GLint rgba_colors[4] = {
|
||||
+ GLX_RED_SIZE,
|
||||
+ GLX_GREEN_SIZE,
|
||||
+ GLX_BLUE_SIZE,
|
||||
+ GLX_ALPHA_SIZE
|
||||
+ };
|
||||
+
|
||||
cs = malloc (sizeof (*cs));
|
||||
if (!cs)
|
||||
goto error;
|
||||
@@ -333,11 +341,38 @@ gl_create_context (Display * dpy, int screen, GLContextState * parent)
|
||||
if (!fbconfigs)
|
||||
goto error;
|
||||
|
||||
- /* Find out a GLXFBConfig compatible with the parent context */
|
||||
+ /* Find out a 8 bit GLXFBConfig compatible with the parent context */
|
||||
for (n = 0; n < n_fbconfigs; n++) {
|
||||
+ gboolean sizes_correct = FALSE;
|
||||
+ int cn;
|
||||
+
|
||||
status = glXGetFBConfigAttrib (parent->display,
|
||||
fbconfigs[n], GLX_FBCONFIG_ID, &val);
|
||||
- if (status == Success && val == fbconfig_id)
|
||||
+ if (status != Success)
|
||||
+ goto error;
|
||||
+ if (val != fbconfig_id)
|
||||
+ continue;
|
||||
+
|
||||
+ /* Iterate over RGBA sizes in fbconfig */
|
||||
+ for (cn = 0; cn < 4; cn++) {
|
||||
+ int size = 0;
|
||||
+
|
||||
+ status = glXGetFBConfigAttrib (parent->display,
|
||||
+ fbconfigs[n], rgba_colors[cn], &size);
|
||||
+ if (status != Success)
|
||||
+ goto error;
|
||||
+
|
||||
+ /* Last check is for alpha
|
||||
+ * and alpha is optional */
|
||||
+ if (cn == 3) {
|
||||
+ if (size == 0 || size == 8) {
|
||||
+ sizes_correct = TRUE;
|
||||
+ break;
|
||||
+ }
|
||||
+ } else if (size != 8)
|
||||
+ break;
|
||||
+ }
|
||||
+ if (sizes_correct)
|
||||
break;
|
||||
}
|
||||
if (n == n_fbconfigs)
|
||||
@@ -809,6 +844,7 @@ gl_create_pixmap_object (Display * dpy, guint width, guint height)
|
||||
GLX_RED_SIZE, 8,
|
||||
GLX_GREEN_SIZE, 8,
|
||||
GLX_BLUE_SIZE, 8,
|
||||
+ GLX_ALPHA_SIZE, 8,
|
||||
GL_NONE,
|
||||
};
|
||||
|
||||
--
|
||||
2.28.0
|
||||
|
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"name": "gstreamer-vaapi",
|
||||
"buildsystem": "meson",
|
||||
"config-opts": [
|
||||
"-Ddoc=disabled",
|
||||
"-Dexamples=disabled",
|
||||
"-Dtests=disabled"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi.git",
|
||||
"tag": "1.18.1",
|
||||
"commit": "f9e925af3645439f7b7a4580700fcd6ce17fc1c9"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"path": "gstreamer-vaapi-glx-select-8-bit-color-size.patch"
|
||||
}
|
||||
]
|
||||
}
|
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"name": "gstreamer",
|
||||
"buildsystem": "meson",
|
||||
"config-opts": [
|
||||
"-Ddoc=disabled",
|
||||
"-Dgtk_doc=disabled",
|
||||
"-Dexamples=disabled",
|
||||
"-Dtests=disabled",
|
||||
"-Dbenchmarks=disabled",
|
||||
"-Dnls=disabled",
|
||||
"-Dgobject-cast-checks=disabled",
|
||||
"-Dglib-asserts=disabled",
|
||||
"-Dglib-checks=disabled",
|
||||
"-Dextra-checks=disabled"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://gitlab.freedesktop.org/gstreamer/gstreamer.git",
|
||||
"tag": "1.18.1",
|
||||
"commit": "29a8099d1d4bd8717c13923e710e92e67e335353"
|
||||
}
|
||||
]
|
||||
}
|
@@ -1,22 +0,0 @@
|
||||
--- a52dec-0.7.4/configure~ 2002-07-28 06:50:42.000000000 +0300
|
||||
+++ a52dec-0.7.4/configure 2006-02-16 23:03:07.000000000 +0200
|
||||
@@ -5839,7 +5839,7 @@
|
||||
shlibpath_overrides_runpath=unknown
|
||||
version_type=none
|
||||
dynamic_linker="$host_os ld.so"
|
||||
-sys_lib_dlsearch_path_spec="/lib /usr/lib"
|
||||
+sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib"
|
||||
sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
|
||||
|
||||
case $host_os in
|
||||
--- a52dec-0.7.4/aclocal.m4~ 2002-07-28 06:50:38.000000000 +0300
|
||||
+++ a52dec-0.7.4/aclocal.m4 2006-02-16 23:02:38.000000000 +0200
|
||||
@@ -2141,7 +2141,7 @@
|
||||
shlibpath_overrides_runpath=unknown
|
||||
version_type=none
|
||||
dynamic_linker="$host_os ld.so"
|
||||
-sys_lib_dlsearch_path_spec="/lib /usr/lib"
|
||||
+sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib"
|
||||
sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
|
||||
|
||||
case $host_os in
|
@@ -1,23 +0,0 @@
|
||||
--- ./configure~ 2002-07-28 06:50:42.000000000 +0300
|
||||
+++ ./configure 2003-04-13 17:20:53.000000000 +0300
|
||||
@@ -2857,13 +2857,13 @@
|
||||
|
||||
case "$host" in
|
||||
i?86-* | k?-*)
|
||||
- case "$host" in
|
||||
- i386-*) OPT_CFLAGS="$CFLAGS -mcpu=i386";;
|
||||
- i486-*) OPT_CFLAGS="$CFLAGS -mcpu=i486";;
|
||||
- i586-*) OPT_CFLAGS="$CFLAGS -mcpu=pentium";;
|
||||
- i686-*) OPT_CFLAGS="$CFLAGS -mcpu=pentiumpro";;
|
||||
- k6-*) OPT_CFLAGS="$CFLAGS -mcpu=k6";;
|
||||
- esac
|
||||
+# case "$host" in
|
||||
+# i386-*) OPT_CFLAGS="$CFLAGS -mcpu=i386";;
|
||||
+# i486-*) OPT_CFLAGS="$CFLAGS -mcpu=i486";;
|
||||
+# i586-*) OPT_CFLAGS="$CFLAGS -mcpu=pentium";;
|
||||
+# i686-*) OPT_CFLAGS="$CFLAGS -mcpu=pentiumpro";;
|
||||
+# k6-*) OPT_CFLAGS="$CFLAGS -mcpu=k6";;
|
||||
+# esac
|
||||
echo "$as_me:$LINENO: checking if $CC supports $OPT_CFLAGS flags" >&5
|
||||
echo $ECHO_N "checking if $CC supports $OPT_CFLAGS flags... $ECHO_C" >&6
|
||||
SAVE_CFLAGS="$CFLAGS"
|
@@ -1,30 +0,0 @@
|
||||
{
|
||||
"name": "ffmpeg",
|
||||
"cleanup": [
|
||||
"/lib/ffmpeg/examples"
|
||||
],
|
||||
"config-opts": [
|
||||
"--disable-debug",
|
||||
"--disable-doc",
|
||||
"--disable-static",
|
||||
"--disable-everything",
|
||||
"--enable-gpl",
|
||||
"--enable-version3",
|
||||
"--enable-shared",
|
||||
"--enable-optimizations",
|
||||
"--enable-runtime-cpudetect",
|
||||
"--enable-pthreads",
|
||||
"--enable-protocol=file",
|
||||
"--enable-decoder=flv,h263,h264,hevc,mjpeg,mpeg2video,mpeg4,mpegvideo,msmpeg4v1,msmpeg4v2,png,tiff,vc1,vp8,vp9,webp,wmv1,wmv2,wmv3,zerocodec",
|
||||
"--enable-decoder=aac,aac_fixed,aac_latm,ac3,ac3_fixed,eac3,flac,mp3,opus,tak,truehd,tta,wmalossless",
|
||||
"--enable-demuxer=gif,yuv4mpegpipe"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://git.ffmpeg.org/ffmpeg.git",
|
||||
"tag": "n4.4",
|
||||
"commit": "dc91b913b6260e85e1304c74ff7bb3c22a8c9fb1"
|
||||
}
|
||||
]
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
From b413ee2c7d458c7005d3d3d1da8822cd86893ac0 Mon Sep 17 00:00:00 2001
|
||||
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
|
||||
Date: Fri, 4 Dec 2020 19:25:34 +0100
|
||||
Subject: [PATCH] popover: Call unrealize on hide
|
||||
|
||||
When popover is shown "realize" method is called which creates a new
|
||||
surface for popup. Unfortunately this causes performance drop on Wayland until that
|
||||
surface is destroyed what happens inside "unrealize" method during popover destruction.
|
||||
|
||||
This commit changes default behavior in a way that surface will be destroyed
|
||||
when popover is closed and app will ragain the performance it lost when
|
||||
popover was shown.
|
||||
---
|
||||
gtk/gtkpopover.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c
|
||||
index 504dcd6cc1..a7a764d483 100644
|
||||
--- a/gtk/gtkpopover.c
|
||||
+++ b/gtk/gtkpopover.c
|
||||
@@ -951,6 +951,7 @@ gtk_popover_hide (GtkWidget *widget)
|
||||
|
||||
gtk_popover_set_mnemonics_visible (GTK_POPOVER (widget), FALSE);
|
||||
_gtk_widget_set_visible_flag (widget, FALSE);
|
||||
+ gtk_widget_unrealize (widget);
|
||||
gtk_widget_unmap (widget);
|
||||
g_signal_emit (widget, signals[CLOSED], 0);
|
||||
}
|
||||
--
|
||||
GitLab
|
||||
|
@@ -1,28 +0,0 @@
|
||||
{
|
||||
"name": "gtk",
|
||||
"buildsystem": "meson",
|
||||
"config-opts": [
|
||||
"--wrap-mode=nofallback",
|
||||
"-Dbroadway-backend=true",
|
||||
"-Dwin32-backend=false",
|
||||
"-Dmacos-backend=false",
|
||||
"-Dmedia-ffmpeg=disabled",
|
||||
"-Dprint-cups=disabled",
|
||||
"-Dprint-cloudprint=disabled",
|
||||
"-Dintrospection=enabled",
|
||||
"-Ddemos=false",
|
||||
"-Dbuild-examples=false",
|
||||
"-Dbuild-tests=false"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://gitlab.gnome.org/GNOME/gtk.git",
|
||||
"commit": "5710df685b0af9b7dd306dfba6c7e174e428950e"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"path": "gtk4-popover-unrealize.patch"
|
||||
}
|
||||
]
|
||||
}
|
@@ -1,39 +0,0 @@
|
||||
From 4c18c43b4d4ccb1d05ae73b813f26ba193fbeee3 Mon Sep 17 00:00:00 2001
|
||||
From: Bastien Nocera <hadess@hadess.net>
|
||||
Date: Fri, 18 Jan 2019 17:37:13 +0100
|
||||
Subject: [PATCH] Prefer PIC
|
||||
|
||||
---
|
||||
configure | 2 +-
|
||||
liba52/configure.incl | 2 +-
|
||||
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/configure b/configure
|
||||
index b81fdff..bc0267c 100755
|
||||
--- a/configure
|
||||
+++ b/configure
|
||||
@@ -9640,7 +9640,7 @@ _ACEOF
|
||||
|
||||
|
||||
|
||||
-LIBA52_CFLAGS="$LIBA52_CFLAGS -prefer-non-pic"
|
||||
+LIBA52_CFLAGS="$LIBA52_CFLAGS -prefer-pic"
|
||||
|
||||
# Check whether --enable-double or --disable-double was given.
|
||||
if test "${enable_double+set}" = set; then
|
||||
diff --git a/liba52/configure.incl b/liba52/configure.incl
|
||||
index 4dbbcea..5eb69ee 100644
|
||||
--- a/liba52/configure.incl
|
||||
+++ b/liba52/configure.incl
|
||||
@@ -2,7 +2,7 @@ AC_SUBST([LIBA52_CFLAGS])
|
||||
AC_SUBST([LIBA52_LIBS])
|
||||
|
||||
dnl avoid -fPIC when possible
|
||||
-LIBA52_CFLAGS="$LIBA52_CFLAGS -prefer-non-pic"
|
||||
+LIBA52_CFLAGS="$LIBA52_CFLAGS -prefer-pic"
|
||||
|
||||
AC_ARG_ENABLE([double],
|
||||
[ --enable-double use double-precision samples])
|
||||
--
|
||||
2.20.1
|
||||
|
@@ -1,17 +0,0 @@
|
||||
diff -ru a52dec.orig/liba52/imdct.c a52dec/liba52/imdct.c
|
||||
--- a52dec.orig/liba52/imdct.c 2012-02-06 19:40:21.000000000 +0200
|
||||
+++ a52dec/liba52/imdct.c 2012-02-06 19:40:53.000000000 +0200
|
||||
@@ -419,13 +419,11 @@
|
||||
|
||||
#ifdef LIBA52_DJBFFT
|
||||
if (mm_accel & MM_ACCEL_DJBFFT) {
|
||||
- fprintf (stderr, "Using djbfft for IMDCT transform\n");
|
||||
ifft128 = (void (*) (complex_t *)) fftc4_un128;
|
||||
ifft64 = (void (*) (complex_t *)) fftc4_un64;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
- fprintf (stderr, "No accelerated IMDCT transform found\n");
|
||||
ifft128 = ifft128_c;
|
||||
ifft64 = ifft64_c;
|
||||
}
|
@@ -1,36 +0,0 @@
|
||||
{
|
||||
"name": "liba52",
|
||||
"config-opts": [ "--enable-shared", "--disable-static" ],
|
||||
"rm-configure": true,
|
||||
"cleanup": [ "/bin/*a52*" ],
|
||||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "http://liba52.sourceforge.net/files/a52dec-0.7.4.tar.gz",
|
||||
"sha256": "a21d724ab3b3933330194353687df82c475b5dfb997513eef4c25de6c865ec33"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"path": "a52dec-0.7.4-rpath64.patch"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"path": "a52dec-configure-optflags.patch"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"path": "liba52-silence.patch"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"path": "liba52-prefer-pic.patch"
|
||||
},
|
||||
{
|
||||
"type":"script",
|
||||
"commands":[
|
||||
"autoreconf -fiv"
|
||||
],
|
||||
"dest-filename":"autogen.sh"
|
||||
}
|
||||
]
|
||||
}
|
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"name": "libass",
|
||||
"config-opts": [ "--enable-shared", "--disable-static" ],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/libass/libass.git",
|
||||
"tag": "0.14.0",
|
||||
"commit": "73284b676b12b47e17af2ef1b430527299e10c17"
|
||||
},
|
||||
{
|
||||
"type":"script",
|
||||
"commands":[
|
||||
"autoreconf -fiv"
|
||||
],
|
||||
"dest-filename":"autogen.sh"
|
||||
}
|
||||
]
|
||||
}
|
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"name": "libdvdcss",
|
||||
"config-opts": [ "--enable-shared", "--disable-static" ],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://code.videolan.org/videolan/libdvdcss.git",
|
||||
"tag": "1.4.2",
|
||||
"commit": "7b7c185704567398627ad0f9a0d948a63514394b"
|
||||
},
|
||||
{
|
||||
"type":"script",
|
||||
"commands":[
|
||||
"autoreconf -fiv"
|
||||
],
|
||||
"dest-filename":"autogen.sh"
|
||||
}
|
||||
]
|
||||
}
|
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"name": "libdvdnav",
|
||||
"config-opts": [ "--enable-shared", "--disable-static" ],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://code.videolan.org/videolan/libdvdnav.git",
|
||||
"tag": "6.1.0",
|
||||
"commit": "4f48efd43efb2e3372cb494a8893342e1fb507ae"
|
||||
},
|
||||
{
|
||||
"type":"script",
|
||||
"commands":[
|
||||
"autoreconf -fiv"
|
||||
],
|
||||
"dest-filename":"autogen.sh"
|
||||
}
|
||||
]
|
||||
}
|
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"name": "libdvdread",
|
||||
"config-opts": [ "--enable-shared", "--disable-static" ],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://code.videolan.org/videolan/libdvdread.git",
|
||||
"tag": "6.1.0",
|
||||
"commit": "d413571ce39acd404523b6742ba361215f6ada68"
|
||||
},
|
||||
{
|
||||
"type":"script",
|
||||
"commands":[
|
||||
"autoreconf -fiv"
|
||||
],
|
||||
"dest-filename":"autogen.sh"
|
||||
}
|
||||
]
|
||||
}
|
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"name": "libgudev",
|
||||
"config-opts": [ "--enable-shared", "--disable-static", "--disable-umockdev" ],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://gitlab.gnome.org/GNOME/libgudev.git",
|
||||
"tag": "234",
|
||||
"commit": "e9342ee019482a08fe435d6b656f8a6bdd196bce"
|
||||
}
|
||||
]
|
||||
}
|
@@ -1,10 +0,0 @@
|
||||
--- libmpeg2/configure.ac 2016-01-20 15:31:37.933547037 +0100
|
||||
+++ libmpeg2.new/configure.ac 2016-01-20 15:05:40.931231465 +0100
|
||||
@@ -149,7 +149,6 @@
|
||||
|
||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
-AC_C_ALWAYS_INLINE
|
||||
AC_C_RESTRICT
|
||||
AC_C_BUILTIN_EXPECT
|
||||
AC_C_BIGENDIAN
|
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"name": "libmpeg2",
|
||||
"config-opts": [ "--enable-shared", "--disable-static" ],
|
||||
"rm-configure": true,
|
||||
"cleanup": [ "/bin/*mpeg2*" ],
|
||||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "http://libmpeg2.sourceforge.net/files/libmpeg2-0.5.1.tar.gz",
|
||||
"sha256": "dee22e893cb5fc2b2b6ebd60b88478ab8556cb3b93f9a0d7ce8f3b61851871d4"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"path": "libmpeg2-inline.patch"
|
||||
},
|
||||
{
|
||||
"type":"script",
|
||||
"commands":[
|
||||
"autoreconf -fiv"
|
||||
],
|
||||
"dest-filename":"autogen.sh"
|
||||
}
|
||||
]
|
||||
}
|
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"name": "libsass",
|
||||
"buildsystem": "meson",
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/lazka/libsass.git",
|
||||
"branch": "meson",
|
||||
"commit": "302397c0c8ae2d7ab02f45ea461c2c3d768f248e"
|
||||
}
|
||||
]
|
||||
}
|