Compare commits
1 Commits
d2ceb962f1
...
gluploader
Author | SHA1 | Date | |
---|---|---|---|
|
5e40079480 |
5
.gitattributes
vendored
Normal file
@@ -0,0 +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
|
58
.github/workflows/documentation.yml
vendored
@@ -1,58 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
name: "Documentation"
|
||||
jobs:
|
||||
documentation:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: registry.fedoraproject.org/fedora
|
||||
options: --privileged
|
||||
steps:
|
||||
- name: Prepare
|
||||
run: |
|
||||
dnf -y install git gcc meson glib2-devel \
|
||||
gstreamer1-devel gstreamer1-plugins-base-devel \
|
||||
gtk4-devel libsoup3-devel libmicrodns-devel \
|
||||
gobject-introspection-devel graphviz gi-docgen
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
- name: Build
|
||||
run: |
|
||||
meson setup builddir -Dauto_features=enabled \
|
||||
-Denhancers-loader=disabled \
|
||||
-Dclapper-app=disabled -Dvapi=disabled -Ddoc=true \
|
||||
-Dglimporter=auto -Dgluploader=auto -Drawimporter=auto
|
||||
cd builddir
|
||||
meson compile
|
||||
- name: Commit files
|
||||
if: ${{ success() && github.ref == 'refs/heads/master' }}
|
||||
continue-on-error: true
|
||||
run: |
|
||||
git config --global --add safe.directory $GITHUB_WORKSPACE
|
||||
git checkout gh-pages
|
||||
rm -rf doc/clapper/*
|
||||
rm -rf doc/clapper-gtk/*
|
||||
mv builddir/doc/reference/clapper/clapper.toml doc/clapper/
|
||||
mv builddir/doc/reference/clapper/clapper/* doc/clapper/
|
||||
mv builddir/doc/reference/clapper-gtk/clapper-gtk.toml doc/clapper-gtk/
|
||||
mv builddir/doc/reference/clapper-gtk/clapper-gtk/* doc/clapper-gtk/
|
||||
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git config --local user.name "github-actions[bot]"
|
||||
git add doc/clapper/* doc/clapper-gtk/*
|
||||
git commit -m "doc: Update" || true
|
||||
- name: Push changes
|
||||
uses: ad-m/github-push-action@master
|
||||
if: ${{ success() && github.ref == 'refs/heads/master' }}
|
||||
continue-on-error: true
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branch: gh-pages
|
50
.github/workflows/flatpak-nightly.yml
vendored
@@ -6,34 +6,33 @@ name: "Flatpak Nightly"
|
||||
jobs:
|
||||
flatpak:
|
||||
name: "Flatpak"
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 600
|
||||
container:
|
||||
image: bilelmoussaoui/flatpak-github-actions:gnome-nightly
|
||||
options: --privileged
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-24.04, ubuntu-24.04-arm]
|
||||
include:
|
||||
- os: ubuntu-24.04
|
||||
arch: x86_64
|
||||
- os: ubuntu-24.04-arm
|
||||
arch: aarch64
|
||||
arch: [x86_64, aarch64]
|
||||
fail-fast: false
|
||||
runs-on: ${{ matrix.os }}
|
||||
container:
|
||||
image: registry.fedoraproject.org/fedora
|
||||
options: --privileged
|
||||
steps:
|
||||
- name: Prepare
|
||||
run: |
|
||||
dnf install -y git git-lfs dbus-daemon flatpak flatpak-builder libappstream-glib ccache zstd xorg-x11-server-Xvfb
|
||||
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||
flatpak remote-add --if-not-exists gnome-nightly https://nightly.gnome.org/gnome-nightly.flatpakrepo
|
||||
flatpak --system install -y --noninteractive flathub org.freedesktop.Sdk.Extension.rust-stable/${{ matrix.arch }}/24.08
|
||||
flatpak --system install -y --noninteractive flathub org.freedesktop.Sdk.Extension.llvm18/${{ matrix.arch }}/24.08
|
||||
flatpak --system install -y --noninteractive flathub org.flatpak.Builder
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build
|
||||
uses: flatpak/flatpak-github-actions/flatpak-builder@master
|
||||
- name: Install Docker
|
||||
run: |
|
||||
dnf -y install docker
|
||||
- name: Setup QEMU
|
||||
id: qemu
|
||||
uses: docker/setup-qemu-action@v1
|
||||
with:
|
||||
platforms: arm64
|
||||
- name: Prepare Runtime
|
||||
run: |
|
||||
flatpak --system install -y --noninteractive flathub org.freedesktop.Sdk.Extension.rust-nightly/${{ matrix.arch }}/21.08
|
||||
flatpak --system install -y --noninteractive flathub org.freedesktop.Sdk.Extension.llvm13/${{ matrix.arch }}/21.08
|
||||
- uses: bilelmoussaoui/flatpak-github-actions/flatpak-builder@v4
|
||||
name: Build
|
||||
with:
|
||||
bundle: com.github.rafostar.Clapper.flatpak
|
||||
manifest-path: pkgs/flatpak/com.github.rafostar.Clapper-nightly.json
|
||||
@@ -41,10 +40,3 @@ jobs:
|
||||
repository-url: https://nightly.gnome.org/gnome-nightly.flatpakrepo
|
||||
cache-key: flatpak-builder-${{ github.sha }}-testing-${{ github.run_number }}
|
||||
arch: ${{ matrix.arch }}
|
||||
upload-artifact: false
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: clapper-flatpak-nightly-${{ matrix.arch }}
|
||||
path: com.github.rafostar.Clapper.flatpak
|
||||
if-no-files-found: error
|
||||
|
43
.github/workflows/flatpak.yml
vendored
@@ -10,40 +10,31 @@ name: "Flatpak"
|
||||
jobs:
|
||||
flatpak:
|
||||
name: "Flatpak"
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 600
|
||||
container:
|
||||
image: bilelmoussaoui/flatpak-github-actions:gnome-42
|
||||
options: --privileged
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-24.04, ubuntu-24.04-arm]
|
||||
include:
|
||||
- os: ubuntu-24.04
|
||||
arch: x86_64
|
||||
- os: ubuntu-24.04-arm
|
||||
arch: aarch64
|
||||
arch: [x86_64, aarch64]
|
||||
fail-fast: false
|
||||
runs-on: ${{ matrix.os }}
|
||||
container:
|
||||
image: registry.fedoraproject.org/fedora
|
||||
options: --privileged
|
||||
steps:
|
||||
- name: Prepare
|
||||
run: |
|
||||
dnf install -y git git-lfs dbus-daemon flatpak flatpak-builder libappstream-glib ccache zstd xorg-x11-server-Xvfb
|
||||
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||
flatpak --system install -y --noninteractive flathub org.flatpak.Builder
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build
|
||||
uses: flatpak/flatpak-github-actions/flatpak-builder@master
|
||||
- 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 }}
|
||||
upload-artifact: false
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: clapper-flatpak-${{ matrix.arch }}
|
||||
path: com.github.rafostar.Clapper.flatpak
|
||||
if-no-files-found: error
|
||||
|
101
.github/workflows/windows.yml
vendored
@@ -1,101 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
name: "Windows"
|
||||
jobs:
|
||||
windows:
|
||||
name: "Windows"
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x86_64]
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup MSYS2
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: MINGW64
|
||||
update: true
|
||||
install: |-
|
||||
mingw-w64-${{ matrix.arch }}-meson
|
||||
mingw-w64-${{ matrix.arch }}-gcc
|
||||
mingw-w64-${{ matrix.arch }}-glib2
|
||||
mingw-w64-${{ matrix.arch }}-gstreamer
|
||||
mingw-w64-${{ matrix.arch }}-gst-plugins-base
|
||||
mingw-w64-${{ matrix.arch }}-gst-plugins-good
|
||||
mingw-w64-${{ matrix.arch }}-gst-plugins-bad
|
||||
mingw-w64-${{ matrix.arch }}-gst-plugins-ugly
|
||||
mingw-w64-${{ matrix.arch }}-gst-libav
|
||||
mingw-w64-${{ matrix.arch }}-libpeas2
|
||||
mingw-w64-${{ matrix.arch }}-libsoup3
|
||||
mingw-w64-${{ matrix.arch }}-libmicrodns
|
||||
mingw-w64-${{ matrix.arch }}-gtk4
|
||||
mingw-w64-${{ matrix.arch }}-libadwaita
|
||||
- name: Prepare
|
||||
run: |
|
||||
BUILD_PREFIX="$GITHUB_WORKSPACE/clapper-win-${{ matrix.arch }}"
|
||||
|
||||
mkdir -p $BUILD_PREFIX/bin
|
||||
cp /mingw64/bin/gdbus.exe $BUILD_PREFIX/bin/
|
||||
cp /mingw64/bin/gst-inspect-1.0.exe $BUILD_PREFIX/bin/
|
||||
|
||||
mkdir -p $BUILD_PREFIX/lib
|
||||
cp -r /mingw64/lib/gio $BUILD_PREFIX/lib/
|
||||
cp -r /mingw64/lib/gstreamer-1.0 $BUILD_PREFIX/lib/
|
||||
cp -r /mingw64/lib/gdk-pixbuf-2.0 $BUILD_PREFIX/lib/
|
||||
|
||||
mkdir -p $BUILD_PREFIX/share/glib-2.0/schemas
|
||||
cp -r /mingw64/share/glib-2.0/schemas/*.xml $BUILD_PREFIX/share/glib-2.0/schemas/
|
||||
cp -r /mingw64/share/icons $BUILD_PREFIX/share/
|
||||
|
||||
mkdir -p $BUILD_PREFIX/share/xml/iso-codes
|
||||
cp /mingw64/share/xml/iso-codes/iso_639.xml $BUILD_PREFIX/share/xml/iso-codes/
|
||||
|
||||
cd "$BUILD_PREFIX/lib/gstreamer-1.0"
|
||||
rm -f \
|
||||
libgstadpcmenc.dll libgstamfcodec.dll libgstdvbsubenc.dll libgstencoding.dll \
|
||||
libgstfrei0r.dll libgstinter.dll libgstlame.dll libgstldac.dll libgstmpeg2enc.dll \
|
||||
libgstmpegpsmux.dll libgstmpegtsmux.dll libgstmplex.dll libgstrealmedia.dll \
|
||||
libgstsubenc.dll libgstsvtav1.dll libgstsvthevcenc.dll libgsttwolame.dll \
|
||||
libgstvoamrwbenc.dll libgstwavenc.dll libgstx264.dll libgstx265.dll \
|
||||
libgstxingmux.dll libgsty4menc.dll libgstzbar.dll
|
||||
- name: Build
|
||||
run: |
|
||||
meson setup builddir --prefix=$GITHUB_WORKSPACE/clapper-win-${{ matrix.arch }}
|
||||
cd builddir
|
||||
meson compile
|
||||
meson install
|
||||
- name: Package
|
||||
run: |
|
||||
BUILD_PREFIX="$GITHUB_WORKSPACE/clapper-win-${{ matrix.arch }}"
|
||||
|
||||
ldd $BUILD_PREFIX/bin/clapper.exe | grep '\/mingw.*\.dll' -o | xargs -I{} cp -n "{}" $BUILD_PREFIX/bin
|
||||
find $BUILD_PREFIX/lib/clapper-0.0/ -name '*\.dll' -type f -exec ldd "{}" \; | grep '\/mingw.*\.dll' -o | xargs -I{} cp -n "{}" $BUILD_PREFIX/bin
|
||||
find $BUILD_PREFIX/lib/gstreamer-1.0/ -name '*\.dll' -type f -exec ldd "{}" \; | grep '\/mingw.*\.dll' -o | xargs -I{} cp -n "{}" $BUILD_PREFIX/bin
|
||||
find $BUILD_PREFIX/lib/gio/ -name '*\.dll' -type f -exec ldd "{}" \; | grep '\/mingw.*\.dll' -o | xargs -I{} cp -n "{}" $BUILD_PREFIX/bin
|
||||
- name: Cleanup
|
||||
run: |
|
||||
BUILD_PREFIX="$GITHUB_WORKSPACE/clapper-win-${{ matrix.arch }}"
|
||||
|
||||
rm -rf $BUILD_PREFIX/include
|
||||
rm -rf $BUILD_PREFIX/lib/pkgconfig
|
||||
- name: Installer
|
||||
uses: Minionguyjpro/Inno-Setup-Action@v1.2.5
|
||||
with:
|
||||
path: builddir/pkgs/windows-installer/clapper.iss
|
||||
options: /O+
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: clapper-win-${{ matrix.arch }}
|
||||
path: builddir/pkgs/windows-installer/InstallerOutput/Clapper*.exe
|
||||
if-no-files-found: error
|
3
.gitignore
vendored
@@ -2,6 +2,3 @@
|
||||
build/
|
||||
install/
|
||||
builddir/
|
||||
|
||||
# flatpak
|
||||
.flatpak-builder/
|
||||
|
47
README.md
@@ -5,37 +5,35 @@
|
||||
[](https://matrix.to/#/#clapper-player:matrix.org)
|
||||
[](https://liberapay.com/Clapper)
|
||||
|
||||
Clapper is a modern media player designed for simplicity and ease of use. Powered by [GStreamer](https://gstreamer.freedesktop.org/) and built for the GNOME
|
||||
desktop environment using [GTK4](https://www.gtk.org/) toolkit, it has a clean and stylish interface that lets you focus on enjoying your favorite videos.
|
||||
|
||||
This application aim is to offer all the essentials features you'd expect from a video player in a simple form.
|
||||
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_01.png">
|
||||
<img src="https://raw.githubusercontent.com/wiki/Rafostar/clapper/media/screenshot-windowed.png"><br>
|
||||
<b>Windowed Mode</b>
|
||||
</p>
|
||||
|
||||
Clapper uses a playback queue where you can add multiple media files. Think of it like a playlist that you can build.
|
||||
You can easily reorder items or remove them from the queue with a simple drag and drop operation.
|
||||
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/wiki/Rafostar/clapper/media/screenshot_03.png">
|
||||
<img src="https://raw.githubusercontent.com/wiki/Rafostar/clapper/media/screenshot-fullscreen.png"><br>
|
||||
<b>Fullscreen Mode</b>
|
||||
</p>
|
||||
|
||||
### Components
|
||||
Clapper's codebase consists of 2 libraries using which main application is built:
|
||||
* [Clapper](https://rafostar.github.io/clapper/doc/clapper/) - a playback library
|
||||
* [ClapperGtk](https://rafostar.github.io/clapper/doc/clapper-gtk/) - a GTK integration library
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/wiki/Rafostar/clapper/media/screenshot-floating.png"><br>
|
||||
<b>Floating Mode</b>
|
||||
</p>
|
||||
|
||||
Both libraries support *GObject Introspection* bindings. A simple application example can be found [here](https://github.com/Rafostar/clapper-vala-test).
|
||||
|
||||
Above libraries are licensed under `LGPL-2.1-or-later`. You are free to use them in your own projects as long as you comply with license terms.
|
||||
Please note that until version 1.0 they should be considered as an unstable API (some things may change without prior notice).
|
||||
|
||||
Clapper `Vala` bindings are part of this repo, while `Rust` bindings can be found [here](https://gitlab.gnome.org/JanGernert/clapper-rs).
|
||||
### Features:
|
||||
* [Hardware acceleration](https://github.com/Rafostar/clapper/wiki/Hardware-acceleration)
|
||||
* [Floating mode](https://github.com/Rafostar/clapper/wiki/Floating-mode)
|
||||
* [Adaptive UI](https://raw.githubusercontent.com/wiki/Rafostar/clapper/media/screenshot-mobile.png)
|
||||
* [Playlist from file](https://github.com/Rafostar/clapper/wiki/Playlists)
|
||||
* Chapters on progress bar
|
||||
* MPRIS support
|
||||
|
||||
## Installation from Flatpak
|
||||
The `Flatpak` package includes all required dependencies and codecs.
|
||||
Additionally it also has a few patches, thus some functionalities work better in `Flatpak` version (until my changes are accepted upstream).
|
||||
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'>
|
||||
@@ -50,14 +48,10 @@ Those are automatically built on each git commit, thus are considered unstable.
|
||||
|
||||
## Installation from Source Code
|
||||
```sh
|
||||
meson setup builddir
|
||||
cd builddir
|
||||
meson compile
|
||||
sudo meson install
|
||||
meson builddir --prefix=/usr/local
|
||||
sudo meson install -C builddir
|
||||
```
|
||||
|
||||
If you want to compile app as `Flatpak`, remember to clone this repo with `--recurse-submodules` option.
|
||||
|
||||
## Questions?
|
||||
Feel free to ask me any questions. Come and talk on Matrix: [#clapper-player:matrix.org](https://matrix.to/#/#clapper-player:matrix.org)
|
||||
|
||||
@@ -72,6 +66,5 @@ so if your language is not available, please contact me first.
|
||||
Many thanks to [sp1ritCS](https://github.com/sp1ritCS) for creating and maintaining package build files.
|
||||
Big thanks to [bridadan](https://github.com/bridadan) and [Uniformbuffer3](https://github.com/Uniformbuffer3) for helping
|
||||
with testing V4L2 and NVDEC hardware acceleration methods.
|
||||
Also words of appreciation for [JanGernert](https://gitlab.gnome.org/JanGernert) who made and is sharing Clapper Rust bindings.
|
||||
|
||||
Thanks a lot to all the people who are supporting the development with their anonymous donations through [Liberapay](https://liberapay.com/Clapper/). I :heart: U.
|
||||
|
46
TODO.md
Normal file
@@ -0,0 +1,46 @@
|
||||
- [X] Implement GstPlayer API
|
||||
- [X] Update to custom GstClapper API
|
||||
- [X] Inhibit screen locking
|
||||
- [X] Hide cursor on video window
|
||||
- Adaptive GUI:
|
||||
- [X] Darker and bigger in fullscreen
|
||||
- [X] Mobile/narrow widths transitions
|
||||
- [ ] Mobile friendly other windows e.g. prefs window (libadwaita)
|
||||
- [X] Dragging player by video (MPV)
|
||||
- [X] Switching video/audio/subtitles tracks from bottom bar (MPV)
|
||||
- [X] Over-amplification supported by default (VLC)
|
||||
- [X] Audio visualizations (VLC)
|
||||
- [X] Clock with current hour and "Ends at" time on top overlay (Kodi)
|
||||
- [ ] Auto select subtitles matching OS language (Totem)
|
||||
- [X] Picture-in-Picture mode window (floating window)
|
||||
- [ ] Touch gestures/swipes support
|
||||
- Media playlists:
|
||||
- [X] Add more items to playlist via D&D
|
||||
- [X] Select video from playlist
|
||||
- [ ] Reorder playlist items via D&D
|
||||
- [X] Load special playlist file (.claps)
|
||||
- [X] Save to playlist file from GUI
|
||||
- Seeking:
|
||||
- [X] Customizable seek time
|
||||
- [X] Set seek mode (default, accurate, fast)
|
||||
- [ ] Statistics and codec info page (VLC)
|
||||
- [X] Resume playback from last position
|
||||
- [X] Chapters support
|
||||
- [ ] Set tracks time offset
|
||||
- [ ] Subtitles offset
|
||||
- [X] Audio offset
|
||||
- [ ] MDNS and UPNP (discovering media in local network)
|
||||
- [X] DND files from Nautilus to play (ignore incompatible ones)
|
||||
- [X] Support dropping whole folders
|
||||
- [ ] Search for subtitles, download and activate (SMplayer)
|
||||
- [ ] Auto add subtitles from same folder
|
||||
- [ ] Set global subtitles folders
|
||||
- [X] RSTP streaming
|
||||
- [X] Playback speed
|
||||
- [X] Remote playback controls via HTTP (VLC) + WebSockets
|
||||
- [ ] Expand available API
|
||||
- [ ] API documentation
|
||||
- [X] Integration with the top bar
|
||||
- [X] MPRIS support
|
||||
- [X] Controls in the notifications panel
|
||||
- [ ] Progress bar in the notifications panel (maybe via extension)
|
14
_service
Normal file
@@ -0,0 +1,14 @@
|
||||
<services>
|
||||
<service name="obs_scm">
|
||||
<param name="scm">git</param>
|
||||
<param name="url">https://github.com/Rafostar/clapper.git</param>
|
||||
<param name="extract">pkgs/rpm/clapper.spec</param>
|
||||
<param name="extract">pkgs/rpm/clapper.rpmlintrc</param>
|
||||
</service>
|
||||
<service name="tar" mode="buildtime"/>
|
||||
<service name="recompress" mode="buildtime">
|
||||
<param name="compression">xz</param>
|
||||
<param name="file">*.tar</param>
|
||||
</service>
|
||||
<service name="set_version" mode="buildtime"/>
|
||||
</services>
|
9
bin/com.github.rafostar.Clapper.in
Normal file
@@ -0,0 +1,9 @@
|
||||
#!@GJS@
|
||||
|
||||
imports.package.init({
|
||||
name: '@PACKAGE_NAME@',
|
||||
version: '@PACKAGE_VERSION@',
|
||||
prefix: '@prefix@',
|
||||
libdir: '@libdir@',
|
||||
});
|
||||
imports.package.run(imports.src.main);
|
22
bin/meson.build
Normal file
@@ -0,0 +1,22 @@
|
||||
bin_conf = configuration_data()
|
||||
|
||||
bin_conf.set('GJS', find_program('gjs').path())
|
||||
bin_conf.set('PACKAGE_NAME', meson.project_name())
|
||||
bin_conf.set('PACKAGE_VERSION', meson.project_version())
|
||||
bin_conf.set('prefix', get_option('prefix'))
|
||||
bin_conf.set('libdir', libdir)
|
||||
|
||||
configure_file(
|
||||
input: 'com.github.rafostar.Clapper.in',
|
||||
output: 'com.github.rafostar.Clapper',
|
||||
configuration: bin_conf,
|
||||
install: true,
|
||||
install_dir: bindir,
|
||||
install_mode: 'rwxr-xr-x'
|
||||
)
|
||||
|
||||
clapper_symlink_cmd = 'ln -fs @0@ $DESTDIR@1@'.format(
|
||||
'com.github.rafostar.Clapper',
|
||||
join_paths(bindir, 'clapper')
|
||||
)
|
||||
meson.add_install_script('sh', '-c', clapper_symlink_cmd)
|
22
build-aux/meson/postinstall.py
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from os import environ, path
|
||||
from subprocess import call
|
||||
|
||||
prefix = environ.get('MESON_INSTALL_PREFIX', '/usr/local')
|
||||
sharedir = path.join(prefix, 'share')
|
||||
destdir = environ.get('DESTDIR', '')
|
||||
|
||||
# Package managers set this so we don't need to run
|
||||
if not destdir:
|
||||
print('Updating icon cache...')
|
||||
call(['gtk4-update-icon-cache', '-qtf', path.join(sharedir, 'icons', 'hicolor')])
|
||||
|
||||
print('Updating mime database...')
|
||||
call(['update-mime-database', path.join(sharedir, 'mime')])
|
||||
|
||||
print('Updating desktop database...')
|
||||
call(['update-desktop-database', '-q', path.join(sharedir, 'applications')])
|
||||
|
||||
print('Compiling GSettings schemas...')
|
||||
call(['glib-compile-schemas', path.join(sharedir, 'glib-2.0', 'schemas')])
|
@@ -1,5 +1,3 @@
|
||||
files:
|
||||
- source: /src/lib/clapper-gtk/po/clapper-gtk.pot
|
||||
translation: /src/lib/clapper-gtk/po/%osx_locale%.po
|
||||
- source: /src/bin/clapper-app/po/clapper-app.pot
|
||||
translation: /src/bin/clapper-app/po/%osx_locale%.po
|
||||
- source: /po/com.github.rafostar.Clapper.pot
|
||||
translation: /po/%osx_locale%.po
|
||||
|
387
css/styles.css
Normal file
@@ -0,0 +1,387 @@
|
||||
/* Defaults */
|
||||
scale marks {
|
||||
color: currentColor;
|
||||
}
|
||||
radio {
|
||||
margin-left: -2px;
|
||||
}
|
||||
scrolledwindow scrollbar.vertical slider {
|
||||
min-height: 16px;
|
||||
}
|
||||
|
||||
/* Adwaita is missing osd ListBox */
|
||||
.clapperplaylist {
|
||||
background: none;
|
||||
}
|
||||
.clapperplaylist row {
|
||||
border-radius: 5px;
|
||||
}
|
||||
.clapperplaylist row {
|
||||
color: @theme_fg_color;
|
||||
}
|
||||
.clapperplaylist row button {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
min-width: 28px;
|
||||
min-height: 28px;
|
||||
}
|
||||
.fullscreen.tvmode .clapperplaylist row button {
|
||||
min-width: 36px;
|
||||
min-height: 36px;
|
||||
margin-left: 2px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
.osd .clapperplaylist row image {
|
||||
-gtk-icon-shadow: none;
|
||||
}
|
||||
.osdheaderbar {
|
||||
background: transparent;
|
||||
}
|
||||
.osdheaderbar button {
|
||||
border: transparent;
|
||||
}
|
||||
.linkseparator {
|
||||
background: rgba(24,24,24,0.72);
|
||||
min-width: 1px;
|
||||
}
|
||||
.linkedleft image {
|
||||
margin-left: 2px;
|
||||
}
|
||||
.linkedright image {
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
/* Flat popovers */
|
||||
popover arrow,
|
||||
popover contents {
|
||||
border-color: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
.popoverseparator separator {
|
||||
background-color: @insensitive_fg_color;
|
||||
}
|
||||
|
||||
/* Rounded corners */
|
||||
.adwrounded.csd {
|
||||
border-radius: 8px;
|
||||
}
|
||||
.adwrounded.fullscreen,
|
||||
.adwrounded.maximized,
|
||||
.adwrounded.tiled,
|
||||
.adwrounded.tiled-top,
|
||||
.adwrounded.tiled-left,
|
||||
.adwrounded.tiled-right,
|
||||
.adwrounded.tiled-bottom {
|
||||
border-radius: 0px;
|
||||
}
|
||||
.roundedcorners {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
/* Reduce sliders size */
|
||||
scale trough slider {
|
||||
min-height: 18px;
|
||||
min-width: 18px;
|
||||
}
|
||||
.fullscreen.tvmode scale trough slider {
|
||||
min-height: 20px;
|
||||
min-width: 20px;
|
||||
}
|
||||
|
||||
.videowidget {
|
||||
min-width: 320px;
|
||||
min-height: 180px;
|
||||
}
|
||||
|
||||
.fullscreen.tvmode popover box {
|
||||
text-shadow: none;
|
||||
font-size: 21px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.clappercontrols {
|
||||
margin-left: 2px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
.fullscreen.tvmode .clappercontrols {
|
||||
margin-left: 1px;
|
||||
margin-right: 1px;
|
||||
}
|
||||
.clappercontrolsbutton {
|
||||
margin: 3px;
|
||||
margin-left: 1px;
|
||||
margin-right: 1px;
|
||||
}
|
||||
.fullscreen.tvmode .clappercontrolsbutton {
|
||||
min-width: 32px;
|
||||
min-height: 32px;
|
||||
margin: 5px;
|
||||
margin-left: 4px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
.clappercontrolsbutton.text-button {
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
}
|
||||
.fullscreen.tvmode button image {
|
||||
-gtk-icon-shadow: none;
|
||||
}
|
||||
.fullscreen.tvmode radio {
|
||||
margin-left: 0px;
|
||||
margin-right: 4px;
|
||||
border: 2px solid;
|
||||
min-width: 17px;
|
||||
min-height: 17px;
|
||||
}
|
||||
|
||||
/* Also affects popover buttons */
|
||||
.fullscreen.tvmode .clappercontrols button image {
|
||||
-gtk-icon-size: 26px;
|
||||
}
|
||||
.clappercontrolsbutton.text-button label {
|
||||
font-family: 'Cantarell', sans-serif;
|
||||
font-variant-numeric: tabular-nums;
|
||||
font-weight: 600;
|
||||
}
|
||||
.fullscreen.tvmode .clappercontrolsbutton.text-button label {
|
||||
font-size: 22px;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
/* Top Revealer */
|
||||
.fullscreen.tvmode .revealertopgrid {
|
||||
font-family: 'Cantarell', sans-serif;
|
||||
}
|
||||
.fullscreen.tvmode .tvtitle {
|
||||
font-size: 28px;
|
||||
font-weight: 500;
|
||||
text-shadow: none;
|
||||
}
|
||||
.fullscreen.tvmode .tvtime {
|
||||
margin-top: -2px;
|
||||
margin-bottom: -2px;
|
||||
min-height: 4px;
|
||||
font-size: 38px;
|
||||
font-weight: 700;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.fullscreen.tvmode .tvendtime {
|
||||
margin-top: -4px;
|
||||
margin-bottom: 2px;
|
||||
min-height: 6px;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
/* Position Scale */
|
||||
.positionscale {
|
||||
margin: -2px;
|
||||
}
|
||||
.positionscale trough highlight {
|
||||
min-height: 6px;
|
||||
}
|
||||
.fullscreen.tvmode .positionscale {
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
}
|
||||
.fullscreen.tvmode .positionscale.fine-tune {
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
}
|
||||
.fullscreen.tvmode .positionscale trough slider {
|
||||
color: transparent;
|
||||
background: transparent;
|
||||
border-color: transparent;
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
}
|
||||
.positionscale mark indicator {
|
||||
min-height: 6px;
|
||||
}
|
||||
.positionscale.fine-tune mark indicator {
|
||||
min-height: 6px;
|
||||
}
|
||||
.fullscreen.tvmode .positionscale mark indicator {
|
||||
min-height: 7px;
|
||||
min-width: 2px;
|
||||
}
|
||||
.fullscreen.tvmode .positionscale.fine-tune mark indicator {
|
||||
min-height: 7px;
|
||||
min-width: 2px;
|
||||
}
|
||||
.positionscale marks.top {
|
||||
margin-top: -6px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.positionscale marks.bottom {
|
||||
margin-top: 4px;
|
||||
margin-bottom: -6px;
|
||||
}
|
||||
.fullscreen.tvmode .positionscale marks.top {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.fullscreen.tvmode .positionscale marks.bottom {
|
||||
margin-top: 2px;
|
||||
}
|
||||
.fullscreen.tvmode .positionscale trough {
|
||||
border-radius: 3px;
|
||||
}
|
||||
.fullscreen.tvmode .positionscale trough highlight {
|
||||
border-radius: 3px;
|
||||
min-height: 20px;
|
||||
}
|
||||
.fullscreen.tvmode .positionscale.fine-tune trough highlight {
|
||||
border-radius: 3px;
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
/* Volume Scale */
|
||||
.volumescale {
|
||||
margin: -2px;
|
||||
margin-left: -8px;
|
||||
margin-right: -6px;
|
||||
min-height: 180px;
|
||||
}
|
||||
.fullscreen.tvmode .volumescale {
|
||||
margin: 2px;
|
||||
margin-left: -6px;
|
||||
margin-right: -4px;
|
||||
min-height: 260px;
|
||||
}
|
||||
.volumescale marks label {
|
||||
margin-right: 4px;
|
||||
margin-top: -4px;
|
||||
margin-bottom: -6px;
|
||||
}
|
||||
.volumescale trough highlight {
|
||||
min-width: 4px;
|
||||
}
|
||||
.fullscreen.tvmode .volumescale trough highlight {
|
||||
min-width: 6px;
|
||||
}
|
||||
.overamp trough highlight {
|
||||
background: @error_color;
|
||||
}
|
||||
|
||||
/* Elapsed Popover */
|
||||
.elapsedpopover {
|
||||
min-width: 326px;
|
||||
}
|
||||
.fullscreen.tvmode .elapsedpopover {
|
||||
min-width: 448px;
|
||||
}
|
||||
.elapsedpopover contents {
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
.speedscale {
|
||||
margin-left: 4px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
.speedscale trough highlight {
|
||||
min-height: 4px;
|
||||
}
|
||||
.fullscreen.tvmode .speedscale trough highlight {
|
||||
min-height: 6px;
|
||||
}
|
||||
|
||||
.narrowbutton {
|
||||
min-width: 8px;
|
||||
}
|
||||
@keyframes halfrotation {
|
||||
to { transform: rotate(0.5turn); }
|
||||
}
|
||||
.halfrotate {
|
||||
animation-name: halfrotation;
|
||||
animation-duration: 200ms;
|
||||
animation-delay: 280ms;
|
||||
animation-timing-function: linear;
|
||||
animation-fill-mode: forwards;
|
||||
animation-iteration-count: 1;
|
||||
}
|
||||
|
||||
/* Chapters */
|
||||
.chapterlabel {
|
||||
min-width: 32px;
|
||||
}
|
||||
.fullscreen.tvmode .chapterlabel {
|
||||
min-width: 40px;
|
||||
text-shadow: none;
|
||||
font-size: 22px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Open URI Dialog */
|
||||
.uridialogbox {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
/* Tweaks */
|
||||
.nobackground {
|
||||
background: none;
|
||||
}
|
||||
.noborder {
|
||||
border: none;
|
||||
}
|
||||
.controlsbox {
|
||||
background: @theme_bg_color;
|
||||
}
|
||||
.gpufriendly {
|
||||
box-shadow: -8px -8px transparent, 8px 8px transparent;
|
||||
}
|
||||
.fullscreen.gpufriendlyfs {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* Error BG */
|
||||
.blackbackground {
|
||||
background: black;
|
||||
}
|
||||
|
||||
/** SCALING LOW-RES **/
|
||||
.fullscreen.tvmode.lowres .clappercontrols button image {
|
||||
-gtk-icon-size: 22px;
|
||||
}
|
||||
.fullscreen.tvmode.lowres .clappercontrolsbutton {
|
||||
min-width: 28px;
|
||||
min-height: 28px;
|
||||
}
|
||||
.fullscreen.tvmode.lowres .clappercontrolsbutton.text-button label {
|
||||
font-size: 21px;
|
||||
}
|
||||
.fullscreen.tvmode.lowres .positionscale trough highlight {
|
||||
min-height: 18px;
|
||||
}
|
||||
.fullscreen.tvmode.lowres .positionscale.fine-tune trough highlight {
|
||||
min-height: 18px;
|
||||
}
|
||||
.fullscreen.tvmode.lowres popover box {
|
||||
font-size: 19px;
|
||||
}
|
||||
.fullscreen.tvmode.lowres radio {
|
||||
min-width: 15px;
|
||||
min-height: 15px;
|
||||
}
|
||||
.fullscreen.tvmode.lowres .clapperplaylist row button {
|
||||
min-width: 32px;
|
||||
min-height: 32px;
|
||||
}
|
||||
.fullscreen.tvmode.lowres .tvtitle {
|
||||
font-size: 26px;
|
||||
}
|
||||
.fullscreen.tvmode.lowres .tvtime {
|
||||
font-size: 34px;
|
||||
}
|
||||
.fullscreen.tvmode.lowres .tvendtime {
|
||||
font-size: 21px;
|
||||
}
|
||||
.fullscreen.tvmode.lowres .elapsedpopover {
|
||||
min-width: 410px;
|
||||
}
|
||||
.fullscreen.tvmode.lowres .chapterlabel {
|
||||
font-size: 21px;
|
||||
}
|
||||
|
||||
/** SCALING HI-RES **/
|
||||
.fullscreen.tvmode.hires .clappercontrols button image {
|
||||
-gtk-icon-size: 24px; /* Sharpest on 2160p with scaling 2x */
|
||||
}
|
Before Width: | Height: | Size: 4.8 KiB 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>
|
@@ -1,22 +1,14 @@
|
||||
[Desktop Entry]
|
||||
# Translators: Do NOT translate app name!
|
||||
Name=Clapper
|
||||
GenericName=Multimedia Player
|
||||
Comment=Play videos and music
|
||||
Categories=GTK;GNOME;AudioVideo;Player;Video;TV;
|
||||
MimeType=application/claps;application/mpeg4-iod;application/mpeg4-muxcodetable;application/mxf;application/ogg;application/ram;application/sdp;application/streamingmedia;application/vnd.apple.mpegurl;application/vnd.ms-asf;application/vnd.rn-realmedia;application/vnd.rn-realmedia-vbr;application/x-extension-m4a;application/x-extension-mp4;application/x-flac;application/x-flash-video;application/x-matroska;application/x-ogg;application/x-streamingmedia;audio/3gpp;audio/3gpp2;audio/aac;audio/ac3;audio/amr;audio/amr-wb;audio/basic;audio/dv;audio/eac3;audio/flac;audio/m4a;audio/midi;audio/mp1;audio/mp2;audio/mp3;audio/mp4;audio/mpeg;audio/mpegurl;audio/mpg;audio/ogg;audio/opus;audio/scpls;audio/vnd.dolby.heaac.1;audio/vnd.dolby.heaac.2;audio/vnd.dolby.mlp;audio/vnd.dts;audio/vnd.dts.hd;audio/vnd.rn-realaudio;audio/wav;audio/webm;audio/x-aac;audio/x-aiff;audio/x-ape;audio/x-flac;audio/x-gsm;audio/x-it;audio/x-m4a;audio/x-matroska;audio/x-mod;audio/x-mp1;audio/x-mp2;audio/x-mp3;audio/x-mpeg;audio/x-mpegurl;audio/x-mpg;audio/x-ms-asf;audio/x-ms-wma;audio/x-musepack;audio/x-pn-aiff;audio/x-pn-au;audio/x-pn-realaudio;audio/x-pn-wav;audio/x-real-audio;audio/x-realaudio;audio/x-s3m;audio/x-scpls;audio/x-shorten;audio/x-speex;audio/x-tta;audio/x-vorbis;audio/x-vorbis+ogg;audio/x-wav;audio/x-wavpack;audio/x-xm;video/3gp;video/3gpp;video/3gpp2;video/divx;video/dv;video/fli;video/flv;video/mp2t;video/mp4;video/mp4v-es;video/mpeg;video/mpeg-system;video/msvideo;video/ogg;video/quicktime;video/vnd.mpegurl;video/vnd.rn-realvideo;video/webm;video/x-avi;video/x-flc;video/x-fli;video/x-flv;video/x-m4v;video/x-matroska;video/x-mpeg;video/x-mpeg-system;video/x-mpeg2;video/x-ms-asf;video/x-ms-wm;video/x-ms-wmv;video/x-ms-wmx;video/x-msvideo;video/x-nsv;video/x-ogm+ogg;video/x-theora;video/x-theora+ogg;x-content/audio-cdda;x-content/audio-player;x-content/video-dvd;x-scheme-handler/mms;x-scheme-handler/mmsh;x-scheme-handler/rtmp;x-scheme-handler/rtp;x-scheme-handler/rtsp;
|
||||
Exec=clapper %U
|
||||
Exec=com.github.rafostar.Clapper %U
|
||||
Icon=com.github.rafostar.Clapper
|
||||
DBusActivatable=true
|
||||
StartupNotify=true
|
||||
Terminal=false
|
||||
Type=Application
|
||||
# Translators: Search terms to find this application. Do NOT translate the semicolons!
|
||||
Keywords=Video;Movie;Film;Clip;Series;Player;Playlist;DVD;TV;Disc;
|
||||
Keywords=Video;Movie;Film;Clip;Series;Player;Playlist;DVD;TV;Disc;Album;Music;GNOME;Clapper;
|
||||
# Translators: Do NOT translate or transliterate this text (these are enum types)!
|
||||
X-Purism-FormFactor=Workstation;Mobile;
|
||||
Actions=new-window;
|
||||
|
||||
[Desktop Action new-window]
|
||||
Name=New Window
|
||||
Exec=clapper --new-window
|
116
data/com.github.rafostar.Clapper.gschema.xml
Normal file
@@ -0,0 +1,116 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<schemalist gettext-domain="com.github.rafostar.Clapper">
|
||||
<schema id="com.github.rafostar.Clapper" path="/com/github/rafostar/Clapper/">
|
||||
<!-- General -->
|
||||
<key name="fullscreen-auto" type="b">
|
||||
<default>false</default>
|
||||
<summary>Automatically enter fullscreen when first file is loaded</summary>
|
||||
</key>
|
||||
<key name="volume-custom" type="b">
|
||||
<default>false</default>
|
||||
<summary>Set custom volume value at startup</summary>
|
||||
</key>
|
||||
<key name="volume-value" type="i">
|
||||
<default>100</default>
|
||||
<summary>Custom initial volume value in percentage after startup</summary>
|
||||
</key>
|
||||
<key name="after-playback" type="i">
|
||||
<default>0</default>
|
||||
<summary>What to do after playback finishes</summary>
|
||||
</key>
|
||||
|
||||
<!-- Behavior -->
|
||||
<key name="seeking-mode" type="i">
|
||||
<default>0</default>
|
||||
<summary>Mode used for seeking</summary>
|
||||
</key>
|
||||
<key name="seeking-value" type="i">
|
||||
<default>10</default>
|
||||
<summary>Time amount to seek with single press of arrow keys</summary>
|
||||
</key>
|
||||
<key name="seeking-unit" type="i">
|
||||
<default>0</default>
|
||||
<summary>Unit ID to use with seeking value</summary>
|
||||
</key>
|
||||
<key name="resume-enabled" type="b">
|
||||
<default>true</default>
|
||||
<summary>Ask to resume unfinished video</summary>
|
||||
</key>
|
||||
<key name="resume-database" type="s">
|
||||
<default>'[]'</default>
|
||||
<summary>Data storing unfinished videos resume info</summary>
|
||||
</key>
|
||||
<key name="floating-stick" type="b">
|
||||
<default>false</default>
|
||||
<summary>Auto stick floating window to all workspaces</summary>
|
||||
</key>
|
||||
|
||||
<!-- Audio -->
|
||||
<key name="audio-offset" type="i">
|
||||
<default>0</default>
|
||||
<summary>Offset time for audio tracks relative to video (milliseconds)</summary>
|
||||
</key>
|
||||
|
||||
<!-- Subtitles -->
|
||||
<key name="subtitle-font" type="s">
|
||||
<default>"Sans 12"</default>
|
||||
<summary>The subtitles font description</summary>
|
||||
</key>
|
||||
|
||||
<!-- Network -->
|
||||
<key name="webserver-enabled" type="b">
|
||||
<default>false</default>
|
||||
<summary>Enable WebSocket server for remote playback control</summary>
|
||||
</key>
|
||||
<key name="webserver-port" type="i">
|
||||
<default>6446</default>
|
||||
<summary>Listening port to use for incoming WebSocket connections</summary>
|
||||
</key>
|
||||
<key name="webapp-enabled" type="b">
|
||||
<default>false</default>
|
||||
<summary>Run built-in broadway based web application</summary>
|
||||
</key>
|
||||
<key name="webapp-port" type="i">
|
||||
<default>8086</default>
|
||||
<summary>Port for running broadwayd service</summary>
|
||||
</key>
|
||||
|
||||
<!-- Tweaks -->
|
||||
<key name="dark-theme" type="b">
|
||||
<default>true</default>
|
||||
<summary>Enable to force the app to use dark theme variant</summary>
|
||||
</key>
|
||||
<key name="render-shadows" type="b">
|
||||
<default>true</default>
|
||||
<summary>Enable rendering window shadows (only if theme has them)</summary>
|
||||
</key>
|
||||
|
||||
<!-- GStreamer -->
|
||||
<key name="plugin-ranking" type="s">
|
||||
<default>'{}'</default>
|
||||
<summary>Custom values for GStreamer plugin ranking</summary>
|
||||
</key>
|
||||
<key name="use-playbin3" type="b">
|
||||
<default>false</default>
|
||||
<summary>Use playbin3 element instead of playbin2</summary>
|
||||
</key>
|
||||
<key name="use-pipewire" type="b">
|
||||
<default>false</default>
|
||||
<summary>Use PipeWire for audio output</summary>
|
||||
</key>
|
||||
<key name="play-flags" type="i">
|
||||
<default>1687</default>
|
||||
<summary>Set PlayFlags for playbin</summary>
|
||||
</key>
|
||||
|
||||
<!-- Other -->
|
||||
<key name="window-size" type="s">
|
||||
<default>'[800, 490]'</default>
|
||||
<summary>Stores window size to restore on next launch</summary>
|
||||
</key>
|
||||
<key name="volume-last" type="d">
|
||||
<default>1</default>
|
||||
<summary>Stores last linear volume value to apply on startup</summary>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
@@ -1,155 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright 2024 Rafał Dzięgiel -->
|
||||
<component type="desktop-application">
|
||||
<id>com.github.rafostar.Clapper</id>
|
||||
<name>Clapper</name>
|
||||
<summary>Lean back and enjoy videos</summary>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>GPL-3.0-or-later</project_license>
|
||||
<!-- Old AppStream compat -->
|
||||
<developer_name>Rafał Dzięgiel</developer_name>
|
||||
<developer id="com.github.rafostar">
|
||||
<name>Rafał Dzięgiel</name>
|
||||
</developer>
|
||||
<translation type="gettext">clapper-app</translation>
|
||||
<name>Clapper</name>
|
||||
<summary>Simple and modern GNOME media player</summary>
|
||||
<translation type="gettext">com.github.rafostar.Clapper</translation>
|
||||
<launchable type="desktop-id">com.github.rafostar.Clapper.desktop</launchable>
|
||||
<description>
|
||||
<p>
|
||||
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 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 only video on top of all other windows for a PiP-like viewing experience.
|
||||
Mobile friendly transitions are also supported.
|
||||
</p>
|
||||
</description>
|
||||
<developer_name>Rafał Dzięgiel</developer_name>
|
||||
<url type="homepage">https://rafostar.github.io/clapper</url>
|
||||
<url type="bugtracker">https://github.com/Rafostar/clapper/issues</url>
|
||||
<url type="donation">https://liberapay.com/Clapper</url>
|
||||
<url type="help">https://github.com/Rafostar/clapper/wiki</url>
|
||||
<url type="vcs-browser">https://github.com/Rafostar/clapper</url>
|
||||
<description>
|
||||
<p>
|
||||
Clapper is a modern media player designed for simplicity and ease of use.
|
||||
Powered by GStreamer and built for the GNOME desktop environment using
|
||||
GTK4 toolkit, it has a clean and stylish interface that lets you focus
|
||||
on enjoying your favorite videos.
|
||||
</p>
|
||||
<p>
|
||||
Clapper uses a playback queue where you can add multiple media files.
|
||||
Think of it like a playlist that you can build. You can easily reorder
|
||||
items or remove them from the queue with a simple drag and drop operation.
|
||||
</p>
|
||||
</description>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image type="source">https://raw.githubusercontent.com/wiki/Rafostar/clapper/media/screenshot_01.png</image>
|
||||
<caption>Modern player with minimalist look</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image type="source">https://raw.githubusercontent.com/wiki/Rafostar/clapper/media/screenshot_02.png</image>
|
||||
<caption>See actual title of what you are watching</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image type="source">https://raw.githubusercontent.com/wiki/Rafostar/clapper/media/screenshot_03.png</image>
|
||||
<caption>Queue multiple media in any order you like</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image type="source">https://raw.githubusercontent.com/wiki/Rafostar/clapper/media/screenshot_04.png</image>
|
||||
<caption>Play either local or network content</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image type="source">https://raw.githubusercontent.com/wiki/Rafostar/clapper/media/screenshot_05.png</image>
|
||||
<caption>Enjoy adaptive UI that fits any screen size</caption>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<!-- Linux Phone Apps parses categories from XML -->
|
||||
<categories>
|
||||
<category>AudioVideo</category>
|
||||
<category>Video</category>
|
||||
</categories>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image type="source">https://raw.githubusercontent.com/wiki/Rafostar/clapper/media/screenshot-windowed.png</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image type="source">https://raw.githubusercontent.com/wiki/Rafostar/clapper/media/screenshot-fullscreen.png</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image type="source">https://raw.githubusercontent.com/wiki/Rafostar/clapper/media/screenshot-floating.png</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image type="source">https://raw.githubusercontent.com/wiki/Rafostar/clapper/media/screenshot-mobile.png</image>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<releases>
|
||||
<release version="0.8.0" date="2025-01-20">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Now uses playbin3 by default</li>
|
||||
<li>Added more command line options - including ability to set custom GStreamer filter and sink elements</li>
|
||||
<li>Support for creating multiple application windows</li>
|
||||
<li>Added menu option to clear playback queue</li>
|
||||
<li>Auto resize window to match aspect ratio with middle click or keyboard shortcut</li>
|
||||
<li>Added unfullscreen with Escape key</li>
|
||||
<li>Brand new libpeas based plugin system</li>
|
||||
<li>Remember and restore optimal bitrate (video quality) when starting adaptive streaming</li>
|
||||
<li>Other various improvements and bug fixes</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="0.6.1" date="2024-07-01">
|
||||
<description>
|
||||
<p>Bug fixes and translation updates</p>
|
||||
</description>
|
||||
</release>
|
||||
<release version="0.6.0" date="2024-04-22">
|
||||
<description>
|
||||
<p>
|
||||
In this release Clapper code was rewritten from scratch. Now split into
|
||||
two libraries and an application built on top of them, with:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Brand new, simplified and consistent UI</li>
|
||||
<li>Player now operates on playback queue model</li>
|
||||
<li>Multiple queue progression modes to choose from (consecutive, repeat item, carousel, shuffle)</li>
|
||||
<li>New media info window (shows media information and GStreamer elements used to play it)</li>
|
||||
<li>More dialogs and windows use libadwaita</li>
|
||||
<li>Multiple new status/info overlays showing what is going and other messages</li>
|
||||
<li>Added video buffering animation</li>
|
||||
<li>Clapper will now inform users about missing GStreamer plugins needed for playback</li>
|
||||
<li>Video chapters now appear throughout the seek bar on hover and while dragging slider</li>
|
||||
<li>Vastly expanded MPRIS implementation</li>
|
||||
<li>Integrated media discovery (see titles of queued items instead of URIs)</li>
|
||||
<li>Expanded WebSocket server functionality (for remote playback control)</li>
|
||||
<li>Increased maximum volume amplification level to 200%</li>
|
||||
<li>Added some new keyboard shortcuts</li>
|
||||
<li>In addition to volume, now also speed and queue progression mode are restored on launch</li>
|
||||
<li>Fixed keyboard shortcuts not being reversed (e.g. seek) in RTL languages</li>
|
||||
<li>Toggle play moved to left mouse button, right one now opens context menu (which was previously hard to access)</li>
|
||||
<li>Many bug fixes and QoL improvements</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="0.5.2" date="2022-06-24">
|
||||
<description>
|
||||
<p>Fixes:</p>
|
||||
<ul>
|
||||
<li>Fix time labels display on RTL languages</li>
|
||||
<li>Improved GL/GLES context automatic selection</li>
|
||||
</ul>
|
||||
<p>New translations:</p>
|
||||
<ul>
|
||||
<li>Hebrew</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="0.5.1" date="2022-05-29">
|
||||
<description>
|
||||
<p>
|
||||
A quick hotfix release. Fixes problems with new video sink on displays with non-100% scaling applied.
|
||||
See 0.5.0 version release notes for full recent changelog.
|
||||
</p>
|
||||
</description>
|
||||
</release>
|
||||
<release version="0.5.0" date="2022-05-28">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Includes and uses new, improved GStreamer video sink</li>
|
||||
<li>All networking ported to libsoup3</li>
|
||||
<li>A lot of cleanup, including removal of unfinished web application and old YT code</li>
|
||||
<li>App now supports D-Bus launching (DBusActivatable)</li>
|
||||
<li>Other small fixes</li>
|
||||
</ul>
|
||||
<p>New translations:</p>
|
||||
<ul>
|
||||
<li>Arabic</li>
|
||||
<li>Basque</li>
|
||||
<li>French</li>
|
||||
<li>Japanese</li>
|
||||
<li>Swedish</li>
|
||||
<li>Turkish</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="0.4.1" date="2021-12-20">
|
||||
<description>
|
||||
<p>Fixes:</p>
|
||||
@@ -284,17 +182,17 @@
|
||||
</description>
|
||||
</release>
|
||||
</releases>
|
||||
<content_rating type="oars-1.1"/>
|
||||
<branding>
|
||||
<color type="primary" scheme_preference="light">#8484ee</color>
|
||||
<color type="primary" scheme_preference="dark">#1a1a74</color>
|
||||
</branding>
|
||||
<content_rating type="oars-1.1" />
|
||||
<recommends>
|
||||
<control>keyboard</control>
|
||||
<control>pointing</control>
|
||||
<control>touch</control>
|
||||
</recommends>
|
||||
<requires>
|
||||
<display_length compare="ge">360</display_length>
|
||||
<display_length compare="ge">small</display_length>
|
||||
</requires>
|
||||
<custom>
|
||||
<value key="Purism::form_factor">workstation</value>
|
||||
<value key="Purism::form_factor">mobile</value>
|
||||
</custom>
|
||||
</component>
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
@@ -31,7 +31,7 @@
|
||||
<arg name="Uri" type="s" direction="in"/>
|
||||
</method>
|
||||
<signal name="Seeked">
|
||||
<arg name="Position" type="x"/>
|
||||
<arg type="x" name="Position"/>
|
||||
</signal>
|
||||
<property name="PlaybackStatus" type="s" access="read"/>
|
||||
<property name="LoopStatus" type="s" access="readwrite"/>
|
||||
@@ -49,38 +49,4 @@
|
||||
<property name="CanSeek" type="b" access="read"/>
|
||||
<property name="CanControl" type="b" access="read"/>
|
||||
</interface>
|
||||
<interface name="org.mpris.MediaPlayer2.TrackList">
|
||||
<method name="GetTracksMetadata">
|
||||
<arg name="TrackIds" type="ao" direction="in"/>
|
||||
<arg name="Metadata" type="aa{sv}" direction="out"/>
|
||||
</method>
|
||||
<method name="AddTrack">
|
||||
<arg name="Uri" type="s" direction="in"/>
|
||||
<arg name="AfterTrack" type="o" direction="in"/>
|
||||
<arg name="SetAsCurrent" type="b" direction="in"/>
|
||||
</method>
|
||||
<method name="RemoveTrack">
|
||||
<arg name="TrackId" type="o" direction="in"/>
|
||||
</method>
|
||||
<method name="GoTo">
|
||||
<arg name="TrackId" type="o" direction="in"/>
|
||||
</method>
|
||||
<signal name="TrackListReplaced">
|
||||
<arg name="Tracks" type="ao"/>
|
||||
<arg name="CurrentTrack" type="o"/>
|
||||
</signal>
|
||||
<signal name="TrackAdded">
|
||||
<arg name="Metadata" type="a{sv}"/>
|
||||
<arg name="AfterTrack" type="o"/>
|
||||
</signal>
|
||||
<signal name="TrackRemoved">
|
||||
<arg name="TrackId" type="o"/>
|
||||
</signal>
|
||||
<signal name="TrackMetadataChanged">
|
||||
<arg name="TrackId" type="o"/>
|
||||
<arg name="Metadata" type="a{sv}"/>
|
||||
</signal>
|
||||
<property name="Tracks" type="ao" access="read"/>
|
||||
<property name="CanEditTracks" 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 |
34
data/meson.build
Normal file
@@ -0,0 +1,34 @@
|
||||
iconsdir = join_paths(datadir, 'icons', 'hicolor')
|
||||
|
||||
appstream_util = find_program('appstream-util', required: false)
|
||||
if appstream_util.found()
|
||||
test('Validate appstream file', appstream_util, args: [
|
||||
'validate-relax',
|
||||
join_paths(meson.current_source_dir(), 'com.github.rafostar.Clapper.metainfo.xml')
|
||||
])
|
||||
endif
|
||||
|
||||
install_data('com.github.rafostar.Clapper.svg',
|
||||
install_dir: join_paths(iconsdir, 'scalable', 'apps')
|
||||
)
|
||||
install_data('com.github.rafostar.Clapper-symbolic.svg',
|
||||
install_dir: join_paths(iconsdir, 'symbolic', 'apps')
|
||||
)
|
||||
install_data('com.github.rafostar.Clapper.gschema.xml',
|
||||
install_dir: join_paths(datadir, 'glib-2.0', 'schemas')
|
||||
)
|
||||
install_data('com.github.rafostar.Clapper.xml',
|
||||
install_dir: join_paths(datadir, 'mime', 'packages')
|
||||
)
|
||||
install_data('com.github.rafostar.Clapper.desktop',
|
||||
install_dir: join_paths(datadir, 'applications')
|
||||
)
|
||||
install_data('com.github.rafostar.Clapper.metainfo.xml',
|
||||
install_dir: join_paths(datadir, 'metainfo')
|
||||
)
|
||||
gnome.compile_resources('com.github.rafostar.Clapper.data',
|
||||
'com.github.rafostar.Clapper.data.gresource.xml',
|
||||
gresource_bundle: true,
|
||||
install: true,
|
||||
install_dir: pkgdatadir,
|
||||
)
|
@@ -1,10 +0,0 @@
|
||||
gi_docgen = find_program('gi-docgen', required: get_option('doc'))
|
||||
dot = find_program('dot', required: get_option('doc')) # Class hierarchy generation
|
||||
build_doc = (gi_docgen.found() and dot.found() and get_option('doc'))
|
||||
|
||||
if build_doc
|
||||
if not build_gir
|
||||
error('Building documentation requires introspection to be compiled')
|
||||
endif
|
||||
subdir('reference')
|
||||
endif
|
@@ -1,64 +0,0 @@
|
||||
[library]
|
||||
version = "@CLAPPER_VERSION@"
|
||||
browse_url = "https://github.com/Rafostar/clapper/"
|
||||
repository_url = "https://github.com/Rafostar/clapper.git"
|
||||
website_url = "https://rafostar.github.io/clapper/"
|
||||
docs_url = "https://rafostar.github.io/clapper/doc/clapper-gtk/"
|
||||
authors = "Rafał Dzięgiel"
|
||||
logo_url = "clapper-logo.svg"
|
||||
license = "LGPL-2.1-or-later"
|
||||
description = "Clapper GTK integration library"
|
||||
devhelp = true
|
||||
search_index = true
|
||||
|
||||
dependencies = ["Clapper@CLAPPER_VERSION_SUFFIX@", "Gtk-4.0"]
|
||||
|
||||
[dependencies."Clapper@CLAPPER_VERSION_SUFFIX@"]
|
||||
name = "Clapper"
|
||||
description = "Clapper playback library"
|
||||
docs_url = "https://rafostar.github.io/clapper/doc/clapper/"
|
||||
|
||||
[dependencies."Gtk-4.0"]
|
||||
name = "Gtk"
|
||||
description = "The GTK toolkit"
|
||||
docs_url = "https://docs.gtk.org/gtk4/"
|
||||
|
||||
related = ["GLib-2.0", "GObject-2.0", "Gio-2.0", "Gst-1.0"]
|
||||
|
||||
[related."GLib-2.0"]
|
||||
name = "GLib"
|
||||
description = "A general-purpose, portable utility library"
|
||||
docs_url = "https://docs.gtk.org/glib/"
|
||||
|
||||
[related."GObject-2.0"]
|
||||
name = "GObject"
|
||||
description = "The base type system library"
|
||||
docs_url = "https://docs.gtk.org/gobject/"
|
||||
|
||||
[related."Gio-2.0"]
|
||||
name = "Gio"
|
||||
description = "GObject Interfaces and Objects, Networking, IPC, and I/O"
|
||||
docs_url = "https://docs.gtk.org/gio/"
|
||||
|
||||
[related."Gst-1.0"]
|
||||
name = "Gst"
|
||||
description = "GStreamer core library"
|
||||
docs_url = "https://gstreamer.freedesktop.org/documentation/gstreamer/gi-index.html"
|
||||
|
||||
[theme]
|
||||
name = "basic"
|
||||
show_index_summary = true
|
||||
show_class_hierarchy = true
|
||||
|
||||
[source-location]
|
||||
base_url = "https://github.com/Rafostar/clapper/tree/master/"
|
||||
|
||||
[extra]
|
||||
# The same order will be used when generating the index
|
||||
content_files = [
|
||||
"migrating-to-010.md",
|
||||
]
|
||||
content_images = [
|
||||
"images/clapper-logo.svg",
|
||||
]
|
||||
urlmap_file = "urlmap.js"
|
@@ -1,29 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 256 256" width="256" height="256">
|
||||
<defs>
|
||||
<path id="b1nGq5BrLC" d="M27.2 243.52C27.2 236.16 27.2 199.83 27.2 134.22C47.64 134.22 211.12 134.22 231.56 134.22C231.56 199.83 231.56 236.16 231.56 243.52C231.56 250.4 225.96 256 218.92 256C183.07 256 57.77 256 39.84 256C32.8 256 27.2 250.4 27.2 243.52Z"></path>
|
||||
<path id="a3jkaoNn4k" d="M24.32 103.65C24.32 106.22 24.32 127.02 24.32 129.58C24.32 132.78 26.72 135.18 29.92 135.18C50.41 135.18 215.08 135.18 235.72 135.18C238.76 135.18 241.32 132.78 241.32 129.58C241.32 127.02 241.32 106.22 241.32 103.65C241.32 100.45 238.76 98.05 235.72 98.05C194.59 98.05 50.41 98.05 29.92 98.05C26.72 98.05 24.32 100.45 24.32 103.65Z"></path>
|
||||
<path id="atpVQ8mnd" d="M174.59 135.18L211.87 98.05L171.07 98.05L133.78 135.18L174.59 135.18Z"></path>
|
||||
<path id="bMtYoNHu0" d="M76.81 135.18L114.1 98.05L73.13 98.05L35.84 135.18L76.81 135.18Z"></path>
|
||||
<path id="b5oP0Glp4" d="M19.04 69.41C19.84 71.97 25.92 91.97 26.72 94.37C27.68 97.41 30.72 99.01 33.76 98.05C54.09 91.81 216.68 42.04 237 35.8C240.04 35 241.64 31.8 240.84 28.92C240.04 26.36 233.96 6.36 233.16 3.96C232.2 0.92 229.16 -0.68 226.12 0.28C185.47 12.6 43.21 56.29 22.88 62.53C19.84 63.33 18.24 66.53 19.04 69.41Z"></path>
|
||||
<path id="lwBgev6DR" d="M176.51 54.37L129.94 29.4L169.15 17.56L215.72 42.52L176.51 54.37Z"></path>
|
||||
<path id="cUsjEMRUu" d="M81.61 83.49L35.04 58.69L74.25 46.69L120.82 71.49L81.61 83.49Z"></path>
|
||||
<path id="c1bcHZGXe" d="M14.72 66.69C14.72 72.93 14.72 123.02 14.72 129.26C14.72 132.62 17.44 135.18 20.64 135.18C26.56 135.18 74.09 135.18 80.01 135.18C84.33 135.18 87.21 130.86 85.61 127.02C82.89 120.78 61.45 70.53 58.73 64.29C57.77 62.05 55.69 60.77 53.29 60.77C46.73 60.77 24 60.77 20.64 60.77C17.44 60.77 14.72 63.33 14.72 66.69Z"></path>
|
||||
<path id="f2PtH0V1vC" d="M32.64 60.61C31.52 60.61 21.92 60.61 20.64 60.61C17.44 60.61 14.72 63.33 14.72 66.53C14.72 72.77 14.72 123.02 14.72 129.26C14.72 132.46 17.44 135.18 20.64 135.18C21.92 135.18 31.52 135.18 32.64 135.18C29.44 135.18 26.72 132.46 26.72 129.26C26.72 116.62 26.72 72.77 26.72 66.53C26.72 63.33 29.44 60.61 32.64 60.61Z"></path>
|
||||
<path id="a1SvrrkqVm" d="M231.56 135.18C231.56 143.82 231.56 148.46 231.56 149.42C231.56 149.42 231.56 149.42 231.56 149.42C108.98 149.42 40.8 149.42 27.2 149.42C27.2 149.42 27.2 149.42 27.2 149.42C27.2 140.94 27.2 136.14 27.2 135.18C27.2 135.18 27.2 135.18 27.2 135.18C149.78 135.18 217.96 135.18 231.56 135.18C231.56 135.18 231.56 135.18 231.56 135.18Z"></path>
|
||||
<path id="agXcvKqh8" d="M104.22 162.46L104.22 234.46L163.22 198.54L104.22 162.46Z"></path>
|
||||
</defs>
|
||||
<g>
|
||||
<g><use xlink:href="#b1nGq5BrLC" fill="#4747d1" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
|
||||
<g><use xlink:href="#a3jkaoNn4k" fill="#4747d1" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
|
||||
<g><use xlink:href="#atpVQ8mnd" fill="#f1f1f1" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
|
||||
<g><use xlink:href="#bMtYoNHu0" fill="#f1f1f1" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
|
||||
<g><use xlink:href="#b5oP0Glp4" fill="#4747d1" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
|
||||
<g><use xlink:href="#lwBgev6DR" fill="#f1f1f1" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
|
||||
<g><use xlink:href="#cUsjEMRUu" fill="#f1f1f1" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
|
||||
<g><use xlink:href="#c1bcHZGXe" fill="#a9a9a9" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
|
||||
<g><use xlink:href="#f2PtH0V1vC" opacity="0.2" fill="#000000" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
|
||||
<g><use xlink:href="#a1SvrrkqVm" opacity="0.2" fill="#000000" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
|
||||
<g><use xlink:href="#agXcvKqh8" fill="#f1f1f1" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 3.8 KiB |
@@ -1,35 +0,0 @@
|
||||
clappergtk_toml = configure_file(
|
||||
input: 'clapper-gtk.toml.in',
|
||||
output: 'clapper-gtk.toml',
|
||||
configuration: doc_version_conf,
|
||||
install: true,
|
||||
install_dir: join_paths(datadir, 'doc', 'clapper-gtk'),
|
||||
)
|
||||
|
||||
extra_md_files = [
|
||||
'migrating-to-010.md',
|
||||
]
|
||||
|
||||
custom_target('clapper-gtk-doc',
|
||||
input: [
|
||||
clappergtk_toml,
|
||||
clappergtk_gir[0],
|
||||
],
|
||||
output: 'clapper-gtk',
|
||||
command: [
|
||||
gi_docgen,
|
||||
'generate',
|
||||
gi_docgen_common_args,
|
||||
'--add-include-path=@0@'.format(join_paths(meson.project_build_root(), 'src', 'lib', 'clapper')),
|
||||
'--add-include-path=@0@'.format(join_paths(meson.project_build_root(), 'src', 'lib', 'clapper-gtk')),
|
||||
'--config=@INPUT0@',
|
||||
'--output-dir=@OUTPUT@',
|
||||
'--content-dir=@0@'.format(meson.current_build_dir()),
|
||||
'--content-dir=@0@'.format(meson.current_source_dir()),
|
||||
'@INPUT1@',
|
||||
],
|
||||
depend_files: extra_md_files,
|
||||
build_by_default: true,
|
||||
install: true,
|
||||
install_dir: join_paths(datadir, 'doc'),
|
||||
)
|
@@ -1,22 +0,0 @@
|
||||
Title: Migrating to ClapperGtk 0.10
|
||||
Slug: migrating-to-010
|
||||
|
||||
### AV widget
|
||||
|
||||
Code of [class@ClapperGtk.Video] was split into a base class [class@ClapperGtk.Av] from which
|
||||
[class@ClapperGtk.Video] and newly added [class@ClapperGtk.Audio] widgets are made.
|
||||
|
||||
This code split implies following changes:
|
||||
|
||||
* Properties `auto-inhibit`, `inhibited` and `player` were moved into AV base class, since these
|
||||
are usually used without explicit need to specify object class they belong to, this change should
|
||||
not affect most use-cases.
|
||||
* Methods to get above properties are now in AV, but also left in video widget for compatibility purposes.
|
||||
* Built-in widget actions starting with `video.` prefix are deprecated (also left for compatibility).
|
||||
Implementations that used them are encouraged to use `av.` actions now. All actions from video widget were
|
||||
ported to AV widget as they were, so updating your app should be as easy as changing this action prefix.
|
||||
|
||||
### Other Info
|
||||
|
||||
Above describes changes to GTK integration library, for the playback library
|
||||
check out [other migration guide](../clapper/migrating-to-010.html).
|
@@ -1,8 +0,0 @@
|
||||
baseURLs = [
|
||||
['GLib', 'https://docs.gtk.org/glib/'],
|
||||
['GObject', 'https://docs.gtk.org/gobject/'],
|
||||
['Gio', 'https://docs.gtk.org/gio/'],
|
||||
['Gtk', 'https://docs.gtk.org/gtk4/'],
|
||||
['Gst', 'https://gstreamer.freedesktop.org/documentation/gstreamer/gi-index.html?'],
|
||||
['Clapper', 'https://rafostar.github.io/clapper/doc/clapper/'],
|
||||
]
|
@@ -1,153 +0,0 @@
|
||||
Title: Clapper Enhancers
|
||||
Slug: clapper-enhancers
|
||||
|
||||
### Overview
|
||||
|
||||
Clapper Enhancers are special plugins loaded through `libpeas` for Clapper library.
|
||||
The idea is to enhance it (including applications that use Clapper) with new
|
||||
capabilities that do stuff outside of `GStreamer` scope of things without increasing
|
||||
number of dependencies of Clapper itself (especially for features that not everyone needs).
|
||||
|
||||
To avoid confusion with term "plugins" that `GStreamer` uses, the name "enhancers"
|
||||
was choosen instead.
|
||||
|
||||
In addition to writing enhancers in pure `C`, they can be written in any programmable
|
||||
language that is supported by `libpeas` and works with Clapper library bindings
|
||||
(examples being `Python`, `GJS` and `Vala`). This makes it possible for individual users
|
||||
to add their own custom functionalities that they want to use individually.
|
||||
|
||||
### Types
|
||||
|
||||
Clapper gives three interfaces for writing enhancers for different things, these are:
|
||||
|
||||
- [Extractable](extractable-enhancers.html)
|
||||
- [Playlistable](playlistable-enhancers.html)
|
||||
- [Reactable](reactable-enhancers.html)
|
||||
|
||||
### Basics
|
||||
|
||||
Each enhancer is a `libpeas` compatible module. As such it follows its requirements for
|
||||
writing plugins and is a [class@GObject.Object] sublass implementing one or more of interfaces
|
||||
that Clapper library provides.
|
||||
|
||||
Due to the plugins nature, written enhancer can be either submitted to the main [Clapper Enhancers
|
||||
repository](https://github.com/Rafostar/clapper-enhancers) when it seems useful for more than a single
|
||||
application. Alternatively, it can be shipped as part your application. Users can also write their
|
||||
own/custom local enhancer plugins.
|
||||
|
||||
### Loading Enhancers
|
||||
|
||||
Clapper will try to lazy load enhancer modules, meaning they will not be loaded unless they are used.
|
||||
As an additional safety precaution, enhancers can be disallowed from their instances being created with
|
||||
[property@Clapper.EnhancerProxy:target-creation-allowed]. Enhancers that operate on-demand
|
||||
(when supported URI is given) such as [iface@Clapper.Extractable] and [iface@Clapper.Playlistable]
|
||||
are allowed (enabled) by default, while [iface@Clapper.Reactable] are not.
|
||||
|
||||
Environment variables:
|
||||
|
||||
* `CLAPPER_ENHANCERS_PATH` - override for default path where Clapper loads enhancers from
|
||||
* `CLAPPER_ENHANCERS_EXTRA_PATH` - additional path to scan for enhancer plugins
|
||||
|
||||
While both allow to specify multiple directories (with `:` separation), applications and
|
||||
users should mostly use extra path in order to add their own enhancers from non-standard
|
||||
installation directory. They can override default path in case where they want to forbid
|
||||
using stock enhancers for some reason.
|
||||
|
||||
### Enhancer Proxies
|
||||
|
||||
In order to create enhancers when needed and use them only within thread they were created in,
|
||||
Clapper manages enhancer instances on its own. It gives applications proxy objects for
|
||||
browsing and configuring them.
|
||||
|
||||
Only after Clapper library is initialized, you can get either the global (application scope) list
|
||||
([class@Clapper.EnhancerProxyList]) of enhancers proxies with [func@Clapper.get_global_enhancer_proxies]
|
||||
or player scope with [method@Clapper.Player.get_enhancer_proxies].
|
||||
|
||||
Properties set on the global list will carry over to all created player instances afterwards.
|
||||
While these set on a list from a player are applied to enhancers created by this player only.
|
||||
You can use that to your advantage to only allow creation of some type of enhancer in only some
|
||||
player instances.
|
||||
|
||||
### Properties
|
||||
|
||||
Some enhancers might want to expose some configuration. For this cases they should install
|
||||
[class@GObject.Object] properties in their class. They must only use fundamental types from the list below:
|
||||
|
||||
* boolean
|
||||
* int
|
||||
* uint
|
||||
* double
|
||||
* string
|
||||
|
||||
They should include one or more of [flags@Clapper.EnhancerParamFlags].
|
||||
Properties in object can have `global`, `local`, neither or both flags at once.
|
||||
|
||||
The ones with [Clapper.EnhancerParamFlags.GLOBAL] are for user to configure. They should
|
||||
be exposed (ideally in the UI) and used for things that make sense to be set for all
|
||||
applications at once (e.g. supported media codec by user device, preferred language, etc.).
|
||||
|
||||
On the other hand, properties with [Clapper.EnhancerParamFlags.LOCAL] are for application scope
|
||||
usage only. They never carry over to other apps, nor they can be set on global enhancers list.
|
||||
Instead they are configured per player instance.
|
||||
|
||||
When property is neither `global` or `local` it is considered to be plugin internal property.
|
||||
Clapper will never access them, as such they can be of any type (not limited to above list).
|
||||
This also makes properties that are already installed in base classes of subclassed object
|
||||
not appear in the UI.
|
||||
|
||||
When both flags are set, property will initially use globally set value by user while still
|
||||
allowing application to override this value locally per player instance.
|
||||
|
||||
Extra flags like [Clapper.EnhancerParamFlags.FILEPATH] and [Clapper.EnhancerParamFlags.DIRPATH]
|
||||
can be used (usually with `string` type of property) in order to let application know that this
|
||||
field holds a file/directory path and allow it to present file selection dialog to the user instead
|
||||
of text entry.
|
||||
|
||||
### Configuring Enhancers
|
||||
|
||||
Applications browse properties of enhancer via [method@Clapper.EnhancerProxy.get_target_properties]
|
||||
which returns a list of [class@GObject.ParamSpec]. By inspecting their `flags` application can know
|
||||
whether property is `global`, `local` or both.
|
||||
|
||||
Use [method@Clapper.EnhancerProxy.get_settings] to get a [class@Gio.Settings] with `global` properties
|
||||
to read and write (note that only users should be able to change them, thus you might want to bind these
|
||||
into some UI widgets for that). These can be (with user consent) set on either proxy from global proxies
|
||||
list or the player one.
|
||||
|
||||
Use [method@Clapper.EnhancerProxy.set_locally] to set `local` properties. These are meant for applications
|
||||
to freely customize as they please. Remember that you can only set them on a enhancer proxy object belonging
|
||||
to some player instance and not the global one.
|
||||
|
||||
### Plugin Info File
|
||||
|
||||
An enhancer plugin should be placed within directory that includes its [Peas] plugin
|
||||
description file. It should be a text file with a `.plugin` extension and contain at least
|
||||
following content:
|
||||
|
||||
```
|
||||
[Plugin]
|
||||
Module=example_enhancer
|
||||
Name=Example Enhancer
|
||||
Description=This enhancer serves as an example
|
||||
Version=0.0.1
|
||||
```
|
||||
|
||||
* `Module` - module entry file name. It also acts as enhancer ID and should be unique for each.
|
||||
It is recommended to use app/custom prefix in its name.
|
||||
* `Name` - module friendly name for displaying in UI and such.
|
||||
* `Description` - description to present to the user for what it does.
|
||||
* `Version` - enhancer version. In order to lazy load enhancers, Clapper will cache each
|
||||
enhancer data and olny reload it if version changes, so keep this always updated.
|
||||
|
||||
If module is written in interpretable programming language it must also contain `Loader` key
|
||||
with interpreter name (e.g. `Loader=python`).
|
||||
|
||||
Some enhancer interfaces require additional fields to be put in this file. They are described
|
||||
in the requirements of each one in their documentation pages that are listed in the
|
||||
[Types section](clapper-enhancers.html#types).
|
||||
|
||||
### Adding Enhancers to Flatpak App
|
||||
|
||||
If you are using Clapper as part of a `Flatpak` application, you can get all the enhancers from their main repo as an extension
|
||||
(info [here](https://github.com/flathub/com.github.rafostar.Clapper?tab=readme-ov-file#comgithubrafostarclapperenhancers)),
|
||||
thus you do not need to build them yourself.
|
@@ -1,78 +0,0 @@
|
||||
[library]
|
||||
version = "@CLAPPER_VERSION@"
|
||||
browse_url = "https://github.com/Rafostar/clapper/"
|
||||
repository_url = "https://github.com/Rafostar/clapper.git"
|
||||
website_url = "https://rafostar.github.io/clapper/"
|
||||
docs_url = "https://rafostar.github.io/clapper/doc/clapper/"
|
||||
authors = "Rafał Dzięgiel"
|
||||
logo_url = "clapper-logo.svg"
|
||||
license = "LGPL-2.1-or-later"
|
||||
description = "Clapper playback library"
|
||||
devhelp = true
|
||||
search_index = true
|
||||
|
||||
dependencies = ["GLib-2.0", "GObject-2.0", "Gio-2.0", "Gst-1.0", "GstBase-1.0", "GstAudio-1.0", "GstTag-1.0", "GstPbutils-1.0"]
|
||||
|
||||
[dependencies."GLib-2.0"]
|
||||
name = "GLib"
|
||||
description = "A general-purpose, portable utility library"
|
||||
docs_url = "https://docs.gtk.org/glib/"
|
||||
|
||||
[dependencies."GObject-2.0"]
|
||||
name = "GObject"
|
||||
description = "The base type system library"
|
||||
docs_url = "https://docs.gtk.org/gobject/"
|
||||
|
||||
[dependencies."Gio-2.0"]
|
||||
name = "Gio"
|
||||
description = "GObject Interfaces and Objects, Networking, IPC, and I/O"
|
||||
docs_url = "https://docs.gtk.org/gio/"
|
||||
|
||||
[dependencies."Gst-1.0"]
|
||||
name = "Gst"
|
||||
description = "GStreamer core library"
|
||||
docs_url = "https://gstreamer.freedesktop.org/documentation/gstreamer/gi-index.html"
|
||||
|
||||
[dependencies."GstBase-1.0"]
|
||||
name = "GstBase"
|
||||
description = "GStreamer base and utility classes"
|
||||
docs_url = "https://gstreamer.freedesktop.org/documentation/base/"
|
||||
|
||||
[dependencies."GstAudio-1.0"]
|
||||
name = "GstAudio"
|
||||
description = "GStreamer audio library"
|
||||
docs_url = "https://gstreamer.freedesktop.org/documentation/audio/"
|
||||
|
||||
[dependencies."GstTag-1.0"]
|
||||
name = "GstTag"
|
||||
description = "GStreamer tag support library"
|
||||
docs_url = "https://gstreamer.freedesktop.org/documentation/tag/"
|
||||
|
||||
[dependencies."GstPbutils-1.0"]
|
||||
name = "GstPbutils"
|
||||
description = "GStreamer base utils library"
|
||||
docs_url = "https://gstreamer.freedesktop.org/documentation/pbutils/"
|
||||
|
||||
related = []
|
||||
|
||||
[theme]
|
||||
name = "basic"
|
||||
show_index_summary = true
|
||||
show_class_hierarchy = true
|
||||
|
||||
[source-location]
|
||||
base_url = "https://github.com/Rafostar/clapper/tree/master/"
|
||||
|
||||
[extra]
|
||||
# The same order will be used when generating the index
|
||||
content_files = [
|
||||
"clapper-enhancers.md",
|
||||
"extractable-enhancers.md",
|
||||
"playlistable-enhancers.md",
|
||||
"reactable-enhancers.md",
|
||||
"migrating-to-010.md",
|
||||
]
|
||||
content_images = [
|
||||
"images/clapper-logo.svg",
|
||||
]
|
||||
urlmap_file = "urlmap.js"
|
@@ -1,76 +0,0 @@
|
||||
Title: Extractable Enhancers
|
||||
Slug: extractable-enhancers
|
||||
|
||||
### Overview
|
||||
|
||||
[iface@Clapper.Extractable] is an interface to implement enhancers that need to
|
||||
resolve given URI into data that `GStreamer` will be able to play. While not
|
||||
limited to, main use-case is for media information extraction.
|
||||
|
||||
While implementer is free to write whole extraction by hand, he can alternatively
|
||||
integrate some 3rd party library that does most of this work. In such case, extractable
|
||||
enhancer is more of a wrapper for integrating said library. This is especially useful
|
||||
if library that you want to use is written in different programming language than Clapper is.
|
||||
|
||||
For the basics about writing enhancers see [Clapper Enhancers](clapper-enhancers.html).
|
||||
|
||||
### Requirements
|
||||
|
||||
Additional fields for `.plugin` info file: `X-Schemes` and `X-Hosts`. The former one should
|
||||
hold the `;` separated list of supported URI schemes, while the latter is for hostnames.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
X-Schemes=https;expl
|
||||
X-Hosts=example.com;other.example.com
|
||||
```
|
||||
|
||||
With this in place, enhancer will be loaded and used for URIs that match combinations
|
||||
of one of the schemes and hosts. The special rule is that when using some custom URI
|
||||
scheme other than `http(s)`, `X-Hosts` can be skipped since such URI explicitly
|
||||
says to use this module.
|
||||
|
||||
Considering all of the above, this enhancer would try to extract URIs like:
|
||||
|
||||
* `https://example.com/video_id=ABCD`
|
||||
* `expl://video.it?id=ABCD`
|
||||
|
||||
It would not act however for:
|
||||
|
||||
* `https://video.it?id=ABCD`
|
||||
* `qwerty://other.example.com/video_id=ABCD`
|
||||
|
||||
An enhancer of this type must implement [vfunc@Clapper.Extractable.extract] virtual method.
|
||||
|
||||
### Harvesting data
|
||||
|
||||
When [vfunc@Clapper.Extractable.extract] is called, newly made [class@Clapper.Harvest]
|
||||
is passed as this function argument. Implementation is responsible for filling it with
|
||||
data (see [method@Clapper.Harvest.fill]) that can be played. Such content can be either
|
||||
a resolved URI to actual media file or some streaming manifest (like `HLS` or `DASH`).
|
||||
|
||||
During extract function, implementation might optionally add media tags such as title
|
||||
(which will be merged with tags of [class@Clapper.MediaItem]) and extra HTTP request
|
||||
headers if any are required to access this content.
|
||||
|
||||
### Multiple items extraction
|
||||
|
||||
It is possible to handle URIs which would normally return more than one media item to play.
|
||||
Examples being playlists, search queries, related videos, etc.
|
||||
|
||||
This can be handled in two ways, depending on set media type:
|
||||
|
||||
1. `text/uri-list`
|
||||
2. `application/clapper-playlist`
|
||||
|
||||
If you use the first option, harvest should be filled with idividual URIs one per line.
|
||||
Clapper will use its built-in URI list parser to create a media item for each URI and
|
||||
place them in its playback queue. This is equivalent of creating [class@Clapper.MediaItem]
|
||||
for each of these URIs without setting any tags in it initially.
|
||||
|
||||
The second option requires for this enhancer to also implement [iface@Clapper.Playlistable]
|
||||
interface. In this case, you can fill harvest with ANY kind of data considering that
|
||||
[vfunc@Clapper.Playlistable.parse] of your own enhancer will be used with the data you
|
||||
passed. With this, you can add more info to media items such as extra tags, timeline markers
|
||||
or subtitle URI. Useful if your extractor extracts both URIs and tags in one go.
|
@@ -1,29 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 256 256" width="256" height="256">
|
||||
<defs>
|
||||
<path id="b1nGq5BrLC" d="M27.2 243.52C27.2 236.16 27.2 199.83 27.2 134.22C47.64 134.22 211.12 134.22 231.56 134.22C231.56 199.83 231.56 236.16 231.56 243.52C231.56 250.4 225.96 256 218.92 256C183.07 256 57.77 256 39.84 256C32.8 256 27.2 250.4 27.2 243.52Z"></path>
|
||||
<path id="a3jkaoNn4k" d="M24.32 103.65C24.32 106.22 24.32 127.02 24.32 129.58C24.32 132.78 26.72 135.18 29.92 135.18C50.41 135.18 215.08 135.18 235.72 135.18C238.76 135.18 241.32 132.78 241.32 129.58C241.32 127.02 241.32 106.22 241.32 103.65C241.32 100.45 238.76 98.05 235.72 98.05C194.59 98.05 50.41 98.05 29.92 98.05C26.72 98.05 24.32 100.45 24.32 103.65Z"></path>
|
||||
<path id="atpVQ8mnd" d="M174.59 135.18L211.87 98.05L171.07 98.05L133.78 135.18L174.59 135.18Z"></path>
|
||||
<path id="bMtYoNHu0" d="M76.81 135.18L114.1 98.05L73.13 98.05L35.84 135.18L76.81 135.18Z"></path>
|
||||
<path id="b5oP0Glp4" d="M19.04 69.41C19.84 71.97 25.92 91.97 26.72 94.37C27.68 97.41 30.72 99.01 33.76 98.05C54.09 91.81 216.68 42.04 237 35.8C240.04 35 241.64 31.8 240.84 28.92C240.04 26.36 233.96 6.36 233.16 3.96C232.2 0.92 229.16 -0.68 226.12 0.28C185.47 12.6 43.21 56.29 22.88 62.53C19.84 63.33 18.24 66.53 19.04 69.41Z"></path>
|
||||
<path id="lwBgev6DR" d="M176.51 54.37L129.94 29.4L169.15 17.56L215.72 42.52L176.51 54.37Z"></path>
|
||||
<path id="cUsjEMRUu" d="M81.61 83.49L35.04 58.69L74.25 46.69L120.82 71.49L81.61 83.49Z"></path>
|
||||
<path id="c1bcHZGXe" d="M14.72 66.69C14.72 72.93 14.72 123.02 14.72 129.26C14.72 132.62 17.44 135.18 20.64 135.18C26.56 135.18 74.09 135.18 80.01 135.18C84.33 135.18 87.21 130.86 85.61 127.02C82.89 120.78 61.45 70.53 58.73 64.29C57.77 62.05 55.69 60.77 53.29 60.77C46.73 60.77 24 60.77 20.64 60.77C17.44 60.77 14.72 63.33 14.72 66.69Z"></path>
|
||||
<path id="f2PtH0V1vC" d="M32.64 60.61C31.52 60.61 21.92 60.61 20.64 60.61C17.44 60.61 14.72 63.33 14.72 66.53C14.72 72.77 14.72 123.02 14.72 129.26C14.72 132.46 17.44 135.18 20.64 135.18C21.92 135.18 31.52 135.18 32.64 135.18C29.44 135.18 26.72 132.46 26.72 129.26C26.72 116.62 26.72 72.77 26.72 66.53C26.72 63.33 29.44 60.61 32.64 60.61Z"></path>
|
||||
<path id="a1SvrrkqVm" d="M231.56 135.18C231.56 143.82 231.56 148.46 231.56 149.42C231.56 149.42 231.56 149.42 231.56 149.42C108.98 149.42 40.8 149.42 27.2 149.42C27.2 149.42 27.2 149.42 27.2 149.42C27.2 140.94 27.2 136.14 27.2 135.18C27.2 135.18 27.2 135.18 27.2 135.18C149.78 135.18 217.96 135.18 231.56 135.18C231.56 135.18 231.56 135.18 231.56 135.18Z"></path>
|
||||
<path id="agXcvKqh8" d="M104.22 162.46L104.22 234.46L163.22 198.54L104.22 162.46Z"></path>
|
||||
</defs>
|
||||
<g>
|
||||
<g><use xlink:href="#b1nGq5BrLC" fill="#4747d1" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
|
||||
<g><use xlink:href="#a3jkaoNn4k" fill="#4747d1" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
|
||||
<g><use xlink:href="#atpVQ8mnd" fill="#f1f1f1" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
|
||||
<g><use xlink:href="#bMtYoNHu0" fill="#f1f1f1" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
|
||||
<g><use xlink:href="#b5oP0Glp4" fill="#4747d1" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
|
||||
<g><use xlink:href="#lwBgev6DR" fill="#f1f1f1" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
|
||||
<g><use xlink:href="#cUsjEMRUu" fill="#f1f1f1" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
|
||||
<g><use xlink:href="#c1bcHZGXe" fill="#a9a9a9" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
|
||||
<g><use xlink:href="#f2PtH0V1vC" opacity="0.2" fill="#000000" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
|
||||
<g><use xlink:href="#a1SvrrkqVm" opacity="0.2" fill="#000000" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
|
||||
<g><use xlink:href="#agXcvKqh8" fill="#f1f1f1" transform="matrix(1, 0, 0, 0.97, 0, 0)"></use></g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 3.8 KiB |
@@ -1,38 +0,0 @@
|
||||
clapper_toml = configure_file(
|
||||
input: 'clapper.toml.in',
|
||||
output: 'clapper.toml',
|
||||
configuration: doc_version_conf,
|
||||
install: true,
|
||||
install_dir: join_paths(datadir, 'doc', 'clapper'),
|
||||
)
|
||||
|
||||
extra_md_files = [
|
||||
'clapper-enhancers.md',
|
||||
'extractable-enhancers.md',
|
||||
'playlistable-enhancers.md',
|
||||
'reactable-enhancers.md',
|
||||
'migrating-to-010.md',
|
||||
]
|
||||
|
||||
custom_target('clapper-doc',
|
||||
input: [
|
||||
clapper_toml,
|
||||
clapper_gir[0],
|
||||
],
|
||||
output: 'clapper',
|
||||
command: [
|
||||
gi_docgen,
|
||||
'generate',
|
||||
gi_docgen_common_args,
|
||||
'--add-include-path=@0@'.format(join_paths(meson.project_build_root(), 'src', 'lib', 'clapper')),
|
||||
'--config=@INPUT0@',
|
||||
'--output-dir=@OUTPUT@',
|
||||
'--content-dir=@0@'.format(meson.current_build_dir()),
|
||||
'--content-dir=@0@'.format(meson.current_source_dir()),
|
||||
'@INPUT1@',
|
||||
],
|
||||
depend_files: extra_md_files,
|
||||
build_by_default: true,
|
||||
install: true,
|
||||
install_dir: join_paths(datadir, 'doc'),
|
||||
)
|
@@ -1,44 +0,0 @@
|
||||
Title: Migrating to Clapper 0.10
|
||||
Slug: migrating-to-010
|
||||
|
||||
### Replace Features with Enhancers
|
||||
|
||||
Clapper 0.10 deprecates [class@Clapper.Feature] objects in favour [Clapper Enhancers](clapper-enhancers.html)
|
||||
used via [class@Clapper.EnhancerProxy].
|
||||
|
||||
Old [class@Clapper.Feature] objects (including `mpris`, `discoverer` and `server`) are left for compatibility
|
||||
reasons, but all apps using them are advised to migrate to enhancer plugins which already surpassed former
|
||||
ones in what can be achieved with them.
|
||||
|
||||
Since these are in the form of plugins scanned during init, one of the differences is that you now check
|
||||
their availability at runtime instead of compile time like before.
|
||||
|
||||
Something like this:
|
||||
|
||||
```c
|
||||
#if CLAPPER_HAVE_MPRIS
|
||||
ClapperFeature *feature = CLAPPER_FEATURE (clapper_mpris_new (
|
||||
mpris_name, APP_NAME, APP_ID));
|
||||
clapper_player_add_feature (player, feature);
|
||||
gst_object_unref (feature);
|
||||
#endif
|
||||
```
|
||||
|
||||
Can be implemented like this:
|
||||
|
||||
```c
|
||||
ClapperEnhancerProxyList *proxies = clapper_player_get_enhancer_proxies (player);
|
||||
ClapperEnhancerProxy *proxy = clapper_enhancer_proxy_list_get_proxy_by_module (proxies, "clapper-mpris");
|
||||
|
||||
if (proxy) {
|
||||
clapper_enhancer_proxy_set_locally (proxy,
|
||||
"own-name", mpris_name,
|
||||
"identity", APP_NAME,
|
||||
"desktop-entry", APP_ID, NULL);
|
||||
clapper_enhancer_proxy_set_target_creation_allowed (proxy, TRUE);
|
||||
gst_object_unref (proxy);
|
||||
}
|
||||
```
|
||||
|
||||
For more information how to use enhancers and how to write your own,
|
||||
see [Clapper Enhancers](clapper-enhancers.html) documentation.
|
@@ -1,39 +0,0 @@
|
||||
Title: Playlistable Enhancers
|
||||
Slug: playlistable-enhancers
|
||||
|
||||
### Overview
|
||||
|
||||
[iface@Clapper.Playlistable] is an interface to implement playlist parsers.
|
||||
Allows to expand Clapper library with an ability to read data from which one
|
||||
or more media items should be created.
|
||||
|
||||
To load playlist within Clapper, just create a new media item which has an URI
|
||||
leading to data that playlistable enhancer will act upon. After parsing, that item
|
||||
will be merged with first parsed item and the rest will be inserted into queue after
|
||||
its position.
|
||||
|
||||
Essentially, such enhancer inserts items from a playlist into playback queue upon
|
||||
which Clapper operates. It can also handle nested playlits (a playlist URI within
|
||||
another playlist) with unlimited amount of nested levels.
|
||||
|
||||
For the basics about writing enhancers see [Clapper Enhancers](clapper-enhancers.html).
|
||||
|
||||
### Requirements
|
||||
|
||||
Additional fields for `.plugin` info file:
|
||||
|
||||
* `X-Data-Prefix` - describe text that data should start with
|
||||
* `X-Data-Contains` - data must contain given phrase
|
||||
* `X-Data-Regex` - regular expression to run on data
|
||||
|
||||
These are used by `typefinder` to determine whether given data is a playlist for
|
||||
this enhancer to handle. At least one of the above must be added to plugin info file.
|
||||
|
||||
An enhancer of this type must implement [vfunc@Clapper.Playlistable.parse] virtual method.
|
||||
|
||||
### Parsing data
|
||||
|
||||
When [vfunc@Clapper.Playlistable.parse] is called, an empty [class@Gio.ListStore] is
|
||||
passed as this function argument. Implementation is responsible for parsing data, creating
|
||||
[class@Clapper.MediaItem] objects and adding them to that list store. While doing so, it
|
||||
can also populate each media item tags, timeline markers and/or set subtitle URI.
|
@@ -1,23 +0,0 @@
|
||||
Title: Reactable Enhancers
|
||||
Slug: reactable-enhancers
|
||||
|
||||
### Overview
|
||||
|
||||
[iface@Clapper.Reactable] is an interface to implement enhancers that react to the
|
||||
playback and/or events that should influence it.
|
||||
|
||||
Such enhancer can work not only in a way that triggers external actions due to some
|
||||
playback events, but also in reverse - alters playback or its queue due to some
|
||||
external event. It can do so by getting a hold of the player that given enhancer
|
||||
instance reacts to with [method@Clapper.Reactable.get_player].
|
||||
|
||||
For the basics about writing enhancers see [Clapper Enhancers](clapper-enhancers.html).
|
||||
|
||||
### Requirements
|
||||
|
||||
An enhancer of this type should implement any of the [iface@Clapper.Reactable] virtual
|
||||
methods that it needs.
|
||||
|
||||
Note that when implementing [vfunc@Clapper.Reactable.queue_item_removed] you probably
|
||||
also want to implement [vfunc@Clapper.Reactable.queue_cleared] as the former is not
|
||||
called for each item when clearing the whole queue for performance reasons.
|
@@ -1,10 +0,0 @@
|
||||
baseURLs = [
|
||||
['GLib', 'https://docs.gtk.org/glib/'],
|
||||
['GObject', 'https://docs.gtk.org/gobject/'],
|
||||
['Gio', 'https://docs.gtk.org/gio/'],
|
||||
['Gst', 'https://gstreamer.freedesktop.org/documentation/gstreamer/gi-index.html?'],
|
||||
['GstBase', 'https://gstreamer.freedesktop.org/documentation/base/?'],
|
||||
['GstAudio', 'https://gstreamer.freedesktop.org/documentation/audio/?'],
|
||||
['GstTag', 'https://gstreamer.freedesktop.org/documentation/tag/?'],
|
||||
['GstPbutils', 'https://gstreamer.freedesktop.org/documentation/pbutils/?'],
|
||||
]
|
@@ -1,18 +0,0 @@
|
||||
doc_version_conf = configuration_data()
|
||||
doc_version_conf.set('CLAPPER_VERSION', meson.project_version())
|
||||
doc_version_conf.set('CLAPPER_VERSION_SUFFIX', clapper_version_suffix)
|
||||
|
||||
gi_docgen_common_args = [
|
||||
'--quiet',
|
||||
'--no-namespace-dir',
|
||||
]
|
||||
if get_option('werror')
|
||||
gi_docgen_common_args += ['--fatal-warnings']
|
||||
endif
|
||||
|
||||
if build_clapper
|
||||
subdir('clapper')
|
||||
endif
|
||||
if build_clappergtk
|
||||
subdir('clapper-gtk')
|
||||
endif
|
@@ -1,49 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import gi
|
||||
gi.require_version('Adw', '1')
|
||||
gi.require_version('Clapper', '0.0')
|
||||
gi.require_version('ClapperGtk', '0.0')
|
||||
gi.require_version('Gtk', '4.0')
|
||||
from gi.repository import Adw, Clapper, ClapperGtk, Gtk
|
||||
|
||||
Clapper.init(None)
|
||||
|
||||
def on_activate(app):
|
||||
# Create our widgets.
|
||||
win = Gtk.ApplicationWindow(application=app, title='Clapper Audio', default_width=640, default_height=96)
|
||||
audio = ClapperGtk.Audio()
|
||||
box = Gtk.Box(valign=Gtk.Align.CENTER, margin_start=8, margin_end=8, spacing=4)
|
||||
prev_btn = ClapperGtk.PreviousItemButton()
|
||||
play_btn = ClapperGtk.TogglePlayButton()
|
||||
next_btn = ClapperGtk.NextItemButton()
|
||||
seek_bar = ClapperGtk.SeekBar()
|
||||
|
||||
# Add media for playback. First media item in queue will be automatically selected.
|
||||
item = Clapper.MediaItem(uri='https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3')
|
||||
audio.props.player.props.queue.add_item(item)
|
||||
|
||||
item = Clapper.MediaItem(uri='https://www.learningcontainer.com/wp-content/uploads/2020/02/Kalimba.mp3')
|
||||
audio.props.player.props.queue.add_item(item)
|
||||
|
||||
# Assemble window.
|
||||
box.append(prev_btn)
|
||||
box.append(play_btn)
|
||||
box.append(next_btn)
|
||||
box.append(seek_bar)
|
||||
audio.set_child(box)
|
||||
win.set_child(audio)
|
||||
win.present()
|
||||
|
||||
# Not too loud. Mind the ears.
|
||||
audio.props.player.props.volume = 0.7
|
||||
|
||||
# Start playback.
|
||||
audio.props.player.play()
|
||||
|
||||
# Create a new application.
|
||||
app = Adw.Application(application_id='com.example.ClapperAudio')
|
||||
app.connect('activate', on_activate)
|
||||
|
||||
# Run the application.
|
||||
app.run(None)
|
@@ -1,57 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import gi
|
||||
gi.require_version('Adw', '1')
|
||||
gi.require_version('Clapper', '0.0')
|
||||
gi.require_version('ClapperGtk', '0.0')
|
||||
gi.require_version('GLib', '2.0')
|
||||
gi.require_version('Gtk', '4.0')
|
||||
from gi.repository import Adw, Clapper, ClapperGtk, GLib, Gtk
|
||||
import shutil
|
||||
|
||||
Clapper.init(None)
|
||||
|
||||
download_dir = GLib.build_filenamev([GLib.get_user_cache_dir(), "example_download_dir", None])
|
||||
print('Using cache directory: {0}'.format(download_dir))
|
||||
|
||||
def on_download_complete(player, item, location):
|
||||
# Media downloaded. Data from this file is still used for current playback (including seeking).
|
||||
print('Download complete: {0} => {1}'.format(item.props.uri, location))
|
||||
|
||||
def on_activate(app):
|
||||
win = Gtk.ApplicationWindow(application=app, default_width=640, default_height=396)
|
||||
video = ClapperGtk.Video()
|
||||
controls = ClapperGtk.SimpleControls(fullscreenable=False)
|
||||
|
||||
# Enable local storage caching and monitor it
|
||||
video.props.player.set_download_dir(download_dir)
|
||||
video.props.player.set_download_enabled(True)
|
||||
video.props.player.connect('download-complete', on_download_complete)
|
||||
|
||||
# Configure playback
|
||||
video.props.player.props.queue.set_progression_mode(Clapper.QueueProgressionMode.CAROUSEL)
|
||||
video.props.player.set_autoplay(True)
|
||||
|
||||
# Assemble window
|
||||
video.add_fading_overlay(controls)
|
||||
win.set_child(video)
|
||||
win.present()
|
||||
|
||||
# Create and add media for playback
|
||||
item_1 = Clapper.MediaItem(uri='http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4')
|
||||
item_2 = Clapper.MediaItem(uri='http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4')
|
||||
video.props.player.props.queue.add_item(item_1)
|
||||
video.props.player.props.queue.add_item(item_2)
|
||||
|
||||
# Create a new application
|
||||
app = Adw.Application(application_id='com.example.ClapperDownloadCache')
|
||||
app.connect('activate', on_activate)
|
||||
|
||||
# Run the application
|
||||
app.run(None)
|
||||
|
||||
# Finally app should cleanup before exit. Possibly moving data to
|
||||
# another dir if it wants to use it on next run and deleting what's
|
||||
# left (so any unfinished downloads will also be removed).
|
||||
print('Cleanup')
|
||||
shutil.rmtree(download_dir)
|
@@ -1,45 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import gi
|
||||
gi.require_version('Adw', '1')
|
||||
gi.require_version('Clapper', '0.0')
|
||||
gi.require_version('ClapperGtk', '0.0')
|
||||
gi.require_version('Gtk', '4.0')
|
||||
from gi.repository import Adw, Clapper, ClapperGtk, Gtk
|
||||
|
||||
Clapper.init(None)
|
||||
|
||||
def on_toggle_fullscreen(video, win):
|
||||
# Since this example uses only video inside normal window, all we
|
||||
# need to toggle fullscreen is to invert its fullscreened property
|
||||
win.props.fullscreened ^= True
|
||||
|
||||
def on_activate(app):
|
||||
win = Gtk.ApplicationWindow(application=app, default_width=640, default_height=396)
|
||||
video = ClapperGtk.Video()
|
||||
controls = ClapperGtk.SimpleControls()
|
||||
|
||||
# This signal will be emitted when user requests fullscreen state change.
|
||||
# It is app job to fullscreen video only (which might require something
|
||||
# more than simply inverting fullscreen on the whole window).
|
||||
video.connect('toggle-fullscreen', on_toggle_fullscreen, win)
|
||||
|
||||
# Create and add media for playback. First added media item to empty
|
||||
# playback queue will be automatically selected.
|
||||
item = Clapper.MediaItem(uri='http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4')
|
||||
video.props.player.props.queue.add_item(item)
|
||||
|
||||
# Assemble window
|
||||
video.add_fading_overlay(controls)
|
||||
win.set_child(video)
|
||||
win.present()
|
||||
|
||||
# Start playback
|
||||
video.props.player.play()
|
||||
|
||||
# Create a new application
|
||||
app = Adw.Application(application_id='com.example.ClapperSimple')
|
||||
app.connect('activate', on_activate)
|
||||
|
||||
# Run the application
|
||||
app.run(None)
|
183
extras/debug/Debug.js
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
const { GLib } = imports.gi;
|
||||
|
||||
let ink = { Ink: null };
|
||||
try {
|
||||
ink = imports.ink;
|
||||
} catch(e) {}
|
||||
const { Ink } = ink;
|
||||
|
||||
const DEBUG_ENV = GLib.getenv('DEBUG');
|
||||
|
||||
var Debugger = class
|
||||
{
|
||||
constructor(name, opts)
|
||||
{
|
||||
opts = (opts && typeof opts === 'object')
|
||||
? opts : {};
|
||||
|
||||
this.name = (name && typeof name === 'string')
|
||||
? name : 'GJS';
|
||||
|
||||
this.print_state = (opts.print_state)
|
||||
? true : false;
|
||||
|
||||
this.json_space = (typeof opts.json_space === 'number')
|
||||
? opts.json_space : 2;
|
||||
|
||||
this.name_printer = opts.name_printer || this._getInkPrinter(true);
|
||||
this.message_printer = opts.message_printer || this._getDefaultPrinter();
|
||||
this.time_printer = opts.time_printer || this._getInkPrinter();
|
||||
this.high_precision = opts.high_precision || false;
|
||||
|
||||
if(typeof opts.color !== 'undefined')
|
||||
this.color = opts.color;
|
||||
|
||||
this._isEnabled = false;
|
||||
this._lastDebug = GLib.get_monotonic_time();
|
||||
|
||||
this.enabled = (typeof opts.enabled !== 'undefined')
|
||||
? opts.enabled : this._enabledAtStart;
|
||||
}
|
||||
|
||||
get enabled()
|
||||
{
|
||||
return this._isEnabled;
|
||||
}
|
||||
|
||||
set enabled(value)
|
||||
{
|
||||
if(this._isEnabled === value)
|
||||
return;
|
||||
|
||||
this._isEnabled = (value) ? true : false;
|
||||
|
||||
if(!this.print_state)
|
||||
return;
|
||||
|
||||
let state = (this.enabled) ? 'en' : 'dis';
|
||||
this._runDebug(`debug ${state}abled`);
|
||||
}
|
||||
|
||||
get color()
|
||||
{
|
||||
return this.name_printer.color;
|
||||
}
|
||||
|
||||
set color(value)
|
||||
{
|
||||
this.name_printer.color = value;
|
||||
this.time_printer.color = this.name_printer.color;
|
||||
}
|
||||
|
||||
get debug()
|
||||
{
|
||||
return message => this._debug(message);
|
||||
}
|
||||
|
||||
get _enabledAtStart()
|
||||
{
|
||||
if(!DEBUG_ENV)
|
||||
return false;
|
||||
|
||||
let envArr = DEBUG_ENV.split(',');
|
||||
|
||||
return envArr.some(el => {
|
||||
if(el === this.name || el === '*')
|
||||
return true;
|
||||
|
||||
let searchType;
|
||||
let offset = 0;
|
||||
|
||||
if(el.startsWith('*')) {
|
||||
searchType = 'ends';
|
||||
} else if(el.endsWith('*')) {
|
||||
searchType = 'starts';
|
||||
offset = 1;
|
||||
}
|
||||
|
||||
if(!searchType)
|
||||
return false;
|
||||
|
||||
return this.name[searchType + 'With'](
|
||||
el.substring(1 - offset, el.length - offset)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
_getInkPrinter(isBold)
|
||||
{
|
||||
if(!Ink)
|
||||
return this._getDefaultPrinter();
|
||||
|
||||
let printer = new Ink.Printer({
|
||||
color: Ink.colorFromText(this.name)
|
||||
});
|
||||
|
||||
if(isBold)
|
||||
printer.font = Ink.Font.BOLD;
|
||||
|
||||
return printer;
|
||||
}
|
||||
|
||||
_getDefaultPrinter()
|
||||
{
|
||||
return {
|
||||
getPainted: function() {
|
||||
return Object.values(arguments);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_debug(message)
|
||||
{
|
||||
if(!this.enabled)
|
||||
return;
|
||||
|
||||
this._runDebug(message);
|
||||
}
|
||||
|
||||
_runDebug(message)
|
||||
{
|
||||
switch(typeof message) {
|
||||
case 'string':
|
||||
break;
|
||||
case 'object':
|
||||
if(
|
||||
message !== null
|
||||
&& (message.constructor === Object
|
||||
|| message.constructor === Array)
|
||||
) {
|
||||
message = JSON.stringify(message, null, this.json_space);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
message = String(message);
|
||||
break;
|
||||
}
|
||||
|
||||
let time = GLib.get_monotonic_time() - this._lastDebug;
|
||||
|
||||
if(!this.high_precision) {
|
||||
time = (time < 1000)
|
||||
? '+0ms'
|
||||
: (time < 1000000)
|
||||
? '+' + Math.floor(time / 1000) + 'ms'
|
||||
: '+' + Math.floor(time / 1000000) + 's';
|
||||
}
|
||||
else {
|
||||
time = (time < 1000)
|
||||
? '+' + time + 'µs'
|
||||
: (time < 1000000)
|
||||
? '+' + (time / 1000).toFixed(3) + 'ms'
|
||||
: '+' + (time / 1000000).toFixed(3) + 's';
|
||||
}
|
||||
|
||||
printerr(
|
||||
this.name_printer.getPainted(this.name),
|
||||
this.message_printer.getPainted(message),
|
||||
this.time_printer.getPainted(time)
|
||||
);
|
||||
|
||||
this._lastDebug = GLib.get_monotonic_time();
|
||||
}
|
||||
}
|
322
extras/ink/Ink.js
vendored
Normal file
@@ -0,0 +1,322 @@
|
||||
const TERM_ESC = '\x1B[';
|
||||
const TERM_RESET = '0m';
|
||||
|
||||
var maxTransparency = 128;
|
||||
|
||||
var Font = {
|
||||
VARIOUS: null,
|
||||
REGULAR: 0,
|
||||
BOLD: 1,
|
||||
DIM: 2,
|
||||
ITALIC: 3,
|
||||
UNDERLINE: 4,
|
||||
BLINK: 5,
|
||||
REVERSE: 7,
|
||||
HIDDEN: 8,
|
||||
STRIKEOUT: 9,
|
||||
};
|
||||
|
||||
var Color = {
|
||||
VARIOUS: null,
|
||||
DEFAULT: 39,
|
||||
BLACK: 30,
|
||||
RED: 31,
|
||||
GREEN: 32,
|
||||
YELLOW: 33,
|
||||
BLUE: 34,
|
||||
MAGENTA: 35,
|
||||
CYAN: 36,
|
||||
LIGHT_GRAY: 37,
|
||||
DARK_GRAY: 90,
|
||||
LIGHT_RED: 91,
|
||||
LIGHT_GREEN: 92,
|
||||
LIGHT_YELLOW: 93,
|
||||
LIGHT_BLUE: 94,
|
||||
LIGHT_MAGENTA: 95,
|
||||
LIGHT_CYAN: 96,
|
||||
WHITE: 97,
|
||||
BROWN: colorFrom256(52),
|
||||
LIGHT_BROWN: colorFrom256(130),
|
||||
PINK: colorFrom256(205),
|
||||
LIGHT_PINK: colorFrom256(211),
|
||||
ORANGE: colorFrom256(208),
|
||||
LIGHT_ORANGE: colorFrom256(214),
|
||||
SALMON: colorFrom256(209),
|
||||
LIGHT_SALMON: colorFrom256(216),
|
||||
};
|
||||
|
||||
function colorFrom256(number)
|
||||
{
|
||||
if(typeof number === 'undefined')
|
||||
number = Math.floor(Math.random() * 256) + 1;
|
||||
|
||||
return `38;5;${number || 0}`;
|
||||
}
|
||||
|
||||
function colorFromRGB(R, G, B, A)
|
||||
{
|
||||
if(typeof R === 'undefined') {
|
||||
R = Math.floor(Math.random() * 256);
|
||||
G = Math.floor(Math.random() * 256);
|
||||
B = Math.floor(Math.random() * 256);
|
||||
}
|
||||
else if(typeof G === 'undefined' && Array.isArray(R)) {
|
||||
A = (R.length > 3) ? R[3] : 255;
|
||||
B = (R.length > 2) ? R[2] : 0;
|
||||
G = (R.length > 1) ? R[1] : 0;
|
||||
R = (R.length > 0) ? R[0] : 0;
|
||||
}
|
||||
|
||||
if(_getIsTransparent(A))
|
||||
return Color.DEFAULT;
|
||||
|
||||
R = R || 0;
|
||||
G = G || 0;
|
||||
B = B || 0;
|
||||
|
||||
return `38;2;${R};${G};${B}`;
|
||||
}
|
||||
|
||||
function colorFromHex(R, G, B, A)
|
||||
{
|
||||
if((Array.isArray(R)))
|
||||
R = R.join('');
|
||||
|
||||
let str = (typeof G === 'undefined')
|
||||
? String(R)
|
||||
: (typeof A !== 'undefined')
|
||||
? String(R) + String(G) + String(B) + String(A)
|
||||
: (typeof B !== 'undefined')
|
||||
? String(R) + String(G) + String(B)
|
||||
: String(R) + String(G);
|
||||
|
||||
let offset = (str[0] === '#') ? 1 : 0;
|
||||
let alphaIndex = 6 + offset;
|
||||
|
||||
while(str.length < alphaIndex)
|
||||
str += '0';
|
||||
|
||||
A = (str.length > alphaIndex)
|
||||
? parseInt(str.substring(alphaIndex, alphaIndex + 2), 16)
|
||||
: 255;
|
||||
str = str.substring(offset, alphaIndex);
|
||||
|
||||
let colorInt = parseInt(str, 16);
|
||||
let u8arr = new Uint8Array(3);
|
||||
|
||||
u8arr[2] = colorInt;
|
||||
u8arr[1] = colorInt >> 8;
|
||||
u8arr[0] = colorInt >> 16;
|
||||
|
||||
return colorFromRGB(u8arr[0], u8arr[1], u8arr[2], A);
|
||||
}
|
||||
|
||||
function colorFromText(text)
|
||||
{
|
||||
let value = _stringToDec(text);
|
||||
|
||||
/* Returns color from 1 to 221 every 10 */
|
||||
return colorFrom256((value % 23) * 10 + 1);
|
||||
}
|
||||
|
||||
function fontFromText(text)
|
||||
{
|
||||
let arr = Object.keys(Font);
|
||||
let value = _stringToDec(text);
|
||||
|
||||
/* Return a font excluding first (null) */
|
||||
return Font[arr[value % (arr.length - 1) + 1]];
|
||||
}
|
||||
|
||||
function _getIsImage(args)
|
||||
{
|
||||
if(args.length !== 1)
|
||||
return false;
|
||||
|
||||
let arg = args[0];
|
||||
let argType = (typeof arg);
|
||||
|
||||
if(argType === 'string' || argType === 'number')
|
||||
return false;
|
||||
|
||||
if(!Array.isArray(arg))
|
||||
return false;
|
||||
|
||||
let depth = 2;
|
||||
while(depth--) {
|
||||
arg = arg[0];
|
||||
if(!Array.isArray(arg))
|
||||
return false;
|
||||
}
|
||||
|
||||
return arg.some(val => val !== 'number');
|
||||
}
|
||||
|
||||
function _getIsTransparent(A)
|
||||
{
|
||||
return (typeof A !== 'undefined' && A <= maxTransparency);
|
||||
}
|
||||
|
||||
function _stringToDec(str)
|
||||
{
|
||||
str = str || '';
|
||||
|
||||
let len = str.length;
|
||||
let total = 0;
|
||||
|
||||
while(len--)
|
||||
total += Number(str.charCodeAt(len).toString(10));
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
var Printer = class
|
||||
{
|
||||
constructor(opts)
|
||||
{
|
||||
opts = opts || {};
|
||||
|
||||
const defaults = {
|
||||
font: Font.REGULAR,
|
||||
color: Color.DEFAULT,
|
||||
background: Color.DEFAULT
|
||||
};
|
||||
|
||||
for(let def in defaults) {
|
||||
this[def] = (typeof opts[def] !== 'undefined')
|
||||
? opts[def] : defaults[def];
|
||||
}
|
||||
}
|
||||
|
||||
print()
|
||||
{
|
||||
(_getIsImage(arguments))
|
||||
? this._printImage(arguments[0], 'stdout')
|
||||
: print(this._getPaintedArgs(arguments));
|
||||
}
|
||||
|
||||
printerr()
|
||||
{
|
||||
(_getIsImage(arguments))
|
||||
? this._printImage(arguments[0], 'stderr')
|
||||
: printerr(this._getPaintedArgs(arguments));
|
||||
}
|
||||
|
||||
getPainted()
|
||||
{
|
||||
return (_getIsImage(arguments))
|
||||
? this._printImage(arguments[0], 'return')
|
||||
: this._getPaintedArgs(arguments);
|
||||
}
|
||||
|
||||
get background()
|
||||
{
|
||||
return this._background;
|
||||
}
|
||||
|
||||
set background(value)
|
||||
{
|
||||
let valueType = (typeof value);
|
||||
|
||||
if(valueType === 'string') {
|
||||
value = (value[2] === ';')
|
||||
? '4' + value.substring(1)
|
||||
: Number(value);
|
||||
}
|
||||
this._background = (valueType === 'object')
|
||||
? null
|
||||
: (value < 40 || value >= 90 && value < 100)
|
||||
? value + 10
|
||||
: value;
|
||||
}
|
||||
|
||||
_getPaintedArgs(args)
|
||||
{
|
||||
let str = '';
|
||||
|
||||
for(let arg of args) {
|
||||
if(Array.isArray(arg))
|
||||
arg = arg.join(',');
|
||||
|
||||
let painted = this._getPaintedString(arg);
|
||||
str += (str.length) ? ' ' + painted : painted;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
_getPaintedString(text, noReset)
|
||||
{
|
||||
let str = TERM_ESC;
|
||||
|
||||
for(let option of ['font', 'color', '_background']) {
|
||||
let optionType = (typeof this[option]);
|
||||
str += (optionType === 'number' || optionType === 'string')
|
||||
? this[option]
|
||||
: (option === 'font' && Array.isArray(this[option]))
|
||||
? this[option].join(';')
|
||||
: (option === 'font')
|
||||
? fontFromText(text)
|
||||
: colorFromText(text);
|
||||
|
||||
str += (option !== '_background') ? ';' : 'm';
|
||||
}
|
||||
str += text;
|
||||
|
||||
return (noReset)
|
||||
? str
|
||||
: (str + TERM_ESC + TERM_RESET);
|
||||
}
|
||||
|
||||
_printImage(pixelsArr, output)
|
||||
{
|
||||
let total = '';
|
||||
let prevColor = this.color;
|
||||
let prevBackground = this._background;
|
||||
|
||||
for(let row of pixelsArr) {
|
||||
let paintedLine = '';
|
||||
let block = ' ';
|
||||
|
||||
for(let i = 0; i < row.length; i++) {
|
||||
let pixel = row[i];
|
||||
let nextPixel = (i < row.length - 1) ? row[i + 1] : null;
|
||||
|
||||
if(nextPixel && pixel.every((value, index) =>
|
||||
value === nextPixel[index]
|
||||
)) {
|
||||
block += ' ';
|
||||
continue;
|
||||
}
|
||||
/* Do not use predefined functions here (it would impact performance) */
|
||||
let isTransparent = (pixel.length >= 3) ? _getIsTransparent(pixel[3]) : false;
|
||||
this.color = (isTransparent)
|
||||
? Color.DEFAULT
|
||||
: `38;2;${pixel[0]};${pixel[1]};${pixel[2]}`;
|
||||
this._background = (isTransparent)
|
||||
? Color.DEFAULT
|
||||
: `48;2;${pixel[0]};${pixel[1]};${pixel[2]}`;
|
||||
paintedLine += `${TERM_ESC}0;${this.color};${this._background}m${block}`;
|
||||
block = ' ';
|
||||
}
|
||||
paintedLine += TERM_ESC + TERM_RESET;
|
||||
|
||||
switch(output) {
|
||||
case 'stderr':
|
||||
printerr(paintedLine);
|
||||
break;
|
||||
case 'return':
|
||||
total += paintedLine + '\n';
|
||||
break;
|
||||
default:
|
||||
print(paintedLine);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.color = prevColor;
|
||||
this._background = prevBackground;
|
||||
|
||||
return total;
|
||||
}
|
||||
}
|
9
COPYING-LGPL → lib/gst/COPYING
vendored
@@ -2,7 +2,7 @@
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
<https://fsf.org/>
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
@@ -484,7 +484,8 @@ convey the exclusion of warranty; and each file should have at least the
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, see <https://www.gnu.org/licenses/>.
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
@@ -495,7 +496,7 @@ necessary. Here is a sample; alter the names:
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Moe Ghoul>, 1 April 1990
|
||||
Moe Ghoul, President of Vice
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
42
lib/gst/clapper/clapper-prelude.h
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
/* GStreamer
|
||||
* Copyright (C) 2018 GStreamer developers
|
||||
* Copyright (C) 2021 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_CLAPPER_PRELUDE_H__
|
||||
#define __GST_CLAPPER_PRELUDE_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#ifndef GST_CLAPPER_API
|
||||
# ifdef BUILDING_GST_CLAPPER
|
||||
# define GST_CLAPPER_API GST_API_EXPORT /* from config.h */
|
||||
# else
|
||||
# define GST_CLAPPER_API GST_API_IMPORT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef GST_DISABLE_DEPRECATED
|
||||
#define GST_CLAPPER_DEPRECATED GST_CLAPPER_API
|
||||
#define GST_CLAPPER_DEPRECATED_FOR(f) GST_CLAPPER_API
|
||||
#else
|
||||
#define GST_CLAPPER_DEPRECATED G_DEPRECATED GST_CLAPPER_API
|
||||
#define GST_CLAPPER_DEPRECATED_FOR(f) G_DEPRECATED_FOR(f) GST_CLAPPER_API
|
||||
#endif
|
||||
|
||||
#endif /* __GST_CLAPPER_PRELUDE_H__ */
|
34
lib/gst/clapper/clapper.h
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
/* GStreamer
|
||||
*
|
||||
* Copyright (C) 2014 Sebastian Dröge <sebastian@centricular.com>
|
||||
* Copyright (C) 2021 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __CLAPPER_H__
|
||||
#define __CLAPPER_H__
|
||||
|
||||
#include <gst/clapper/clapper-prelude.h>
|
||||
#include <gst/clapper/gstclapper.h>
|
||||
#include <gst/clapper/gstclapper-media-info.h>
|
||||
#include <gst/clapper/gstclapper-g-main-context-signal-dispatcher.h>
|
||||
#include <gst/clapper/gstclapper-video-overlay-video-renderer.h>
|
||||
#include <gst/clapper/gstclapper-visualization.h>
|
||||
#include <gst/clapper/gstclapper-mpris.h>
|
||||
#include <gst/clapper/gstclapper-gtk4-plugin.h>
|
||||
|
||||
#endif /* __CLAPPER_H__ */
|
214
lib/gst/clapper/gstclapper-g-main-context-signal-dispatcher.c
vendored
Normal file
@@ -0,0 +1,214 @@
|
||||
/* GStreamer
|
||||
*
|
||||
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
|
||||
* Copyright (C) 2021 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:gstclapper-gmaincontextsignaldispatcher
|
||||
* @title: GstClapperGMainContextSignalDispatcher
|
||||
* @short_description: Clapper GLib MainContext dispatcher
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gstclapper-g-main-context-signal-dispatcher.h"
|
||||
|
||||
struct _GstClapperGMainContextSignalDispatcher
|
||||
{
|
||||
GObject parent;
|
||||
GMainContext *application_context;
|
||||
};
|
||||
|
||||
struct _GstClapperGMainContextSignalDispatcherClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
static void
|
||||
gst_clapper_g_main_context_signal_dispatcher_interface_init
|
||||
(GstClapperSignalDispatcherInterface * iface);
|
||||
|
||||
enum
|
||||
{
|
||||
G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_0,
|
||||
G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_APPLICATION_CONTEXT,
|
||||
G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_LAST
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GstClapperGMainContextSignalDispatcher,
|
||||
gst_clapper_g_main_context_signal_dispatcher, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (GST_TYPE_CLAPPER_SIGNAL_DISPATCHER,
|
||||
gst_clapper_g_main_context_signal_dispatcher_interface_init));
|
||||
|
||||
static GParamSpec
|
||||
* g_main_context_signal_dispatcher_param_specs
|
||||
[G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_LAST] = { NULL, };
|
||||
|
||||
static void
|
||||
gst_clapper_g_main_context_signal_dispatcher_finalize (GObject * object)
|
||||
{
|
||||
GstClapperGMainContextSignalDispatcher *self =
|
||||
GST_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER (object);
|
||||
|
||||
if (self->application_context)
|
||||
g_main_context_unref (self->application_context);
|
||||
|
||||
G_OBJECT_CLASS
|
||||
(gst_clapper_g_main_context_signal_dispatcher_parent_class)->finalize
|
||||
(object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_g_main_context_signal_dispatcher_set_property (GObject * object,
|
||||
guint prop_id, const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstClapperGMainContextSignalDispatcher *self =
|
||||
GST_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_APPLICATION_CONTEXT:
|
||||
self->application_context = g_value_dup_boxed (value);
|
||||
if (!self->application_context)
|
||||
self->application_context = g_main_context_ref_thread_default ();
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_g_main_context_signal_dispatcher_get_property (GObject * object,
|
||||
guint prop_id, GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstClapperGMainContextSignalDispatcher *self =
|
||||
GST_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_APPLICATION_CONTEXT:
|
||||
g_value_set_boxed (value, self->application_context);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_g_main_context_signal_dispatcher_class_init
|
||||
(GstClapperGMainContextSignalDispatcherClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->finalize =
|
||||
gst_clapper_g_main_context_signal_dispatcher_finalize;
|
||||
gobject_class->set_property =
|
||||
gst_clapper_g_main_context_signal_dispatcher_set_property;
|
||||
gobject_class->get_property =
|
||||
gst_clapper_g_main_context_signal_dispatcher_get_property;
|
||||
|
||||
g_main_context_signal_dispatcher_param_specs
|
||||
[G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_APPLICATION_CONTEXT] =
|
||||
g_param_spec_boxed ("application-context", "Application Context",
|
||||
"Application GMainContext to dispatch signals to", G_TYPE_MAIN_CONTEXT,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class,
|
||||
G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_LAST,
|
||||
g_main_context_signal_dispatcher_param_specs);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_g_main_context_signal_dispatcher_init
|
||||
(G_GNUC_UNUSED GstClapperGMainContextSignalDispatcher * self)
|
||||
{
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void (*emitter) (gpointer data);
|
||||
gpointer data;
|
||||
GDestroyNotify destroy;
|
||||
} GMainContextSignalDispatcherData;
|
||||
|
||||
static gboolean
|
||||
g_main_context_signal_dispatcher_dispatch_gsourcefunc (gpointer user_data)
|
||||
{
|
||||
GMainContextSignalDispatcherData *data = user_data;
|
||||
|
||||
data->emitter (data->data);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
g_main_context_signal_dispatcher_dispatch_destroy (gpointer user_data)
|
||||
{
|
||||
GMainContextSignalDispatcherData *data = user_data;
|
||||
|
||||
if (data->destroy)
|
||||
data->destroy (data->data);
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_g_main_context_signal_dispatcher_dispatch (GstClapperSignalDispatcher
|
||||
* iface, G_GNUC_UNUSED GstClapper * clapper, void (*emitter) (gpointer data),
|
||||
gpointer data, GDestroyNotify destroy)
|
||||
{
|
||||
GstClapperGMainContextSignalDispatcher *self =
|
||||
GST_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER (iface);
|
||||
GMainContextSignalDispatcherData *gsourcefunc_data =
|
||||
g_new (GMainContextSignalDispatcherData, 1);
|
||||
|
||||
gsourcefunc_data->emitter = emitter;
|
||||
gsourcefunc_data->data = data;
|
||||
gsourcefunc_data->destroy = destroy;
|
||||
|
||||
g_main_context_invoke_full (self->application_context,
|
||||
G_PRIORITY_DEFAULT, g_main_context_signal_dispatcher_dispatch_gsourcefunc,
|
||||
gsourcefunc_data, g_main_context_signal_dispatcher_dispatch_destroy);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_g_main_context_signal_dispatcher_interface_init
|
||||
(GstClapperSignalDispatcherInterface * iface)
|
||||
{
|
||||
iface->dispatch = gst_clapper_g_main_context_signal_dispatcher_dispatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_g_main_context_signal_dispatcher_new:
|
||||
* @application_context: (allow-none): GMainContext to use or %NULL
|
||||
*
|
||||
* Creates a new GstClapperSignalDispatcher that uses @application_context,
|
||||
* or the thread default one if %NULL is used. See gst_clapper_new().
|
||||
*
|
||||
* Returns: (transfer full): the new GstClapperSignalDispatcher
|
||||
*/
|
||||
GstClapperSignalDispatcher *
|
||||
gst_clapper_g_main_context_signal_dispatcher_new (GMainContext *
|
||||
application_context)
|
||||
{
|
||||
return g_object_new (GST_TYPE_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER,
|
||||
"application-context", application_context, NULL);
|
||||
}
|
51
lib/gst/clapper/gstclapper-g-main-context-signal-dispatcher.h
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
/* GStreamer
|
||||
*
|
||||
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
|
||||
* Copyright (C) 2021 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER_H__
|
||||
#define __GST_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER_H__
|
||||
|
||||
#include <gst/clapper/gstclapper-types.h>
|
||||
#include <gst/clapper/gstclapper-signal-dispatcher.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GstClapperGMainContextSignalDispatcher
|
||||
GstClapperGMainContextSignalDispatcher;
|
||||
typedef struct _GstClapperGMainContextSignalDispatcherClass
|
||||
GstClapperGMainContextSignalDispatcherClass;
|
||||
|
||||
#define GST_TYPE_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER (gst_clapper_g_main_context_signal_dispatcher_get_type ())
|
||||
#define GST_IS_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER))
|
||||
#define GST_IS_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER))
|
||||
#define GST_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER, GstClapperGMainContextSignalDispatcherClass))
|
||||
#define GST_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER, GstClapperGMainContextSignalDispatcher))
|
||||
#define GST_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER, GstClapperGMainContextSignalDispatcherClass))
|
||||
#define GST_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER_CAST(obj) ((GstClapperGMainContextSignalDispatcher*)(obj))
|
||||
|
||||
GST_CLAPPER_API
|
||||
GType gst_clapper_g_main_context_signal_dispatcher_get_type (void);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstClapperSignalDispatcher * gst_clapper_g_main_context_signal_dispatcher_new (GMainContext * application_context);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_CLAPPER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER_H__ */
|
123
lib/gst/clapper/gstclapper-gtk4-plugin.c
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
/* GStreamer
|
||||
*
|
||||
* Copyright (C) 2021 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:gstclapper-gtk4plugin
|
||||
* @title: GstClapperGtk4Plugin
|
||||
* @short_description: Clapper GTK4 plugin
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gstclapper-gtk4-plugin.h"
|
||||
#include "gtk4/gstclapperglsink.h"
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_VIDEO_SINK,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
#define parent_class gst_clapper_gtk4_plugin_parent_class
|
||||
G_DEFINE_TYPE_WITH_CODE (GstClapperGtk4Plugin, gst_clapper_gtk4_plugin,
|
||||
G_TYPE_OBJECT, NULL);
|
||||
|
||||
static GParamSpec *param_specs[PROP_LAST] = { NULL, };
|
||||
|
||||
static void gst_clapper_gtk4_plugin_constructed (GObject * object);
|
||||
static void gst_clapper_gtk4_plugin_finalize (GObject * object);
|
||||
static void gst_clapper_gtk4_plugin_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static void gst_clapper_gtk4_plugin_init
|
||||
(G_GNUC_UNUSED GstClapperGtk4Plugin * self)
|
||||
{
|
||||
}
|
||||
|
||||
static void gst_clapper_gtk4_plugin_class_init
|
||||
(G_GNUC_UNUSED GstClapperGtk4PluginClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = (GObjectClass *) klass;
|
||||
|
||||
gobject_class->constructed = gst_clapper_gtk4_plugin_constructed;
|
||||
gobject_class->get_property = gst_clapper_gtk4_plugin_get_property;
|
||||
gobject_class->finalize = gst_clapper_gtk4_plugin_finalize;
|
||||
|
||||
param_specs[PROP_VIDEO_SINK] =
|
||||
g_param_spec_object ("video-sink",
|
||||
"Video Sink", "Video sink to use with video renderer",
|
||||
GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class, PROP_LAST, param_specs);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_gtk4_plugin_constructed (GObject * object)
|
||||
{
|
||||
GstClapperGtk4Plugin *self = GST_CLAPPER_GTK4_PLUGIN (object);
|
||||
|
||||
self->video_sink = g_object_new (GST_TYPE_CLAPPER_GL_SINK, NULL);
|
||||
gst_object_ref_sink (self->video_sink);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_gtk4_plugin_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstClapperGtk4Plugin *self = GST_CLAPPER_GTK4_PLUGIN (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_VIDEO_SINK:
|
||||
g_value_set_object (value, self->video_sink);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_gtk4_plugin_finalize (GObject * object)
|
||||
{
|
||||
GstClapperGtk4Plugin *self = GST_CLAPPER_GTK4_PLUGIN (object);
|
||||
|
||||
gst_object_unref (self->video_sink);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_gtk4_plugin_new:
|
||||
*
|
||||
* Creates a new GTK4 plugin.
|
||||
*
|
||||
* Returns: (transfer full): the new GstClapperGtk4Plugin
|
||||
*/
|
||||
GstClapperGtk4Plugin *
|
||||
gst_clapper_gtk4_plugin_new (void)
|
||||
{
|
||||
return g_object_new (GST_TYPE_CLAPPER_GTK4_PLUGIN, NULL);
|
||||
}
|
72
lib/gst/clapper/gstclapper-gtk4-plugin.h
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
/* GStreamer
|
||||
*
|
||||
* Copyright (C) 2021 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_CLAPPER_GTK4_PLUGIN_H__
|
||||
#define __GST_CLAPPER_GTK4_PLUGIN_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/clapper/clapper-prelude.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_CLAPPER_GTK4_PLUGIN (gst_clapper_gtk4_plugin_get_type ())
|
||||
#define GST_IS_CLAPPER_GTK4_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CLAPPER_GTK4_PLUGIN))
|
||||
#define GST_IS_CLAPPER_GTK4_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CLAPPER_GTK4_PLUGIN))
|
||||
#define GST_CLAPPER_GTK4_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CLAPPER_GTK4_PLUGIN, GstClapperGtk4PluginClass))
|
||||
#define GST_CLAPPER_GTK4_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CLAPPER_GTK4_PLUGIN, GstClapperGtk4Plugin))
|
||||
#define GST_CLAPPER_GTK4_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_CLAPPER_GTK4_PLUGIN, GstClapperGtk4PluginClass))
|
||||
#define GST_CLAPPER_GTK4_PLUGIN_CAST(obj) ((GstClapperGtk4Plugin*)(obj))
|
||||
|
||||
typedef struct _GstClapperGtk4Plugin GstClapperGtk4Plugin;
|
||||
typedef struct _GstClapperGtk4PluginClass GstClapperGtk4PluginClass;
|
||||
|
||||
/**
|
||||
* GstClapperGtk4Plugin:
|
||||
*
|
||||
* Opaque #GstClapperGtk4Plugin object
|
||||
*/
|
||||
struct _GstClapperGtk4Plugin
|
||||
{
|
||||
/* <private> */
|
||||
GObject parent;
|
||||
|
||||
GstElement *video_sink;
|
||||
};
|
||||
|
||||
/**
|
||||
* GstClapperGtk4PluginClass:
|
||||
*
|
||||
* The #GstClapperGtk4PluginClass struct only contains private data
|
||||
*/
|
||||
struct _GstClapperGtk4PluginClass
|
||||
{
|
||||
/* <private> */
|
||||
GstElementClass parent_class;
|
||||
};
|
||||
|
||||
GST_CLAPPER_API
|
||||
GType gst_clapper_gtk4_plugin_get_type (void);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstClapperGtk4Plugin * gst_clapper_gtk4_plugin_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_CLAPPER_GTK4_PLUGIN__ */
|
125
lib/gst/clapper/gstclapper-media-info-private.h
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
/* GStreamer
|
||||
*
|
||||
* Copyright (C) 2015 Brijesh Singh <brijesh.ksingh@gmail.com>
|
||||
* Copyright (C) 2021 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "gstclapper-media-info.h"
|
||||
|
||||
#ifndef __GST_CLAPPER_MEDIA_INFO_PRIVATE_H__
|
||||
#define __GST_CLAPPER_MEDIA_INFO_PRIVATE_H__
|
||||
|
||||
struct _GstClapperStreamInfo
|
||||
{
|
||||
GObject parent;
|
||||
|
||||
gchar *codec;
|
||||
|
||||
GstCaps *caps;
|
||||
gint stream_index;
|
||||
GstTagList *tags;
|
||||
gchar *stream_id;
|
||||
};
|
||||
|
||||
struct _GstClapperStreamInfoClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
struct _GstClapperSubtitleInfo
|
||||
{
|
||||
GstClapperStreamInfo parent;
|
||||
|
||||
gchar *title;
|
||||
gchar *language;
|
||||
};
|
||||
|
||||
struct _GstClapperSubtitleInfoClass
|
||||
{
|
||||
GstClapperStreamInfoClass parent_class;
|
||||
};
|
||||
|
||||
struct _GstClapperAudioInfo
|
||||
{
|
||||
GstClapperStreamInfo parent;
|
||||
|
||||
gint channels;
|
||||
gint sample_rate;
|
||||
|
||||
guint bitrate;
|
||||
guint max_bitrate;
|
||||
|
||||
gchar *language;
|
||||
};
|
||||
|
||||
struct _GstClapperAudioInfoClass
|
||||
{
|
||||
GstClapperStreamInfoClass parent_class;
|
||||
};
|
||||
|
||||
struct _GstClapperVideoInfo
|
||||
{
|
||||
GstClapperStreamInfo parent;
|
||||
|
||||
gint width;
|
||||
gint height;
|
||||
gint framerate_num;
|
||||
gint framerate_denom;
|
||||
gint par_num;
|
||||
gint par_denom;
|
||||
|
||||
guint bitrate;
|
||||
guint max_bitrate;
|
||||
};
|
||||
|
||||
struct _GstClapperVideoInfoClass
|
||||
{
|
||||
GstClapperStreamInfoClass parent_class;
|
||||
};
|
||||
|
||||
struct _GstClapperMediaInfo
|
||||
{
|
||||
GObject parent;
|
||||
|
||||
gchar *uri;
|
||||
gchar *title;
|
||||
gchar *container;
|
||||
gboolean seekable, is_live;
|
||||
GstTagList *tags;
|
||||
GstToc *toc;
|
||||
GstSample *image_sample;
|
||||
|
||||
GList *stream_list;
|
||||
GList *audio_stream_list;
|
||||
GList *video_stream_list;
|
||||
GList *subtitle_stream_list;
|
||||
|
||||
GstClockTime duration;
|
||||
};
|
||||
|
||||
struct _GstClapperMediaInfoClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
G_GNUC_INTERNAL GstClapperMediaInfo * gst_clapper_media_info_new (const gchar *uri);
|
||||
G_GNUC_INTERNAL GstClapperMediaInfo * gst_clapper_media_info_copy (GstClapperMediaInfo *ref);
|
||||
G_GNUC_INTERNAL GstClapperStreamInfo * gst_clapper_stream_info_new (gint stream_index, GType type);
|
||||
G_GNUC_INTERNAL GstClapperStreamInfo * gst_clapper_stream_info_copy (GstClapperStreamInfo *ref);
|
||||
|
||||
#endif /* __GST_CLAPPER_MEDIA_INFO_PRIVATE_H__ */
|
885
lib/gst/clapper/gstclapper-media-info.c
vendored
Normal file
@@ -0,0 +1,885 @@
|
||||
/* GStreamer
|
||||
*
|
||||
* Copyright (C) 2015 Brijesh Singh <brijesh.ksingh@gmail.com>
|
||||
* Copyright (C) 2021 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:gstclapper-mediainfo
|
||||
* @title: GstClapperMediaInfo
|
||||
* @short_description: Clapper Media Information
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gstclapper-media-info.h"
|
||||
#include "gstclapper-media-info-private.h"
|
||||
|
||||
/* Per-stream information */
|
||||
G_DEFINE_ABSTRACT_TYPE (GstClapperStreamInfo, gst_clapper_stream_info,
|
||||
G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
gst_clapper_stream_info_init (GstClapperStreamInfo * sinfo)
|
||||
{
|
||||
sinfo->stream_index = -1;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_stream_info_finalize (GObject * object)
|
||||
{
|
||||
GstClapperStreamInfo *sinfo = GST_CLAPPER_STREAM_INFO (object);
|
||||
|
||||
g_free (sinfo->codec);
|
||||
g_free (sinfo->stream_id);
|
||||
|
||||
if (sinfo->caps)
|
||||
gst_caps_unref (sinfo->caps);
|
||||
|
||||
if (sinfo->tags)
|
||||
gst_tag_list_unref (sinfo->tags);
|
||||
|
||||
G_OBJECT_CLASS (gst_clapper_stream_info_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_stream_info_class_init (GstClapperStreamInfoClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = (GObjectClass *) klass;
|
||||
|
||||
gobject_class->finalize = gst_clapper_stream_info_finalize;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_stream_info_get_index:
|
||||
* @info: a #GstClapperStreamInfo
|
||||
*
|
||||
* Function to get stream index from #GstClapperStreamInfo instance.
|
||||
*
|
||||
* Returns: the stream index of this stream.
|
||||
*/
|
||||
gint
|
||||
gst_clapper_stream_info_get_index (const GstClapperStreamInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_STREAM_INFO (info), -1);
|
||||
|
||||
return info->stream_index;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_stream_info_get_stream_type:
|
||||
* @info: a #GstClapperStreamInfo
|
||||
*
|
||||
* Function to return human readable name for the stream type
|
||||
* of the given @info (ex: "audio", "video", "subtitle")
|
||||
*
|
||||
* Returns: a human readable name
|
||||
*/
|
||||
const gchar *
|
||||
gst_clapper_stream_info_get_stream_type (const GstClapperStreamInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_STREAM_INFO (info), NULL);
|
||||
|
||||
if (GST_IS_CLAPPER_VIDEO_INFO (info))
|
||||
return "video";
|
||||
else if (GST_IS_CLAPPER_AUDIO_INFO (info))
|
||||
return "audio";
|
||||
else
|
||||
return "subtitle";
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_stream_info_get_tags:
|
||||
* @info: a #GstClapperStreamInfo
|
||||
*
|
||||
* Returns: (transfer none): the tags contained in this stream.
|
||||
*/
|
||||
GstTagList *
|
||||
gst_clapper_stream_info_get_tags (const GstClapperStreamInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_STREAM_INFO (info), NULL);
|
||||
|
||||
return info->tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_stream_info_get_codec:
|
||||
* @info: a #GstClapperStreamInfo
|
||||
*
|
||||
* A string describing codec used in #GstClapperStreamInfo.
|
||||
*
|
||||
* Returns: codec string or NULL on unknown.
|
||||
*/
|
||||
const gchar *
|
||||
gst_clapper_stream_info_get_codec (const GstClapperStreamInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_STREAM_INFO (info), NULL);
|
||||
|
||||
return info->codec;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_stream_info_get_caps:
|
||||
* @info: a #GstClapperStreamInfo
|
||||
*
|
||||
* Returns: (transfer none): the #GstCaps of the stream.
|
||||
*/
|
||||
GstCaps *
|
||||
gst_clapper_stream_info_get_caps (const GstClapperStreamInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_STREAM_INFO (info), NULL);
|
||||
|
||||
return info->caps;
|
||||
}
|
||||
|
||||
/* Video information */
|
||||
G_DEFINE_TYPE (GstClapperVideoInfo, gst_clapper_video_info,
|
||||
GST_TYPE_CLAPPER_STREAM_INFO);
|
||||
|
||||
static void
|
||||
gst_clapper_video_info_init (GstClapperVideoInfo * info)
|
||||
{
|
||||
info->width = -1;
|
||||
info->height = -1;
|
||||
info->framerate_num = 0;
|
||||
info->framerate_denom = 1;
|
||||
info->par_num = 1;
|
||||
info->par_denom = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_video_info_class_init (G_GNUC_UNUSED GstClapperVideoInfoClass * klass)
|
||||
{
|
||||
/* nothing to do here */
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_video_info_get_width:
|
||||
* @info: a #GstClapperVideoInfo
|
||||
*
|
||||
* Returns: the width of video in #GstClapperVideoInfo.
|
||||
*/
|
||||
gint
|
||||
gst_clapper_video_info_get_width (const GstClapperVideoInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_VIDEO_INFO (info), -1);
|
||||
|
||||
return info->width;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_video_info_get_height:
|
||||
* @info: a #GstClapperVideoInfo
|
||||
*
|
||||
* Returns: the height of video in #GstClapperVideoInfo.
|
||||
*/
|
||||
gint
|
||||
gst_clapper_video_info_get_height (const GstClapperVideoInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_VIDEO_INFO (info), -1);
|
||||
|
||||
return info->height;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_video_info_get_framerate:
|
||||
* @info: a #GstClapperVideoInfo
|
||||
* @fps_n: (out): Numerator of frame rate
|
||||
* @fps_d: (out): Denominator of frame rate
|
||||
*
|
||||
*/
|
||||
void
|
||||
gst_clapper_video_info_get_framerate (const GstClapperVideoInfo * info,
|
||||
gint * fps_n, gint * fps_d)
|
||||
{
|
||||
g_return_if_fail (GST_IS_CLAPPER_VIDEO_INFO (info));
|
||||
|
||||
*fps_n = info->framerate_num;
|
||||
*fps_d = info->framerate_denom;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_video_info_get_pixel_aspect_ratio:
|
||||
* @info: a #GstClapperVideoInfo
|
||||
* @par_n: (out): numerator
|
||||
* @par_d: (out): denominator
|
||||
*
|
||||
* Returns the pixel aspect ratio in @par_n and @par_d
|
||||
*
|
||||
*/
|
||||
void
|
||||
gst_clapper_video_info_get_pixel_aspect_ratio (const GstClapperVideoInfo * info,
|
||||
guint * par_n, guint * par_d)
|
||||
{
|
||||
g_return_if_fail (GST_IS_CLAPPER_VIDEO_INFO (info));
|
||||
|
||||
*par_n = info->par_num;
|
||||
*par_d = info->par_denom;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_video_info_get_bitrate:
|
||||
* @info: a #GstClapperVideoInfo
|
||||
*
|
||||
* Returns: the current bitrate of video in #GstClapperVideoInfo.
|
||||
*/
|
||||
gint
|
||||
gst_clapper_video_info_get_bitrate (const GstClapperVideoInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_VIDEO_INFO (info), -1);
|
||||
|
||||
return info->bitrate;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_video_info_get_max_bitrate:
|
||||
* @info: a #GstClapperVideoInfo
|
||||
*
|
||||
* Returns: the maximum bitrate of video in #GstClapperVideoInfo.
|
||||
*/
|
||||
gint
|
||||
gst_clapper_video_info_get_max_bitrate (const GstClapperVideoInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_VIDEO_INFO (info), -1);
|
||||
|
||||
return info->max_bitrate;
|
||||
}
|
||||
|
||||
/* Audio information */
|
||||
G_DEFINE_TYPE (GstClapperAudioInfo, gst_clapper_audio_info,
|
||||
GST_TYPE_CLAPPER_STREAM_INFO);
|
||||
|
||||
static void
|
||||
gst_clapper_audio_info_init (GstClapperAudioInfo * info)
|
||||
{
|
||||
info->channels = 0;
|
||||
info->sample_rate = 0;
|
||||
info->bitrate = -1;
|
||||
info->max_bitrate = -1;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_audio_info_finalize (GObject * object)
|
||||
{
|
||||
GstClapperAudioInfo *info = GST_CLAPPER_AUDIO_INFO (object);
|
||||
|
||||
g_free (info->language);
|
||||
|
||||
G_OBJECT_CLASS (gst_clapper_audio_info_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_audio_info_class_init (GstClapperAudioInfoClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = (GObjectClass *) klass;
|
||||
|
||||
gobject_class->finalize = gst_clapper_audio_info_finalize;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_audio_info_get_language:
|
||||
* @info: a #GstClapperAudioInfo
|
||||
*
|
||||
* Returns: the language of the stream, or NULL if unknown.
|
||||
*/
|
||||
const gchar *
|
||||
gst_clapper_audio_info_get_language (const GstClapperAudioInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_AUDIO_INFO (info), NULL);
|
||||
|
||||
return info->language;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_audio_info_get_channels:
|
||||
* @info: a #GstClapperAudioInfo
|
||||
*
|
||||
* Returns: the number of audio channels in #GstClapperAudioInfo.
|
||||
*/
|
||||
gint
|
||||
gst_clapper_audio_info_get_channels (const GstClapperAudioInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_AUDIO_INFO (info), 0);
|
||||
|
||||
return info->channels;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_audio_info_get_sample_rate:
|
||||
* @info: a #GstClapperAudioInfo
|
||||
*
|
||||
* Returns: the audio sample rate in #GstClapperAudioInfo.
|
||||
*/
|
||||
gint
|
||||
gst_clapper_audio_info_get_sample_rate (const GstClapperAudioInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_AUDIO_INFO (info), 0);
|
||||
|
||||
return info->sample_rate;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_audio_info_get_bitrate:
|
||||
* @info: a #GstClapperAudioInfo
|
||||
*
|
||||
* Returns: the audio bitrate in #GstClapperAudioInfo.
|
||||
*/
|
||||
gint
|
||||
gst_clapper_audio_info_get_bitrate (const GstClapperAudioInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_AUDIO_INFO (info), -1);
|
||||
|
||||
return info->bitrate;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_audio_info_get_max_bitrate:
|
||||
* @info: a #GstClapperAudioInfo
|
||||
*
|
||||
* Returns: the audio maximum bitrate in #GstClapperAudioInfo.
|
||||
*/
|
||||
gint
|
||||
gst_clapper_audio_info_get_max_bitrate (const GstClapperAudioInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_AUDIO_INFO (info), -1);
|
||||
|
||||
return info->max_bitrate;
|
||||
}
|
||||
|
||||
/* Subtitle information */
|
||||
G_DEFINE_TYPE (GstClapperSubtitleInfo, gst_clapper_subtitle_info,
|
||||
GST_TYPE_CLAPPER_STREAM_INFO);
|
||||
|
||||
static void
|
||||
gst_clapper_subtitle_info_init (G_GNUC_UNUSED GstClapperSubtitleInfo * info)
|
||||
{
|
||||
/* nothing to do */
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_subtitle_info_finalize (GObject * object)
|
||||
{
|
||||
GstClapperSubtitleInfo *info = GST_CLAPPER_SUBTITLE_INFO (object);
|
||||
|
||||
g_free (info->title);
|
||||
g_free (info->language);
|
||||
|
||||
G_OBJECT_CLASS (gst_clapper_subtitle_info_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_subtitle_info_class_init (GstClapperSubtitleInfoClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = (GObjectClass *) klass;
|
||||
|
||||
gobject_class->finalize = gst_clapper_subtitle_info_finalize;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_subtitle_info_get_title:
|
||||
* @info: a #GstClapperSubtitleInfo
|
||||
*
|
||||
* Returns: the title of the stream, or NULL if unknown.
|
||||
*/
|
||||
const gchar *
|
||||
gst_clapper_subtitle_info_get_title (const GstClapperSubtitleInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_SUBTITLE_INFO (info), NULL);
|
||||
|
||||
return info->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_subtitle_info_get_language:
|
||||
* @info: a #GstClapperSubtitleInfo
|
||||
*
|
||||
* Returns: the language of the stream, or NULL if unknown.
|
||||
*/
|
||||
const gchar *
|
||||
gst_clapper_subtitle_info_get_language (const GstClapperSubtitleInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_SUBTITLE_INFO (info), NULL);
|
||||
|
||||
return info->language;
|
||||
}
|
||||
|
||||
/* Global media information */
|
||||
G_DEFINE_TYPE (GstClapperMediaInfo, gst_clapper_media_info, G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
gst_clapper_media_info_init (GstClapperMediaInfo * info)
|
||||
{
|
||||
info->duration = -1;
|
||||
info->is_live = FALSE;
|
||||
info->seekable = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_media_info_finalize (GObject * object)
|
||||
{
|
||||
GstClapperMediaInfo *info = GST_CLAPPER_MEDIA_INFO (object);
|
||||
|
||||
g_free (info->uri);
|
||||
g_free (info->title);
|
||||
g_free (info->container);
|
||||
|
||||
if (info->tags)
|
||||
gst_tag_list_unref (info->tags);
|
||||
if (info->toc)
|
||||
gst_toc_unref (info->toc);
|
||||
if (info->image_sample)
|
||||
gst_sample_unref (info->image_sample);
|
||||
if (info->audio_stream_list)
|
||||
g_list_free (info->audio_stream_list);
|
||||
if (info->video_stream_list)
|
||||
g_list_free (info->video_stream_list);
|
||||
if (info->subtitle_stream_list)
|
||||
g_list_free (info->subtitle_stream_list);
|
||||
if (info->stream_list)
|
||||
g_list_free_full (info->stream_list, g_object_unref);
|
||||
|
||||
G_OBJECT_CLASS (gst_clapper_media_info_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_media_info_class_init (GstClapperMediaInfoClass * klass)
|
||||
{
|
||||
GObjectClass *oclass = (GObjectClass *) klass;
|
||||
|
||||
oclass->finalize = gst_clapper_media_info_finalize;
|
||||
}
|
||||
|
||||
static GstClapperVideoInfo *
|
||||
gst_clapper_video_info_new (void)
|
||||
{
|
||||
return g_object_new (GST_TYPE_CLAPPER_VIDEO_INFO, NULL);
|
||||
}
|
||||
|
||||
static GstClapperAudioInfo *
|
||||
gst_clapper_audio_info_new (void)
|
||||
{
|
||||
return g_object_new (GST_TYPE_CLAPPER_AUDIO_INFO, NULL);
|
||||
}
|
||||
|
||||
static GstClapperSubtitleInfo *
|
||||
gst_clapper_subtitle_info_new (void)
|
||||
{
|
||||
return g_object_new (GST_TYPE_CLAPPER_SUBTITLE_INFO, NULL);
|
||||
}
|
||||
|
||||
static GstClapperStreamInfo *
|
||||
gst_clapper_video_info_copy (GstClapperVideoInfo * ref)
|
||||
{
|
||||
GstClapperVideoInfo *ret;
|
||||
|
||||
ret = gst_clapper_video_info_new ();
|
||||
|
||||
ret->width = ref->width;
|
||||
ret->height = ref->height;
|
||||
ret->framerate_num = ref->framerate_num;
|
||||
ret->framerate_denom = ref->framerate_denom;
|
||||
ret->par_num = ref->par_num;
|
||||
ret->par_denom = ref->par_denom;
|
||||
ret->bitrate = ref->bitrate;
|
||||
ret->max_bitrate = ref->max_bitrate;
|
||||
|
||||
return (GstClapperStreamInfo *) ret;
|
||||
}
|
||||
|
||||
static GstClapperStreamInfo *
|
||||
gst_clapper_audio_info_copy (GstClapperAudioInfo * ref)
|
||||
{
|
||||
GstClapperAudioInfo *ret;
|
||||
|
||||
ret = gst_clapper_audio_info_new ();
|
||||
|
||||
ret->sample_rate = ref->sample_rate;
|
||||
ret->channels = ref->channels;
|
||||
ret->bitrate = ref->bitrate;
|
||||
ret->max_bitrate = ref->max_bitrate;
|
||||
|
||||
if (ref->language)
|
||||
ret->language = g_strdup (ref->language);
|
||||
|
||||
return (GstClapperStreamInfo *) ret;
|
||||
}
|
||||
|
||||
static GstClapperStreamInfo *
|
||||
gst_clapper_subtitle_info_copy (GstClapperSubtitleInfo * ref)
|
||||
{
|
||||
GstClapperSubtitleInfo *ret;
|
||||
|
||||
ret = gst_clapper_subtitle_info_new ();
|
||||
if (ref->title)
|
||||
ret->title = g_strdup (ref->title);
|
||||
if (ref->language)
|
||||
ret->language = g_strdup (ref->language);
|
||||
|
||||
return (GstClapperStreamInfo *) ret;
|
||||
}
|
||||
|
||||
GstClapperStreamInfo *
|
||||
gst_clapper_stream_info_copy (GstClapperStreamInfo * ref)
|
||||
{
|
||||
GstClapperStreamInfo *info = NULL;
|
||||
|
||||
if (!ref)
|
||||
return NULL;
|
||||
|
||||
if (GST_IS_CLAPPER_VIDEO_INFO (ref))
|
||||
info = gst_clapper_video_info_copy ((GstClapperVideoInfo *) ref);
|
||||
else if (GST_IS_CLAPPER_AUDIO_INFO (ref))
|
||||
info = gst_clapper_audio_info_copy ((GstClapperAudioInfo *) ref);
|
||||
else
|
||||
info = gst_clapper_subtitle_info_copy ((GstClapperSubtitleInfo *) ref);
|
||||
|
||||
info->stream_index = ref->stream_index;
|
||||
if (ref->tags)
|
||||
info->tags = gst_tag_list_ref (ref->tags);
|
||||
if (ref->caps)
|
||||
info->caps = gst_caps_copy (ref->caps);
|
||||
if (ref->codec)
|
||||
info->codec = g_strdup (ref->codec);
|
||||
if (ref->stream_id)
|
||||
info->stream_id = g_strdup (ref->stream_id);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
GstClapperMediaInfo *
|
||||
gst_clapper_media_info_copy (GstClapperMediaInfo * ref)
|
||||
{
|
||||
GList *l;
|
||||
GstClapperMediaInfo *info;
|
||||
|
||||
if (!ref)
|
||||
return NULL;
|
||||
|
||||
info = gst_clapper_media_info_new (ref->uri);
|
||||
info->duration = ref->duration;
|
||||
info->seekable = ref->seekable;
|
||||
info->is_live = ref->is_live;
|
||||
if (ref->tags)
|
||||
info->tags = gst_tag_list_ref (ref->tags);
|
||||
if (ref->toc)
|
||||
info->toc = gst_toc_ref (ref->toc);
|
||||
if (ref->title)
|
||||
info->title = g_strdup (ref->title);
|
||||
if (ref->container)
|
||||
info->container = g_strdup (ref->container);
|
||||
if (ref->image_sample)
|
||||
info->image_sample = gst_sample_ref (ref->image_sample);
|
||||
|
||||
for (l = ref->stream_list; l != NULL; l = l->next) {
|
||||
GstClapperStreamInfo *s;
|
||||
|
||||
s = gst_clapper_stream_info_copy ((GstClapperStreamInfo *) l->data);
|
||||
info->stream_list = g_list_append (info->stream_list, s);
|
||||
|
||||
if (GST_IS_CLAPPER_AUDIO_INFO (s))
|
||||
info->audio_stream_list = g_list_append (info->audio_stream_list, s);
|
||||
else if (GST_IS_CLAPPER_VIDEO_INFO (s))
|
||||
info->video_stream_list = g_list_append (info->video_stream_list, s);
|
||||
else
|
||||
info->subtitle_stream_list =
|
||||
g_list_append (info->subtitle_stream_list, s);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
GstClapperStreamInfo *
|
||||
gst_clapper_stream_info_new (gint stream_index, GType type)
|
||||
{
|
||||
GstClapperStreamInfo *info = NULL;
|
||||
|
||||
if (type == GST_TYPE_CLAPPER_AUDIO_INFO)
|
||||
info = (GstClapperStreamInfo *) gst_clapper_audio_info_new ();
|
||||
else if (type == GST_TYPE_CLAPPER_VIDEO_INFO)
|
||||
info = (GstClapperStreamInfo *) gst_clapper_video_info_new ();
|
||||
else
|
||||
info = (GstClapperStreamInfo *) gst_clapper_subtitle_info_new ();
|
||||
|
||||
info->stream_index = stream_index;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
GstClapperMediaInfo *
|
||||
gst_clapper_media_info_new (const gchar * uri)
|
||||
{
|
||||
GstClapperMediaInfo *info;
|
||||
|
||||
g_return_val_if_fail (uri != NULL, NULL);
|
||||
|
||||
info = g_object_new (GST_TYPE_CLAPPER_MEDIA_INFO, NULL);
|
||||
info->uri = g_strdup (uri);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_media_info_get_uri:
|
||||
* @info: a #GstClapperMediaInfo
|
||||
*
|
||||
* Returns: the URI associated with #GstClapperMediaInfo.
|
||||
*/
|
||||
const gchar *
|
||||
gst_clapper_media_info_get_uri (const GstClapperMediaInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), NULL);
|
||||
|
||||
return info->uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_media_info_is_seekable:
|
||||
* @info: a #GstClapperMediaInfo
|
||||
*
|
||||
* Returns: %TRUE if the media is seekable.
|
||||
*/
|
||||
gboolean
|
||||
gst_clapper_media_info_is_seekable (const GstClapperMediaInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), FALSE);
|
||||
|
||||
return info->seekable;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_media_info_is_live:
|
||||
* @info: a #GstClapperMediaInfo
|
||||
*
|
||||
* Returns: %TRUE if the media is live.
|
||||
*/
|
||||
gboolean
|
||||
gst_clapper_media_info_is_live (const GstClapperMediaInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), FALSE);
|
||||
|
||||
return info->is_live;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_media_info_get_stream_list:
|
||||
* @info: a #GstClapperMediaInfo
|
||||
*
|
||||
* Returns: (transfer none) (element-type GstClapperStreamInfo): A #GList of
|
||||
* matching #GstClapperStreamInfo.
|
||||
*/
|
||||
GList *
|
||||
gst_clapper_media_info_get_stream_list (const GstClapperMediaInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), NULL);
|
||||
|
||||
return info->stream_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_media_info_get_video_streams:
|
||||
* @info: a #GstClapperMediaInfo
|
||||
*
|
||||
* Returns: (transfer none) (element-type GstClapperVideoInfo): A #GList of
|
||||
* matching #GstClapperVideoInfo.
|
||||
*/
|
||||
GList *
|
||||
gst_clapper_media_info_get_video_streams (const GstClapperMediaInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), NULL);
|
||||
|
||||
return info->video_stream_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_media_info_get_subtitle_streams:
|
||||
* @info: a #GstClapperMediaInfo
|
||||
*
|
||||
* Returns: (transfer none) (element-type GstClapperSubtitleInfo): A #GList of
|
||||
* matching #GstClapperSubtitleInfo.
|
||||
*/
|
||||
GList *
|
||||
gst_clapper_media_info_get_subtitle_streams (const GstClapperMediaInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), NULL);
|
||||
|
||||
return info->subtitle_stream_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_media_info_get_audio_streams:
|
||||
* @info: a #GstClapperMediaInfo
|
||||
*
|
||||
* Returns: (transfer none) (element-type GstClapperAudioInfo): A #GList of
|
||||
* matching #GstClapperAudioInfo.
|
||||
*/
|
||||
GList *
|
||||
gst_clapper_media_info_get_audio_streams (const GstClapperMediaInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), NULL);
|
||||
|
||||
return info->audio_stream_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_media_info_get_duration:
|
||||
* @info: a #GstClapperMediaInfo
|
||||
*
|
||||
* Returns: duration of the media.
|
||||
*/
|
||||
GstClockTime
|
||||
gst_clapper_media_info_get_duration (const GstClapperMediaInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), -1);
|
||||
|
||||
return info->duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_media_info_get_tags:
|
||||
* @info: a #GstClapperMediaInfo
|
||||
*
|
||||
* Returns: (transfer none): the tags contained in media info.
|
||||
*/
|
||||
GstTagList *
|
||||
gst_clapper_media_info_get_tags (const GstClapperMediaInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), NULL);
|
||||
|
||||
return info->tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_media_info_get_toc:
|
||||
* @info: a #GstClapperMediaInfo
|
||||
*
|
||||
* Returns: (transfer none): the toc contained in media info.
|
||||
*/
|
||||
GstToc *
|
||||
gst_clapper_media_info_get_toc (const GstClapperMediaInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), NULL);
|
||||
|
||||
return info->toc;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_media_info_get_title:
|
||||
* @info: a #GstClapperMediaInfo
|
||||
*
|
||||
* Returns: the media title. When metadata does not contain title,
|
||||
* returns title parsed from URI.
|
||||
*/
|
||||
const gchar *
|
||||
gst_clapper_media_info_get_title (const GstClapperMediaInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), NULL);
|
||||
|
||||
return info->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_media_info_get_container_format:
|
||||
* @info: a #GstClapperMediaInfo
|
||||
*
|
||||
* Returns: the container format.
|
||||
*/
|
||||
const gchar *
|
||||
gst_clapper_media_info_get_container_format (const GstClapperMediaInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), NULL);
|
||||
|
||||
return info->container;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_media_info_get_image_sample:
|
||||
* @info: a #GstClapperMediaInfo
|
||||
*
|
||||
* Function to get the image (or preview-image) stored in taglist.
|
||||
* Application can use `gst_sample_*_()` API's to get caps, buffer etc.
|
||||
*
|
||||
* Returns: (transfer none): GstSample or NULL.
|
||||
*/
|
||||
GstSample *
|
||||
gst_clapper_media_info_get_image_sample (const GstClapperMediaInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), NULL);
|
||||
|
||||
return info->image_sample;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_media_info_get_number_of_streams:
|
||||
* @info: a #GstClapperMediaInfo
|
||||
*
|
||||
* Returns: number of total streams.
|
||||
*/
|
||||
guint
|
||||
gst_clapper_media_info_get_number_of_streams (const GstClapperMediaInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), 0);
|
||||
|
||||
return g_list_length (info->stream_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_media_info_get_number_of_video_streams:
|
||||
* @info: a #GstClapperMediaInfo
|
||||
*
|
||||
* Returns: number of video streams.
|
||||
*/
|
||||
guint
|
||||
gst_clapper_media_info_get_number_of_video_streams (const GstClapperMediaInfo *
|
||||
info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), 0);
|
||||
|
||||
return g_list_length (info->video_stream_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_media_info_get_number_of_audio_streams:
|
||||
* @info: a #GstClapperMediaInfo
|
||||
*
|
||||
* Returns: number of audio streams.
|
||||
*/
|
||||
guint
|
||||
gst_clapper_media_info_get_number_of_audio_streams (const GstClapperMediaInfo *
|
||||
info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), 0);
|
||||
|
||||
return g_list_length (info->audio_stream_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_media_info_get_number_of_subtitle_streams:
|
||||
* @info: a #GstClapperMediaInfo
|
||||
*
|
||||
* Returns: number of subtitle streams.
|
||||
*/
|
||||
guint gst_clapper_media_info_get_number_of_subtitle_streams
|
||||
(const GstClapperMediaInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_MEDIA_INFO (info), 0);
|
||||
|
||||
return g_list_length (info->subtitle_stream_list);
|
||||
}
|
253
lib/gst/clapper/gstclapper-media-info.h
vendored
Normal file
@@ -0,0 +1,253 @@
|
||||
/* GStreamer
|
||||
*
|
||||
* Copyright (C) 2015 Brijesh Singh <brijesh.ksingh@gmail.com>
|
||||
* Copyright (C) 2021 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_CLAPPER_MEDIA_INFO_H__
|
||||
#define __GST_CLAPPER_MEDIA_INFO_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/clapper/clapper-prelude.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_CLAPPER_STREAM_INFO \
|
||||
(gst_clapper_stream_info_get_type ())
|
||||
#define GST_CLAPPER_STREAM_INFO(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CLAPPER_STREAM_INFO,GstClapperStreamInfo))
|
||||
#define GST_CLAPPER_STREAM_INFO_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CLAPPER_STREAM_INFO,GstClapperStreamInfo))
|
||||
#define GST_IS_CLAPPER_STREAM_INFO(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CLAPPER_STREAM_INFO))
|
||||
#define GST_IS_CLAPPER_STREAM_INFO_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CLAPPER_STREAM_INFO))
|
||||
|
||||
/**
|
||||
* GstClapperStreamInfo:
|
||||
*
|
||||
* Base structure for information concerning a media stream. Depending on
|
||||
* the stream type, one can find more media-specific information in
|
||||
* #GstClapperVideoInfo, #GstClapperAudioInfo, #GstClapperSubtitleInfo.
|
||||
*/
|
||||
typedef struct _GstClapperStreamInfo GstClapperStreamInfo;
|
||||
typedef struct _GstClapperStreamInfoClass GstClapperStreamInfoClass;
|
||||
|
||||
GST_CLAPPER_API
|
||||
GType gst_clapper_stream_info_get_type (void);
|
||||
|
||||
GST_CLAPPER_API
|
||||
gint gst_clapper_stream_info_get_index (const GstClapperStreamInfo *info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
const gchar* gst_clapper_stream_info_get_stream_type (const GstClapperStreamInfo *info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstTagList* gst_clapper_stream_info_get_tags (const GstClapperStreamInfo *info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstCaps* gst_clapper_stream_info_get_caps (const GstClapperStreamInfo *info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
const gchar* gst_clapper_stream_info_get_codec (const GstClapperStreamInfo *info);
|
||||
|
||||
#define GST_TYPE_CLAPPER_VIDEO_INFO \
|
||||
(gst_clapper_video_info_get_type ())
|
||||
#define GST_CLAPPER_VIDEO_INFO(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CLAPPER_VIDEO_INFO, GstClapperVideoInfo))
|
||||
#define GST_CLAPPER_VIDEO_INFO_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((obj),GST_TYPE_CLAPPER_VIDEO_INFO, GstClapperVideoInfoClass))
|
||||
#define GST_IS_CLAPPER_VIDEO_INFO(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CLAPPER_VIDEO_INFO))
|
||||
#define GST_IS_CLAPPER_VIDEO_INFO_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((obj),GST_TYPE_CLAPPER_VIDEO_INFO))
|
||||
|
||||
/**
|
||||
* GstClapperVideoInfo:
|
||||
*
|
||||
* #GstClapperStreamInfo specific to video streams.
|
||||
*/
|
||||
typedef struct _GstClapperVideoInfo GstClapperVideoInfo;
|
||||
typedef struct _GstClapperVideoInfoClass GstClapperVideoInfoClass;
|
||||
|
||||
GST_CLAPPER_API
|
||||
GType gst_clapper_video_info_get_type (void);
|
||||
|
||||
GST_CLAPPER_API
|
||||
gint gst_clapper_video_info_get_bitrate (const GstClapperVideoInfo * info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
gint gst_clapper_video_info_get_max_bitrate (const GstClapperVideoInfo * info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
gint gst_clapper_video_info_get_width (const GstClapperVideoInfo * info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
gint gst_clapper_video_info_get_height (const GstClapperVideoInfo * info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_video_info_get_framerate (const GstClapperVideoInfo * info,
|
||||
gint * fps_n,
|
||||
gint * fps_d);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_video_info_get_pixel_aspect_ratio (const GstClapperVideoInfo * info,
|
||||
guint * par_n,
|
||||
guint * par_d);
|
||||
|
||||
#define GST_TYPE_CLAPPER_AUDIO_INFO \
|
||||
(gst_clapper_audio_info_get_type ())
|
||||
#define GST_CLAPPER_AUDIO_INFO(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CLAPPER_AUDIO_INFO, GstClapperAudioInfo))
|
||||
#define GST_CLAPPER_AUDIO_INFO_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CLAPPER_AUDIO_INFO, GstClapperAudioInfoClass))
|
||||
#define GST_IS_CLAPPER_AUDIO_INFO(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CLAPPER_AUDIO_INFO))
|
||||
#define GST_IS_CLAPPER_AUDIO_INFO_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CLAPPER_AUDIO_INFO))
|
||||
|
||||
/**
|
||||
* GstClapperAudioInfo:
|
||||
*
|
||||
* #GstClapperStreamInfo specific to audio streams.
|
||||
*/
|
||||
typedef struct _GstClapperAudioInfo GstClapperAudioInfo;
|
||||
typedef struct _GstClapperAudioInfoClass GstClapperAudioInfoClass;
|
||||
|
||||
GST_CLAPPER_API
|
||||
GType gst_clapper_audio_info_get_type (void);
|
||||
|
||||
GST_CLAPPER_API
|
||||
gint gst_clapper_audio_info_get_channels (const GstClapperAudioInfo* info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
gint gst_clapper_audio_info_get_sample_rate (const GstClapperAudioInfo* info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
gint gst_clapper_audio_info_get_bitrate (const GstClapperAudioInfo* info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
gint gst_clapper_audio_info_get_max_bitrate (const GstClapperAudioInfo* info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
const gchar* gst_clapper_audio_info_get_language (const GstClapperAudioInfo* info);
|
||||
|
||||
#define GST_TYPE_CLAPPER_SUBTITLE_INFO \
|
||||
(gst_clapper_subtitle_info_get_type ())
|
||||
#define GST_CLAPPER_SUBTITLE_INFO(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CLAPPER_SUBTITLE_INFO, GstClapperSubtitleInfo))
|
||||
#define GST_CLAPPER_SUBTITLE_INFO_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CLAPPER_SUBTITLE_INFO,GstClapperSubtitleInfoClass))
|
||||
#define GST_IS_CLAPPER_SUBTITLE_INFO(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CLAPPER_SUBTITLE_INFO))
|
||||
#define GST_IS_CLAPPER_SUBTITLE_INFO_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CLAPPER_SUBTITLE_INFO))
|
||||
|
||||
/**
|
||||
* GstClapperSubtitleInfo:
|
||||
*
|
||||
* #GstClapperStreamInfo specific to subtitle streams.
|
||||
*/
|
||||
typedef struct _GstClapperSubtitleInfo GstClapperSubtitleInfo;
|
||||
typedef struct _GstClapperSubtitleInfoClass GstClapperSubtitleInfoClass;
|
||||
|
||||
GST_CLAPPER_API
|
||||
GType gst_clapper_subtitle_info_get_type (void);
|
||||
|
||||
GST_CLAPPER_API
|
||||
const gchar * gst_clapper_subtitle_info_get_title (const GstClapperSubtitleInfo *info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
const gchar * gst_clapper_subtitle_info_get_language (const GstClapperSubtitleInfo *info);
|
||||
|
||||
#define GST_TYPE_CLAPPER_MEDIA_INFO \
|
||||
(gst_clapper_media_info_get_type())
|
||||
#define GST_CLAPPER_MEDIA_INFO(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CLAPPER_MEDIA_INFO,GstClapperMediaInfo))
|
||||
#define GST_CLAPPER_MEDIA_INFO_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CLAPPER_MEDIA_INFO,GstClapperMediaInfoClass))
|
||||
#define GST_IS_CLAPPER_MEDIA_INFO(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CLAPPER_MEDIA_INFO))
|
||||
#define GST_IS_CLAPPER_MEDIA_INFO_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CLAPPER_MEDIA_INFO))
|
||||
|
||||
/**
|
||||
* GstClapperMediaInfo:
|
||||
*
|
||||
* Structure containing the media information of a URI.
|
||||
*/
|
||||
typedef struct _GstClapperMediaInfo GstClapperMediaInfo;
|
||||
typedef struct _GstClapperMediaInfoClass GstClapperMediaInfoClass;
|
||||
|
||||
GST_CLAPPER_API
|
||||
GType gst_clapper_media_info_get_type (void);
|
||||
|
||||
GST_CLAPPER_API
|
||||
const gchar * gst_clapper_media_info_get_uri (const GstClapperMediaInfo *info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
gboolean gst_clapper_media_info_is_seekable (const GstClapperMediaInfo *info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
gboolean gst_clapper_media_info_is_live (const GstClapperMediaInfo *info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstClockTime gst_clapper_media_info_get_duration (const GstClapperMediaInfo *info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GList * gst_clapper_media_info_get_stream_list (const GstClapperMediaInfo *info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
guint gst_clapper_media_info_get_number_of_streams (const GstClapperMediaInfo *info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GList * gst_clapper_media_info_get_video_streams (const GstClapperMediaInfo *info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
guint gst_clapper_media_info_get_number_of_video_streams (const GstClapperMediaInfo *info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GList * gst_clapper_media_info_get_audio_streams (const GstClapperMediaInfo *info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
guint gst_clapper_media_info_get_number_of_audio_streams (const GstClapperMediaInfo *info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GList * gst_clapper_media_info_get_subtitle_streams (const GstClapperMediaInfo *info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
guint gst_clapper_media_info_get_number_of_subtitle_streams (const GstClapperMediaInfo *info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstTagList * gst_clapper_media_info_get_tags (const GstClapperMediaInfo *info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstToc * gst_clapper_media_info_get_toc (const GstClapperMediaInfo *info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
const gchar * gst_clapper_media_info_get_title (const GstClapperMediaInfo *info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
const gchar * gst_clapper_media_info_get_container_format (const GstClapperMediaInfo *info);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstSample * gst_clapper_media_info_get_image_sample (const GstClapperMediaInfo *info);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_CLAPPER_MEDIA_INFO_H */
|
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__ */
|
35
lib/gst/clapper/gstclapper-signal-dispatcher-private.h
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
/* GStreamer
|
||||
*
|
||||
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
|
||||
* Copyright (C) 2021 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_CLAPPER_SIGNAL_DISPATCHER_PRIVATE_H__
|
||||
#define __GST_CLAPPER_SIGNAL_DISPATCHER_PRIVATE_H__
|
||||
|
||||
#include <gst/clapper/gstclapper-signal-dispatcher.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
G_GNUC_INTERNAL void gst_clapper_signal_dispatcher_dispatch (GstClapperSignalDispatcher * self,
|
||||
GstClapper * clapper, GstClapperSignalDispatcherFunc emitter, gpointer data,
|
||||
GDestroyNotify destroy);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_CLAPPER_SIGNAL_DISPATCHER_PRIVATE_H__ */
|
58
lib/gst/clapper/gstclapper-signal-dispatcher.c
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
/* GStreamer
|
||||
*
|
||||
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
|
||||
* Copyright (C) 2021 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gstclapper-signal-dispatcher.h"
|
||||
#include "gstclapper-signal-dispatcher-private.h"
|
||||
|
||||
G_DEFINE_INTERFACE (GstClapperSignalDispatcher, gst_clapper_signal_dispatcher,
|
||||
G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
gst_clapper_signal_dispatcher_default_init (G_GNUC_UNUSED
|
||||
GstClapperSignalDispatcherInterface * iface)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
gst_clapper_signal_dispatcher_dispatch (GstClapperSignalDispatcher * self,
|
||||
GstClapper * clapper, GstClapperSignalDispatcherFunc emitter, gpointer data,
|
||||
GDestroyNotify destroy)
|
||||
{
|
||||
GstClapperSignalDispatcherInterface *iface;
|
||||
|
||||
if (!self) {
|
||||
emitter (data);
|
||||
if (destroy)
|
||||
destroy (data);
|
||||
return;
|
||||
}
|
||||
|
||||
g_return_if_fail (GST_IS_CLAPPER_SIGNAL_DISPATCHER (self));
|
||||
iface = GST_CLAPPER_SIGNAL_DISPATCHER_GET_INTERFACE (self);
|
||||
g_return_if_fail (iface->dispatch != NULL);
|
||||
|
||||
iface->dispatch (self, clapper, emitter, data, destroy);
|
||||
}
|
53
lib/gst/clapper/gstclapper-signal-dispatcher.h
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
/* GStreamer
|
||||
*
|
||||
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
|
||||
* Copyright (C) 2021 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_CLAPPER_SIGNAL_DISPATCHER_H__
|
||||
#define __GST_CLAPPER_SIGNAL_DISPATCHER_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/clapper/gstclapper-types.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GstClapperSignalDispatcher GstClapperSignalDispatcher;
|
||||
typedef struct _GstClapperSignalDispatcherInterface GstClapperSignalDispatcherInterface;
|
||||
|
||||
#define GST_TYPE_CLAPPER_SIGNAL_DISPATCHER (gst_clapper_signal_dispatcher_get_type ())
|
||||
#define GST_CLAPPER_SIGNAL_DISPATCHER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CLAPPER_SIGNAL_DISPATCHER, GstClapperSignalDispatcher))
|
||||
#define GST_IS_CLAPPER_SIGNAL_DISPATCHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CLAPPER_SIGNAL_DISPATCHER))
|
||||
#define GST_CLAPPER_SIGNAL_DISPATCHER_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_CLAPPER_SIGNAL_DISPATCHER, GstClapperSignalDispatcherInterface))
|
||||
|
||||
typedef void (*GstClapperSignalDispatcherFunc) (gpointer data);
|
||||
|
||||
struct _GstClapperSignalDispatcherInterface {
|
||||
GTypeInterface parent_iface;
|
||||
|
||||
void (*dispatch) (GstClapperSignalDispatcher * self, GstClapper * clapper,
|
||||
GstClapperSignalDispatcherFunc emitter, gpointer data,
|
||||
GDestroyNotify destroy);
|
||||
};
|
||||
|
||||
GST_CLAPPER_API
|
||||
GType gst_clapper_signal_dispatcher_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_CLAPPER_SIGNAL_DISPATCHER_H__ */
|
37
lib/gst/clapper/gstclapper-types.h
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
/* GStreamer
|
||||
*
|
||||
* Copyright (C) 2015 Sebastian Dröge <sebastian@centricular.com>
|
||||
* Copyright (C) 2021 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_CLAPPER_TYPES_H__
|
||||
#define __GST_CLAPPER_TYPES_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/clapper/clapper-prelude.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GstClapper GstClapper;
|
||||
typedef struct _GstClapperClass GstClapperClass;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_CLAPPER_TYPES_H__ */
|
||||
|
||||
|
345
lib/gst/clapper/gstclapper-video-overlay-video-renderer.c
vendored
Normal file
@@ -0,0 +1,345 @@
|
||||
/* GStreamer
|
||||
*
|
||||
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
|
||||
* Copyright (C) 2021 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:gstclapper-videooverlayvideorenderer
|
||||
* @title: GstClapperVideoOverlayVideoRenderer
|
||||
* @short_description: Clapper Video Overlay Video Renderer
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gstclapper-video-overlay-video-renderer.h"
|
||||
#include "gstclapper.h"
|
||||
|
||||
#include <gst/video/video.h>
|
||||
|
||||
struct _GstClapperVideoOverlayVideoRenderer
|
||||
{
|
||||
GObject parent;
|
||||
|
||||
GstVideoOverlay *video_overlay;
|
||||
gpointer window_handle;
|
||||
gint x, y, width, height;
|
||||
|
||||
GstElement *video_sink; /* configured video sink, or NULL */
|
||||
};
|
||||
|
||||
struct _GstClapperVideoOverlayVideoRendererClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
static void
|
||||
gst_clapper_video_overlay_video_renderer_interface_init
|
||||
(GstClapperVideoRendererInterface * iface);
|
||||
|
||||
enum
|
||||
{
|
||||
VIDEO_OVERLAY_VIDEO_RENDERER_PROP_0,
|
||||
VIDEO_OVERLAY_VIDEO_RENDERER_PROP_WINDOW_HANDLE,
|
||||
VIDEO_OVERLAY_VIDEO_RENDERER_PROP_VIDEO_SINK,
|
||||
VIDEO_OVERLAY_VIDEO_RENDERER_PROP_LAST
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GstClapperVideoOverlayVideoRenderer,
|
||||
gst_clapper_video_overlay_video_renderer, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (GST_TYPE_CLAPPER_VIDEO_RENDERER,
|
||||
gst_clapper_video_overlay_video_renderer_interface_init));
|
||||
|
||||
static GParamSpec
|
||||
* video_overlay_video_renderer_param_specs
|
||||
[VIDEO_OVERLAY_VIDEO_RENDERER_PROP_LAST] = { NULL, };
|
||||
|
||||
static void
|
||||
gst_clapper_video_overlay_video_renderer_set_property (GObject * object,
|
||||
guint prop_id, const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstClapperVideoOverlayVideoRenderer *self =
|
||||
GST_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case VIDEO_OVERLAY_VIDEO_RENDERER_PROP_WINDOW_HANDLE:
|
||||
self->window_handle = g_value_get_pointer (value);
|
||||
if (self->video_overlay)
|
||||
gst_video_overlay_set_window_handle (self->video_overlay,
|
||||
(guintptr) self->window_handle);
|
||||
break;
|
||||
case VIDEO_OVERLAY_VIDEO_RENDERER_PROP_VIDEO_SINK:
|
||||
self->video_sink = gst_object_ref_sink (g_value_get_object (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_video_overlay_video_renderer_get_property (GObject * object,
|
||||
guint prop_id, GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstClapperVideoOverlayVideoRenderer *self =
|
||||
GST_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case VIDEO_OVERLAY_VIDEO_RENDERER_PROP_WINDOW_HANDLE:
|
||||
g_value_set_pointer (value, self->window_handle);
|
||||
break;
|
||||
case VIDEO_OVERLAY_VIDEO_RENDERER_PROP_VIDEO_SINK:
|
||||
g_value_set_object (value, self->video_sink);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_video_overlay_video_renderer_finalize (GObject * object)
|
||||
{
|
||||
GstClapperVideoOverlayVideoRenderer *self =
|
||||
GST_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER (object);
|
||||
|
||||
if (self->video_overlay)
|
||||
gst_object_unref (self->video_overlay);
|
||||
|
||||
if (self->video_sink)
|
||||
gst_object_unref (self->video_sink);
|
||||
|
||||
G_OBJECT_CLASS
|
||||
(gst_clapper_video_overlay_video_renderer_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_video_overlay_video_renderer_class_init
|
||||
(GstClapperVideoOverlayVideoRendererClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->set_property =
|
||||
gst_clapper_video_overlay_video_renderer_set_property;
|
||||
gobject_class->get_property =
|
||||
gst_clapper_video_overlay_video_renderer_get_property;
|
||||
gobject_class->finalize = gst_clapper_video_overlay_video_renderer_finalize;
|
||||
|
||||
video_overlay_video_renderer_param_specs
|
||||
[VIDEO_OVERLAY_VIDEO_RENDERER_PROP_WINDOW_HANDLE] =
|
||||
g_param_spec_pointer ("window-handle", "Window Handle",
|
||||
"Window handle to embed the video into",
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
video_overlay_video_renderer_param_specs
|
||||
[VIDEO_OVERLAY_VIDEO_RENDERER_PROP_VIDEO_SINK] =
|
||||
g_param_spec_object ("video-sink", "Video Sink",
|
||||
"the video output element to use (NULL = default sink)",
|
||||
GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class,
|
||||
VIDEO_OVERLAY_VIDEO_RENDERER_PROP_LAST,
|
||||
video_overlay_video_renderer_param_specs);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_video_overlay_video_renderer_init
|
||||
(GstClapperVideoOverlayVideoRenderer * self)
|
||||
{
|
||||
self->x = self->y = self->width = self->height = -1;
|
||||
self->video_sink = NULL;
|
||||
}
|
||||
|
||||
static GstElement *gst_clapper_video_overlay_video_renderer_create_video_sink
|
||||
(GstClapperVideoRenderer * iface, GstClapper * clapper)
|
||||
{
|
||||
GstElement *video_overlay;
|
||||
GstClapperVideoOverlayVideoRenderer *self =
|
||||
GST_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER (iface);
|
||||
|
||||
if (self->video_overlay)
|
||||
gst_object_unref (self->video_overlay);
|
||||
|
||||
video_overlay = gst_clapper_get_pipeline (clapper);
|
||||
g_return_val_if_fail (GST_IS_VIDEO_OVERLAY (video_overlay), NULL);
|
||||
|
||||
self->video_overlay = GST_VIDEO_OVERLAY (video_overlay);
|
||||
|
||||
gst_video_overlay_set_window_handle (self->video_overlay,
|
||||
(guintptr) self->window_handle);
|
||||
if (self->width != -1 || self->height != -1)
|
||||
gst_video_overlay_set_render_rectangle (self->video_overlay, self->x,
|
||||
self->y, self->width, self->height);
|
||||
|
||||
return self->video_sink;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_video_overlay_video_renderer_interface_init
|
||||
(GstClapperVideoRendererInterface * iface)
|
||||
{
|
||||
iface->create_video_sink =
|
||||
gst_clapper_video_overlay_video_renderer_create_video_sink;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_video_overlay_video_renderer_new:
|
||||
* @window_handle: (allow-none): Window handle to use or %NULL
|
||||
*
|
||||
* Returns: (transfer full):
|
||||
*/
|
||||
GstClapperVideoRenderer *
|
||||
gst_clapper_video_overlay_video_renderer_new (gpointer window_handle)
|
||||
{
|
||||
return g_object_new (GST_TYPE_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER,
|
||||
"window-handle", window_handle, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_video_overlay_video_renderer_new_with_sink:
|
||||
* @window_handle: (allow-none): Window handle to use or %NULL
|
||||
* @video_sink: (transfer floating): the custom video_sink element to be set for the video renderer
|
||||
*
|
||||
* Returns: (transfer full): clapper video renderer
|
||||
*/
|
||||
GstClapperVideoRenderer *
|
||||
gst_clapper_video_overlay_video_renderer_new_with_sink (gpointer window_handle,
|
||||
GstElement * video_sink)
|
||||
{
|
||||
return g_object_new (GST_TYPE_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER,
|
||||
"window-handle", window_handle, "video-sink", video_sink, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_video_overlay_video_renderer_set_window_handle:
|
||||
* @self: #GstClapperVideoRenderer instance
|
||||
* @window_handle: handle referencing to the platform specific window
|
||||
*
|
||||
* Sets the platform specific window handle into which the video
|
||||
* should be rendered
|
||||
**/
|
||||
void gst_clapper_video_overlay_video_renderer_set_window_handle
|
||||
(GstClapperVideoOverlayVideoRenderer * self, gpointer window_handle)
|
||||
{
|
||||
g_return_if_fail (GST_IS_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER (self));
|
||||
|
||||
g_object_set (self, "window-handle", window_handle, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_video_overlay_video_renderer_get_window_handle:
|
||||
* @self: #GstClapperVideoRenderer instance
|
||||
*
|
||||
* Returns: (transfer none): The currently set, platform specific window
|
||||
* handle
|
||||
*/
|
||||
gpointer
|
||||
gst_clapper_video_overlay_video_renderer_get_window_handle
|
||||
(GstClapperVideoOverlayVideoRenderer * self) {
|
||||
gpointer window_handle;
|
||||
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER (self),
|
||||
NULL);
|
||||
|
||||
g_object_get (self, "window-handle", &window_handle, NULL);
|
||||
|
||||
return window_handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_video_overlay_video_renderer_expose:
|
||||
* @self: a #GstClapperVideoOverlayVideoRenderer instance.
|
||||
*
|
||||
* Tell an overlay that it has been exposed. This will redraw the current frame
|
||||
* in the drawable even if the pipeline is PAUSED.
|
||||
*/
|
||||
void gst_clapper_video_overlay_video_renderer_expose
|
||||
(GstClapperVideoOverlayVideoRenderer * self)
|
||||
{
|
||||
g_return_if_fail (GST_IS_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER (self));
|
||||
|
||||
if (self->video_overlay)
|
||||
gst_video_overlay_expose (self->video_overlay);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_video_overlay_video_renderer_set_render_rectangle:
|
||||
* @self: a #GstClapperVideoOverlayVideoRenderer instance
|
||||
* @x: the horizontal offset of the render area inside the window
|
||||
* @y: the vertical offset of the render area inside the window
|
||||
* @width: the width of the render area inside the window
|
||||
* @height: the height of the render area inside the window
|
||||
*
|
||||
* Configure a subregion as a video target within the window set by
|
||||
* gst_clapper_video_overlay_video_renderer_set_window_handle(). If this is not
|
||||
* used or not supported the video will fill the area of the window set as the
|
||||
* overlay to 100%. By specifying the rectangle, the video can be overlaid to
|
||||
* a specific region of that window only. After setting the new rectangle one
|
||||
* should call gst_clapper_video_overlay_video_renderer_expose() to force a
|
||||
* redraw. To unset the region pass -1 for the @width and @height parameters.
|
||||
*
|
||||
* This method is needed for non fullscreen video overlay in UI toolkits that
|
||||
* do not support subwindows.
|
||||
*
|
||||
*/
|
||||
void gst_clapper_video_overlay_video_renderer_set_render_rectangle
|
||||
(GstClapperVideoOverlayVideoRenderer * self, gint x, gint y, gint width,
|
||||
gint height)
|
||||
{
|
||||
g_return_if_fail (GST_IS_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER (self));
|
||||
|
||||
self->x = x;
|
||||
self->y = y;
|
||||
self->width = width;
|
||||
self->height = height;
|
||||
|
||||
if (self->video_overlay)
|
||||
gst_video_overlay_set_render_rectangle (self->video_overlay,
|
||||
x, y, width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_video_overlay_video_renderer_get_render_rectangle:
|
||||
* @self: a #GstClapperVideoOverlayVideoRenderer instance
|
||||
* @x: (out) (allow-none): the horizontal offset of the render area inside the window
|
||||
* @y: (out) (allow-none): the vertical offset of the render area inside the window
|
||||
* @width: (out) (allow-none): the width of the render area inside the window
|
||||
* @height: (out) (allow-none): the height of the render area inside the window
|
||||
*
|
||||
* Return the currently configured render rectangle. See gst_clapper_video_overlay_video_renderer_set_render_rectangle()
|
||||
* for details.
|
||||
*
|
||||
*/
|
||||
void gst_clapper_video_overlay_video_renderer_get_render_rectangle
|
||||
(GstClapperVideoOverlayVideoRenderer * self, gint * x, gint * y,
|
||||
gint * width, gint * height)
|
||||
{
|
||||
g_return_if_fail (GST_IS_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER (self));
|
||||
|
||||
if (x)
|
||||
*x = self->x;
|
||||
if (y)
|
||||
*y = self->y;
|
||||
if (width)
|
||||
*width = self->width;
|
||||
if (height)
|
||||
*height = self->height;
|
||||
}
|
71
lib/gst/clapper/gstclapper-video-overlay-video-renderer.h
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
/* GStreamer
|
||||
*
|
||||
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
|
||||
* Copyright (C) 2021 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER_H__
|
||||
#define __GST_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER_H__
|
||||
|
||||
#include <gst/clapper/gstclapper-types.h>
|
||||
#include <gst/clapper/gstclapper-video-renderer.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GstClapperVideoOverlayVideoRenderer
|
||||
GstClapperVideoOverlayVideoRenderer;
|
||||
typedef struct _GstClapperVideoOverlayVideoRendererClass
|
||||
GstClapperVideoOverlayVideoRendererClass;
|
||||
|
||||
#define GST_TYPE_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER (gst_clapper_video_overlay_video_renderer_get_type ())
|
||||
#define GST_IS_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER))
|
||||
#define GST_IS_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER))
|
||||
#define GST_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER, GstClapperVideoOverlayVideoRendererClass))
|
||||
#define GST_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER, GstClapperVideoOverlayVideoRenderer))
|
||||
#define GST_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER, GstClapperVideoOverlayVideoRendererClass))
|
||||
#define GST_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER_CAST(obj) ((GstClapperVideoOverlayVideoRenderer*)(obj))
|
||||
|
||||
GST_CLAPPER_API
|
||||
GType gst_clapper_video_overlay_video_renderer_get_type (void);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstClapperVideoRenderer *
|
||||
gst_clapper_video_overlay_video_renderer_new (gpointer window_handle);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstClapperVideoRenderer *
|
||||
gst_clapper_video_overlay_video_renderer_new_with_sink (gpointer window_handle, GstElement *video_sink);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_video_overlay_video_renderer_set_window_handle (GstClapperVideoOverlayVideoRenderer *self, gpointer window_handle);
|
||||
|
||||
GST_CLAPPER_API
|
||||
gpointer gst_clapper_video_overlay_video_renderer_get_window_handle (GstClapperVideoOverlayVideoRenderer *self);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_video_overlay_video_renderer_expose (GstClapperVideoOverlayVideoRenderer *self);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_video_overlay_video_renderer_set_render_rectangle (GstClapperVideoOverlayVideoRenderer *self, gint x, gint y, gint width, gint height);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_video_overlay_video_renderer_get_render_rectangle (GstClapperVideoOverlayVideoRenderer *self, gint *x, gint *y, gint *width, gint *height);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_CLAPPER_VIDEO_OVERLAY_VIDEO_RENDERER_H__ */
|
33
lib/gst/clapper/gstclapper-video-renderer-private.h
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
/* GStreamer
|
||||
*
|
||||
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
|
||||
* Copyright (C) 2021 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_CLAPPER_VIDEO_RENDERER_PRIVATE_H__
|
||||
#define __GST_CLAPPER_VIDEO_RENDERER_PRIVATE_H__
|
||||
|
||||
#include <gst/clapper/gstclapper-video-renderer.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
G_GNUC_INTERNAL GstElement * gst_clapper_video_renderer_create_video_sink (GstClapperVideoRenderer *self, GstClapper *clapper);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_CLAPPER_VIDEO_RENDERER_PRIVATE_H__ */
|
50
lib/gst/clapper/gstclapper-video-renderer.c
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
/* GStreamer
|
||||
*
|
||||
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
|
||||
* Copyright (C) 2021 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gstclapper-video-renderer.h"
|
||||
#include "gstclapper-video-renderer-private.h"
|
||||
|
||||
G_DEFINE_INTERFACE (GstClapperVideoRenderer, gst_clapper_video_renderer,
|
||||
G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
gst_clapper_video_renderer_default_init (G_GNUC_UNUSED
|
||||
GstClapperVideoRendererInterface * iface)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
GstElement *
|
||||
gst_clapper_video_renderer_create_video_sink (GstClapperVideoRenderer * self,
|
||||
GstClapper * clapper)
|
||||
{
|
||||
GstClapperVideoRendererInterface *iface;
|
||||
|
||||
g_return_val_if_fail (GST_IS_CLAPPER_VIDEO_RENDERER (self), NULL);
|
||||
iface = GST_CLAPPER_VIDEO_RENDERER_GET_INTERFACE (self);
|
||||
g_return_val_if_fail (iface->create_video_sink != NULL, NULL);
|
||||
|
||||
return iface->create_video_sink (self, clapper);
|
||||
}
|
49
lib/gst/clapper/gstclapper-video-renderer.h
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
/* GStreamer
|
||||
*
|
||||
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
|
||||
* Copyright (C) 2021 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_CLAPPER_VIDEO_RENDERER_H__
|
||||
#define __GST_CLAPPER_VIDEO_RENDERER_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/clapper/gstclapper-types.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GstClapperVideoRenderer GstClapperVideoRenderer;
|
||||
typedef struct _GstClapperVideoRendererInterface GstClapperVideoRendererInterface;
|
||||
|
||||
#define GST_TYPE_CLAPPER_VIDEO_RENDERER (gst_clapper_video_renderer_get_type ())
|
||||
#define GST_CLAPPER_VIDEO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CLAPPER_VIDEO_RENDERER, GstClapperVideoRenderer))
|
||||
#define GST_IS_CLAPPER_VIDEO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CLAPPER_VIDEO_RENDERER))
|
||||
#define GST_CLAPPER_VIDEO_RENDERER_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_CLAPPER_VIDEO_RENDERER, GstClapperVideoRendererInterface))
|
||||
|
||||
struct _GstClapperVideoRendererInterface {
|
||||
GTypeInterface parent_iface;
|
||||
|
||||
GstElement * (*create_video_sink) (GstClapperVideoRenderer * self, GstClapper * clapper);
|
||||
};
|
||||
|
||||
GST_CLAPPER_API
|
||||
GType gst_clapper_video_renderer_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_CLAPPER_VIDEO_RENDERER_H__ */
|
180
lib/gst/clapper/gstclapper-visualization.c
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
/* GStreamer
|
||||
*
|
||||
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
|
||||
* Copyright (C) 2015 Brijesh Singh <brijesh.ksingh@gmail.com>
|
||||
* Copyright (C) 2021 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:gstclapper-visualization
|
||||
* @title: GstClapperVisualization
|
||||
* @short_description: Clapper Visualization
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gstclapper-visualization.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static GMutex vis_lock;
|
||||
static GQueue vis_list = G_QUEUE_INIT;
|
||||
static guint32 vis_cookie;
|
||||
|
||||
G_DEFINE_BOXED_TYPE (GstClapperVisualization, gst_clapper_visualization,
|
||||
(GBoxedCopyFunc) gst_clapper_visualization_copy,
|
||||
(GBoxedFreeFunc) gst_clapper_visualization_free);
|
||||
|
||||
/**
|
||||
* gst_clapper_visualization_free:
|
||||
* @vis: #GstClapperVisualization instance
|
||||
*
|
||||
* Frees a #GstClapperVisualization.
|
||||
*/
|
||||
void
|
||||
gst_clapper_visualization_free (GstClapperVisualization * vis)
|
||||
{
|
||||
g_return_if_fail (vis != NULL);
|
||||
|
||||
g_free (vis->name);
|
||||
g_free (vis->description);
|
||||
g_free (vis);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_visualization_copy:
|
||||
* @vis: #GstClapperVisualization instance
|
||||
*
|
||||
* Makes a copy of the #GstClapperVisualization. The result must be
|
||||
* freed using gst_clapper_visualization_free().
|
||||
*
|
||||
* Returns: (transfer full): an allocated copy of @vis.
|
||||
*/
|
||||
GstClapperVisualization *
|
||||
gst_clapper_visualization_copy (const GstClapperVisualization * vis)
|
||||
{
|
||||
GstClapperVisualization *ret;
|
||||
|
||||
g_return_val_if_fail (vis != NULL, NULL);
|
||||
|
||||
ret = g_new0 (GstClapperVisualization, 1);
|
||||
ret->name = vis->name ? g_strdup (vis->name) : NULL;
|
||||
ret->description = vis->description ? g_strdup (vis->description) : NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_visualizations_free:
|
||||
* @viss: a %NULL terminated array of #GstClapperVisualization to free
|
||||
*
|
||||
* Frees a %NULL terminated array of #GstClapperVisualization.
|
||||
*/
|
||||
void
|
||||
gst_clapper_visualizations_free (GstClapperVisualization ** viss)
|
||||
{
|
||||
GstClapperVisualization **p;
|
||||
|
||||
g_return_if_fail (viss != NULL);
|
||||
|
||||
p = viss;
|
||||
while (*p) {
|
||||
g_free ((*p)->name);
|
||||
g_free ((*p)->description);
|
||||
g_free (*p);
|
||||
p++;
|
||||
}
|
||||
g_free (viss);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_update_visualization_list (void)
|
||||
{
|
||||
GList *features;
|
||||
GList *l;
|
||||
guint32 cookie;
|
||||
GstClapperVisualization *vis;
|
||||
|
||||
g_mutex_lock (&vis_lock);
|
||||
|
||||
/* check if we need to update the list */
|
||||
cookie = gst_registry_get_feature_list_cookie (gst_registry_get ());
|
||||
if (vis_cookie == cookie) {
|
||||
g_mutex_unlock (&vis_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* if update is needed then first free the existing list */
|
||||
while ((vis = g_queue_pop_head (&vis_list)))
|
||||
gst_clapper_visualization_free (vis);
|
||||
|
||||
features = gst_registry_get_feature_list (gst_registry_get (),
|
||||
GST_TYPE_ELEMENT_FACTORY);
|
||||
|
||||
for (l = features; l; l = l->next) {
|
||||
GstPluginFeature *feature = l->data;
|
||||
const gchar *klass;
|
||||
|
||||
klass = gst_element_factory_get_metadata (GST_ELEMENT_FACTORY (feature),
|
||||
GST_ELEMENT_METADATA_KLASS);
|
||||
|
||||
if (strstr (klass, "Visualization")) {
|
||||
vis = g_new0 (GstClapperVisualization, 1);
|
||||
|
||||
vis->name = g_strdup (gst_plugin_feature_get_name (feature));
|
||||
vis->description =
|
||||
g_strdup (gst_element_factory_get_metadata (GST_ELEMENT_FACTORY
|
||||
(feature), GST_ELEMENT_METADATA_DESCRIPTION));
|
||||
g_queue_push_tail (&vis_list, vis);
|
||||
}
|
||||
}
|
||||
gst_plugin_feature_list_free (features);
|
||||
|
||||
vis_cookie = cookie;
|
||||
|
||||
g_mutex_unlock (&vis_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clapper_visualizations_get:
|
||||
*
|
||||
* Returns: (transfer full) (array zero-terminated=1) (element-type GstClapperVisualization):
|
||||
* a %NULL terminated array containing all available
|
||||
* visualizations. Use gst_clapper_visualizations_free() after
|
||||
* usage.
|
||||
*/
|
||||
GstClapperVisualization **
|
||||
gst_clapper_visualizations_get (void)
|
||||
{
|
||||
gint i = 0;
|
||||
GList *l;
|
||||
GstClapperVisualization **ret;
|
||||
|
||||
gst_clapper_update_visualization_list ();
|
||||
|
||||
g_mutex_lock (&vis_lock);
|
||||
ret = g_new0 (GstClapperVisualization *, g_queue_get_length (&vis_list) + 1);
|
||||
for (l = vis_list.head; l; l = l->next)
|
||||
ret[i++] = gst_clapper_visualization_copy (l->data);
|
||||
g_mutex_unlock (&vis_lock);
|
||||
|
||||
return ret;
|
||||
}
|
61
lib/gst/clapper/gstclapper-visualization.h
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
/* GStreamer
|
||||
*
|
||||
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
|
||||
* Copyright (C) 2015 Brijesh Singh <brijesh.ksingh@gmail.com>
|
||||
* Copyright (C) 2021 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_CLAPPER_VISUALIZATION_H__
|
||||
#define __GST_CLAPPER_VISUALIZATION_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/clapper/clapper-prelude.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GstClapperVisualization GstClapperVisualization;
|
||||
/**
|
||||
* GstClapperVisualization:
|
||||
* @name: name of the visualization.
|
||||
* @description: description of the visualization.
|
||||
*
|
||||
* A #GstClapperVisualization descriptor.
|
||||
*/
|
||||
struct _GstClapperVisualization {
|
||||
gchar *name;
|
||||
gchar *description;
|
||||
};
|
||||
|
||||
GST_CLAPPER_API
|
||||
GType gst_clapper_visualization_get_type (void);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstClapperVisualization * gst_clapper_visualization_copy (const GstClapperVisualization *vis);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_visualization_free (GstClapperVisualization *vis);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstClapperVisualization ** gst_clapper_visualizations_get (void);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_visualizations_free (GstClapperVisualization **viss);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_CLAPPER_VISUALIZATION_H__ */
|
5294
lib/gst/clapper/gstclapper.c
vendored
Normal file
318
lib/gst/clapper/gstclapper.h
vendored
Normal file
@@ -0,0 +1,318 @@
|
||||
/* GStreamer
|
||||
*
|
||||
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
|
||||
* Copyright (C) 2021 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_CLAPPER_H__
|
||||
#define __GST_CLAPPER_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/video/video.h>
|
||||
|
||||
#include <gst/clapper/clapper-prelude.h>
|
||||
#include <gst/clapper/gstclapper-types.h>
|
||||
#include <gst/clapper/gstclapper-signal-dispatcher.h>
|
||||
#include <gst/clapper/gstclapper-video-renderer.h>
|
||||
#include <gst/clapper/gstclapper-media-info.h>
|
||||
#include <gst/clapper/gstclapper-mpris.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/* ClapperState */
|
||||
GST_CLAPPER_API
|
||||
GType gst_clapper_state_get_type (void);
|
||||
#define GST_TYPE_CLAPPER_STATE (gst_clapper_state_get_type ())
|
||||
|
||||
/**
|
||||
* GstClapperState:
|
||||
* @GST_CLAPPER_STATE_STOPPED: clapper is stopped.
|
||||
* @GST_CLAPPER_STATE_BUFFERING: clapper is buffering.
|
||||
* @GST_CLAPPER_STATE_PAUSED: clapper is paused.
|
||||
* @GST_CLAPPER_STATE_PLAYING: clapper is currently playing a stream.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
GST_CLAPPER_STATE_STOPPED,
|
||||
GST_CLAPPER_STATE_BUFFERING,
|
||||
GST_CLAPPER_STATE_PAUSED,
|
||||
GST_CLAPPER_STATE_PLAYING
|
||||
} GstClapperState;
|
||||
|
||||
GST_CLAPPER_API
|
||||
const gchar * gst_clapper_state_get_name (GstClapperState state);
|
||||
|
||||
/* ClapperSeekMode */
|
||||
GST_CLAPPER_API
|
||||
GType gst_clapper_seek_mode_get_type (void);
|
||||
#define GST_TYPE_CLAPPER_SEEK_MODE (gst_clapper_seek_mode_get_type ())
|
||||
|
||||
/**
|
||||
* GstClapperSeekMode:
|
||||
* @GST_CLAPPER_SEEK_MODE_DEFAULT: default seek method (flush only).
|
||||
* @GST_CLAPPER_SEEK_MODE_ACCURATE: accurate seek method.
|
||||
* @GST_CLAPPER_SEEK_MODE_FAST: fast seek method (next keyframe).
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
GST_CLAPPER_SEEK_MODE_DEFAULT,
|
||||
GST_CLAPPER_SEEK_MODE_ACCURATE,
|
||||
GST_CLAPPER_SEEK_MODE_FAST,
|
||||
} GstClapperSeekMode;
|
||||
|
||||
/* ClapperError */
|
||||
GST_CLAPPER_API
|
||||
GQuark gst_clapper_error_quark (void);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GType gst_clapper_error_get_type (void);
|
||||
#define GST_CLAPPER_ERROR (gst_clapper_error_quark ())
|
||||
#define GST_TYPE_CLAPPER_ERROR (gst_clapper_error_get_type ())
|
||||
|
||||
/**
|
||||
* GstClapperError:
|
||||
* @GST_CLAPPER_ERROR_FAILED: generic error.
|
||||
*/
|
||||
typedef enum {
|
||||
GST_CLAPPER_ERROR_FAILED = 0
|
||||
} GstClapperError;
|
||||
|
||||
GST_CLAPPER_API
|
||||
const gchar * gst_clapper_error_get_name (GstClapperError error);
|
||||
|
||||
/* ClapperColorBalanceType */
|
||||
GST_CLAPPER_API
|
||||
GType gst_clapper_color_balance_type_get_type (void);
|
||||
#define GST_TYPE_CLAPPER_COLOR_BALANCE_TYPE (gst_clapper_color_balance_type_get_type ())
|
||||
|
||||
/**
|
||||
* GstClapperColorBalanceType:
|
||||
* @GST_CLAPPER_COLOR_BALANCE_BRIGHTNESS: brightness or black level.
|
||||
* @GST_CLAPPER_COLOR_BALANCE_CONTRAST: contrast or luma gain.
|
||||
* @GST_CLAPPER_COLOR_BALANCE_SATURATION: color saturation or chroma
|
||||
* gain.
|
||||
* @GST_CLAPPER_COLOR_BALANCE_HUE: hue or color balance.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
GST_CLAPPER_COLOR_BALANCE_BRIGHTNESS,
|
||||
GST_CLAPPER_COLOR_BALANCE_CONTRAST,
|
||||
GST_CLAPPER_COLOR_BALANCE_SATURATION,
|
||||
GST_CLAPPER_COLOR_BALANCE_HUE,
|
||||
} GstClapperColorBalanceType;
|
||||
|
||||
GST_CLAPPER_API
|
||||
const gchar * gst_clapper_color_balance_type_get_name (GstClapperColorBalanceType type);
|
||||
|
||||
/* ClapperSnapshotFormat */
|
||||
|
||||
/**
|
||||
* GstClapperSnapshotFormat:
|
||||
* @GST_CLAPPER_THUMBNAIL_RAW_NATIVE: RAW Native.
|
||||
* @GST_CLAPPER_THUMBNAIL_RAW_xRGB: RAW xRGB.
|
||||
* @GST_CLAPPER_THUMBNAIL_RAW_BGRx: RAW BGRx.
|
||||
* @GST_CLAPPER_THUMBNAIL_JPG: JPG.
|
||||
* @GST_CLAPPER_THUMBNAIL_PNG: PNG.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
GST_CLAPPER_THUMBNAIL_RAW_NATIVE = 0,
|
||||
GST_CLAPPER_THUMBNAIL_RAW_xRGB,
|
||||
GST_CLAPPER_THUMBNAIL_RAW_BGRx,
|
||||
GST_CLAPPER_THUMBNAIL_JPG,
|
||||
GST_CLAPPER_THUMBNAIL_PNG
|
||||
} GstClapperSnapshotFormat;
|
||||
|
||||
#define GST_TYPE_CLAPPER (gst_clapper_get_type ())
|
||||
#define GST_IS_CLAPPER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CLAPPER))
|
||||
#define GST_IS_CLAPPER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CLAPPER))
|
||||
#define GST_CLAPPER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CLAPPER, GstClapperClass))
|
||||
#define GST_CLAPPER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CLAPPER, GstClapper))
|
||||
#define GST_CLAPPER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_CLAPPER, GstClapperClass))
|
||||
#define GST_CLAPPER_CAST(obj) ((GstClapper*)(obj))
|
||||
|
||||
#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstClapper, gst_object_unref)
|
||||
#endif
|
||||
|
||||
GST_CLAPPER_API
|
||||
GType gst_clapper_get_type (void);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_gst_init (int *argc, char **argv[]);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstClapper * gst_clapper_new (GstClapperVideoRenderer *video_renderer, GstClapperSignalDispatcher *signal_dispatcher,
|
||||
GstClapperMpris *mpris);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_play (GstClapper *clapper);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_pause (GstClapper *clapper);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_toggle_play (GstClapper *clapper);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_stop (GstClapper *clapper);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_seek (GstClapper *clapper, GstClockTime position);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_seek_offset (GstClapper *clapper, GstClockTime offset);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstClapperState
|
||||
gst_clapper_get_state (GstClapper *clapper);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstClapperSeekMode
|
||||
gst_clapper_get_seek_mode (GstClapper *clapper);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_set_seek_mode (GstClapper *clapper, GstClapperSeekMode mode);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_set_rate (GstClapper *clapper, gdouble rate);
|
||||
|
||||
GST_CLAPPER_API
|
||||
gdouble gst_clapper_get_rate (GstClapper *clapper);
|
||||
|
||||
GST_CLAPPER_API
|
||||
gchar * gst_clapper_get_uri (GstClapper *clapper);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_set_uri (GstClapper *clapper, const gchar *uri);
|
||||
|
||||
GST_CLAPPER_API
|
||||
gchar * gst_clapper_get_subtitle_uri (GstClapper *clapper);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_set_subtitle_uri (GstClapper *clapper, const gchar *uri);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstClockTime gst_clapper_get_position (GstClapper *clapper);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstClockTime gst_clapper_get_duration (GstClapper *clapper);
|
||||
|
||||
GST_CLAPPER_API
|
||||
gdouble gst_clapper_get_volume (GstClapper *clapper);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_set_volume (GstClapper *clapper, gdouble val);
|
||||
|
||||
GST_CLAPPER_API
|
||||
gboolean gst_clapper_get_mute (GstClapper *clapper);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_set_mute (GstClapper *clapper, gboolean val);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstElement * gst_clapper_get_pipeline (GstClapper *clapper);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstClapperMpris *
|
||||
gst_clapper_get_mpris (GstClapper *clapper);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_set_video_track_enabled (GstClapper *clapper, gboolean enabled);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_set_audio_track_enabled (GstClapper *clapper, gboolean enabled);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_set_subtitle_track_enabled (GstClapper *clapper, gboolean enabled);
|
||||
|
||||
GST_CLAPPER_API
|
||||
gboolean gst_clapper_set_audio_track (GstClapper *clapper, gint stream_index);
|
||||
|
||||
GST_CLAPPER_API
|
||||
gboolean gst_clapper_set_video_track (GstClapper *clapper, gint stream_index);
|
||||
|
||||
GST_CLAPPER_API
|
||||
gboolean gst_clapper_set_subtitle_track (GstClapper *clapper, gint stream_index);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstClapperMediaInfo *
|
||||
gst_clapper_get_media_info (GstClapper *clapper);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstClapperAudioInfo *
|
||||
gst_clapper_get_current_audio_track (GstClapper *clapper);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstClapperVideoInfo *
|
||||
gst_clapper_get_current_video_track (GstClapper *clapper);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstClapperSubtitleInfo *
|
||||
gst_clapper_get_current_subtitle_track (GstClapper *clapper);
|
||||
|
||||
GST_CLAPPER_API
|
||||
gboolean gst_clapper_set_visualization (GstClapper *clapper, const gchar *name);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_set_visualization_enabled (GstClapper *clapper, gboolean enabled);
|
||||
|
||||
GST_CLAPPER_API
|
||||
gchar * gst_clapper_get_current_visualization (GstClapper *clapper);
|
||||
|
||||
GST_CLAPPER_API
|
||||
gboolean gst_clapper_has_color_balance (GstClapper *clapper);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_set_color_balance (GstClapper *clapper, GstClapperColorBalanceType type, gdouble value);
|
||||
|
||||
GST_CLAPPER_API
|
||||
gdouble gst_clapper_get_color_balance (GstClapper *clapper, GstClapperColorBalanceType type);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstVideoMultiviewFramePacking
|
||||
gst_clapper_get_multiview_mode (GstClapper *clapper);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_set_multiview_mode (GstClapper *clapper, GstVideoMultiviewFramePacking mode);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstVideoMultiviewFlags
|
||||
gst_clapper_get_multiview_flags (GstClapper *clapper);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_set_multiview_flags (GstClapper *clapper, GstVideoMultiviewFlags flags);
|
||||
|
||||
GST_CLAPPER_API
|
||||
gint64 gst_clapper_get_audio_video_offset (GstClapper *clapper);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_set_audio_video_offset (GstClapper *clapper, gint64 offset);
|
||||
|
||||
GST_CLAPPER_API
|
||||
gint64 gst_clapper_get_subtitle_video_offset (GstClapper *clapper);
|
||||
|
||||
GST_CLAPPER_API
|
||||
void gst_clapper_set_subtitle_video_offset (GstClapper *clapper, gint64 offset);
|
||||
|
||||
GST_CLAPPER_API
|
||||
GstSample * gst_clapper_get_video_snapshot (GstClapper *clapper, GstClapperSnapshotFormat format, const GstStructure *config);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_CLAPPER_H__ */
|
759
lib/gst/clapper/gtk4/gstclapperglsink.c
Normal file
@@ -0,0 +1,759 @@
|
||||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
* Copyright (C) 2020 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:gstclapperglsink
|
||||
* @title: GstClapperGLSink
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <gst/gl/gstglfuncs.h>
|
||||
|
||||
#include "gstclapperglsink.h"
|
||||
#include "gstgtkutils.h"
|
||||
|
||||
GST_DEBUG_CATEGORY (gst_debug_clapper_gl_sink);
|
||||
#define GST_CAT_DEFAULT gst_debug_clapper_gl_sink
|
||||
|
||||
#define GST_CLAPPER_GL_SINK_CAPS \
|
||||
"video/x-raw(" GST_CAPS_FEATURE_MEMORY_GL_MEMORY "), " \
|
||||
"format = (string) RGBA, " \
|
||||
"width = " GST_VIDEO_SIZE_RANGE ", " \
|
||||
"height = " GST_VIDEO_SIZE_RANGE ", " \
|
||||
"framerate = " GST_VIDEO_FPS_RANGE ", " \
|
||||
"texture-target = (string) { 2D, external-oes } " \
|
||||
" ; " \
|
||||
"video/x-raw(" GST_CAPS_FEATURE_MEMORY_GL_MEMORY "," \
|
||||
GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION "), " \
|
||||
"format = (string) RGBA, " \
|
||||
"width = " GST_VIDEO_SIZE_RANGE ", " \
|
||||
"height = " GST_VIDEO_SIZE_RANGE ", " \
|
||||
"framerate = " GST_VIDEO_FPS_RANGE ", " \
|
||||
"texture-target = (string) { 2D, external-oes } "
|
||||
|
||||
static GstStaticPadTemplate gst_clapper_gl_sink_template =
|
||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS (GST_CLAPPER_GL_SINK_CAPS));
|
||||
|
||||
static void gst_clapper_gl_sink_finalize (GObject * object);
|
||||
static void gst_clapper_gl_sink_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * param_spec);
|
||||
static void gst_clapper_gl_sink_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * param_spec);
|
||||
|
||||
static gboolean gst_clapper_gl_sink_propose_allocation (GstBaseSink * bsink,
|
||||
GstQuery * query);
|
||||
static gboolean gst_clapper_gl_sink_query (GstBaseSink * bsink, GstQuery * query);
|
||||
static gboolean gst_clapper_gl_sink_start (GstBaseSink * bsink);
|
||||
static gboolean gst_clapper_gl_sink_stop (GstBaseSink * bsink);
|
||||
static GstFlowReturn gst_clapper_gl_sink_wait_event (GstBaseSink * bsink, GstEvent * event);
|
||||
|
||||
static GstStateChangeReturn
|
||||
gst_clapper_gl_sink_change_state (GstElement * element,
|
||||
GstStateChange transition);
|
||||
|
||||
static void gst_clapper_gl_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
|
||||
GstClockTime * start, GstClockTime * end);
|
||||
static GstCaps *gst_clapper_gl_sink_get_caps (GstBaseSink * bsink,
|
||||
GstCaps * filter);
|
||||
static gboolean gst_clapper_gl_sink_set_caps (GstBaseSink * bsink,
|
||||
GstCaps * caps);
|
||||
static GstFlowReturn gst_clapper_gl_sink_show_frame (GstVideoSink * bsink,
|
||||
GstBuffer * buf);
|
||||
|
||||
static void
|
||||
gst_clapper_gl_sink_navigation_interface_init (GstNavigationInterface * iface);
|
||||
|
||||
#define gst_clapper_gl_sink_parent_class parent_class
|
||||
G_DEFINE_TYPE_WITH_CODE (GstClapperGLSink, gst_clapper_gl_sink,
|
||||
GST_TYPE_VIDEO_SINK,
|
||||
G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION,
|
||||
gst_clapper_gl_sink_navigation_interface_init);
|
||||
GST_DEBUG_CATEGORY_INIT (gst_debug_clapper_gl_sink,
|
||||
"clapperglsink", 0, "Clapper GL Sink"));
|
||||
|
||||
static void
|
||||
gst_clapper_gl_sink_class_init (GstClapperGLSinkClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
GstBaseSinkClass *gstbasesink_class;
|
||||
GstVideoSinkClass *gstvideosink_class;
|
||||
GstClapperGLSinkClass *gstclapperglsink_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
gstbasesink_class = (GstBaseSinkClass *) klass;
|
||||
gstvideosink_class = (GstVideoSinkClass *) klass;
|
||||
gstclapperglsink_class = (GstClapperGLSinkClass *) klass;
|
||||
|
||||
gobject_class->set_property = gst_clapper_gl_sink_set_property;
|
||||
gobject_class->get_property = gst_clapper_gl_sink_get_property;
|
||||
gobject_class->finalize = gst_clapper_gl_sink_finalize;
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_WIDGET,
|
||||
g_param_spec_object ("widget", "GTK Widget",
|
||||
"The GtkWidget to place in the widget hierarchy "
|
||||
"(must only be get from the GTK main thread)",
|
||||
GTK_TYPE_WIDGET, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
gst_gtk_install_shared_properties (gobject_class);
|
||||
|
||||
gstelement_class->change_state = gst_clapper_gl_sink_change_state;
|
||||
|
||||
gstbasesink_class->get_caps = gst_clapper_gl_sink_get_caps;
|
||||
gstbasesink_class->set_caps = gst_clapper_gl_sink_set_caps;
|
||||
gstbasesink_class->get_times = gst_clapper_gl_sink_get_times;
|
||||
gstbasesink_class->propose_allocation = gst_clapper_gl_sink_propose_allocation;
|
||||
gstbasesink_class->query = gst_clapper_gl_sink_query;
|
||||
gstbasesink_class->start = gst_clapper_gl_sink_start;
|
||||
gstbasesink_class->stop = gst_clapper_gl_sink_stop;
|
||||
gstbasesink_class->wait_event = gst_clapper_gl_sink_wait_event;
|
||||
|
||||
gstvideosink_class->show_frame = gst_clapper_gl_sink_show_frame;
|
||||
|
||||
gstclapperglsink_class->create_widget = gtk_clapper_gl_widget_new;
|
||||
gstclapperglsink_class->window_title = "GTK4 GL Renderer";
|
||||
|
||||
gst_element_class_set_metadata (gstelement_class,
|
||||
"GTK4 GL Video Sink",
|
||||
"Sink/Video", "A video sink that renders to a GtkWidget using OpenGL",
|
||||
"Matthew Waters <matthew@centricular.com>, "
|
||||
"Rafał Dzięgiel <rafostar.github@gmail.com>");
|
||||
|
||||
gst_element_class_add_static_pad_template (gstelement_class,
|
||||
&gst_clapper_gl_sink_template);
|
||||
|
||||
gst_type_mark_as_plugin_api (GST_TYPE_CLAPPER_GL_SINK, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_gl_sink_init (GstClapperGLSink * clapper_sink)
|
||||
{
|
||||
clapper_sink->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO;
|
||||
clapper_sink->par_n = DEFAULT_PAR_N;
|
||||
clapper_sink->par_d = DEFAULT_PAR_D;
|
||||
clapper_sink->keep_last_frame = DEFAULT_KEEP_LAST_FRAME;
|
||||
|
||||
clapper_sink->had_eos = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_gl_sink_finalize (GObject * object)
|
||||
{
|
||||
GstClapperGLSink *clapper_sink = GST_CLAPPER_GL_SINK (object);
|
||||
|
||||
GST_DEBUG ("Finalizing Clapper GL sink");
|
||||
|
||||
GST_OBJECT_LOCK (clapper_sink);
|
||||
if (clapper_sink->window && clapper_sink->window_destroy_id)
|
||||
g_signal_handler_disconnect (clapper_sink->window, clapper_sink->window_destroy_id);
|
||||
if (clapper_sink->widget && clapper_sink->widget_destroy_id)
|
||||
g_signal_handler_disconnect (clapper_sink->widget, clapper_sink->widget_destroy_id);
|
||||
|
||||
g_clear_object (&clapper_sink->widget);
|
||||
GST_OBJECT_UNLOCK (clapper_sink);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
widget_destroy_cb (GtkWidget * widget, GstClapperGLSink * clapper_sink)
|
||||
{
|
||||
GST_OBJECT_LOCK (clapper_sink);
|
||||
g_clear_object (&clapper_sink->widget);
|
||||
GST_OBJECT_UNLOCK (clapper_sink);
|
||||
}
|
||||
|
||||
static void
|
||||
window_destroy_cb (GtkWidget * widget, GstClapperGLSink * clapper_sink)
|
||||
{
|
||||
GST_OBJECT_LOCK (clapper_sink);
|
||||
if (clapper_sink->widget) {
|
||||
if (clapper_sink->widget_destroy_id) {
|
||||
g_signal_handler_disconnect (clapper_sink->widget,
|
||||
clapper_sink->widget_destroy_id);
|
||||
clapper_sink->widget_destroy_id = 0;
|
||||
}
|
||||
g_clear_object (&clapper_sink->widget);
|
||||
}
|
||||
clapper_sink->window = NULL;
|
||||
GST_OBJECT_UNLOCK (clapper_sink);
|
||||
}
|
||||
|
||||
static GtkClapperGLWidget *
|
||||
gst_clapper_gl_sink_get_widget (GstClapperGLSink * clapper_sink)
|
||||
{
|
||||
if (clapper_sink->widget != NULL)
|
||||
return clapper_sink->widget;
|
||||
|
||||
/* Ensure GTK is initialized, this has no side effect if it was already
|
||||
* initialized. Also, we do that lazily, so the application can be first */
|
||||
if (!gtk_init_check ()) {
|
||||
GST_ERROR_OBJECT (clapper_sink, "Could not ensure GTK initialization.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_assert (GST_CLAPPER_GL_SINK_GET_CLASS (clapper_sink)->create_widget);
|
||||
clapper_sink->widget = (GtkClapperGLWidget *)
|
||||
GST_CLAPPER_GL_SINK_GET_CLASS (clapper_sink)->create_widget ();
|
||||
|
||||
g_object_bind_property (clapper_sink, "force-aspect-ratio", clapper_sink->widget,
|
||||
"force-aspect-ratio", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
g_object_bind_property (clapper_sink, "pixel-aspect-ratio", clapper_sink->widget,
|
||||
"pixel-aspect-ratio", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
g_object_bind_property (clapper_sink, "keep-last-frame", clapper_sink->widget,
|
||||
"keep-last-frame", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
|
||||
/* Take the floating ref, other wise the destruction of the container will
|
||||
* make this widget disappear possibly before we are done. */
|
||||
gst_object_ref_sink (clapper_sink->widget);
|
||||
|
||||
clapper_sink->widget_destroy_id = g_signal_connect (clapper_sink->widget, "destroy",
|
||||
G_CALLBACK (widget_destroy_cb), clapper_sink);
|
||||
|
||||
/* back pointer */
|
||||
gtk_clapper_gl_widget_set_element (GTK_CLAPPER_GL_WIDGET (clapper_sink->widget),
|
||||
GST_ELEMENT (clapper_sink));
|
||||
|
||||
return clapper_sink->widget;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_gl_sink_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstClapperGLSink *clapper_sink = GST_CLAPPER_GL_SINK (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_WIDGET:
|
||||
{
|
||||
GObject *widget = NULL;
|
||||
|
||||
GST_OBJECT_LOCK (clapper_sink);
|
||||
if (clapper_sink->widget != NULL)
|
||||
widget = G_OBJECT (clapper_sink->widget);
|
||||
GST_OBJECT_UNLOCK (clapper_sink);
|
||||
|
||||
if (!widget)
|
||||
widget =
|
||||
gst_gtk_invoke_on_main ((GThreadFunc) gst_clapper_gl_sink_get_widget,
|
||||
clapper_sink);
|
||||
|
||||
g_value_set_object (value, widget);
|
||||
break;
|
||||
}
|
||||
case PROP_FORCE_ASPECT_RATIO:
|
||||
g_value_set_boolean (value, clapper_sink->force_aspect_ratio);
|
||||
break;
|
||||
case PROP_PIXEL_ASPECT_RATIO:
|
||||
gst_value_set_fraction (value, clapper_sink->par_n, clapper_sink->par_d);
|
||||
break;
|
||||
case PROP_KEEP_LAST_FRAME:
|
||||
g_value_set_boolean (value, clapper_sink->keep_last_frame);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_gl_sink_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstClapperGLSink *clapper_sink = GST_CLAPPER_GL_SINK (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_FORCE_ASPECT_RATIO:
|
||||
clapper_sink->force_aspect_ratio = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_PIXEL_ASPECT_RATIO:
|
||||
clapper_sink->par_n = gst_value_get_fraction_numerator (value);
|
||||
clapper_sink->par_d = gst_value_get_fraction_denominator (value);
|
||||
break;
|
||||
case PROP_KEEP_LAST_FRAME:
|
||||
clapper_sink->keep_last_frame = g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_gl_sink_navigation_send_event (GstNavigation * navigation,
|
||||
GstStructure * structure)
|
||||
{
|
||||
GstClapperGLSink *sink = GST_CLAPPER_GL_SINK (navigation);
|
||||
GstEvent *event;
|
||||
GstPad *pad;
|
||||
|
||||
event = gst_event_new_navigation (structure);
|
||||
pad = gst_pad_get_peer (GST_VIDEO_SINK_PAD (sink));
|
||||
|
||||
GST_TRACE_OBJECT (sink, "navigation event %" GST_PTR_FORMAT, structure);
|
||||
|
||||
if (GST_IS_PAD (pad) && GST_IS_EVENT (event)) {
|
||||
if (!gst_pad_send_event (pad, gst_event_ref (event))) {
|
||||
/* If upstream didn't handle the event we'll post a message with it
|
||||
* for the application in case it wants to do something with it */
|
||||
gst_element_post_message (GST_ELEMENT_CAST (sink),
|
||||
gst_navigation_message_new_event (GST_OBJECT_CAST (sink), event));
|
||||
}
|
||||
gst_event_unref (event);
|
||||
gst_object_unref (pad);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_gl_sink_navigation_interface_init (GstNavigationInterface * iface)
|
||||
{
|
||||
iface->send_event = gst_clapper_gl_sink_navigation_send_event;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_clapper_gl_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
|
||||
{
|
||||
GstClapperGLSink *clapper_sink = GST_CLAPPER_GL_SINK (bsink);
|
||||
GstBufferPool *pool = NULL;
|
||||
GstStructure *config;
|
||||
GstCaps *caps;
|
||||
GstVideoInfo info;
|
||||
guint size;
|
||||
gboolean need_pool;
|
||||
GstStructure *allocation_meta = NULL;
|
||||
gint display_width, display_height;
|
||||
|
||||
if (!clapper_sink->display || !clapper_sink->context)
|
||||
return FALSE;
|
||||
|
||||
gst_query_parse_allocation (query, &caps, &need_pool);
|
||||
|
||||
if (caps == NULL)
|
||||
goto no_caps;
|
||||
|
||||
if (!gst_video_info_from_caps (&info, caps))
|
||||
goto invalid_caps;
|
||||
|
||||
/* the normal size of a frame */
|
||||
size = info.size;
|
||||
|
||||
if (need_pool) {
|
||||
GST_DEBUG_OBJECT (clapper_sink, "create new pool");
|
||||
pool = gst_gl_buffer_pool_new (clapper_sink->context);
|
||||
|
||||
config = gst_buffer_pool_get_config (pool);
|
||||
gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
|
||||
gst_buffer_pool_config_add_option (config,
|
||||
GST_BUFFER_POOL_OPTION_GL_SYNC_META);
|
||||
|
||||
if (!gst_buffer_pool_set_config (pool, config)) {
|
||||
gst_object_unref (pool);
|
||||
goto config_failed;
|
||||
}
|
||||
}
|
||||
|
||||
/* we need at least 2 buffer because we hold on to the last one */
|
||||
gst_query_add_allocation_pool (query, pool, size, 2, 0);
|
||||
if (pool)
|
||||
gst_object_unref (pool);
|
||||
|
||||
GST_OBJECT_LOCK (clapper_sink);
|
||||
display_width = clapper_sink->display_width;
|
||||
display_height = clapper_sink->display_height;
|
||||
GST_OBJECT_UNLOCK (clapper_sink);
|
||||
|
||||
if (display_width != 0 && display_height != 0) {
|
||||
GST_DEBUG_OBJECT (clapper_sink, "sending alloc query with size %dx%d",
|
||||
display_width, display_height);
|
||||
allocation_meta = gst_structure_new ("GstVideoOverlayCompositionMeta",
|
||||
"width", G_TYPE_UINT, display_width,
|
||||
"height", G_TYPE_UINT, display_height, NULL);
|
||||
}
|
||||
|
||||
gst_query_add_allocation_meta (query,
|
||||
GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, allocation_meta);
|
||||
|
||||
if (allocation_meta)
|
||||
gst_structure_free (allocation_meta);
|
||||
|
||||
/* we also support various metadata */
|
||||
gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, 0);
|
||||
|
||||
if (clapper_sink->context->gl_vtable->FenceSync)
|
||||
gst_query_add_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, 0);
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
no_caps:
|
||||
{
|
||||
GST_DEBUG_OBJECT (bsink, "no caps specified");
|
||||
return FALSE;
|
||||
}
|
||||
invalid_caps:
|
||||
{
|
||||
GST_DEBUG_OBJECT (bsink, "invalid caps specified");
|
||||
return FALSE;
|
||||
}
|
||||
config_failed:
|
||||
{
|
||||
GST_DEBUG_OBJECT (bsink, "failed setting config");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_clapper_gl_sink_query (GstBaseSink * bsink, GstQuery * query)
|
||||
{
|
||||
GstClapperGLSink *clapper_sink = GST_CLAPPER_GL_SINK (bsink);
|
||||
gboolean res = FALSE;
|
||||
|
||||
switch (GST_QUERY_TYPE (query)) {
|
||||
case GST_QUERY_CONTEXT:
|
||||
res = gst_gl_handle_context_query ((GstElement *) clapper_sink, query,
|
||||
clapper_sink->display, clapper_sink->context, clapper_sink->gtk_context);
|
||||
break;
|
||||
default:
|
||||
res = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query);
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_clapper_gl_sink_start_on_main (GstBaseSink * bsink)
|
||||
{
|
||||
GstClapperGLSink *gst_sink = GST_CLAPPER_GL_SINK (bsink);
|
||||
GstClapperGLSinkClass *klass = GST_CLAPPER_GL_SINK_GET_CLASS (bsink);
|
||||
GtkWidget *toplevel;
|
||||
GtkRoot *root;
|
||||
|
||||
if (gst_clapper_gl_sink_get_widget (gst_sink) == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* After this point, clapper_sink->widget will always be set */
|
||||
|
||||
root = gtk_widget_get_root (GTK_WIDGET (gst_sink->widget));
|
||||
if (!GTK_IS_ROOT (root)) {
|
||||
GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (gst_sink->widget));
|
||||
if (parent) {
|
||||
GtkWidget *temp_parent;
|
||||
while ((temp_parent = gtk_widget_get_parent (parent)))
|
||||
parent = temp_parent;
|
||||
}
|
||||
toplevel = (parent) ? parent : GTK_WIDGET (gst_sink->widget);
|
||||
|
||||
/* sanity check */
|
||||
g_assert (klass->window_title);
|
||||
|
||||
/* User did not add widget its own UI, let's popup a new GtkWindow to
|
||||
* make gst-launch-1.0 work. */
|
||||
gst_sink->window = gtk_window_new ();
|
||||
gtk_window_set_default_size (GTK_WINDOW (gst_sink->window), 640, 480);
|
||||
gtk_window_set_title (GTK_WINDOW (gst_sink->window), klass->window_title);
|
||||
gtk_window_set_child (GTK_WINDOW (gst_sink->window), toplevel);
|
||||
|
||||
gst_sink->window_destroy_id = g_signal_connect (
|
||||
GTK_WINDOW (gst_sink->window),
|
||||
"destroy", G_CALLBACK (window_destroy_cb), gst_sink);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_clapper_gl_sink_start (GstBaseSink * bsink)
|
||||
{
|
||||
GstClapperGLSink *clapper_sink = GST_CLAPPER_GL_SINK (bsink);
|
||||
GtkClapperGLWidget *clapper_widget;
|
||||
|
||||
if (!(! !gst_gtk_invoke_on_main ((GThreadFunc) (GCallback)
|
||||
gst_clapper_gl_sink_start_on_main, bsink)))
|
||||
return FALSE;
|
||||
|
||||
/* After this point, clapper_sink->widget will always be set */
|
||||
clapper_widget = GTK_CLAPPER_GL_WIDGET (clapper_sink->widget);
|
||||
|
||||
if (!gtk_clapper_gl_widget_init_winsys (clapper_widget)) {
|
||||
GST_ELEMENT_ERROR (bsink, RESOURCE, NOT_FOUND, ("%s",
|
||||
"Failed to initialize OpenGL with GTK"), (NULL));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!clapper_sink->display)
|
||||
clapper_sink->display = gtk_clapper_gl_widget_get_display (clapper_widget);
|
||||
if (!clapper_sink->context)
|
||||
clapper_sink->context = gtk_clapper_gl_widget_get_context (clapper_widget);
|
||||
if (!clapper_sink->gtk_context)
|
||||
clapper_sink->gtk_context = gtk_clapper_gl_widget_get_gtk_context (clapper_widget);
|
||||
|
||||
if (!clapper_sink->display || !clapper_sink->context || !clapper_sink->gtk_context) {
|
||||
GST_ELEMENT_ERROR (bsink, RESOURCE, NOT_FOUND, ("%s",
|
||||
"Failed to retrieve OpenGL context from GTK"), (NULL));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gst_gl_element_propagate_display_context (GST_ELEMENT (bsink),
|
||||
clapper_sink->display);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_clapper_gl_sink_stop_on_main (GstBaseSink * bsink)
|
||||
{
|
||||
GstClapperGLSink *gst_sink = GST_CLAPPER_GL_SINK (bsink);
|
||||
|
||||
if (gst_sink->window) {
|
||||
gtk_window_destroy (GTK_WINDOW (gst_sink->window));
|
||||
gst_sink->window = NULL;
|
||||
gst_sink->widget = NULL;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_clapper_gl_sink_stop (GstBaseSink * bsink)
|
||||
{
|
||||
GstClapperGLSink *clapper_sink = GST_CLAPPER_GL_SINK (bsink);
|
||||
|
||||
if (clapper_sink->display) {
|
||||
gst_object_unref (clapper_sink->display);
|
||||
clapper_sink->display = NULL;
|
||||
}
|
||||
if (clapper_sink->context) {
|
||||
gst_object_unref (clapper_sink->context);
|
||||
clapper_sink->context = NULL;
|
||||
}
|
||||
if (clapper_sink->gtk_context) {
|
||||
gst_object_unref (clapper_sink->gtk_context);
|
||||
clapper_sink->gtk_context = NULL;
|
||||
}
|
||||
if (clapper_sink->window)
|
||||
return ! !gst_gtk_invoke_on_main ((GThreadFunc) (GCallback)
|
||||
gst_clapper_gl_sink_stop_on_main, bsink);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_gtk_window_show_all_and_unref (GtkWidget * window)
|
||||
{
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
g_object_unref (window);
|
||||
}
|
||||
|
||||
static GstStateChangeReturn
|
||||
gst_clapper_gl_sink_change_state (GstElement * element, GstStateChange transition)
|
||||
{
|
||||
GstClapperGLSink *clapper_sink = GST_CLAPPER_GL_SINK (element);
|
||||
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
|
||||
|
||||
GST_DEBUG_OBJECT (element, "changing state: %s => %s",
|
||||
gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
|
||||
gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
|
||||
|
||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
||||
if (ret == GST_STATE_CHANGE_FAILURE)
|
||||
return ret;
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
||||
GST_OBJECT_LOCK (clapper_sink);
|
||||
clapper_sink->had_eos = FALSE;
|
||||
if (clapper_sink->widget) {
|
||||
GTK_CLAPPER_GL_WIDGET_LOCK (clapper_sink->widget);
|
||||
clapper_sink->widget->ignore_buffers = FALSE;
|
||||
GTK_CLAPPER_GL_WIDGET_UNLOCK (clapper_sink->widget);
|
||||
}
|
||||
GST_OBJECT_UNLOCK (clapper_sink);
|
||||
break;
|
||||
case GST_STATE_CHANGE_READY_TO_PAUSED:{
|
||||
GtkWindow *window = NULL;
|
||||
|
||||
GST_OBJECT_LOCK (clapper_sink);
|
||||
if (clapper_sink->window)
|
||||
window = g_object_ref (GTK_WINDOW (clapper_sink->window));
|
||||
GST_OBJECT_UNLOCK (clapper_sink);
|
||||
|
||||
if (window) {
|
||||
gst_gtk_invoke_on_main ((GThreadFunc) (GCallback)
|
||||
gst_gtk_window_show_all_and_unref, window);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||
GST_OBJECT_LOCK (clapper_sink);
|
||||
if (clapper_sink->widget) {
|
||||
GTK_CLAPPER_GL_WIDGET_LOCK (clapper_sink->widget);
|
||||
clapper_sink->widget->ignore_buffers =
|
||||
!clapper_sink->had_eos || !clapper_sink->keep_last_frame;
|
||||
GTK_CLAPPER_GL_WIDGET_UNLOCK (clapper_sink->widget);
|
||||
}
|
||||
GST_OBJECT_UNLOCK (clapper_sink);
|
||||
/* Fall through to render black bg */
|
||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||
GST_OBJECT_LOCK (clapper_sink);
|
||||
if (clapper_sink->widget)
|
||||
gtk_clapper_gl_widget_set_buffer (clapper_sink->widget, NULL);
|
||||
GST_OBJECT_UNLOCK (clapper_sink);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_gl_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
|
||||
GstClockTime * start, GstClockTime * end)
|
||||
{
|
||||
GstClapperGLSink *clapper_sink = GST_CLAPPER_GL_SINK (bsink);
|
||||
|
||||
if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
|
||||
*start = GST_BUFFER_TIMESTAMP (buf);
|
||||
if (GST_BUFFER_DURATION_IS_VALID (buf))
|
||||
*end = *start + GST_BUFFER_DURATION (buf);
|
||||
else {
|
||||
if (GST_VIDEO_INFO_FPS_N (&clapper_sink->v_info) > 0) {
|
||||
*end = *start +
|
||||
gst_util_uint64_scale_int (GST_SECOND,
|
||||
GST_VIDEO_INFO_FPS_D (&clapper_sink->v_info),
|
||||
GST_VIDEO_INFO_FPS_N (&clapper_sink->v_info));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
gst_clapper_gl_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
|
||||
{
|
||||
GstCaps *tmp = NULL;
|
||||
GstCaps *result = NULL;
|
||||
|
||||
tmp = gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink));
|
||||
|
||||
if (filter) {
|
||||
GST_DEBUG_OBJECT (bsink, "intersecting with filter caps %" GST_PTR_FORMAT,
|
||||
filter);
|
||||
|
||||
result = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
|
||||
gst_caps_unref (tmp);
|
||||
} else {
|
||||
result = tmp;
|
||||
}
|
||||
|
||||
result = gst_gl_overlay_compositor_add_caps (result);
|
||||
|
||||
GST_DEBUG_OBJECT (bsink, "returning caps: %" GST_PTR_FORMAT, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_clapper_gl_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
||||
{
|
||||
GstClapperGLSink *clapper_sink = GST_CLAPPER_GL_SINK (bsink);
|
||||
gboolean res = FALSE;
|
||||
|
||||
GST_DEBUG ("set caps with %" GST_PTR_FORMAT, caps);
|
||||
|
||||
if (!gst_video_info_from_caps (&clapper_sink->v_info, caps))
|
||||
return FALSE;
|
||||
|
||||
GST_OBJECT_LOCK (clapper_sink);
|
||||
|
||||
if (clapper_sink->widget == NULL) {
|
||||
GST_OBJECT_UNLOCK (clapper_sink);
|
||||
GST_ELEMENT_ERROR (clapper_sink, RESOURCE, NOT_FOUND,
|
||||
("%s", "Output widget was destroyed"), (NULL));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!gtk_clapper_gl_widget_set_format (clapper_sink->widget, &clapper_sink->v_info)) {
|
||||
GST_OBJECT_UNLOCK (clapper_sink);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
res = gtk_clapper_gl_widget_update_output_format (clapper_sink->widget, caps);
|
||||
GST_OBJECT_UNLOCK (clapper_sink);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_clapper_gl_sink_wait_event (GstBaseSink * bsink, GstEvent * event)
|
||||
{
|
||||
GstClapperGLSink *clapper_sink = GST_CLAPPER_GL_SINK (bsink);
|
||||
GstFlowReturn ret;
|
||||
|
||||
ret = GST_BASE_SINK_CLASS (parent_class)->wait_event (bsink, event);
|
||||
|
||||
switch (event->type) {
|
||||
case GST_EVENT_EOS:
|
||||
if (ret == GST_FLOW_OK) {
|
||||
GST_OBJECT_LOCK (clapper_sink);
|
||||
clapper_sink->had_eos = TRUE;
|
||||
GST_OBJECT_UNLOCK (clapper_sink);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_clapper_gl_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
|
||||
{
|
||||
GstClapperGLSink *clapper_sink;
|
||||
|
||||
GST_TRACE ("rendering buffer:%p", buf);
|
||||
|
||||
clapper_sink = GST_CLAPPER_GL_SINK (vsink);
|
||||
|
||||
GST_OBJECT_LOCK (clapper_sink);
|
||||
|
||||
if (clapper_sink->widget == NULL) {
|
||||
GST_OBJECT_UNLOCK (clapper_sink);
|
||||
GST_ELEMENT_ERROR (clapper_sink, RESOURCE, NOT_FOUND,
|
||||
("%s", "Output widget was destroyed"), (NULL));
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
gtk_clapper_gl_widget_set_buffer (clapper_sink->widget, buf);
|
||||
|
||||
GST_OBJECT_UNLOCK (clapper_sink);
|
||||
|
||||
return GST_FLOW_OK;
|
||||
}
|
105
lib/gst/clapper/gtk4/gstclapperglsink.h
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
* Copyright (C) 2020 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_CLAPPER_GL_SINK_H__
|
||||
#define __GST_CLAPPER_GL_SINK_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gst/gst.h>
|
||||
#include <gst/video/gstvideosink.h>
|
||||
#include <gst/video/video.h>
|
||||
#include <gst/gl/gl.h>
|
||||
|
||||
#include "gtkclapperglwidget.h"
|
||||
|
||||
#define GST_TYPE_CLAPPER_GL_SINK (gst_clapper_gl_sink_get_type())
|
||||
#define GST_CLAPPER_GL_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CLAPPER_GL_SINK,GstClapperGLSink))
|
||||
#define GST_CLAPPER_GL_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CLAPPER_GL_SINK,GstClapperGLClass))
|
||||
#define GST_CLAPPER_GL_SINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CLAPPER_GL_SINK, GstClapperGLSinkClass))
|
||||
#define GST_IS_CLAPPER_GL_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CLAPPER_GL_SINK))
|
||||
#define GST_IS_CLAPPER_GL_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CLAPPER_GL_SINK))
|
||||
#define GST_CLAPPER_GL_SINK_CAST(obj) ((GstClapperGLSink*)(obj))
|
||||
|
||||
G_BEGIN_DECLS
|
||||
typedef struct _GstClapperGLSink GstClapperGLSink;
|
||||
typedef struct _GstClapperGLSinkClass GstClapperGLSinkClass;
|
||||
|
||||
GType gst_clapper_gl_sink_get_type (void);
|
||||
|
||||
/**
|
||||
* GstClapperGLSink:
|
||||
*
|
||||
* Opaque #GstClapperGLSink object
|
||||
*/
|
||||
struct _GstClapperGLSink
|
||||
{
|
||||
/* <private> */
|
||||
GstVideoSink parent;
|
||||
|
||||
GstVideoInfo v_info;
|
||||
|
||||
GtkClapperGLWidget *widget;
|
||||
|
||||
gboolean had_eos;
|
||||
|
||||
/* properties */
|
||||
gboolean force_aspect_ratio;
|
||||
gint par_n, par_d;
|
||||
gboolean keep_last_frame;
|
||||
|
||||
gboolean ignore_textures;
|
||||
|
||||
GtkWidget *window;
|
||||
gulong widget_destroy_id;
|
||||
gulong window_destroy_id;
|
||||
|
||||
GstGLDisplay *display;
|
||||
GstGLContext *context;
|
||||
GstGLContext *gtk_context;
|
||||
|
||||
GstGLUpload *upload;
|
||||
GstBuffer *uploaded_buffer;
|
||||
|
||||
/* read/write with object lock */
|
||||
gint display_width, display_height;
|
||||
};
|
||||
|
||||
/**
|
||||
* GstClapperGLSinkClass:
|
||||
*
|
||||
* The #GstClapperGLSinkClass struct only contains private data
|
||||
*/
|
||||
struct _GstClapperGLSinkClass
|
||||
{
|
||||
GstVideoSinkClass object_class;
|
||||
|
||||
/* metadata */
|
||||
const gchar *window_title;
|
||||
|
||||
/* virtuals */
|
||||
GtkWidget* (*create_widget) (void);
|
||||
};
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GstClapperGLSink, gst_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_CLAPPER_GL_SINK_H__ */
|
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__ */
|
95
lib/gst/clapper/gtk4/gstgtkutils.c
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
* Copyright (C) 2015 Thibault Saunier <tsaunier@gnome.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include "gstgtkutils.h"
|
||||
|
||||
struct invoke_context
|
||||
{
|
||||
GThreadFunc func;
|
||||
gpointer data;
|
||||
GMutex lock;
|
||||
GCond cond;
|
||||
gboolean fired;
|
||||
|
||||
gpointer res;
|
||||
};
|
||||
|
||||
static gboolean
|
||||
gst_gtk_invoke_func (struct invoke_context *info)
|
||||
{
|
||||
g_mutex_lock (&info->lock);
|
||||
info->res = info->func (info->data);
|
||||
info->fired = TRUE;
|
||||
g_cond_signal (&info->cond);
|
||||
g_mutex_unlock (&info->lock);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
gpointer
|
||||
gst_gtk_invoke_on_main (GThreadFunc func, gpointer data)
|
||||
{
|
||||
GMainContext *main_context = g_main_context_default ();
|
||||
struct invoke_context info;
|
||||
|
||||
g_mutex_init (&info.lock);
|
||||
g_cond_init (&info.cond);
|
||||
info.fired = FALSE;
|
||||
info.func = func;
|
||||
info.data = data;
|
||||
|
||||
g_main_context_invoke (main_context, (GSourceFunc) gst_gtk_invoke_func,
|
||||
&info);
|
||||
|
||||
g_mutex_lock (&info.lock);
|
||||
while (!info.fired)
|
||||
g_cond_wait (&info.cond, &info.lock);
|
||||
g_mutex_unlock (&info.lock);
|
||||
|
||||
g_mutex_clear (&info.lock);
|
||||
g_cond_clear (&info.cond);
|
||||
|
||||
return info.res;
|
||||
}
|
||||
|
||||
void
|
||||
gst_gtk_install_shared_properties (GObjectClass *gobject_class)
|
||||
{
|
||||
g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
|
||||
g_param_spec_boolean ("force-aspect-ratio",
|
||||
"Force aspect ratio",
|
||||
"When enabled, scaling will respect original aspect ratio",
|
||||
DEFAULT_FORCE_ASPECT_RATIO,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
|
||||
gst_param_spec_fraction ("pixel-aspect-ratio", "Pixel Aspect Ratio",
|
||||
"The pixel aspect ratio of the device", DEFAULT_PAR_N, DEFAULT_PAR_D,
|
||||
G_MAXINT, 1, 1, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_KEEP_LAST_FRAME,
|
||||
g_param_spec_boolean ("keep-last-frame",
|
||||
"Keep last frame",
|
||||
"Keep showing last video frame after playback instead of black screen",
|
||||
DEFAULT_KEEP_LAST_FRAME,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
}
|
46
lib/gst/clapper/gtk4/gstgtkutils.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
* Copyright (C) 2015 Thibault Saunier <tsaunier@gnome.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_GTK_UTILS_H__
|
||||
#define __GST_GTK_UTILS_H__
|
||||
|
||||
#define DEFAULT_FORCE_ASPECT_RATIO TRUE
|
||||
#define DEFAULT_PAR_N 0
|
||||
#define DEFAULT_PAR_D 1
|
||||
#define DEFAULT_KEEP_LAST_FRAME FALSE
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_WIDGET,
|
||||
PROP_FORCE_ASPECT_RATIO,
|
||||
PROP_PIXEL_ASPECT_RATIO,
|
||||
PROP_KEEP_LAST_FRAME
|
||||
};
|
||||
|
||||
gpointer gst_gtk_invoke_on_main (GThreadFunc func, gpointer data);
|
||||
|
||||
void gst_gtk_install_shared_properties (GObjectClass *gobject_class);
|
||||
|
||||
#endif /* __GST_GTK_UTILS_H__ */
|
1248
lib/gst/clapper/gtk4/gtkclapperglwidget.c
Normal file
113
lib/gst/clapper/gtk4/gtkclapperglwidget.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
* Copyright (C) 2020 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GTK_CLAPPER_GL_WIDGET_H__
|
||||
#define __GTK_CLAPPER_GL_WIDGET_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gst/gst.h>
|
||||
#include <gst/video/video.h>
|
||||
#include <gst/gl/gl.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GType gtk_clapper_gl_widget_get_type (void);
|
||||
#define GTK_TYPE_CLAPPER_GL_WIDGET (gtk_clapper_gl_widget_get_type())
|
||||
#define GTK_CLAPPER_GL_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GTK_TYPE_CLAPPER_GL_WIDGET,GtkClapperGLWidget))
|
||||
#define GTK_CLAPPER_GL_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GTK_TYPE_CLAPPER_GL_WIDGET,GtkClapperGLWidgetClass))
|
||||
#define GTK_IS_CLAPPER_GL_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GTK_TYPE_CLAPPER_GL_WIDGET))
|
||||
#define GTK_IS_CLAPPER_GL_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GTK_TYPE_CLAPPER_GL_WIDGET))
|
||||
#define GTK_CLAPPER_GL_WIDGET_CAST(obj) ((GtkClapperGLWidget*)(obj))
|
||||
#define GTK_CLAPPER_GL_WIDGET_LOCK(w) g_mutex_lock(&((GtkClapperGLWidget*)(w))->lock)
|
||||
#define GTK_CLAPPER_GL_WIDGET_UNLOCK(w) g_mutex_unlock(&((GtkClapperGLWidget*)(w))->lock)
|
||||
|
||||
typedef struct _GtkClapperGLWidget GtkClapperGLWidget;
|
||||
typedef struct _GtkClapperGLWidgetClass GtkClapperGLWidgetClass;
|
||||
typedef struct _GtkClapperGLWidgetPrivate GtkClapperGLWidgetPrivate;
|
||||
|
||||
struct _GtkClapperGLWidget
|
||||
{
|
||||
/* <private> */
|
||||
GtkGLArea parent;
|
||||
GtkClapperGLWidgetPrivate *priv;
|
||||
|
||||
/* properties */
|
||||
gboolean force_aspect_ratio;
|
||||
gint par_n, par_d;
|
||||
gboolean keep_last_frame;
|
||||
|
||||
gint display_width;
|
||||
gint display_height;
|
||||
|
||||
/* Widget dimensions */
|
||||
gint scaled_width;
|
||||
gint scaled_height;
|
||||
|
||||
/* Position coords */
|
||||
gdouble last_pos_x;
|
||||
gdouble last_pos_y;
|
||||
|
||||
gboolean negotiated;
|
||||
gboolean ignore_buffers;
|
||||
GstBuffer *pending_buffer;
|
||||
GstBuffer *buffer;
|
||||
GstVideoInfo v_info;
|
||||
|
||||
/* resize */
|
||||
gboolean pending_resize;
|
||||
GstVideoInfo pending_v_info;
|
||||
guint display_ratio_num;
|
||||
guint display_ratio_den;
|
||||
|
||||
/*< private >*/
|
||||
GMutex lock;
|
||||
GWeakRef element;
|
||||
|
||||
/* event controllers */
|
||||
GtkEventController *key_controller;
|
||||
GtkEventController *motion_controller;
|
||||
GtkGesture *click_gesture;
|
||||
|
||||
/* Pending draw idles callback */
|
||||
guint draw_id;
|
||||
};
|
||||
|
||||
struct _GtkClapperGLWidgetClass
|
||||
{
|
||||
GtkGLAreaClass parent_class;
|
||||
};
|
||||
|
||||
/* API */
|
||||
gboolean gtk_clapper_gl_widget_set_format (GtkClapperGLWidget * widget, GstVideoInfo * v_info);
|
||||
void gtk_clapper_gl_widget_set_buffer (GtkClapperGLWidget * widget, GstBuffer * buffer);
|
||||
void gtk_clapper_gl_widget_set_element (GtkClapperGLWidget * widget, GstElement * element);
|
||||
|
||||
GtkWidget * gtk_clapper_gl_widget_new (void);
|
||||
|
||||
gboolean gtk_clapper_gl_widget_init_winsys (GtkClapperGLWidget * widget);
|
||||
GstGLDisplay * gtk_clapper_gl_widget_get_display (GtkClapperGLWidget * widget);
|
||||
GstGLContext * gtk_clapper_gl_widget_get_context (GtkClapperGLWidget * widget);
|
||||
GstGLContext * gtk_clapper_gl_widget_get_gtk_context (GtkClapperGLWidget * widget);
|
||||
gboolean gtk_clapper_gl_widget_update_output_format (GtkClapperGLWidget * widget, GstCaps * caps);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_CLAPPER_GL_WIDGET_H__ */
|
106
lib/gst/clapper/meson.build
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
gstclapper_sources = [
|
||||
'gstclapper.c',
|
||||
'gstclapper-signal-dispatcher.c',
|
||||
'gstclapper-video-renderer.c',
|
||||
'gstclapper-media-info.c',
|
||||
'gstclapper-g-main-context-signal-dispatcher.c',
|
||||
'gstclapper-video-overlay-video-renderer.c',
|
||||
'gstclapper-visualization.c',
|
||||
'gstclapper-mpris.c',
|
||||
'gstclapper-gtk4-plugin.c',
|
||||
|
||||
'gtk4/gstclapperglsink.c',
|
||||
'gtk4/gstgtkutils.c',
|
||||
'gtk4/gtkclapperglwidget.c',
|
||||
'gtk4/gstclapperglutils.c',
|
||||
]
|
||||
gstclapper_headers = [
|
||||
'clapper.h',
|
||||
'clapper-prelude.h',
|
||||
'gstclapper.h',
|
||||
'gstclapper-types.h',
|
||||
'gstclapper-signal-dispatcher.h',
|
||||
'gstclapper-video-renderer.h',
|
||||
'gstclapper-media-info.h',
|
||||
'gstclapper-g-main-context-signal-dispatcher.h',
|
||||
'gstclapper-video-overlay-video-renderer.h',
|
||||
'gstclapper-visualization.h',
|
||||
'gstclapper-mpris.h',
|
||||
'gstclapper-gtk4-plugin.h',
|
||||
]
|
||||
gstclapper_defines = [
|
||||
'-DHAVE_CONFIG_H',
|
||||
'-DBUILDING_GST_CLAPPER',
|
||||
'-DGST_USE_UNSTABLE_API',
|
||||
'-DHAVE_GTK_GL',
|
||||
]
|
||||
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
|
||||
|
||||
if not have_gtk_gl_windowing
|
||||
error('GTK4 widget requires GL windowing')
|
||||
endif
|
||||
|
||||
gstclapper_mpris_gdbus = gnome.gdbus_codegen('gstclapper-mpris-gdbus',
|
||||
sources: '../../../data/gstclapper-mpris-gdbus.xml',
|
||||
interface_prefix: 'org.mpris.',
|
||||
namespace: 'GstClapperMpris'
|
||||
)
|
||||
|
||||
gstclapper = library('gstclapper-' + api_version,
|
||||
gstclapper_sources + gstclapper_mpris_gdbus,
|
||||
c_args: gstclapper_defines,
|
||||
link_args: noseh_link_args,
|
||||
include_directories: [configinc, libsinc],
|
||||
version: libversion,
|
||||
install: true,
|
||||
install_dir: pkglibdir,
|
||||
dependencies: [gtk4_dep, glib_dep, gio_dep, giounix_dep,
|
||||
gstbase_dep, gstvideo_dep, gstaudio_dep,
|
||||
gsttag_dep, gstpbutils_dep, libm] + gtk_deps,
|
||||
)
|
||||
|
||||
clapper_gir = gnome.generate_gir(gstclapper,
|
||||
sources: gstclapper_sources + gstclapper_headers,
|
||||
namespace: 'GstClapper',
|
||||
nsversion: api_version,
|
||||
identifier_prefix: 'Gst',
|
||||
symbol_prefix: 'gst',
|
||||
export_packages: 'gstreamer-clapper-1.0',
|
||||
includes: ['Gst-1.0', 'GstPbutils-1.0', 'GstBase-1.0', 'GstVideo-1.0',
|
||||
'GstAudio-1.0', 'GstTag-1.0'],
|
||||
install: true,
|
||||
install_dir_typelib: join_paths(pkglibdir, 'girepository-1.0'),
|
||||
extra_args: gir_init_section + ['-DGST_USE_UNSTABLE_API'],
|
||||
dependencies: [gstbase_dep, gstvideo_dep, gstaudio_dep,
|
||||
gsttag_dep, gstpbutils_dep]
|
||||
)
|
5
lib/gst/meson.build
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
if get_option('lib')
|
||||
subdir('clapper')
|
||||
endif
|
||||
|
||||
subdir('plugin')
|
@@ -12,8 +12,9 @@
|
||||
* 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, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
* 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
|
||||
@@ -88,14 +89,6 @@ _default_create_pool (GstClapperImporter *self, GstStructure **config)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
_default_add_allocation_metas (GstClapperImporter *importer, GstQuery *query)
|
||||
{
|
||||
/* Importer base class handles GstVideoOverlayCompositionMeta */
|
||||
gst_query_add_allocation_meta (query, GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, NULL);
|
||||
gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
|
||||
}
|
||||
|
||||
static GdkTexture *
|
||||
_default_generate_texture (GstClapperImporter *self,
|
||||
GstBuffer *buffer, GstVideoInfo *v_info)
|
||||
@@ -126,8 +119,6 @@ gst_clapper_importer_finalize (GObject *object)
|
||||
|
||||
GST_TRACE ("Finalize");
|
||||
|
||||
gst_clear_caps (&self->pending_caps);
|
||||
|
||||
gst_clear_buffer (&self->pending_buffer);
|
||||
gst_clear_buffer (&self->buffer);
|
||||
|
||||
@@ -151,7 +142,6 @@ gst_clapper_importer_class_init (GstClapperImporterClass *klass)
|
||||
gobject_class->finalize = gst_clapper_importer_finalize;
|
||||
|
||||
importer_class->create_pool = _default_create_pool;
|
||||
importer_class->add_allocation_metas = _default_add_allocation_metas;
|
||||
importer_class->generate_texture = _default_generate_texture;
|
||||
}
|
||||
|
||||
@@ -256,9 +246,6 @@ gst_clapper_importer_prepare_overlays_locked (GstClapperImporter *self)
|
||||
if ((v_meta = gst_buffer_get_video_meta (comp_buffer))) {
|
||||
gst_video_info_set_format (&v_info, v_meta->format, v_meta->width, v_meta->height);
|
||||
v_info.stride[0] = v_meta->stride[0];
|
||||
|
||||
if (alpha_flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA)
|
||||
v_info.flags |= GST_VIDEO_FLAG_PREMULTIPLIED_ALPHA;
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (!gst_video_frame_map (&comp_frame, &v_info, comp_buffer, GST_MAP_READ)))
|
||||
@@ -303,13 +290,37 @@ gst_clapper_importer_prepare_overlays_locked (GstClapperImporter *self)
|
||||
GST_LOG_OBJECT (self, "Prepared overlays: %u", self->pending_overlays->len);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_clapper_importer_prepare (GstClapperImporter *self)
|
||||
{
|
||||
GstClapperImporterClass *importer_class = GST_CLAPPER_IMPORTER_GET_CLASS (self);
|
||||
|
||||
if (importer_class->prepare) {
|
||||
if (!importer_class->prepare (self))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Importer prepared");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
gst_clapper_importer_share_data (GstClapperImporter *self, GstClapperImporter *dest)
|
||||
{
|
||||
GstClapperImporterClass *importer_class = GST_CLAPPER_IMPORTER_GET_CLASS (self);
|
||||
|
||||
if (importer_class->share_data)
|
||||
importer_class->share_data (self, dest);
|
||||
}
|
||||
|
||||
void
|
||||
gst_clapper_importer_set_caps (GstClapperImporter *self, GstCaps *caps)
|
||||
{
|
||||
GstClapperImporterClass *importer_class = GST_CLAPPER_IMPORTER_GET_CLASS (self);
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
gst_caps_replace (&self->pending_caps, caps);
|
||||
self->has_pending_v_info = gst_video_info_from_caps (&self->pending_v_info, caps);
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
if (importer_class->set_caps)
|
||||
@@ -319,14 +330,10 @@ gst_clapper_importer_set_caps (GstClapperImporter *self, GstCaps *caps)
|
||||
void
|
||||
gst_clapper_importer_set_buffer (GstClapperImporter *self, GstBuffer *buffer)
|
||||
{
|
||||
/* Both overlays and pending buffer must be
|
||||
* set within a single importer locking */
|
||||
GST_OBJECT_LOCK (self);
|
||||
|
||||
/* Pending v_info, buffer and overlays must be
|
||||
* set within a single importer locking */
|
||||
if (self->pending_caps) {
|
||||
self->has_pending_v_info = gst_video_info_from_caps (&self->pending_v_info, self->pending_caps);
|
||||
gst_clear_caps (&self->pending_caps);
|
||||
}
|
||||
gst_buffer_replace (&self->pending_buffer, buffer);
|
||||
gst_clapper_importer_prepare_overlays_locked (self);
|
||||
|
||||
@@ -346,12 +353,25 @@ gst_clapper_importer_add_allocation_metas (GstClapperImporter *self, GstQuery *q
|
||||
{
|
||||
GstClapperImporterClass *importer_class = GST_CLAPPER_IMPORTER_GET_CLASS (self);
|
||||
|
||||
importer_class->add_allocation_metas (self, query);
|
||||
if (importer_class->add_allocation_metas)
|
||||
importer_class->add_allocation_metas (self, query);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_clapper_importer_handle_context_query (GstClapperImporter *self,
|
||||
GstBaseSink *bsink, GstQuery *query)
|
||||
{
|
||||
GstClapperImporterClass *importer_class = GST_CLAPPER_IMPORTER_GET_CLASS (self);
|
||||
|
||||
if (!importer_class->handle_context_query)
|
||||
return FALSE;
|
||||
|
||||
return importer_class->handle_context_query (self, bsink, query);
|
||||
}
|
||||
|
||||
void
|
||||
gst_clapper_importer_snapshot (GstClapperImporter *self, GdkSnapshot *snapshot,
|
||||
gdouble width, gdouble height)
|
||||
gdouble width, gdouble height, gfloat scale_x, gfloat scale_y)
|
||||
{
|
||||
guint i;
|
||||
gboolean buffer_changed;
|
||||
@@ -360,13 +380,15 @@ gst_clapper_importer_snapshot (GstClapperImporter *self, GdkSnapshot *snapshot,
|
||||
* lock ourselves to make sure everything matches */
|
||||
GST_OBJECT_LOCK (self);
|
||||
|
||||
if (self->has_pending_v_info) {
|
||||
buffer_changed = gst_buffer_replace (&self->buffer, self->pending_buffer);
|
||||
|
||||
/* Only replace v_info when buffer changed, this way
|
||||
* we still use old (correct) v_info when resizing */
|
||||
if (buffer_changed && self->has_pending_v_info) {
|
||||
self->v_info = self->pending_v_info;
|
||||
self->has_pending_v_info = FALSE;
|
||||
}
|
||||
|
||||
buffer_changed = gst_buffer_replace (&self->buffer, self->pending_buffer);
|
||||
|
||||
/* Ref overlays associated with current buffer */
|
||||
for (i = 0; i < self->pending_overlays->len; i++) {
|
||||
GstClapperGdkOverlay *overlay = g_ptr_array_index (self->pending_overlays, i);
|
||||
@@ -395,21 +417,12 @@ gst_clapper_importer_snapshot (GstClapperImporter *self, GdkSnapshot *snapshot,
|
||||
if (G_LIKELY (self->texture)) {
|
||||
gtk_snapshot_append_texture (snapshot, self->texture, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
|
||||
if (self->overlays->len > 0) {
|
||||
gfloat scale_x, scale_y;
|
||||
for (i = 0; i < self->overlays->len; i++) {
|
||||
GstClapperGdkOverlay *overlay = g_ptr_array_index (self->overlays, i);
|
||||
|
||||
/* FIXME: GStreamer scales subtitles without considering pixel aspect ratio.
|
||||
* See: https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/issues/20 */
|
||||
scale_x = (gfloat) width / GST_VIDEO_INFO_WIDTH (&self->v_info);
|
||||
scale_y = (gfloat) height / GST_VIDEO_INFO_HEIGHT (&self->v_info);
|
||||
|
||||
for (i = 0; i < self->overlays->len; i++) {
|
||||
GstClapperGdkOverlay *overlay = g_ptr_array_index (self->overlays, i);
|
||||
|
||||
gtk_snapshot_append_texture (snapshot, overlay->texture,
|
||||
&GRAPHENE_RECT_INIT (overlay->x * scale_x, overlay->y * scale_y,
|
||||
overlay->width * scale_x, overlay->height * scale_y));
|
||||
}
|
||||
gtk_snapshot_append_texture (snapshot, overlay->texture,
|
||||
&GRAPHENE_RECT_INIT (overlay->x * scale_x, overlay->y * scale_y,
|
||||
overlay->width * scale_x, overlay->height * scale_y));
|
||||
}
|
||||
} else {
|
||||
GST_ERROR_OBJECT (self, "Failed import of %" GST_PTR_FORMAT, self->buffer);
|
@@ -12,8 +12,9 @@
|
||||
* 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, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
* 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
|
||||
@@ -22,8 +23,6 @@
|
||||
#include <gst/gst.h>
|
||||
#include <gst/video/video.h>
|
||||
|
||||
#include "gst/plugin/clapper-gst-visibility.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_CLAPPER_IMPORTER (gst_clapper_importer_get_type())
|
||||
@@ -34,11 +33,10 @@ G_BEGIN_DECLS
|
||||
#define GST_CLAPPER_IMPORTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_CLAPPER_IMPORTER, GstClapperImporterClass))
|
||||
#define GST_CLAPPER_IMPORTER_CAST(obj) ((GstClapperImporter *)(obj))
|
||||
|
||||
#define GST_CLAPPER_IMPORTER_DEFINE(camel,lower,type) \
|
||||
G_DEFINE_TYPE (camel, lower, type) \
|
||||
G_MODULE_EXPORT GstClapperImporter *make_importer (GPtrArray *context_handlers); \
|
||||
G_MODULE_EXPORT GstCaps *make_caps (gboolean is_template, \
|
||||
GstRank *rank, GPtrArray *context_handlers);
|
||||
#define GST_CLAPPER_IMPORTER_DEFINE(camel,lower,type) \
|
||||
G_DEFINE_TYPE (camel, lower, type) \
|
||||
G_MODULE_EXPORT GstClapperImporter *make_importer (void); \
|
||||
G_MODULE_EXPORT GstCaps *make_caps (GstRank *rank, GStrv *context_types);
|
||||
|
||||
typedef struct _GstClapperImporter GstClapperImporter;
|
||||
typedef struct _GstClapperImporterClass GstClapperImporterClass;
|
||||
@@ -51,7 +49,6 @@ struct _GstClapperImporter
|
||||
{
|
||||
GstObject parent;
|
||||
|
||||
GstCaps *pending_caps;
|
||||
GstBuffer *pending_buffer, *buffer;
|
||||
GPtrArray *pending_overlays, *overlays;
|
||||
GstVideoInfo pending_v_info, v_info;
|
||||
@@ -66,9 +63,18 @@ struct _GstClapperImporterClass
|
||||
{
|
||||
GstObjectClass parent_class;
|
||||
|
||||
gboolean (* prepare) (GstClapperImporter *importer);
|
||||
|
||||
void (* share_data) (GstClapperImporter *src,
|
||||
GstClapperImporter *dest);
|
||||
|
||||
void (* set_caps) (GstClapperImporter *importer,
|
||||
GstCaps *caps);
|
||||
|
||||
gboolean (* handle_context_query) (GstClapperImporter *importer,
|
||||
GstBaseSink *bsink,
|
||||
GstQuery *query);
|
||||
|
||||
GstBufferPool * (* create_pool) (GstClapperImporter *importer,
|
||||
GstStructure **config);
|
||||
|
||||
@@ -80,15 +86,17 @@ struct _GstClapperImporterClass
|
||||
GstVideoInfo *v_info);
|
||||
};
|
||||
|
||||
CLAPPER_GST_API
|
||||
GType gst_clapper_importer_get_type (void);
|
||||
|
||||
gboolean gst_clapper_importer_prepare (GstClapperImporter *importer);
|
||||
void gst_clapper_importer_share_data (GstClapperImporter *importer, GstClapperImporter *dest);
|
||||
gboolean gst_clapper_importer_handle_context_query (GstClapperImporter *importer, GstBaseSink *bsink, GstQuery *query);
|
||||
GstBufferPool * gst_clapper_importer_create_pool (GstClapperImporter *importer, GstStructure **config);
|
||||
void gst_clapper_importer_add_allocation_metas (GstClapperImporter *importer, GstQuery *query);
|
||||
|
||||
void gst_clapper_importer_set_caps (GstClapperImporter *importer, GstCaps *caps);
|
||||
void gst_clapper_importer_set_buffer (GstClapperImporter *importer, GstBuffer *buffer);
|
||||
|
||||
void gst_clapper_importer_snapshot (GstClapperImporter *importer, GdkSnapshot *snapshot, gdouble width, gdouble height);
|
||||
void gst_clapper_importer_snapshot (GstClapperImporter *importer, GdkSnapshot *snapshot, gdouble width, gdouble height, gfloat scale_x, gfloat scale_y);
|
||||
|
||||
G_END_DECLS
|
417
lib/gst/plugin/gstclapperimporterloader.c
vendored
Normal file
@@ -0,0 +1,417 @@
|
||||
/*
|
||||
* 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 <gmodule.h>
|
||||
|
||||
#include "gstclapperimporterloader.h"
|
||||
#include "gstclapperimporter.h"
|
||||
|
||||
#define GST_CAT_DEFAULT gst_clapper_importer_loader_debug
|
||||
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
||||
|
||||
typedef GstClapperImporter* (* MakeImporter) (void);
|
||||
typedef GstCaps* (* MakeCaps) (GstRank *rank, GStrv *context_types);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gchar *module_path;
|
||||
GModule *open_module;
|
||||
GstCaps *caps;
|
||||
GstRank rank;
|
||||
GStrv context_types;
|
||||
} GstClapperImporterData;
|
||||
|
||||
static void
|
||||
gst_clapper_importer_data_free (GstClapperImporterData *data)
|
||||
{
|
||||
g_free (data->module_path);
|
||||
|
||||
if (data->open_module)
|
||||
g_module_close (data->open_module);
|
||||
|
||||
gst_clear_caps (&data->caps);
|
||||
g_strfreev (data->context_types);
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_open_importer (GstClapperImporterData *data)
|
||||
{
|
||||
g_return_val_if_fail (data && data->module_path, FALSE);
|
||||
|
||||
/* Already open */
|
||||
if (data->open_module)
|
||||
return TRUE;
|
||||
|
||||
GST_DEBUG ("Opening module: %s", data->module_path);
|
||||
data->open_module = g_module_open (data->module_path, G_MODULE_BIND_LAZY);
|
||||
|
||||
if (!data->open_module) {
|
||||
GST_WARNING ("Could not load importer: %s, reason: %s",
|
||||
data->module_path, g_module_error ());
|
||||
return FALSE;
|
||||
}
|
||||
GST_DEBUG ("Opened importer module");
|
||||
|
||||
/* Make sure module stays loaded. Seems to be needed for
|
||||
* reusing exported symbols from the same module again */
|
||||
g_module_make_resident (data->open_module);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_close_importer (GstClapperImporterData *data)
|
||||
{
|
||||
if (!data || !data->open_module)
|
||||
return;
|
||||
|
||||
if (G_LIKELY (g_module_close (data->open_module)))
|
||||
GST_DEBUG ("Closed module: %s", data->module_path);
|
||||
else
|
||||
GST_WARNING ("Could not close importer module");
|
||||
|
||||
data->open_module = NULL;
|
||||
}
|
||||
|
||||
static GstClapperImporter *
|
||||
_obtain_importer_internal (GstClapperImporterData *data)
|
||||
{
|
||||
MakeImporter make_importer;
|
||||
GstClapperImporter *importer = NULL;
|
||||
|
||||
if (!_open_importer (data))
|
||||
goto finish;
|
||||
|
||||
if (!g_module_symbol (data->open_module, "make_importer", (gpointer *) &make_importer)
|
||||
|| make_importer == NULL) {
|
||||
GST_WARNING ("Make function missing in importer");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Do not close the module, we are gonna continue using it */
|
||||
if ((importer = make_importer ()))
|
||||
goto finish;
|
||||
|
||||
fail:
|
||||
_close_importer (data);
|
||||
|
||||
finish:
|
||||
return importer;
|
||||
}
|
||||
|
||||
static GstClapperImporterData *
|
||||
_fill_importer_data (const gchar *module_path)
|
||||
{
|
||||
MakeCaps make_caps;
|
||||
GstClapperImporterData *data;
|
||||
|
||||
data = g_new0 (GstClapperImporterData, 1);
|
||||
data->module_path = g_strdup (module_path);
|
||||
data->open_module = g_module_open (data->module_path, G_MODULE_BIND_LAZY);
|
||||
|
||||
if (!data->open_module)
|
||||
goto fail;
|
||||
|
||||
if (!g_module_symbol (data->open_module, "make_caps", (gpointer *) &make_caps)
|
||||
|| make_caps == NULL) {
|
||||
GST_WARNING ("Make caps function missing in importer");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
data->caps = make_caps (&data->rank, &data->context_types);
|
||||
GST_DEBUG ("Caps reading %ssuccessful", data->caps ? "" : "un");
|
||||
|
||||
if (!data->caps)
|
||||
goto fail;
|
||||
|
||||
/* Once we obtain importer data, close module afterwards */
|
||||
_close_importer (data);
|
||||
|
||||
return data;
|
||||
|
||||
fail:
|
||||
gst_clapper_importer_data_free (data);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gint
|
||||
_sort_importers_cb (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
GstClapperImporterData *data_a, *data_b;
|
||||
|
||||
data_a = *((GstClapperImporterData **) a);
|
||||
data_b = *((GstClapperImporterData **) b);
|
||||
|
||||
return (data_b->rank - data_a->rank);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
_obtain_available_importers (G_GNUC_UNUSED gpointer data)
|
||||
{
|
||||
GPtrArray *importers;
|
||||
GFile *dir;
|
||||
GFileEnumerator *dir_enum;
|
||||
GError *error = NULL;
|
||||
|
||||
importers = g_ptr_array_new_with_free_func (
|
||||
(GDestroyNotify) gst_clapper_importer_data_free);
|
||||
|
||||
GST_INFO ("Checking available clapper sink importers");
|
||||
|
||||
dir = g_file_new_for_path (CLAPPER_SINK_IMPORTER_PATH);
|
||||
|
||||
if ((dir_enum = g_file_enumerate_children (dir,
|
||||
G_FILE_ATTRIBUTE_STANDARD_NAME,
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &error))) {
|
||||
while (TRUE) {
|
||||
GFileInfo *info = NULL;
|
||||
GstClapperImporterData *data;
|
||||
gchar *module_path;
|
||||
const gchar *module_name;
|
||||
|
||||
if (!g_file_enumerator_iterate (dir_enum, &info,
|
||||
NULL, NULL, &error) || !info)
|
||||
break;
|
||||
|
||||
module_name = g_file_info_get_name (info);
|
||||
|
||||
if (!g_str_has_suffix (module_name, G_MODULE_SUFFIX))
|
||||
continue;
|
||||
|
||||
module_path = g_module_build_path (CLAPPER_SINK_IMPORTER_PATH, module_name);
|
||||
data = _fill_importer_data (module_path);
|
||||
g_free (module_path);
|
||||
|
||||
if (!data) {
|
||||
GST_WARNING ("Could not read importer data: %s", module_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
GST_INFO ("Found importer: %s, caps: %" GST_PTR_FORMAT, module_name, data->caps);
|
||||
g_ptr_array_add (importers, data);
|
||||
}
|
||||
|
||||
g_object_unref (dir_enum);
|
||||
}
|
||||
|
||||
g_object_unref (dir);
|
||||
|
||||
if (error) {
|
||||
GST_ERROR ("Could not load importer, reason: %s",
|
||||
(error->message) ? error->message : "unknown");
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_ptr_array_sort (importers, (GCompareFunc) _sort_importers_cb);
|
||||
|
||||
return importers;
|
||||
}
|
||||
|
||||
static const GPtrArray *
|
||||
gst_clapper_importer_loader_get_available_importers (void)
|
||||
{
|
||||
static GOnce once = G_ONCE_INIT;
|
||||
|
||||
g_once (&once, _obtain_available_importers, NULL);
|
||||
return (const GPtrArray *) once.retval;
|
||||
}
|
||||
|
||||
static GstClapperImporterData *
|
||||
_find_open_importer_data (const GPtrArray *importers)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < importers->len; i++) {
|
||||
GstClapperImporterData *data = g_ptr_array_index (importers, i);
|
||||
|
||||
if (data->open_module)
|
||||
return data;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GstClapperImporterData *
|
||||
_get_importer_data_for_caps (const GPtrArray *importers, const GstCaps *caps)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < importers->len; i++) {
|
||||
GstClapperImporterData *data = g_ptr_array_index (importers, i);
|
||||
|
||||
if (!gst_caps_is_always_compatible (caps, data->caps))
|
||||
continue;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GstClapperImporterData *
|
||||
_get_importer_data_for_context_type (const GPtrArray *importers, const gchar *context_type)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < importers->len; i++) {
|
||||
GstClapperImporterData *data = g_ptr_array_index (importers, i);
|
||||
guint j;
|
||||
|
||||
if (!data->context_types)
|
||||
continue;
|
||||
|
||||
for (j = 0; data->context_types[j]; j++) {
|
||||
if (strcmp (context_type, data->context_types[j]))
|
||||
continue;
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
gst_clapper_importer_loader_unload_all (void)
|
||||
{
|
||||
const GPtrArray *importers;
|
||||
guint i;
|
||||
|
||||
importers = gst_clapper_importer_loader_get_available_importers ();
|
||||
GST_TRACE ("Unloading all open modules");
|
||||
|
||||
for (i = 0; i < importers->len; i++) {
|
||||
GstClapperImporterData *data = g_ptr_array_index (importers, i);
|
||||
|
||||
_close_importer (data);
|
||||
}
|
||||
}
|
||||
|
||||
GstPadTemplate *
|
||||
gst_clapper_importer_loader_make_sink_pad_template (void)
|
||||
{
|
||||
const GPtrArray *importers;
|
||||
GstCaps *sink_caps;
|
||||
GstPadTemplate *templ;
|
||||
guint i;
|
||||
|
||||
/* This is only called once from sink class init function */
|
||||
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clapperimporterloader", 0,
|
||||
"Clapper Importer Loader");
|
||||
|
||||
importers = gst_clapper_importer_loader_get_available_importers ();
|
||||
sink_caps = gst_caps_new_empty ();
|
||||
|
||||
for (i = 0; i < importers->len; i++) {
|
||||
GstClapperImporterData *data = g_ptr_array_index (importers, i);
|
||||
GstCaps *copied_caps;
|
||||
|
||||
copied_caps = gst_caps_copy (data->caps);
|
||||
gst_caps_append (sink_caps, copied_caps);
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (gst_caps_is_empty (sink_caps)))
|
||||
gst_caps_append (sink_caps, gst_caps_new_any ());
|
||||
|
||||
templ = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sink_caps);
|
||||
gst_caps_unref (sink_caps);
|
||||
|
||||
return templ;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_find_importer_internal (GstCaps *caps, GstQuery *query, GstClapperImporter **importer)
|
||||
{
|
||||
const GPtrArray *importers;
|
||||
GstClapperImporterData *old_data = NULL, *new_data = NULL;
|
||||
GstClapperImporter *found_importer = NULL;
|
||||
|
||||
importers = gst_clapper_importer_loader_get_available_importers ();
|
||||
old_data = _find_open_importer_data (importers);
|
||||
|
||||
if (caps) {
|
||||
GST_DEBUG ("Requested importer for caps: %" GST_PTR_FORMAT, caps);
|
||||
new_data = _get_importer_data_for_caps (importers, caps);
|
||||
} else if (query) {
|
||||
const gchar *context_type;
|
||||
|
||||
gst_query_parse_context_type (query, &context_type);
|
||||
|
||||
GST_DEBUG ("Requested importer for context: %s", context_type);
|
||||
new_data = _get_importer_data_for_context_type (importers, context_type);
|
||||
|
||||
/* In case missing importer for context query, leave the old one.
|
||||
* We should allow some queries to go through unresponded */
|
||||
if (!new_data)
|
||||
new_data = old_data;
|
||||
}
|
||||
GST_LOG ("Old importer path: %s, new path: %s",
|
||||
(old_data != NULL) ? old_data->module_path : NULL,
|
||||
(new_data != NULL) ? new_data->module_path : NULL);
|
||||
|
||||
if (old_data == new_data) {
|
||||
GST_DEBUG ("No importer change");
|
||||
|
||||
if (*importer && caps)
|
||||
gst_clapper_importer_set_caps (*importer, caps);
|
||||
|
||||
return (*importer != NULL);
|
||||
}
|
||||
|
||||
if (new_data) {
|
||||
found_importer = _obtain_importer_internal (new_data);
|
||||
|
||||
if (*importer && found_importer)
|
||||
gst_clapper_importer_share_data (*importer, found_importer);
|
||||
}
|
||||
|
||||
gst_clear_object (importer);
|
||||
_close_importer (old_data);
|
||||
|
||||
if (found_importer && gst_clapper_importer_prepare (found_importer)) {
|
||||
if (caps)
|
||||
gst_clapper_importer_set_caps (found_importer, caps);
|
||||
|
||||
*importer = found_importer;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gst_clear_object (&found_importer);
|
||||
_close_importer (new_data);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_clapper_importer_loader_find_importer_for_caps (GstCaps *caps, GstClapperImporter **importer)
|
||||
{
|
||||
return _find_importer_internal (caps, NULL, importer);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_clapper_importer_loader_find_importer_for_context_query (GstQuery *query, GstClapperImporter **importer)
|
||||
{
|
||||
return _find_importer_internal (NULL, query, importer);
|
||||
}
|
36
lib/gst/plugin/gstclapperimporterloader.h
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "gstclapperimporter.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GstPadTemplate * gst_clapper_importer_loader_make_sink_pad_template (void);
|
||||
|
||||
gboolean gst_clapper_importer_loader_find_importer_for_caps (GstCaps *caps, GstClapperImporter **importer);
|
||||
|
||||
gboolean gst_clapper_importer_loader_find_importer_for_context_query (GstQuery *query, GstClapperImporter **importer);
|
||||
|
||||
void gst_clapper_importer_loader_unload_all (void);
|
||||
|
||||
G_END_DECLS
|
@@ -12,8 +12,9 @@
|
||||
* 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, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
* 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
|
||||
@@ -22,8 +23,6 @@
|
||||
|
||||
#include "gstclapperpaintable.h"
|
||||
|
||||
#include "gstgtkutils.h"
|
||||
|
||||
#define DEFAULT_PAR_N 1
|
||||
#define DEFAULT_PAR_D 1
|
||||
|
||||
@@ -54,20 +53,14 @@ gst_clapper_paintable_class_init (GstClapperPaintableClass *klass)
|
||||
static void
|
||||
gst_clapper_paintable_init (GstClapperPaintable *self)
|
||||
{
|
||||
self->display_width = 1;
|
||||
self->display_height = 1;
|
||||
self->display_aspect_ratio = 1.0;
|
||||
|
||||
self->rotation = GST_VIDEO_ORIENTATION_IDENTITY;
|
||||
|
||||
self->par_n = DEFAULT_PAR_N;
|
||||
self->par_d = DEFAULT_PAR_D;
|
||||
self->pixel_aspect = ((gdouble) self->par_d / self->par_n);
|
||||
|
||||
g_mutex_init (&self->lock);
|
||||
g_mutex_init (&self->importer_lock);
|
||||
|
||||
gst_video_info_init (&self->v_info);
|
||||
g_weak_ref_init (&self->widget, NULL);
|
||||
g_weak_ref_init (&self->importer, NULL);
|
||||
|
||||
gdk_rgba_parse (&self->bg, "black");
|
||||
}
|
||||
@@ -86,10 +79,6 @@ gst_clapper_paintable_dispose (GObject *object)
|
||||
|
||||
GST_CLAPPER_PAINTABLE_UNLOCK (self);
|
||||
|
||||
GST_CLAPPER_PAINTABLE_IMPORTER_LOCK (self);
|
||||
gst_clear_object (&self->importer);
|
||||
GST_CLAPPER_PAINTABLE_IMPORTER_UNLOCK (self);
|
||||
|
||||
GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
|
||||
}
|
||||
|
||||
@@ -101,9 +90,8 @@ gst_clapper_paintable_finalize (GObject *object)
|
||||
GST_TRACE ("Finalize");
|
||||
|
||||
g_weak_ref_clear (&self->widget);
|
||||
|
||||
g_weak_ref_clear (&self->importer);
|
||||
g_mutex_clear (&self->lock);
|
||||
g_mutex_clear (&self->importer_lock);
|
||||
|
||||
GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
|
||||
}
|
||||
@@ -114,8 +102,8 @@ calculate_display_par (GstClapperPaintable *self, const GstVideoInfo *info)
|
||||
gint width, height, par_n, par_d, req_par_n, req_par_d;
|
||||
gboolean success;
|
||||
|
||||
gst_gtk_get_width_height_for_rotation (GST_VIDEO_INFO_WIDTH (info),
|
||||
GST_VIDEO_INFO_HEIGHT (info), &width, &height, self->rotation);
|
||||
width = GST_VIDEO_INFO_WIDTH (info);
|
||||
height = GST_VIDEO_INFO_HEIGHT (info);
|
||||
|
||||
/* Cannot apply aspect ratio if there is no video */
|
||||
if (width == 0 || height == 0)
|
||||
@@ -155,13 +143,14 @@ invalidate_paintable_size_internal (GstClapperPaintable *self)
|
||||
|
||||
GST_CLAPPER_PAINTABLE_LOCK (self);
|
||||
|
||||
gst_gtk_get_width_height_for_rotation (GST_VIDEO_INFO_WIDTH (&self->v_info),
|
||||
GST_VIDEO_INFO_HEIGHT (&self->v_info), &video_height, &video_width,
|
||||
self->rotation);
|
||||
video_width = GST_VIDEO_INFO_WIDTH (&self->v_info);
|
||||
video_height = GST_VIDEO_INFO_HEIGHT (&self->v_info);
|
||||
|
||||
display_ratio_num = self->display_ratio_num;
|
||||
display_ratio_den = self->display_ratio_den;
|
||||
|
||||
self->pixel_aspect = ((gdouble) self->par_d / self->par_n);
|
||||
|
||||
GST_CLAPPER_PAINTABLE_UNLOCK (self);
|
||||
|
||||
if (video_height % display_ratio_den == 0) {
|
||||
@@ -243,9 +232,7 @@ gst_clapper_paintable_set_widget (GstClapperPaintable *self, GtkWidget *widget)
|
||||
void
|
||||
gst_clapper_paintable_set_importer (GstClapperPaintable *self, GstClapperImporter *importer)
|
||||
{
|
||||
GST_CLAPPER_PAINTABLE_IMPORTER_LOCK (self);
|
||||
gst_object_replace ((GstObject **) &self->importer, GST_OBJECT_CAST (importer));
|
||||
GST_CLAPPER_PAINTABLE_IMPORTER_UNLOCK (self);
|
||||
g_weak_ref_set (&self->importer, importer);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -326,38 +313,6 @@ gst_clapper_paintable_set_pixel_aspect_ratio (GstClapperPaintable *self,
|
||||
GST_CLAPPER_PAINTABLE_UNLOCK (self);
|
||||
}
|
||||
|
||||
void
|
||||
gst_clapper_paintable_set_rotation (GstClapperPaintable *self,
|
||||
GstVideoOrientationMethod rotation)
|
||||
{
|
||||
GST_CLAPPER_PAINTABLE_LOCK (self);
|
||||
|
||||
self->rotation = rotation;
|
||||
|
||||
if (G_UNLIKELY (!calculate_display_par (self, &self->v_info))) {
|
||||
GST_CLAPPER_PAINTABLE_UNLOCK (self);
|
||||
return;
|
||||
}
|
||||
|
||||
self->pending_resize = TRUE;
|
||||
|
||||
GST_CLAPPER_PAINTABLE_UNLOCK (self);
|
||||
}
|
||||
|
||||
GstVideoOrientationMethod
|
||||
gst_clapper_paintable_get_rotation (GstClapperPaintable *self)
|
||||
{
|
||||
GstVideoOrientationMethod rotation;
|
||||
|
||||
GST_CLAPPER_PAINTABLE_LOCK (self);
|
||||
|
||||
rotation = self->rotation;
|
||||
|
||||
GST_CLAPPER_PAINTABLE_UNLOCK (self);
|
||||
|
||||
return rotation;
|
||||
}
|
||||
|
||||
/*
|
||||
* GdkPaintableInterface
|
||||
*/
|
||||
@@ -366,9 +321,8 @@ gst_clapper_paintable_snapshot_internal (GstClapperPaintable *self,
|
||||
GdkSnapshot *snapshot, gdouble width, gdouble height,
|
||||
gint widget_width, gint widget_height)
|
||||
{
|
||||
GstClapperImporter *importer;
|
||||
gfloat scale_x, scale_y;
|
||||
gdouble snapshot_width, snapshot_height;
|
||||
GskTransform *transform = NULL;
|
||||
|
||||
GST_LOG_OBJECT (self, "Snapshot");
|
||||
|
||||
@@ -393,72 +347,14 @@ gst_clapper_paintable_snapshot_internal (GstClapperPaintable *self,
|
||||
}
|
||||
}
|
||||
|
||||
GST_CLAPPER_PAINTABLE_IMPORTER_LOCK (self);
|
||||
|
||||
if (self->importer) {
|
||||
switch (self->rotation) {
|
||||
case GST_VIDEO_ORIENTATION_IDENTITY:
|
||||
default:
|
||||
snapshot_width = width;
|
||||
snapshot_height = height;
|
||||
break;
|
||||
case GST_VIDEO_ORIENTATION_90R:
|
||||
transform = gsk_transform_rotate (transform, 90);
|
||||
transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (0, -width));
|
||||
snapshot_width = height;
|
||||
snapshot_height = width;
|
||||
break;
|
||||
case GST_VIDEO_ORIENTATION_180:
|
||||
transform = gsk_transform_rotate (transform, 180);
|
||||
transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (-width, -height));
|
||||
snapshot_width = width;
|
||||
snapshot_height = height;
|
||||
break;
|
||||
case GST_VIDEO_ORIENTATION_90L:
|
||||
transform = gsk_transform_rotate (transform, 270);
|
||||
transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (-height, 0));
|
||||
snapshot_width = height;
|
||||
snapshot_height = width;
|
||||
break;
|
||||
case GST_VIDEO_ORIENTATION_HORIZ:
|
||||
transform = gsk_transform_rotate_3d (transform, 180, graphene_vec3_y_axis ());
|
||||
transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (-width, 0));
|
||||
snapshot_width = width;
|
||||
snapshot_height = height;
|
||||
break;
|
||||
case GST_VIDEO_ORIENTATION_VERT:
|
||||
transform = gsk_transform_rotate_3d (transform, 180, graphene_vec3_x_axis ());
|
||||
transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (0, -height));
|
||||
snapshot_width = width;
|
||||
snapshot_height = height;
|
||||
break;
|
||||
case GST_VIDEO_ORIENTATION_UL_LR:
|
||||
transform = gsk_transform_rotate (transform, 90);
|
||||
transform = gsk_transform_rotate_3d (transform, 180, graphene_vec3_x_axis ());
|
||||
snapshot_width = height;
|
||||
snapshot_height = width;
|
||||
break;
|
||||
case GST_VIDEO_ORIENTATION_UR_LL:
|
||||
transform = gsk_transform_rotate (transform, 90);
|
||||
transform = gsk_transform_rotate_3d (transform, 180, graphene_vec3_y_axis ());
|
||||
transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (-height, -width));
|
||||
snapshot_width = height;
|
||||
snapshot_height = width;
|
||||
break;
|
||||
}
|
||||
|
||||
if (transform) {
|
||||
gtk_snapshot_transform (snapshot, transform);
|
||||
gsk_transform_unref (transform);
|
||||
}
|
||||
|
||||
gst_clapper_importer_snapshot (self->importer, snapshot, snapshot_width, snapshot_height);
|
||||
if ((importer = g_weak_ref_get (&self->importer))) {
|
||||
gst_clapper_importer_snapshot (importer, snapshot, width, height,
|
||||
scale_x * self->pixel_aspect, scale_y);
|
||||
g_object_unref (importer);
|
||||
} else {
|
||||
GST_LOG_OBJECT (self, "No texture importer, drawing black");
|
||||
gtk_snapshot_append_color (snapshot, &self->bg, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
}
|
||||
|
||||
GST_CLAPPER_PAINTABLE_IMPORTER_UNLOCK (self);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -470,8 +366,11 @@ gst_clapper_paintable_snapshot (GdkPaintable *paintable,
|
||||
gint widget_width = 0, widget_height = 0;
|
||||
|
||||
if ((widget = g_weak_ref_get (&self->widget))) {
|
||||
widget_width = gtk_widget_get_width (widget);
|
||||
widget_height = gtk_widget_get_height (widget);
|
||||
gint scale_factor;
|
||||
|
||||
scale_factor = gtk_widget_get_scale_factor (widget);
|
||||
widget_width = gtk_widget_get_width (widget) * scale_factor;
|
||||
widget_height = gtk_widget_get_height (widget) * scale_factor;
|
||||
|
||||
g_object_unref (widget);
|
||||
}
|
@@ -12,8 +12,9 @@
|
||||
* 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, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
* 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
|
||||
@@ -35,27 +36,23 @@ G_DECLARE_FINAL_TYPE (GstClapperPaintable, gst_clapper_paintable, GST, CLAPPER_P
|
||||
#define GST_CLAPPER_PAINTABLE_LOCK(obj) g_mutex_lock (GST_CLAPPER_PAINTABLE_GET_LOCK(obj))
|
||||
#define GST_CLAPPER_PAINTABLE_UNLOCK(obj) g_mutex_unlock (GST_CLAPPER_PAINTABLE_GET_LOCK(obj))
|
||||
|
||||
#define GST_CLAPPER_PAINTABLE_IMPORTER_GET_LOCK(obj) (&GST_CLAPPER_PAINTABLE_CAST(obj)->importer_lock)
|
||||
#define GST_CLAPPER_PAINTABLE_IMPORTER_LOCK(obj) g_mutex_lock (GST_CLAPPER_PAINTABLE_IMPORTER_GET_LOCK(obj))
|
||||
#define GST_CLAPPER_PAINTABLE_IMPORTER_UNLOCK(obj) g_mutex_unlock (GST_CLAPPER_PAINTABLE_IMPORTER_GET_LOCK(obj))
|
||||
|
||||
struct _GstClapperPaintable
|
||||
{
|
||||
GObject parent;
|
||||
|
||||
GMutex lock;
|
||||
GMutex importer_lock;
|
||||
|
||||
GstVideoInfo v_info;
|
||||
|
||||
GdkRGBA bg;
|
||||
|
||||
GWeakRef widget;
|
||||
GstClapperImporter *importer;
|
||||
GWeakRef widget, importer;
|
||||
|
||||
/* Sink properties */
|
||||
gint par_n, par_d;
|
||||
GstVideoOrientationMethod rotation;
|
||||
|
||||
/* For drawing overlays */
|
||||
gdouble pixel_aspect;
|
||||
|
||||
/* Resize */
|
||||
gboolean pending_resize;
|
||||
@@ -71,13 +68,11 @@ struct _GstClapperPaintable
|
||||
guint draw_id;
|
||||
};
|
||||
|
||||
GstClapperPaintable * gst_clapper_paintable_new (void);
|
||||
void gst_clapper_paintable_queue_draw (GstClapperPaintable *paintable);
|
||||
void gst_clapper_paintable_set_widget (GstClapperPaintable *paintable, GtkWidget *widget);
|
||||
void gst_clapper_paintable_set_importer (GstClapperPaintable *paintable, GstClapperImporter *importer);
|
||||
gboolean gst_clapper_paintable_set_video_info (GstClapperPaintable *paintable, const GstVideoInfo *v_info);
|
||||
void gst_clapper_paintable_set_pixel_aspect_ratio (GstClapperPaintable *paintable, gint par_n, gint par_d);
|
||||
void gst_clapper_paintable_set_rotation (GstClapperPaintable *paintable, GstVideoOrientationMethod rotation);
|
||||
GstVideoOrientationMethod gst_clapper_paintable_get_rotation (GstClapperPaintable *paintable);
|
||||
GstClapperPaintable * gst_clapper_paintable_new (void);
|
||||
void gst_clapper_paintable_queue_draw (GstClapperPaintable *paintable);
|
||||
void gst_clapper_paintable_set_widget (GstClapperPaintable *paintable, GtkWidget *widget);
|
||||
void gst_clapper_paintable_set_importer (GstClapperPaintable *paintable, GstClapperImporter *importer);
|
||||
gboolean gst_clapper_paintable_set_video_info (GstClapperPaintable *paintable, const GstVideoInfo *v_info);
|
||||
void gst_clapper_paintable_set_pixel_aspect_ratio (GstClapperPaintable *paintable, gint par_n, gint par_d);
|
||||
|
||||
G_END_DECLS
|
@@ -12,8 +12,9 @@
|
||||
* 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, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
* 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
|
||||
@@ -21,13 +22,13 @@
|
||||
#endif
|
||||
|
||||
#include "gstclappersink.h"
|
||||
#include "gstclapperimporterloader.h"
|
||||
#include "gstgtkutils.h"
|
||||
|
||||
#define DEFAULT_FORCE_ASPECT_RATIO TRUE
|
||||
#define DEFAULT_PAR_N 1
|
||||
#define DEFAULT_PAR_D 1
|
||||
#define DEFAULT_KEEP_LAST_FRAME FALSE
|
||||
#define DEFAULT_ROTATION GST_VIDEO_ORIENTATION_AUTO
|
||||
|
||||
#define WINDOW_CSS_CLASS_NAME "clappersinkwindow"
|
||||
|
||||
@@ -38,7 +39,6 @@ enum
|
||||
PROP_FORCE_ASPECT_RATIO,
|
||||
PROP_PIXEL_ASPECT_RATIO,
|
||||
PROP_KEEP_LAST_FRAME,
|
||||
PROP_ROTATE_METHOD,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
@@ -68,6 +68,7 @@ window_clear_no_lock (GstClapperSink *self)
|
||||
self->window_destroy_id = 0;
|
||||
}
|
||||
self->window = NULL;
|
||||
self->presented_window = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -117,9 +118,8 @@ calculate_stream_coords (GstClapperSink *self, GtkWidget *widget,
|
||||
|
||||
GST_CLAPPER_SINK_LOCK (self);
|
||||
|
||||
gst_gtk_get_width_height_for_rotation (GST_VIDEO_INFO_WIDTH (&self->v_info),
|
||||
GST_VIDEO_INFO_HEIGHT (&self->v_info), &video_height, &video_width,
|
||||
gst_clapper_paintable_get_rotation (self->paintable));
|
||||
video_width = GST_VIDEO_INFO_WIDTH (&self->v_info);
|
||||
video_height = GST_VIDEO_INFO_HEIGHT (&self->v_info);
|
||||
force_aspect_ratio = self->force_aspect_ratio;
|
||||
|
||||
GST_CLAPPER_SINK_UNLOCK (self);
|
||||
@@ -280,15 +280,8 @@ gst_clapper_sink_get_widget (GstClapperSink *self)
|
||||
gst_clapper_paintable_set_widget (self->paintable, self->widget);
|
||||
|
||||
/* Set earlier remembered property */
|
||||
#if GTK_CHECK_VERSION(4,8,0)
|
||||
if (self->force_aspect_ratio)
|
||||
gtk_picture_set_content_fit (GTK_PICTURE (self->widget), GTK_CONTENT_FIT_CONTAIN);
|
||||
else
|
||||
gtk_picture_set_content_fit (GTK_PICTURE (self->widget), GTK_CONTENT_FIT_FILL);
|
||||
#else
|
||||
gtk_picture_set_keep_aspect_ratio (GTK_PICTURE (self->widget),
|
||||
self->force_aspect_ratio);
|
||||
#endif
|
||||
|
||||
gtk_picture_set_paintable (GTK_PICTURE (self->widget), GDK_PAINTABLE (self->paintable));
|
||||
|
||||
@@ -345,9 +338,6 @@ gst_clapper_sink_get_property (GObject *object, guint prop_id,
|
||||
case PROP_KEEP_LAST_FRAME:
|
||||
g_value_set_boolean (value, self->keep_last_frame);
|
||||
break;
|
||||
case PROP_ROTATE_METHOD:
|
||||
g_value_set_enum (value, self->rotation_mode);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -369,15 +359,8 @@ gst_clapper_sink_set_property (GObject *object, guint prop_id,
|
||||
self->force_aspect_ratio = g_value_get_boolean (value);
|
||||
|
||||
if (self->widget) {
|
||||
#if GTK_CHECK_VERSION(4,8,0)
|
||||
if (self->force_aspect_ratio)
|
||||
gtk_picture_set_content_fit (GTK_PICTURE (self->widget), GTK_CONTENT_FIT_CONTAIN);
|
||||
else
|
||||
gtk_picture_set_content_fit (GTK_PICTURE (self->widget), GTK_CONTENT_FIT_FILL);
|
||||
#else
|
||||
gtk_picture_set_keep_aspect_ratio (GTK_PICTURE (self->widget),
|
||||
self->force_aspect_ratio);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case PROP_PIXEL_ASPECT_RATIO:
|
||||
@@ -390,13 +373,6 @@ gst_clapper_sink_set_property (GObject *object, guint prop_id,
|
||||
case PROP_KEEP_LAST_FRAME:
|
||||
self->keep_last_frame = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_ROTATE_METHOD:
|
||||
self->rotation_mode = g_value_get_enum (value);
|
||||
|
||||
gst_clapper_paintable_set_rotation (self->paintable,
|
||||
(self->rotation_mode == GST_VIDEO_ORIENTATION_AUTO) ?
|
||||
self->stream_orientation : self->rotation_mode);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -411,18 +387,24 @@ gst_clapper_sink_navigation_send_event (GstNavigation *navigation,
|
||||
{
|
||||
GstClapperSink *sink = GST_CLAPPER_SINK_CAST (navigation);
|
||||
GstEvent *event;
|
||||
GstPad *pad;
|
||||
|
||||
GST_TRACE_OBJECT (sink, "Navigation event: %" GST_PTR_FORMAT, structure);
|
||||
event = gst_event_new_navigation (structure); // transfer full
|
||||
pad = gst_pad_get_peer (GST_VIDEO_SINK_PAD (sink));
|
||||
event = gst_event_new_navigation (structure);
|
||||
|
||||
if (G_LIKELY (pad != NULL)) {
|
||||
if (!gst_pad_send_event (pad, event)) // transfer full
|
||||
GST_LOG_OBJECT (sink, "Upstream did not handle navigation event");
|
||||
if (G_LIKELY (event)) {
|
||||
GstPad *pad;
|
||||
|
||||
gst_object_unref (pad);
|
||||
} else {
|
||||
pad = gst_pad_get_peer (GST_VIDEO_SINK_PAD (sink));
|
||||
|
||||
if (G_LIKELY (pad)) {
|
||||
if (!gst_pad_send_event (pad, gst_event_ref (event))) {
|
||||
/* If upstream didn't handle the event we'll post a message with it
|
||||
* for the application in case it wants to do something with it */
|
||||
gst_element_post_message (GST_ELEMENT_CAST (sink),
|
||||
gst_navigation_message_new_event (GST_OBJECT_CAST (sink), event));
|
||||
}
|
||||
gst_object_unref (pad);
|
||||
}
|
||||
gst_event_unref (event);
|
||||
}
|
||||
}
|
||||
@@ -431,7 +413,7 @@ static gboolean
|
||||
gst_clapper_sink_propose_allocation (GstBaseSink *bsink, GstQuery *query)
|
||||
{
|
||||
GstClapperSink *self = GST_CLAPPER_SINK_CAST (bsink);
|
||||
GstClapperImporter *importer = NULL;
|
||||
GstBufferPool *pool = NULL;
|
||||
GstCaps *caps;
|
||||
GstVideoInfo info;
|
||||
guint size, min_buffers;
|
||||
@@ -449,16 +431,6 @@ gst_clapper_sink_propose_allocation (GstBaseSink *bsink, GstQuery *query)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GST_CLAPPER_SINK_LOCK (self);
|
||||
if (self->importer)
|
||||
importer = gst_object_ref (self->importer);
|
||||
GST_CLAPPER_SINK_UNLOCK (self);
|
||||
|
||||
if (!importer) {
|
||||
GST_DEBUG_OBJECT (self, "No importer to propose allocation");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Normal size of a frame */
|
||||
size = GST_VIDEO_INFO_SIZE (&info);
|
||||
|
||||
@@ -466,11 +438,13 @@ gst_clapper_sink_propose_allocation (GstBaseSink *bsink, GstQuery *query)
|
||||
min_buffers = 3;
|
||||
|
||||
if (need_pool) {
|
||||
GstBufferPool *pool;
|
||||
GstStructure *config = NULL;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Need to create buffer pool");
|
||||
pool = gst_clapper_importer_create_pool (importer, &config);
|
||||
|
||||
GST_CLAPPER_SINK_LOCK (self);
|
||||
pool = gst_clapper_importer_create_pool (self->importer, &config);
|
||||
GST_CLAPPER_SINK_UNLOCK (self);
|
||||
|
||||
if (pool) {
|
||||
/* If we did not get config, use default one */
|
||||
@@ -481,22 +455,23 @@ gst_clapper_sink_propose_allocation (GstBaseSink *bsink, GstQuery *query)
|
||||
|
||||
if (!gst_buffer_pool_set_config (pool, config)) {
|
||||
gst_object_unref (pool);
|
||||
gst_object_unref (importer);
|
||||
|
||||
GST_ERROR_OBJECT (self, "Failed to set config");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gst_query_add_allocation_pool (query, pool, size, min_buffers, 0);
|
||||
gst_object_unref (pool);
|
||||
} else if (config) {
|
||||
GST_WARNING_OBJECT (self, "Got config without a pool to apply it");
|
||||
gst_structure_free (config);
|
||||
}
|
||||
}
|
||||
|
||||
gst_clapper_importer_add_allocation_metas (importer, query);
|
||||
gst_object_unref (importer);
|
||||
gst_query_add_allocation_pool (query, pool, size, min_buffers, 0);
|
||||
if (pool)
|
||||
gst_object_unref (pool);
|
||||
|
||||
GST_CLAPPER_SINK_LOCK (self);
|
||||
gst_clapper_importer_add_allocation_metas (self->importer, query);
|
||||
GST_CLAPPER_SINK_UNLOCK (self);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -507,12 +482,25 @@ gst_clapper_sink_query (GstBaseSink *bsink, GstQuery *query)
|
||||
GstClapperSink *self = GST_CLAPPER_SINK_CAST (bsink);
|
||||
gboolean res = FALSE;
|
||||
|
||||
GST_CLAPPER_SINK_LOCK (self);
|
||||
|
||||
if (GST_QUERY_TYPE (query) == GST_QUERY_CONTEXT) {
|
||||
GST_CLAPPER_SINK_LOCK (self);
|
||||
res = gst_clapper_importer_loader_handle_context_query (self->loader, bsink, query);
|
||||
GST_CLAPPER_SINK_UNLOCK (self);
|
||||
gboolean is_inactive;
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
is_inactive = (GST_STATE (self) < GST_STATE_PAUSED);
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
/* Some random context query in the middle of playback
|
||||
* should not trigger importer replacement */
|
||||
if (is_inactive)
|
||||
gst_clapper_importer_loader_find_importer_for_context_query (query, &self->importer);
|
||||
if (self->importer)
|
||||
res = gst_clapper_importer_handle_context_query (self->importer, bsink, query);
|
||||
}
|
||||
|
||||
GST_CLAPPER_SINK_UNLOCK (self);
|
||||
|
||||
if (res)
|
||||
return TRUE;
|
||||
|
||||
@@ -573,9 +561,6 @@ gst_clapper_sink_start_on_main (GstClapperSink *self)
|
||||
|
||||
self->window_destroy_id = g_signal_connect (self->window,
|
||||
"destroy", G_CALLBACK (window_destroy_cb), self);
|
||||
|
||||
GST_INFO_OBJECT (self, "Presenting window");
|
||||
gtk_window_present (self->window);
|
||||
}
|
||||
|
||||
GST_CLAPPER_SINK_UNLOCK (self);
|
||||
@@ -583,18 +568,24 @@ gst_clapper_sink_start_on_main (GstClapperSink *self)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
window_present_on_main_idle (GtkWindow *window)
|
||||
{
|
||||
GST_INFO ("Presenting window");
|
||||
gtk_window_present (window);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_clapper_sink_start (GstBaseSink *bsink)
|
||||
{
|
||||
GstClapperSink *self = GST_CLAPPER_SINK_CAST (bsink);
|
||||
gboolean with_clapper_gtk;
|
||||
|
||||
GST_INFO_OBJECT (self, "Start");
|
||||
|
||||
with_clapper_gtk = g_type_from_name ("ClapperGtkVideo");
|
||||
|
||||
if (G_UNLIKELY (!with_clapper_gtk && !(! !gst_gtk_invoke_on_main (
|
||||
(GThreadFunc) (GCallback) gst_clapper_sink_start_on_main, self)))) {
|
||||
if (G_UNLIKELY (!(! !gst_gtk_invoke_on_main ((GThreadFunc) (GCallback)
|
||||
gst_clapper_sink_start_on_main, self)))) {
|
||||
GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
|
||||
("GtkWidget could not be created"), (NULL));
|
||||
|
||||
@@ -642,32 +633,6 @@ gst_clapper_sink_stop (GstBaseSink *bsink)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_clapper_sink_event (GstBaseSink *bsink, GstEvent *event)
|
||||
{
|
||||
GstClapperSink *self = GST_CLAPPER_SINK_CAST (bsink);
|
||||
GstTagList *taglist;
|
||||
GstVideoOrientationMethod orientation;
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_TAG:
|
||||
gst_event_parse_tag (event, &taglist);
|
||||
|
||||
if (gst_video_orientation_from_tag (taglist, &orientation)) {
|
||||
GST_CLAPPER_SINK_LOCK (self);
|
||||
self->stream_orientation = orientation;
|
||||
if (self->rotation_mode == GST_VIDEO_ORIENTATION_AUTO)
|
||||
gst_clapper_paintable_set_rotation (self->paintable, orientation);
|
||||
GST_CLAPPER_SINK_UNLOCK (self);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return GST_BASE_SINK_CLASS (parent_class)->event (bsink, event);
|
||||
}
|
||||
|
||||
static GstStateChangeReturn
|
||||
gst_clapper_sink_change_state (GstElement *element, GstStateChange transition)
|
||||
{
|
||||
@@ -678,14 +643,6 @@ gst_clapper_sink_change_state (GstElement *element, GstStateChange transition)
|
||||
gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
||||
/* Reset stream_orientation */
|
||||
GST_CLAPPER_SINK_LOCK (self);
|
||||
self->stream_orientation = GST_VIDEO_ORIENTATION_IDENTITY;
|
||||
if (self->rotation_mode == GST_VIDEO_ORIENTATION_AUTO)
|
||||
gst_clapper_paintable_set_rotation (self->paintable, self->stream_orientation);
|
||||
GST_CLAPPER_SINK_UNLOCK (self);
|
||||
break;
|
||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||
GST_CLAPPER_SINK_LOCK (self);
|
||||
if (!self->keep_last_frame && self->importer) {
|
||||
@@ -694,6 +651,16 @@ gst_clapper_sink_change_state (GstElement *element, GstStateChange transition)
|
||||
}
|
||||
GST_CLAPPER_SINK_UNLOCK (self);
|
||||
break;
|
||||
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
||||
GST_CLAPPER_SINK_LOCK (self);
|
||||
if (G_UNLIKELY (self->window && !self->presented_window)) {
|
||||
g_idle_add_full (G_PRIORITY_DEFAULT,
|
||||
(GSourceFunc) window_present_on_main_idle,
|
||||
g_object_ref (self->window), (GDestroyNotify) g_object_unref);
|
||||
self->presented_window = TRUE;
|
||||
}
|
||||
GST_CLAPPER_SINK_UNLOCK (self);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -729,10 +696,9 @@ gst_clapper_sink_get_times (GstBaseSink *bsink, GstBuffer *buffer,
|
||||
static GstCaps *
|
||||
gst_clapper_sink_get_caps (GstBaseSink *bsink, GstCaps *filter)
|
||||
{
|
||||
GstClapperSink *self = GST_CLAPPER_SINK_CAST (bsink);
|
||||
GstCaps *result, *tmp;
|
||||
|
||||
tmp = gst_clapper_importer_loader_make_actual_caps (self->loader);
|
||||
tmp = gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink));
|
||||
|
||||
if (filter) {
|
||||
GST_DEBUG ("Intersecting with filter caps: %" GST_PTR_FORMAT, filter);
|
||||
@@ -762,7 +728,7 @@ gst_clapper_sink_set_caps (GstBaseSink *bsink, GstCaps *caps)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!gst_clapper_importer_loader_find_importer_for_caps (self->loader, caps, &self->importer)) {
|
||||
if (!gst_clapper_importer_loader_find_importer_for_caps (caps, &self->importer)) {
|
||||
GST_CLAPPER_SINK_UNLOCK (self);
|
||||
GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
|
||||
("No importer for given caps found"), (NULL));
|
||||
@@ -837,13 +803,11 @@ gst_clapper_sink_init (GstClapperSink *self)
|
||||
self->par_n = DEFAULT_PAR_N;
|
||||
self->par_d = DEFAULT_PAR_D;
|
||||
self->keep_last_frame = DEFAULT_KEEP_LAST_FRAME;
|
||||
self->rotation_mode = DEFAULT_ROTATION;
|
||||
|
||||
g_mutex_init (&self->lock);
|
||||
gst_video_info_init (&self->v_info);
|
||||
|
||||
self->paintable = gst_clapper_paintable_new ();
|
||||
self->loader = gst_clapper_importer_loader_new ();
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -871,7 +835,7 @@ gst_clapper_sink_finalize (GObject *object)
|
||||
|
||||
GST_TRACE ("Finalize");
|
||||
|
||||
gst_clear_object (&self->loader);
|
||||
gst_clapper_importer_loader_unload_all ();
|
||||
g_mutex_clear (&self->lock);
|
||||
|
||||
GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
|
||||
@@ -913,12 +877,6 @@ gst_clapper_sink_class_init (GstClapperSinkClass *klass)
|
||||
DEFAULT_KEEP_LAST_FRAME,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_ROTATE_METHOD,
|
||||
g_param_spec_enum ("rotate-method", "Rotate Method",
|
||||
"Rotate method to use",
|
||||
GST_TYPE_VIDEO_ORIENTATION_METHOD, DEFAULT_ROTATION,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
gstelement_class->change_state = gst_clapper_sink_change_state;
|
||||
|
||||
gstbasesink_class->get_caps = gst_clapper_sink_get_caps;
|
||||
@@ -928,12 +886,11 @@ gst_clapper_sink_class_init (GstClapperSinkClass *klass)
|
||||
gstbasesink_class->query = gst_clapper_sink_query;
|
||||
gstbasesink_class->start = gst_clapper_sink_start;
|
||||
gstbasesink_class->stop = gst_clapper_sink_stop;
|
||||
gstbasesink_class->event = gst_clapper_sink_event;
|
||||
|
||||
gstvideosink_class->set_info = gst_clapper_sink_set_info;
|
||||
gstvideosink_class->show_frame = gst_clapper_sink_show_frame;
|
||||
|
||||
gst_element_class_set_static_metadata (gstelement_class,
|
||||
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>");
|
@@ -12,8 +12,9 @@
|
||||
* 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, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
* 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
|
||||
@@ -24,7 +25,6 @@
|
||||
#include <gst/video/video.h>
|
||||
|
||||
#include "gstclapperpaintable.h"
|
||||
#include "gstclapperimporterloader.h"
|
||||
#include "gstclapperimporter.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
@@ -46,19 +46,18 @@ struct _GstClapperSink
|
||||
GMutex lock;
|
||||
|
||||
GstClapperPaintable *paintable;
|
||||
GstClapperImporterLoader *loader;
|
||||
GstClapperImporter *importer;
|
||||
GstVideoInfo v_info;
|
||||
GstVideoOrientationMethod stream_orientation;
|
||||
|
||||
GtkWidget *widget;
|
||||
GtkWindow *window;
|
||||
|
||||
gboolean presented_window;
|
||||
|
||||
/* Properties */
|
||||
gboolean force_aspect_ratio;
|
||||
gint par_n, par_d;
|
||||
gboolean keep_last_frame;
|
||||
GstVideoOrientationMethod rotation_mode;
|
||||
|
||||
/* Position coords */
|
||||
gdouble last_pos_x;
|
@@ -12,8 +12,9 @@
|
||||
* 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, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
* 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 <glib.h>
|
@@ -15,14 +15,13 @@
|
||||
* 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, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
* 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"
|
||||
|
||||
#define _IS_FRAME_PREMULTIPLIED(f) (GST_VIDEO_INFO_FLAG_IS_SET (&(f)->info, GST_VIDEO_FLAG_PREMULTIPLIED_ALPHA))
|
||||
|
||||
struct invoke_context
|
||||
{
|
||||
GThreadFunc func;
|
||||
@@ -72,29 +71,21 @@ gst_gtk_invoke_on_main (GThreadFunc func, gpointer data)
|
||||
return info.res;
|
||||
}
|
||||
|
||||
static GdkMemoryFormat
|
||||
gst_gdk_memory_format_from_frame (GstVideoFrame *frame)
|
||||
/* For use with `GdkMemoryTexture` only! */
|
||||
GdkMemoryFormat
|
||||
gst_video_format_to_gdk_memory_format (GstVideoFormat format)
|
||||
{
|
||||
switch (GST_VIDEO_FRAME_FORMAT (frame)) {
|
||||
switch (format) {
|
||||
case GST_VIDEO_FORMAT_RGBA64_LE:
|
||||
case GST_VIDEO_FORMAT_RGBA64_BE:
|
||||
return (_IS_FRAME_PREMULTIPLIED (frame))
|
||||
? GDK_MEMORY_R16G16B16A16_PREMULTIPLIED
|
||||
: GDK_MEMORY_R16G16B16A16;
|
||||
return GDK_MEMORY_R16G16B16A16_PREMULTIPLIED;
|
||||
case GST_VIDEO_FORMAT_RGBA:
|
||||
return (_IS_FRAME_PREMULTIPLIED (frame))
|
||||
? GDK_MEMORY_R8G8B8A8_PREMULTIPLIED
|
||||
: GDK_MEMORY_R8G8B8A8;
|
||||
return GDK_MEMORY_R8G8B8A8;
|
||||
case GST_VIDEO_FORMAT_BGRA:
|
||||
return (_IS_FRAME_PREMULTIPLIED (frame))
|
||||
? GDK_MEMORY_B8G8R8A8_PREMULTIPLIED
|
||||
: GDK_MEMORY_B8G8R8A8;
|
||||
return GDK_MEMORY_B8G8R8A8;
|
||||
case GST_VIDEO_FORMAT_ARGB:
|
||||
return (_IS_FRAME_PREMULTIPLIED (frame))
|
||||
? GDK_MEMORY_A8R8G8B8_PREMULTIPLIED
|
||||
: GDK_MEMORY_A8R8G8B8;
|
||||
return GDK_MEMORY_A8R8G8B8;
|
||||
case GST_VIDEO_FORMAT_ABGR:
|
||||
/* GTK is missing premultiplied ABGR support */
|
||||
return GDK_MEMORY_A8B8G8R8;
|
||||
case GST_VIDEO_FORMAT_RGBx:
|
||||
return GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
|
||||
@@ -131,7 +122,7 @@ gst_video_frame_into_gdk_texture (GstVideoFrame *frame)
|
||||
texture = gdk_memory_texture_new (
|
||||
GST_VIDEO_FRAME_WIDTH (frame),
|
||||
GST_VIDEO_FRAME_HEIGHT (frame),
|
||||
gst_gdk_memory_format_from_frame (frame),
|
||||
gst_video_format_to_gdk_memory_format (GST_VIDEO_FRAME_FORMAT (frame)),
|
||||
bytes,
|
||||
GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0));
|
||||
|
||||
@@ -139,23 +130,3 @@ gst_video_frame_into_gdk_texture (GstVideoFrame *frame)
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
void
|
||||
gst_gtk_get_width_height_for_rotation (gint width, gint height,
|
||||
gint *out_width, gint *out_height,
|
||||
GstVideoOrientationMethod rotation)
|
||||
{
|
||||
switch (rotation) {
|
||||
case GST_VIDEO_ORIENTATION_90R:
|
||||
case GST_VIDEO_ORIENTATION_90L:
|
||||
case GST_VIDEO_ORIENTATION_UL_LR:
|
||||
case GST_VIDEO_ORIENTATION_UR_LL:
|
||||
*out_width = height;
|
||||
*out_height = width;
|
||||
break;
|
||||
default:
|
||||
*out_width = width;
|
||||
*out_height = height;
|
||||
break;
|
||||
}
|
||||
}
|
@@ -15,8 +15,9 @@
|
||||
* 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, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
* 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
|
||||
@@ -25,18 +26,12 @@
|
||||
#include <gtk/gtk.h>
|
||||
#include <gst/video/video.h>
|
||||
|
||||
#include "gst/plugin/clapper-gst-visibility.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
CLAPPER_GST_API
|
||||
gpointer gst_gtk_invoke_on_main (GThreadFunc func, gpointer data);
|
||||
|
||||
CLAPPER_GST_API
|
||||
GdkMemoryFormat gst_video_format_to_gdk_memory_format (GstVideoFormat format);
|
||||
|
||||
GdkTexture * gst_video_frame_into_gdk_texture (GstVideoFrame *frame);
|
||||
|
||||
void gst_gtk_get_width_height_for_rotation (gint width, gint height,
|
||||
gint *out_width, gint *out_height,
|
||||
GstVideoOrientationMethod rotation);
|
||||
|
||||
G_END_DECLS
|
@@ -12,8 +12,9 @@
|
||||
* 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, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
* 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
|
549
lib/gst/plugin/importers/gstclapperglbaseimporter.c
vendored
Normal file
@@ -0,0 +1,549 @@
|
||||
/*
|
||||
* 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 "gstclapperglbaseimporter.h"
|
||||
#include "gst/plugin/gstgdkformats.h"
|
||||
#include "gst/plugin/gstgtkutils.h"
|
||||
|
||||
#include <gst/gl/gstglfuncs.h>
|
||||
|
||||
#if GST_CLAPPER_GL_BASE_IMPORTER_HAVE_WAYLAND
|
||||
#include <gdk/wayland/gdkwayland.h>
|
||||
#include <gst/gl/wayland/gstgldisplay_wayland.h>
|
||||
#endif
|
||||
|
||||
#if GST_CLAPPER_GL_BASE_IMPORTER_HAVE_X11
|
||||
#include <gdk/x11/gdkx.h>
|
||||
#endif
|
||||
#if GST_CLAPPER_GL_BASE_IMPORTER_HAVE_X11_GLX
|
||||
#include <gst/gl/x11/gstgldisplay_x11.h>
|
||||
#endif
|
||||
#if GST_CLAPPER_GL_BASE_IMPORTER_HAVE_X11_EGL
|
||||
#include <gst/gl/egl/gstgldisplay_egl.h>
|
||||
#endif
|
||||
|
||||
#define GST_CAT_DEFAULT gst_clapper_gl_base_importer_debug
|
||||
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
||||
|
||||
#define parent_class gst_clapper_gl_base_importer_parent_class
|
||||
G_DEFINE_TYPE (GstClapperGLBaseImporter, gst_clapper_gl_base_importer, GST_TYPE_CLAPPER_IMPORTER);
|
||||
|
||||
static GstGLContext *
|
||||
wrap_current_gl (GstGLDisplay *display, GdkGLAPI gdk_gl_api, GstGLPlatform platform)
|
||||
{
|
||||
GstGLAPI gst_gl_api = GST_GL_API_NONE;
|
||||
|
||||
switch (gdk_gl_api) {
|
||||
case GDK_GL_API_GL:
|
||||
gst_gl_api = GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
|
||||
break;
|
||||
case GDK_GL_API_GLES:
|
||||
gst_gl_api = GST_GL_API_GLES2;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
if (gst_gl_api != GST_GL_API_NONE) {
|
||||
guintptr gl_handle;
|
||||
|
||||
gst_gl_display_filter_gl_api (display, gst_gl_api);
|
||||
|
||||
if ((gl_handle = gst_gl_context_get_current_gl_context (platform)))
|
||||
return gst_gl_context_new_wrapped (display, gl_handle, platform, gst_gl_api);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
retrieve_gl_context_on_main (GstClapperGLBaseImporter *self)
|
||||
{
|
||||
GstClapperGLBaseImporterClass *gl_bi_class = GST_CLAPPER_GL_BASE_IMPORTER_GET_CLASS (self);
|
||||
GdkDisplay *gdk_display;
|
||||
GdkGLContext *gdk_context;
|
||||
GError *error = NULL;
|
||||
GdkGLAPI gdk_gl_api;
|
||||
GstGLPlatform platform = GST_GL_PLATFORM_NONE;
|
||||
gint gl_major = 0, gl_minor = 0;
|
||||
|
||||
if (!gtk_init_check ()) {
|
||||
GST_ERROR_OBJECT (self, "Could not ensure GTK initialization");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Make sure we are clean here, otherwise data sharing
|
||||
* between GL-based importers may lead to leaks */
|
||||
gst_clear_object (&self->wrapped_context);
|
||||
g_clear_object (&self->gdk_context);
|
||||
gst_clear_object (&self->gst_display);
|
||||
|
||||
gdk_display = gdk_display_get_default ();
|
||||
|
||||
if (!(gdk_context = gdk_display_create_gl_context (gdk_display, &error))) {
|
||||
GST_ERROR_OBJECT (self, "Error creating Gdk GL context: %s",
|
||||
error ? error->message : "No error set by Gdk");
|
||||
g_clear_error (&error);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!gl_bi_class->gdk_context_realize (self, gdk_context)) {
|
||||
GST_ERROR_OBJECT (self, "Could not realize Gdk context: %" GST_PTR_FORMAT,
|
||||
gdk_context);
|
||||
g_object_unref (gdk_context);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
gdk_gl_api = gdk_gl_context_get_api (gdk_context);
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
|
||||
self->gdk_context = gdk_context;
|
||||
|
||||
#if GST_CLAPPER_GL_BASE_IMPORTER_HAVE_WAYLAND
|
||||
if (GDK_IS_WAYLAND_DISPLAY (gdk_display)) {
|
||||
struct wl_display *wayland_display =
|
||||
gdk_wayland_display_get_wl_display (gdk_display);
|
||||
self->gst_display = (GstGLDisplay *)
|
||||
gst_gl_display_wayland_new_with_display (wayland_display);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if GST_CLAPPER_GL_BASE_IMPORTER_HAVE_X11
|
||||
if (GDK_IS_X11_DISPLAY (gdk_display)) {
|
||||
gpointer display_ptr;
|
||||
#if GST_CLAPPER_GL_BASE_IMPORTER_HAVE_X11_EGL
|
||||
display_ptr = gdk_x11_display_get_egl_display (gdk_display);
|
||||
if (display_ptr) {
|
||||
self->gst_display = (GstGLDisplay *)
|
||||
gst_gl_display_egl_new_with_egl_display (display_ptr);
|
||||
}
|
||||
#endif
|
||||
#if GST_CLAPPER_GL_BASE_IMPORTER_HAVE_X11_GLX
|
||||
if (!self->gst_display) {
|
||||
display_ptr = gdk_x11_display_get_xdisplay (gdk_display);
|
||||
self->gst_display = (GstGLDisplay *)
|
||||
gst_gl_display_x11_new_with_display (display_ptr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Fallback to generic display */
|
||||
if (G_UNLIKELY (!self->gst_display)) {
|
||||
GST_WARNING_OBJECT (self, "Unknown Gdk display!");
|
||||
self->gst_display = gst_gl_display_new ();
|
||||
}
|
||||
|
||||
#if GST_CLAPPER_GL_BASE_IMPORTER_HAVE_WAYLAND
|
||||
if (GST_IS_GL_DISPLAY_WAYLAND (self->gst_display)) {
|
||||
platform = GST_GL_PLATFORM_EGL;
|
||||
GST_INFO_OBJECT (self, "Using EGL on Wayland");
|
||||
goto have_display;
|
||||
}
|
||||
#endif
|
||||
#if GST_CLAPPER_GL_BASE_IMPORTER_HAVE_X11_EGL
|
||||
if (GST_IS_GL_DISPLAY_EGL (self->gst_display)) {
|
||||
platform = GST_GL_PLATFORM_EGL;
|
||||
GST_INFO_OBJECT (self, "Using EGL on x11");
|
||||
goto have_display;
|
||||
}
|
||||
#endif
|
||||
#if GST_CLAPPER_GL_BASE_IMPORTER_HAVE_X11_GLX
|
||||
if (GST_IS_GL_DISPLAY_X11 (self->gst_display)) {
|
||||
platform = GST_GL_PLATFORM_GLX;
|
||||
GST_INFO_OBJECT (self, "Using GLX on x11");
|
||||
goto have_display;
|
||||
}
|
||||
#endif
|
||||
|
||||
g_clear_object (&self->gdk_context);
|
||||
gst_clear_object (&self->gst_display);
|
||||
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
GST_ERROR_OBJECT (self, "Unsupported GL platform");
|
||||
return FALSE;
|
||||
|
||||
have_display:
|
||||
gdk_gl_context_make_current (self->gdk_context);
|
||||
|
||||
self->wrapped_context = wrap_current_gl (self->gst_display, gdk_gl_api, platform);
|
||||
if (!self->wrapped_context) {
|
||||
GST_ERROR ("Could not retrieve Gdk OpenGL context");
|
||||
gdk_gl_context_clear_current ();
|
||||
|
||||
g_clear_object (&self->gdk_context);
|
||||
gst_clear_object (&self->gst_display);
|
||||
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GST_INFO ("Retrieved Gdk OpenGL context %" GST_PTR_FORMAT, self->wrapped_context);
|
||||
gst_gl_context_activate (self->wrapped_context, TRUE);
|
||||
|
||||
if (!gst_gl_context_fill_info (self->wrapped_context, &error)) {
|
||||
GST_ERROR ("Failed to fill Gdk context info: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
|
||||
gst_gl_context_activate (self->wrapped_context, FALSE);
|
||||
|
||||
gst_clear_object (&self->wrapped_context);
|
||||
g_clear_object (&self->gdk_context);
|
||||
gst_clear_object (&self->gst_display);
|
||||
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gst_gl_context_get_gl_version (self->wrapped_context, &gl_major, &gl_minor);
|
||||
GST_INFO ("Using OpenGL%s %i.%i", (gdk_gl_api == GDK_GL_API_GLES) ? " ES" : "",
|
||||
gl_major, gl_minor);
|
||||
|
||||
/* Deactivate in both places */
|
||||
gst_gl_context_activate (self->wrapped_context, FALSE);
|
||||
gdk_gl_context_clear_current ();
|
||||
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
retrieve_gst_context (GstClapperGLBaseImporter *self)
|
||||
{
|
||||
GstGLDisplay *gst_display = NULL;
|
||||
GstGLContext *gst_context = NULL;
|
||||
GError *error = NULL;
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
|
||||
gst_display = gst_object_ref (self->gst_display);
|
||||
|
||||
/* GstGLDisplay operations require display object lock to be held */
|
||||
GST_OBJECT_LOCK (gst_display);
|
||||
|
||||
if (!self->gst_context) {
|
||||
GST_TRACE_OBJECT (self, "Creating new GstGLContext");
|
||||
|
||||
if (!gst_gl_display_create_context (gst_display, self->wrapped_context,
|
||||
&self->gst_context, &error)) {
|
||||
GST_WARNING ("Could not create OpenGL context: %s",
|
||||
error ? error->message : "Unknown");
|
||||
g_clear_error (&error);
|
||||
|
||||
GST_OBJECT_UNLOCK (gst_display);
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
gst_context = gst_object_ref (self->gst_context);
|
||||
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
gst_gl_display_add_context (gst_display, gst_context);
|
||||
|
||||
GST_OBJECT_UNLOCK (gst_display);
|
||||
|
||||
gst_object_unref (gst_display);
|
||||
gst_object_unref (gst_context);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_clapper_gl_base_importer_prepare (GstClapperImporter *importer)
|
||||
{
|
||||
GstClapperGLBaseImporter *self = GST_CLAPPER_GL_BASE_IMPORTER_CAST (importer);
|
||||
gboolean need_invoke;
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
need_invoke = (!self->gdk_context || !self->gst_display || !self->wrapped_context);
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
if (need_invoke) {
|
||||
if (!(! !gst_gtk_invoke_on_main ((GThreadFunc) (GCallback)
|
||||
retrieve_gl_context_on_main, self)))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!retrieve_gst_context (self))
|
||||
return FALSE;
|
||||
|
||||
if (!GST_CLAPPER_IMPORTER_CLASS (parent_class)->prepare)
|
||||
return TRUE;
|
||||
|
||||
return GST_CLAPPER_IMPORTER_CLASS (parent_class)->prepare (importer);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_gl_base_importer_share_data (GstClapperImporter *importer, GstClapperImporter *dest_importer)
|
||||
{
|
||||
GstClapperGLBaseImporter *self = GST_CLAPPER_GL_BASE_IMPORTER (importer);
|
||||
|
||||
if (GST_IS_CLAPPER_GL_BASE_IMPORTER (dest_importer)) {
|
||||
GstClapperGLBaseImporter *dest = GST_CLAPPER_GL_BASE_IMPORTER (dest_importer);
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
GST_OBJECT_LOCK (dest);
|
||||
|
||||
/* Successfully prepared GL importer should have all three */
|
||||
if (self->gdk_context && self->gst_display && self->wrapped_context) {
|
||||
g_clear_object (&dest->gdk_context);
|
||||
dest->gdk_context = g_object_ref (self->gdk_context);
|
||||
|
||||
gst_clear_object (&dest->gst_display);
|
||||
dest->gst_display = gst_object_ref (self->gst_display);
|
||||
|
||||
gst_clear_object (&dest->wrapped_context);
|
||||
dest->wrapped_context = gst_object_ref (self->wrapped_context);
|
||||
}
|
||||
|
||||
/* This context is not required, we can create it ourselves
|
||||
* using gst_display and wrapped_context */
|
||||
if (self->gst_context) {
|
||||
gst_clear_object (&dest->gst_context);
|
||||
dest->gst_context = gst_object_ref (self->gst_context);
|
||||
}
|
||||
|
||||
GST_OBJECT_UNLOCK (dest);
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
}
|
||||
|
||||
if (GST_CLAPPER_IMPORTER_CLASS (parent_class)->share_data)
|
||||
GST_CLAPPER_IMPORTER_CLASS (parent_class)->share_data (importer, dest_importer);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_clapper_gl_base_importer_handle_context_query (GstClapperImporter *importer,
|
||||
GstBaseSink *bsink, GstQuery *query)
|
||||
{
|
||||
GstClapperGLBaseImporter *self = GST_CLAPPER_GL_BASE_IMPORTER_CAST (importer);
|
||||
gboolean res;
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
res = gst_gl_handle_context_query (GST_ELEMENT_CAST (bsink), query,
|
||||
self->gst_display, self->gst_context, self->wrapped_context);
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static GstBufferPool *
|
||||
gst_clapper_gl_base_importer_create_pool (GstClapperImporter *importer, GstStructure **config)
|
||||
{
|
||||
GstClapperGLBaseImporter *self = GST_CLAPPER_GL_BASE_IMPORTER_CAST (importer);
|
||||
GstBufferPool *pool;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Creating new GL buffer pool");
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
pool = gst_gl_buffer_pool_new (self->gst_context);
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
*config = gst_buffer_pool_get_config (pool);
|
||||
|
||||
gst_buffer_pool_config_add_option (*config, GST_BUFFER_POOL_OPTION_VIDEO_META);
|
||||
gst_buffer_pool_config_add_option (*config, GST_BUFFER_POOL_OPTION_GL_SYNC_META);
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_gl_base_importer_add_allocation_metas (GstClapperImporter *importer, GstQuery *query)
|
||||
{
|
||||
GstClapperGLBaseImporter *self = GST_CLAPPER_GL_BASE_IMPORTER_CAST (importer);
|
||||
|
||||
gst_query_add_allocation_meta (query, GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, NULL);
|
||||
gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
if (self->gst_context->gl_vtable->FenceSync)
|
||||
gst_query_add_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, NULL);
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_clapper_gl_base_importer_gdk_context_realize (GstClapperGLBaseImporter *self, GdkGLContext *gdk_context)
|
||||
{
|
||||
GdkGLAPI allowed_apis;
|
||||
GError *error = NULL;
|
||||
const gchar *gl_env;
|
||||
gboolean success;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Realizing GdkGLContext with default implementation");
|
||||
|
||||
/* Use single "GST_GL_API" env to also influence Gdk GL selection */
|
||||
gl_env = g_getenv ("GST_GL_API");
|
||||
allowed_apis = (!gl_env || g_str_has_prefix (gl_env, "gles"))
|
||||
? GDK_GL_API_GLES
|
||||
: (g_str_has_prefix (gl_env, "opengl"))
|
||||
? GDK_GL_API_GL
|
||||
: GDK_GL_API_GL | GDK_GL_API_GLES;
|
||||
|
||||
gdk_gl_context_set_allowed_apis (gdk_context, allowed_apis);
|
||||
if (!(success = gdk_gl_context_realize (gdk_context, &error))) {
|
||||
GST_WARNING_OBJECT (self, "Could not realize Gdk context with %s: %s",
|
||||
(allowed_apis & GDK_GL_API_GL) ? "GL" : "GLES", error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
if (!success && !gl_env) {
|
||||
gdk_gl_context_set_allowed_apis (gdk_context, GDK_GL_API_GL);
|
||||
if (!(success = gdk_gl_context_realize (gdk_context, &error))) {
|
||||
GST_WARNING_OBJECT (self, "Could not realize Gdk context with GL: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_gl_base_importer_init (GstClapperGLBaseImporter *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_gl_base_importer_finalize (GObject *object)
|
||||
{
|
||||
GstClapperGLBaseImporter *self = GST_CLAPPER_GL_BASE_IMPORTER_CAST (object);
|
||||
|
||||
g_clear_object (&self->gdk_context);
|
||||
|
||||
gst_clear_object (&self->gst_display);
|
||||
gst_clear_object (&self->wrapped_context);
|
||||
gst_clear_object (&self->gst_context);
|
||||
|
||||
GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_gl_base_importer_class_init (GstClapperGLBaseImporterClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = (GObjectClass *) klass;
|
||||
GstClapperImporterClass *importer_class = (GstClapperImporterClass *) klass;
|
||||
GstClapperGLBaseImporterClass *gl_bi_class = (GstClapperGLBaseImporterClass *) klass;
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clapperglbaseimporter", 0,
|
||||
"Clapper GL Base Importer");
|
||||
|
||||
gobject_class->finalize = gst_clapper_gl_base_importer_finalize;
|
||||
|
||||
importer_class->prepare = gst_clapper_gl_base_importer_prepare;
|
||||
importer_class->share_data = gst_clapper_gl_base_importer_share_data;
|
||||
importer_class->handle_context_query = gst_clapper_gl_base_importer_handle_context_query;
|
||||
importer_class->create_pool = gst_clapper_gl_base_importer_create_pool;
|
||||
importer_class->add_allocation_metas = gst_clapper_gl_base_importer_add_allocation_metas;
|
||||
|
||||
gl_bi_class->gdk_context_realize = gst_clapper_gl_base_importer_gdk_context_realize;
|
||||
}
|
||||
|
||||
GstCaps *
|
||||
gst_clapper_gl_base_importer_make_supported_gdk_gl_caps (void)
|
||||
{
|
||||
GstCaps *caps, *tmp;
|
||||
|
||||
tmp = gst_caps_from_string (
|
||||
GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_GL_MEMORY,
|
||||
"{ " GST_GDK_GL_TEXTURE_FORMATS " }") ", "
|
||||
"texture-target = (string) { " GST_GL_TEXTURE_TARGET_2D_STR " }");
|
||||
|
||||
caps = gst_caps_copy (tmp);
|
||||
gst_caps_set_features_simple (caps, gst_caps_features_new (
|
||||
GST_CAPS_FEATURE_MEMORY_GL_MEMORY,
|
||||
GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION, NULL));
|
||||
|
||||
gst_caps_append (caps, tmp);
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
GStrv
|
||||
gst_clapper_gl_base_importer_make_gl_context_types (void)
|
||||
{
|
||||
GStrv context_types;
|
||||
GStrvBuilder *builder = g_strv_builder_new ();
|
||||
|
||||
g_strv_builder_add (builder, GST_GL_DISPLAY_CONTEXT_TYPE);
|
||||
g_strv_builder_add (builder, "gst.gl.app_context");
|
||||
g_strv_builder_add (builder, "gst.gl.local_context");
|
||||
|
||||
context_types = g_strv_builder_end (builder);
|
||||
g_strv_builder_unref (builder);
|
||||
|
||||
return context_types;
|
||||
}
|
||||
|
||||
GdkTexture *
|
||||
gst_clapper_gl_base_importer_make_gl_texture (GstClapperGLBaseImporter *self,
|
||||
GstBuffer *buffer, GstVideoInfo *v_info)
|
||||
{
|
||||
GdkTexture *texture;
|
||||
GstGLSyncMeta *sync_meta;
|
||||
GstVideoFrame frame;
|
||||
|
||||
if (G_UNLIKELY (!gst_video_frame_map (&frame, v_info, buffer, GST_MAP_READ | GST_MAP_GL))) {
|
||||
GST_ERROR_OBJECT (self, "Could not map input buffer for reading");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
|
||||
/* Must have context active here for both sync meta
|
||||
* and Gdk texture format auto-detection to work */
|
||||
gdk_gl_context_make_current (self->gdk_context);
|
||||
gst_gl_context_activate (self->wrapped_context, TRUE);
|
||||
|
||||
sync_meta = gst_buffer_get_gl_sync_meta (buffer);
|
||||
|
||||
/* Wait for all previous OpenGL commands to complete,
|
||||
* before we start using the input texture */
|
||||
if (sync_meta) {
|
||||
gst_gl_sync_meta_set_sync_point (sync_meta, self->gst_context);
|
||||
gst_gl_sync_meta_wait (sync_meta, self->wrapped_context);
|
||||
}
|
||||
|
||||
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),
|
||||
(GDestroyNotify) gst_buffer_unref,
|
||||
gst_buffer_ref (buffer));
|
||||
|
||||
gst_gl_context_activate (self->wrapped_context, FALSE);
|
||||
gdk_gl_context_clear_current ();
|
||||
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
gst_video_frame_unmap (&frame);
|
||||
|
||||
return texture;
|
||||
}
|
75
lib/gst/plugin/importers/gstclapperglbaseimporter.h
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gst/gl/gl.h>
|
||||
|
||||
#include "gst/plugin/gstclapperimporter.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_CLAPPER_GL_BASE_IMPORTER (gst_clapper_gl_base_importer_get_type())
|
||||
#define GST_IS_CLAPPER_GL_BASE_IMPORTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CLAPPER_GL_BASE_IMPORTER))
|
||||
#define GST_IS_CLAPPER_GL_BASE_IMPORTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CLAPPER_GL_BASE_IMPORTER))
|
||||
#define GST_CLAPPER_GL_BASE_IMPORTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CLAPPER_GL_BASE_IMPORTER, GstClapperGLBaseImporterClass))
|
||||
#define GST_CLAPPER_GL_BASE_IMPORTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CLAPPER_GL_BASE_IMPORTER, GstClapperGLBaseImporter))
|
||||
#define GST_CLAPPER_GL_BASE_IMPORTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_CLAPPER_GL_BASE_IMPORTER, GstClapperGLBaseImporterClass))
|
||||
#define GST_CLAPPER_GL_BASE_IMPORTER_CAST(obj) ((GstClapperGLBaseImporter *)(obj))
|
||||
|
||||
#define GST_CLAPPER_GL_BASE_IMPORTER_HAVE_WAYLAND (GST_GL_HAVE_WINDOW_WAYLAND && defined (GDK_WINDOWING_WAYLAND))
|
||||
#define GST_CLAPPER_GL_BASE_IMPORTER_HAVE_X11 (GST_GL_HAVE_WINDOW_X11 && defined (GDK_WINDOWING_X11))
|
||||
#define GST_CLAPPER_GL_BASE_IMPORTER_HAVE_X11_GLX (GST_CLAPPER_GL_BASE_IMPORTER_HAVE_X11 && GST_GL_HAVE_PLATFORM_GLX)
|
||||
#define GST_CLAPPER_GL_BASE_IMPORTER_HAVE_X11_EGL (GST_CLAPPER_GL_BASE_IMPORTER_HAVE_X11 && GST_GL_HAVE_PLATFORM_EGL)
|
||||
|
||||
typedef struct _GstClapperGLBaseImporter GstClapperGLBaseImporter;
|
||||
typedef struct _GstClapperGLBaseImporterClass GstClapperGLBaseImporterClass;
|
||||
|
||||
#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GstClapperGLBaseImporter, gst_object_unref)
|
||||
#endif
|
||||
|
||||
struct _GstClapperGLBaseImporter
|
||||
{
|
||||
GstClapperImporter parent;
|
||||
|
||||
GdkGLContext *gdk_context;
|
||||
|
||||
GstGLDisplay *gst_display;
|
||||
GstGLContext *wrapped_context;
|
||||
GstGLContext *gst_context;
|
||||
};
|
||||
|
||||
struct _GstClapperGLBaseImporterClass
|
||||
{
|
||||
GstClapperImporterClass parent_class;
|
||||
|
||||
gboolean (* gdk_context_realize) (GstClapperGLBaseImporter *gl_bi,
|
||||
GdkGLContext *gdk_context);
|
||||
};
|
||||
|
||||
GType gst_clapper_gl_base_importer_get_type (void);
|
||||
|
||||
GstCaps * gst_clapper_gl_base_importer_make_supported_gdk_gl_caps (void);
|
||||
|
||||
GStrv gst_clapper_gl_base_importer_make_gl_context_types (void);
|
||||
|
||||
GdkTexture * gst_clapper_gl_base_importer_make_gl_texture (GstClapperGLBaseImporter *self, GstBuffer *buffer, GstVideoInfo *v_info);
|
||||
|
||||
G_END_DECLS
|
70
lib/gst/plugin/importers/gstclapperglimporter.c
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gstclapperglimporter.h"
|
||||
|
||||
#define GST_CAT_DEFAULT gst_clapper_gl_importer_debug
|
||||
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
||||
|
||||
#define parent_class gst_clapper_gl_importer_parent_class
|
||||
GST_CLAPPER_IMPORTER_DEFINE (GstClapperGLImporter, gst_clapper_gl_importer, GST_TYPE_CLAPPER_GL_BASE_IMPORTER);
|
||||
|
||||
static GdkTexture *
|
||||
gst_clapper_gl_importer_generate_texture (GstClapperImporter *importer,
|
||||
GstBuffer *buffer, GstVideoInfo *v_info)
|
||||
{
|
||||
GstClapperGLBaseImporter *gl_bi = GST_CLAPPER_GL_BASE_IMPORTER_CAST (importer);
|
||||
|
||||
return gst_clapper_gl_base_importer_make_gl_texture (gl_bi, buffer, v_info);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_gl_importer_init (GstClapperGLImporter *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gst_clapper_gl_importer_class_init (GstClapperGLImporterClass *klass)
|
||||
{
|
||||
GstClapperImporterClass *importer_class = (GstClapperImporterClass *) klass;
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clapperglimporter", 0,
|
||||
"Clapper GL Importer");
|
||||
|
||||
importer_class->generate_texture = gst_clapper_gl_importer_generate_texture;
|
||||
}
|
||||
|
||||
GstClapperImporter *
|
||||
make_importer (void)
|
||||
{
|
||||
return g_object_new (GST_TYPE_CLAPPER_GL_IMPORTER, NULL);
|
||||
}
|
||||
|
||||
GstCaps *
|
||||
make_caps (GstRank *rank, GStrv *context_types)
|
||||
{
|
||||
*rank = GST_RANK_SECONDARY;
|
||||
*context_types = gst_clapper_gl_base_importer_make_gl_context_types ();
|
||||
|
||||
return gst_clapper_gl_base_importer_make_supported_gdk_gl_caps ();
|
||||
}
|