2 Commits

Author SHA1 Message Date
Rafał Dzięgiel
2076309aaa flatpak: Build gtuber 2021-10-18 15:32:55 +02:00
Rafał Dzięgiel
79618edd1e Port to new gtuber lib
Current YouTube code was broken for quite some time. Replace it with
the new Gtuber lib to make this code separate, independent and easier to maintain.
2021-10-18 15:28:34 +02:00
528 changed files with 34849 additions and 78853 deletions

5
.gitattributes vendored Normal file
View 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

View File

@@ -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

View File

@@ -1,39 +1,32 @@
on:
workflow_dispatch:
schedule:
- cron: "0 0 * * *"
name: "Flatpak Nightly"
jobs:
flatpak:
name: "Flatpak"
runs-on: ubuntu-latest
container:
image: bilelmoussaoui/flatpak-github-actions:gnome-nightly
options: --privileged
strategy:
matrix:
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
- 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 +34,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

View File

@@ -1,5 +1,4 @@
on:
workflow_dispatch:
push:
branches:
- master
@@ -10,40 +9,30 @@ name: "Flatpak"
jobs:
flatpak:
name: "Flatpak"
runs-on: ubuntu-latest
container:
image: bilelmoussaoui/flatpak-github-actions:gnome-40
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

View File

@@ -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
View File

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

View File

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

View File

@@ -2,62 +2,58 @@
[![Flatpak](https://github.com/Rafostar/clapper/actions/workflows/flatpak.yml/badge.svg?event=push)](https://github.com/Rafostar/clapper/actions/workflows/flatpak.yml)
[![Flatpak Nightly](https://github.com/Rafostar/clapper/actions/workflows/flatpak-nightly.yml/badge.svg?event=schedule)](https://github.com/Rafostar/clapper/actions/workflows/flatpak-nightly.yml)
[![Crowdin](https://badges.crowdin.net/clapper/localized.svg)](https://crowdin.com/project/clapper)
[![Matrix](https://img.shields.io/matrix/clapper-player:matrix.org?label=matrix)](https://matrix.to/#/#clapper-player:matrix.org)
[![Donate](https://img.shields.io/liberapay/receives/Clapper.svg?logo=liberapay)](https://liberapay.com/Clapper)
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'>
<img width='240' alt='Download on Flathub' src='https://flathub.org/assets/badges/flathub-badge-en.png'/>
</a>
## Packages in Linux Distributions
[![Packaging status](https://repology.org/badge/vertical-allrepos/clapper.svg)](https://repology.org/project/clapper/versions)
## Packages
#### Fedora & openSUSE
Pre-built packages are available in [my repo](https://software.opensuse.org//download.html?project=home%3ARafostar&package=clapper) ([see status](https://build.opensuse.org/package/show/home:Rafostar/clapper)).<br>
Those are automatically built on each git commit, and are thus considered unstable.
Pre-built RPM packages are also available in [my repo](https://software.opensuse.org//download.html?project=home%3ARafostar&package=clapper) ([see status](https://build.opensuse.org/package/show/home:Rafostar/clapper)).<br>
Those are automatically built on each git commit, thus are considered unstable.
#### Arch Linux
You can get Clapper from the AUR:
* [clapper](https://aur.archlinux.org/packages/clapper) (stable version)
* [clapper-git](https://aur.archlinux.org/packages/clapper-git)
## Installation from Source Code
## 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 +68,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
View 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
View 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>

View 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@ID_POSTFIX@);

28
bin/meson.build Normal file
View File

@@ -0,0 +1,28 @@
clapper_apps = ['', 'Remote', 'Daemon']
foreach id_postfix : clapper_apps
app_postfix = (id_postfix != '') ? '.' + id_postfix : ''
bin_conf = configuration_data()
bin_conf.set('GJS', find_program('gjs').path())
bin_conf.set('PACKAGE_NAME', meson.project_name())
bin_conf.set('PACKAGE_VERSION', meson.project_version())
bin_conf.set('ID_POSTFIX', id_postfix)
bin_conf.set('prefix', get_option('prefix'))
bin_conf.set('libdir', libdir)
configure_file(
input: 'com.github.rafostar.Clapper.in',
output: 'com.github.rafostar.Clapper' + app_postfix,
configuration: bin_conf,
install: true,
install_dir: bindir,
install_mode: 'rwxr-xr-x'
)
endforeach
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
View 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')])

View File

@@ -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

384
css/styles.css Normal file
View File

@@ -0,0 +1,384 @@
/* Defaults */
scale marks {
color: currentColor;
}
radio {
margin-left: -2px;
}
scrolledwindow scrollbar.vertical slider {
min-height: 16px;
}
/* Adwaita is missing osd ListBox */
.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 {
background: none;
}
.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 highlight {
border-radius: 3px;
min-height: 20px;
}
.fullscreen.tvmode .positionscale.fine-tune trough highlight {
border-radius: 3px;
min-height: 20px;
}
/* Volume Scale */
.volumescale {
margin: -2px;
margin-left: -8px;
margin-right: -6px;
min-height: 180px;
}
.fullscreen.tvmode .volumescale {
margin: 2px;
margin-left: -6px;
margin-right: -4px;
min-height: 260px;
}
.volumescale marks label {
margin-right: 4px;
margin-top: -4px;
margin-bottom: -6px;
}
.volumescale trough highlight {
min-width: 4px;
}
.fullscreen.tvmode .volumescale trough highlight {
min-width: 6px;
}
.overamp trough highlight {
background: @error_color;
}
/* Elapsed Popover */
.elapsedpopover {
min-width: 326px;
}
.fullscreen.tvmode .elapsedpopover {
min-width: 448px;
}
.elapsedpopover contents {
padding-bottom: 0px;
}
.speedscale {
margin-left: 4px;
margin-right: 4px;
}
.speedscale trough highlight {
min-height: 4px;
}
.fullscreen.tvmode .speedscale trough highlight {
min-height: 6px;
}
.narrowbutton {
min-width: 8px;
}
@keyframes halfrotation {
to { transform: rotate(0.5turn); }
}
.halfrotate {
animation-name: halfrotation;
animation-duration: 200ms;
animation-delay: 280ms;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-iteration-count: 1;
}
/* Chapters */
.chapterlabel {
min-width: 32px;
}
.fullscreen.tvmode .chapterlabel {
min-width: 40px;
text-shadow: none;
font-size: 22px;
font-weight: 600;
}
/* Open URI Dialog */
.uridialogbox {
margin: 10px;
}
/* Tweaks */
.nobackground {
background: none;
}
.noborder {
border: none;
}
.controlsbox {
background: @theme_bg_color;
}
.gpufriendly {
box-shadow: -8px -8px transparent, 8px 8px transparent;
}
.fullscreen.gpufriendlyfs {
box-shadow: none;
}
/* Error BG */
.blackbackground {
background: black;
}
/** SCALING LOW-RES **/
.fullscreen.tvmode.lowres .clappercontrols button image {
-gtk-icon-size: 22px;
}
.fullscreen.tvmode.lowres .clappercontrolsbutton {
min-width: 28px;
min-height: 28px;
}
.fullscreen.tvmode.lowres .clappercontrolsbutton.text-button label {
font-size: 21px;
}
.fullscreen.tvmode.lowres .positionscale trough highlight {
min-height: 18px;
}
.fullscreen.tvmode.lowres .positionscale.fine-tune trough highlight {
min-height: 18px;
}
.fullscreen.tvmode.lowres popover box {
font-size: 19px;
}
.fullscreen.tvmode.lowres radio {
min-width: 15px;
min-height: 15px;
}
.fullscreen.tvmode.lowres .clapperplaylist row button {
min-width: 32px;
min-height: 32px;
}
.fullscreen.tvmode.lowres .tvtitle {
font-size: 26px;
}
.fullscreen.tvmode.lowres .tvtime {
font-size: 34px;
}
.fullscreen.tvmode.lowres .tvendtime {
font-size: 21px;
}
.fullscreen.tvmode.lowres .elapsedpopover {
min-width: 410px;
}
.fullscreen.tvmode.lowres .chapterlabel {
font-size: 21px;
}
/** SCALING HI-RES **/
.fullscreen.tvmode.hires .clappercontrols button image {
-gtk-icon-size: 24px; /* Sharpest on 2160p with scaling 2x */
}

View File

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View 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>

View File

@@ -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

View File

@@ -0,0 +1,126 @@
<?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>
<!-- Gtuber -->
<key name="yt-adaptive-enabled" type="b">
<default>false</default>
<summary>Enable to use adaptive streaming</summary>
</key>
<key name="yt-quality-type" type="i">
<default>1</default>
<summary>Max online video quality type</summary>
</key>
<!-- Other -->
<key name="window-size" type="s">
<default>'[800, 490]'</default>
<summary>Stores window size to restore on next launch</summary>
</key>
<key name="volume-last" type="d">
<default>1</default>
<summary>Stores last linear volume value to apply on startup</summary>
</key>
</schema>
</schemalist>

View File

@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>com.github.rafostar.Clapper</id>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-3.0-or-later</project_license>
<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>
<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.4.0" date="2021-09-12">
<description>
<p>Changes:</p>
<ul>
<li>Now uses libadwaita</li>
<li>New and adaptive preferences window</li>
<li>Improved open URI dialog</li>
<li>Few small tweaks to fullscreen UI design</li>
<li>Show current video and audio decoders in popovers (easy way to check if HW accel is used)</li>
<li>Enabled NVDEC hardware acceleration by default (requires Nvidia proprietary drivers)</li>
<li>Added option to use PipeWire for audio output (experimental)</li>
<li>Added option to use playbin3 element (experimental)</li>
<li>New PiP icon from icon development kit</li>
<li>Improved performance on devices running OpenGL ES</li>
<li>Translations support</li>
<li>Various bug fixes</li>
</ul>
<p>New keyboard shortcuts:</p>
<ul>
<li>Leave fullscreen with Escape key</li>
<li>Toggle mute with Ctrl+M</li>
</ul>
<p>More touchscreen gestures:</p>
<ul>
<li>Toggle playback with a long press</li>
<li>Switch playlist items via double tap on screen side</li>
</ul>
<p>New translations:</p>
<ul>
<li>Catalan</li>
<li>Dutch</li>
<li>German</li>
<li>Italian</li>
<li>Polish</li>
</ul>
</description>
</release>
<release version="0.3.0" date="2021-06-18">
<description>
<p>Changes:</p>
<ul>
<li>Added MPRIS support</li>
<li>Added repeat modes: single video, whole playlist and shuffle</li>
<li>Support opening folders with media files</li>
<li>Append playlist items by holding Ctrl while doing Drag and Drop</li>
<li>Improved handling of keyboard shortcuts</li>
<li>Added more keyboard shortcuts</li>
<li>Added window that shows available keyboard shortcuts</li>
<li>Show black screen by default after playback (make showing last frame optional instead)</li>
<li>Added ability to export playlist to file</li>
<li>Improve handling of changing displays with different resolutions</li>
<li>Added support for EGL under x11 with GTK 4.3.1 or later</li>
<li>Added missing symbolic app icon</li>
<li>Some misc bug fixes and code cleanups</li>
</ul>
</description>
</release>
<release version="0.2.1" date="2021-04-19">
<description>
<p>Player:</p>
<ul>
<li>Fix missing top left menu buttons on some system configurations</li>
<li>Fix potential video sink deadlock</li>
<li>Do not show mobile controls transition on launch</li>
<li>Show tooltip with full playlist item text on hover</li>
</ul>
<p>YouTube:</p>
<ul>
<li>Auto select best matching resolution for used monitor</li>
<li>Added some YouTube related preferences</li>
<li>Added support for live HLS videos</li>
<li>Added support for non-adaptive live HLS streaming</li>
</ul>
</description>
</release>
<release version="0.2.0" date="2021-04-13">
<description>
<p>New features:</p>
<ul>
<li>YouTube support - drag and drop videos from youtube or use open URI dialog to play them</li>
<li>Added convenient ways of opening external subtitles</li>
</ul>
<p>Changes:</p>
<ul>
<li>Few GUI layout improvements</li>
<li>Simplified video sink code</li>
<li>Fixed missing Ctrl+O common keybinding</li>
<li>Fixed error when playback finishes during controls reveal animation</li>
<li>Fixed startup window size on Xorg</li>
<li>Fixed top time not showing up on fullscreen startup</li>
<li>Fixed missing file extensions in online URIs</li>
<li>Fixed some error messages not being displayed</li>
</ul>
</description>
</release>
<release version="0.1.0" date="2021-02-26">
<description>
<p>First stable release</p>
</description>
</release>
<release version="0.0.0" date="2020-10-31">
<description>
<p>GitHub version</p>
</description>
</release>
</releases>
<content_rating type="oars-1.1" />
<recommends>
<control>keyboard</control>
<control>pointing</control>
<control>touch</control>
</recommends>
<requires>
<display_length compare="ge">small</display_length>
</requires>
<custom>
<value key="Purism::form_factor">workstation</value>
<value key="Purism::form_factor">mobile</value>
</custom>
</component>

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -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>

View 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

View 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

View 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

View 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
View 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,
)

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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'),
)

View File

@@ -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).

View File

@@ -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/'],
]

View File

@@ -1,180 +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 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 or 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 [flags@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 [flags@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 while still
allowing application to override it content locally per player instance.
Extra flags like [flags@Clapper.EnhancerParamFlags.FILEPATH] and [flags@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 can browse properties of enhancer via [method@Clapper.EnhancerProxy.get_target_properties]
which returns a list of [class@GObject.ParamSpec]. By inspecting their `flags` they can know whether
property is `global`, `local` or both. Properties without any of these 2 flags set (internal ones)
will not appear on this list.
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 list.
### 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.
### Configuration Sharing in Flatpak
In native system packages/installations where property with [flags@Clapper.EnhancerParamFlags.GLOBAL] flag is set
for an enhancer, all apps get the same config values. In sandbox however, default permissions prevent access
to config of these properties, thus setting them will only affect [class@Clapper.Player] instances in this
particular application. Keep this in mind when writing your own enhancer plugin.
You can allow configuration sharing in `Flatpak` by adding below permission to each application that uses
Clapper Enhancers plugins (including Clapper itself):
```sh
--filesystem=xdg-config/clapper-0.0/enhancers:create
```
This can be done manually through either `sudo flatpak override` or tools such as
[Flatseal](https://flathub.org/apps/com.github.tchx84.Flatseal).
When this permission is set, users can configure enhancers from within Clapper application
preferences in cases when a 3rd party app does not have any UI to configure them.
Please note that when doing so, any properties storing file/directory paths as values also
need a permission override from user to access this specific file/directory. A good practice is
to create a single directory for such files and allow all `Flatpak` with enhancers to access
this directory (including subdirectories) or just store them somewhere in allowed above
user config directory (usually: `~/.config/clapper-0.0/enhancers`).

View File

@@ -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"

View File

@@ -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.

View File

@@ -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

View File

@@ -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'),
)

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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/?'],
]

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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
View 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
View 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;
}
}

View File

@@ -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
View 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
View 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__ */

View 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);
}

View 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
View 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);
}

View 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__ */

View 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
View 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
View 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 */

View 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__ */

View 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);
}

View 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__ */

View 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__ */

View 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);
}

View 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
View 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__ */

View 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;
}

View 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__ */

View 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__ */

View 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);
}

View 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__ */

View 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;
}

View 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__ */

5076
lib/gst/clapper/gstclapper.c vendored Normal file

File diff suppressed because it is too large Load Diff

318
lib/gst/clapper/gstclapper.h vendored Normal file
View 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__ */

View 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;
}

View 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__ */

View 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);
}
}

View 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__ */

View 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));
}

View File

@@ -2,7 +2,6 @@
* GStreamer
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
* Copyright (C) 2015 Thibault Saunier <tsaunier@gnome.org>
* Copyright (C) 2022 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -15,28 +14,33 @@
* 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
#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 <gtk/gtk.h>
#include <gst/video/video.h>
#include <glib-object.h>
#include "gst/plugin/clapper-gst-visibility.h"
enum
{
PROP_0,
PROP_WIDGET,
PROP_FORCE_ASPECT_RATIO,
PROP_PIXEL_ASPECT_RATIO,
PROP_KEEP_LAST_FRAME
};
G_BEGIN_DECLS
gpointer gst_gtk_invoke_on_main (GThreadFunc func, gpointer data);
CLAPPER_GST_API
gpointer gst_gtk_invoke_on_main (GThreadFunc func, gpointer data);
void gst_gtk_install_shared_properties (GObjectClass *gobject_class);
CLAPPER_GST_API
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
#endif /* __GST_GTK_UTILS_H__ */

File diff suppressed because it is too large Load Diff

View 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
View 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]
)

1
lib/gst/meson.build vendored Normal file
View File

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

271
lib/meson.build vendored Normal file
View File

@@ -0,0 +1,271 @@
glib_req = '>= 2.56.0'
gst_req = '>= 1.18.0'
api_version = '1.0'
libversion = meson.project_version()
cc = meson.get_compiler('c')
cxx = meson.get_compiler('cpp')
cdata = configuration_data()
if cc.get_id() == 'msvc'
msvc_args = [
# Ignore several spurious warnings for things gstreamer does very commonly
# If a warning is completely useless and spammy, use '/wdXXXX' to suppress it
# If a warning is harmless but hard to fix, use '/woXXXX' so it's shown once
# NOTE: Only add warnings here if you are sure they're spurious
'/wd4018', # implicit signed/unsigned conversion
'/wd4146', # unary minus on unsigned (beware INT_MIN)
'/wd4244', # lossy type conversion (e.g. double -> int)
'/wd4305', # truncating type conversion (e.g. double -> float)
cc.get_supported_arguments(['/utf-8']), # set the input encoding to utf-8
# Enable some warnings on MSVC to match GCC/Clang behaviour
'/w14062', # enumerator 'identifier' in switch of enum 'enumeration' is not handled
'/w14101', # 'identifier' : unreferenced local variable
'/w14189', # 'identifier' : local variable is initialized but not referenced
]
add_project_arguments(msvc_args, language: ['c', 'cpp'])
noseh_link_args = ['/SAFESEH:NO']
else
if cxx.has_argument('-Wno-non-virtual-dtor')
add_project_arguments('-Wno-non-virtual-dtor', language: 'cpp')
endif
noseh_link_args = []
endif
if cc.has_link_argument('-Wl,-Bsymbolic-functions')
add_project_link_arguments('-Wl,-Bsymbolic-functions', language: 'c')
endif
# Symbol visibility
if cc.get_id() == 'msvc'
export_define = '__declspec(dllexport) extern'
elif cc.has_argument('-fvisibility=hidden')
add_project_arguments('-fvisibility=hidden', language: 'c')
add_project_arguments('-fvisibility=hidden', language: 'cpp')
export_define = 'extern __attribute__ ((visibility ("default")))'
else
export_define = 'extern'
endif
# Passing this through the command line would be too messy
cdata.set('GST_API_EXPORT', export_define)
# Disable strict aliasing
if cc.has_argument('-fno-strict-aliasing')
add_project_arguments('-fno-strict-aliasing', language: 'c')
endif
if cxx.has_argument('-fno-strict-aliasing')
add_project_arguments('-fno-strict-aliasing', language: 'cpp')
endif
if not get_option('deprecated-glib-api')
message('Disabling deprecated GLib API')
add_project_arguments('-DG_DISABLE_DEPRECATED', language: 'c')
endif
if not get_option('devel-checks')
message('Disabling GLib cast checks')
add_project_arguments('-DG_DISABLE_CAST_CHECKS', language: 'c')
message('Disabling GLib asserts')
add_project_arguments('-DG_DISABLE_ASSERT', language: 'c')
message('Disabling GLib checks')
add_project_arguments('-DG_DISABLE_CHECKS', language: 'c')
endif
check_headers = [
['HAVE_DLFCN_H', 'dlfcn.h'],
['HAVE_FCNTL_H', 'fcntl.h'],
['HAVE_INTTYPES_H', 'inttypes.h'],
['HAVE_MEMORY_H', 'memory.h'],
['HAVE_NETINET_IN_H', 'netinet/in.h'],
['HAVE_NETINET_IP_H', 'netinet/ip.h'],
['HAVE_NETINET_TCP_H', 'netinet/tcp.h'],
['HAVE_PTHREAD_H', 'pthread.h'],
['HAVE_STDINT_H', 'stdint.h'],
['HAVE_STDLIB_H', 'stdlib.h'],
['HAVE_STRINGS_H', 'strings.h'],
['HAVE_STRING_H', 'string.h'],
['HAVE_SYS_PARAM_H', 'sys/param.h'],
['HAVE_SYS_SOCKET_H', 'sys/socket.h'],
['HAVE_SYS_STAT_H', 'sys/stat.h'],
['HAVE_SYS_TIME_H', 'sys/time.h'],
['HAVE_SYS_TYPES_H', 'sys/types.h'],
['HAVE_SYS_UTSNAME_H', 'sys/utsname.h'],
['HAVE_UNISTD_H', 'unistd.h'],
]
foreach h : check_headers
if cc.has_header(h.get(1))
cdata.set(h.get(0), 1)
endif
endforeach
check_functions = [
['HAVE_DCGETTEXT', 'dcgettext'],
['HAVE_GETPAGESIZE', 'getpagesize'],
['HAVE_GMTIME_R', 'gmtime_r'],
['HAVE_MEMFD_CREATE', 'memfd_create'],
['HAVE_MMAP', 'mmap'],
['HAVE_PIPE2', 'pipe2'],
['HAVE_GETRUSAGE', 'getrusage', '#include<sys/resource.h>'],
]
foreach f : check_functions
prefix = ''
if f.length() == 3
prefix = f.get(2)
endif
if cc.has_function(f.get(1), prefix: prefix)
cdata.set(f.get(0), 1)
endif
endforeach
cdata.set('SIZEOF_CHAR', cc.sizeof('char'))
cdata.set('SIZEOF_INT', cc.sizeof('int'))
cdata.set('SIZEOF_LONG', cc.sizeof('long'))
cdata.set('SIZEOF_SHORT', cc.sizeof('short'))
cdata.set('SIZEOF_VOIDP', cc.sizeof('void*'))
cdata.set_quoted('VERSION', libversion)
cdata.set_quoted('PACKAGE', 'gst-plugins-clapper')
cdata.set_quoted('PACKAGE_VERSION', libversion)
cdata.set_quoted('PACKAGE_BUGREPORT', 'https://github.com/Rafostar/clapper/issues/new')
cdata.set_quoted('PACKAGE_NAME', 'GStreamer Clapper Libs')
cdata.set_quoted('GST_API_VERSION', api_version)
cdata.set_quoted('GST_LICENSE', 'LGPL')
cdata.set_quoted('LIBDIR', pkglibdir)
cdata.set_quoted('LOCALEDIR', join_paths(get_option('prefix'), get_option('localedir')))
warning_flags = [
'-Wmissing-declarations',
'-Wredundant-decls',
'-Wwrite-strings',
'-Wformat',
'-Wformat-security',
'-Winit-self',
'-Wmissing-include-dirs',
'-Waddress',
'-Wno-multichar',
'-Wvla',
'-Wpointer-arith',
]
warning_c_flags = [
'-Wmissing-prototypes',
'-Wdeclaration-after-statement',
'-Wold-style-definition',
]
warning_cxx_flags = [
'-Wformat-nonliteral',
]
foreach extra_arg : warning_c_flags
if cc.has_argument (extra_arg)
add_project_arguments([extra_arg], language: 'c')
endif
endforeach
foreach extra_arg : warning_cxx_flags
if cxx.has_argument (extra_arg)
add_project_arguments([extra_arg], language: 'cpp')
endif
endforeach
foreach extra_arg : warning_flags
if cc.has_argument (extra_arg)
add_project_arguments([extra_arg], language: 'c')
endif
if cxx.has_argument (extra_arg)
add_project_arguments([extra_arg], language: 'cpp')
endif
endforeach
cdata.set_quoted('GST_PACKAGE_NAME', 'GStreamer Plugins Clapper')
cdata.set_quoted('GST_PACKAGE_ORIGIN', 'https://github.com/Rafostar/clapper')
# Mandatory GST deps
gst_dep = dependency('gstreamer-1.0', version: gst_req,
fallback: ['gstreamer', 'gst_dep'])
gstbase_dep = dependency('gstreamer-base-1.0', version: gst_req,
fallback: ['gstreamer', 'gst_base_dep'])
gstpbutils_dep = dependency('gstreamer-pbutils-1.0', version: gst_req,
fallback: ['gst-plugins-base', 'pbutils_dep'])
gstaudio_dep = dependency('gstreamer-audio-1.0', version: gst_req,
fallback: ['gst-plugins-base', 'audio_dep'])
gsttag_dep = dependency('gstreamer-tag-1.0', version: gst_req,
fallback: ['gst-plugins-base', 'tag_dep'])
gstvideo_dep = dependency('gstreamer-video-1.0', version: gst_req,
fallback: ['gst-plugins-base', 'video_dep'])
# GStreamer OpenGL
gstgl_dep = dependency('gstreamer-gl-1.0', version: gst_req,
fallback: ['gst-plugins-base', 'gstgl_dep'], required: true)
gstglx11_dep = dependency('', required: false)
gstglwayland_dep = dependency('', required: false)
gstglegl_dep = dependency('', required: false)
gst_gl_apis = gstgl_dep.get_pkgconfig_variable('gl_apis')
gst_gl_winsys = gstgl_dep.get_pkgconfig_variable('gl_winsys')
gst_gl_platforms = gstgl_dep.get_pkgconfig_variable('gl_platforms')
message('GStreamer OpenGL window systems: @0@'.format(gst_gl_winsys))
message('GStreamer OpenGL platforms: @0@'.format(gst_gl_platforms))
message('GStreamer OpenGL apis: @0@'.format(gst_gl_apis))
foreach ws : ['x11', 'wayland', 'android', 'cocoa', 'eagl', 'win32', 'dispmanx', 'viv_fb']
set_variable('gst_gl_have_window_@0@'.format(ws), gst_gl_winsys.contains(ws))
endforeach
foreach p : ['glx', 'egl', 'cgl', 'eagl', 'wgl']
set_variable('gst_gl_have_platform_@0@'.format(p), gst_gl_platforms.contains(p))
endforeach
foreach api : ['gl', 'gles2']
set_variable('gst_gl_have_api_@0@'.format(api), gst_gl_apis.contains(api))
endforeach
gstglproto_dep = dependency('gstreamer-gl-prototypes-1.0', version: gst_req,
fallback: ['gst-plugins-base', 'gstglproto_dep'], required: true)
if gst_gl_have_window_x11
gstglx11_dep = dependency('gstreamer-gl-x11-1.0', version: gst_req,
fallback: ['gst-plugins-base', 'gstglx11_dep'], required: true)
endif
if gst_gl_have_window_wayland
gstglwayland_dep = dependency('gstreamer-gl-wayland-1.0', version: gst_req,
fallback: ['gst-plugins-base', 'gstglwayland_dep'], required: true)
endif
if gst_gl_have_platform_egl
gstglegl_dep = dependency('gstreamer-gl-egl-1.0', version: gst_req,
fallback: ['gst-plugins-base', 'gstglegl_dep'], required: true)
endif
libm = cc.find_library('m', required: false)
glib_dep = dependency('glib-2.0', version: glib_req, fallback: ['glib', 'libglib_dep'])
gmodule_dep = dependency('gmodule-2.0', fallback: ['glib', 'libgmodule_dep'])
gio_dep = dependency('gio-2.0', fallback: ['glib', 'libgio_dep'])
giounix_dep = dependency('gio-unix-2.0', version: glib_req, fallback: ['glib', 'libgiounix_dep'])
cdata.set('DISABLE_ORC', 1)
cdata.set('GST_ENABLE_EXTRA_CHECKS', get_option('devel-checks'))
cdata.set_quoted('GST_PACKAGE_RELEASE_DATETIME', 'Unknown')
configinc = include_directories('.')
libsinc = include_directories('gst')
gir = find_program('g-ir-scanner', required: true)
if not gir.found()
error('Clapper requires GI bindings to be compiled')
endif
gir_init_section = ['--add-init-section=extern void gst_init(gint*,gchar**);' + \
'g_setenv("GST_REGISTRY_1.0", "@0@", TRUE);'.format(meson.current_build_dir() + '/gir_empty_registry.reg') + \
'g_setenv("GST_PLUGIN_PATH_1_0", "", TRUE);' + \
'g_setenv("GST_PLUGIN_SYSTEM_PATH_1_0", "", TRUE);' + \
'gst_init(NULL,NULL);', '--quiet'
]
subdir('gst')
configure_file(output: 'config.h', configuration: cdata)

View File

@@ -1,173 +1,41 @@
project('clapper', 'c',
version: '0.9.1',
meson_version: '>= 0.64.0',
license: 'LGPL-2.1-or-later AND GPL-3.0-or-later', # LGPL-2.1+ for libs and gst-plugin, GPL-3.0+ for app
project('com.github.rafostar.Clapper', 'c', 'cpp',
version: '0.4.0',
meson_version: '>= 0.50.0',
license: 'GPL-3.0-or-later',
default_options: [
'warning_level=1',
'buildtype=debugoptimized',
],
'buildtype=debugoptimized'
]
)
glib_req = '>= 2.76.0'
gst_req = '>= 1.24.0'
gtk4_req = '>= 4.10.0'
adw_req = '>= 1.5.0'
clapper_version = meson.project_version().split('-')[0]
version_array = clapper_version.split('.')
clapper_version_suffix = '-' + version_array[0] + '.0'
clapper_api_name = meson.project_name() + clapper_version_suffix
devenv = environment()
gnome = import('gnome')
pkgconfig = import('pkgconfig')
i18n = import('i18n')
python = import('python')
prefix = get_option('prefix')
bindir = get_option('bindir')
datadir = get_option('datadir')
libdir = get_option('libdir')
localedir = get_option('localedir')
includedir = get_option('includedir')
optimization = get_option('optimization')
bindir = join_paths(get_option('prefix'), get_option('bindir'))
libdir = join_paths(get_option('prefix'), get_option('libdir'))
datadir = join_paths(get_option('prefix'), get_option('datadir'))
clapper_libdir = join_paths(prefix, libdir, clapper_api_name)
build_optimized = optimization in ['2', '3', 's']
pkglibdir = join_paths(libdir, meson.project_name())
pkgdatadir = join_paths(datadir, meson.project_name())
gst_dep = dependency('gstreamer-1.0',
version: gst_req,
required: false,
)
gst_base_dep = dependency('gstreamer-base-1.0',
version: gst_req,
required: false,
)
gst_video_dep = dependency('gstreamer-video-1.0',
version: gst_req,
required: false,
)
gst_audio_dep = dependency('gstreamer-audio-1.0',
version: gst_req,
required: false,
)
gst_pbutils_dep = dependency('gstreamer-pbutils-1.0',
version: gst_req,
required: false,
)
gst_tag_dep = dependency('gstreamer-tag-1.0',
version: gst_req,
required: false,
)
glib_dep = dependency('glib-2.0',
version: glib_req,
required: false,
)
gobject_dep = dependency('gobject-2.0',
version: glib_req,
required: false,
)
gio_dep = dependency('gio-2.0',
version: glib_req,
required: false,
)
gmodule_dep = dependency('gmodule-2.0',
version: glib_req,
required: false,
)
gtk4_dep = dependency('gtk4',
version: gtk4_req,
required: false,
)
libadwaita_dep = dependency('libadwaita-1',
version: adw_req,
required: false,
)
if get_option('lib')
subdir('lib')
endif
# Optional
peas_dep = dependency('libpeas-2',
required: false,
)
cgraph_dep = dependency('libcgraph',
required: false,
)
gvc_dep = dependency('libgvc',
required: false,
)
if get_option('player')
subdir('bin')
subdir('data')
subdir('po')
cc = meson.get_compiler('c')
libm = cc.find_library('m', required: false)
install_subdir('src', install_dir: pkgdatadir)
install_subdir('extras', install_dir: pkgdatadir)
install_subdir('css', install_dir: pkgdatadir)
install_subdir('ui', install_dir: pkgdatadir)
warning_flags = [
'-Wmissing-declarations',
'-Wredundant-decls',
'-Wwrite-strings',
'-Wformat',
'-Wformat-security',
'-Winit-self',
'-Wmissing-include-dirs',
'-Waddress',
'-Wno-multichar',
'-Wvla',
'-Wpointer-arith',
'-Wmissing-prototypes',
'-Wdeclaration-after-statement',
'-Wold-style-definition',
'-Wsign-compare',
]
foreach extra_arg : warning_flags
if cc.has_argument (extra_arg)
add_project_arguments([extra_arg], language: 'c')
python_bin = python.find_installation('python3')
if not python_bin.found()
error('No valid python3 binary found')
endif
endforeach
if build_optimized
message('Disabling GLib cast checks')
add_project_arguments('-DG_DISABLE_CAST_CHECKS', language: 'c')
message('Disabling GLib asserts')
add_project_arguments('-DG_DISABLE_ASSERT', language: 'c')
message('Disabling GLib checks')
add_project_arguments('-DG_DISABLE_CHECKS', language: 'c')
endif
subdir('src')
subdir('doc')
subdir('pkgs')
meson.add_devenv(devenv)
summary({
'prefix': prefix,
'bindir': bindir,
'datadir': datadir,
'libdir': libdir,
'localedir': localedir,
'includedir': includedir,
'optimization': optimization,
}, section: 'Directories')
summary('clapper', build_clapper ? 'Yes' : 'No', section: 'Build')
summary('clapper-gtk', build_clappergtk ? 'Yes' : 'No', section: 'Build')
summary('clapper-app', build_clapperapp ? 'Yes' : 'No', section: 'Build')
summary('gst-plugin', build_gst_plugin ? 'Yes' : 'No', section: 'Build')
summary('introspection', build_gir ? 'Yes' : 'No', section: 'Build')
summary('vapi', build_vapi ? 'Yes' : 'No', section: 'Build')
summary('doc', build_doc ? 'Yes' : 'No', section: 'Build')
if build_clapper
foreach name : clapper_possible_functionalities
summary(name, clapper_available_functionalities.contains(name) ? 'Yes' : 'No', section: 'Functionalities')
endforeach
foreach name : clapper_possible_features
summary(name, clapper_available_features.contains(name) ? 'Yes' : 'No', section: 'Features')
endforeach
endif
if build_clapperapp
foreach name : clapperapp_possible_functionalities
summary(name, clapperapp_available_functionalities.contains(name) ? 'Yes' : 'No', section: 'Functionalities')
endforeach
meson.add_install_script('build-aux/meson/postinstall.py')
endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

3
pkgs/rpm/.gitignore vendored Normal file
View File

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

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