1 Commits

Author SHA1 Message Date
Rafostar
f64f438f1e API: Add playlist support 2021-06-06 19:54:56 +02:00
502 changed files with 21646 additions and 79165 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,50 +0,0 @@
on:
workflow_dispatch:
schedule:
- cron: "0 0 * * *"
name: "Flatpak Nightly"
jobs:
flatpak:
name: "Flatpak"
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
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
with:
submodules: recursive
- name: Build
uses: flatpak/flatpak-github-actions/flatpak-builder@master
with:
bundle: com.github.rafostar.Clapper.flatpak
manifest-path: pkgs/flatpak/com.github.rafostar.Clapper-nightly.json
repository-name: gnome-nightly
repository-url: https://nightly.gnome.org/gnome-nightly.flatpakrepo
cache-key: flatpak-builder-${{ github.sha }}-testing-${{ github.run_number }}
arch: ${{ matrix.arch }}
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,49 +0,0 @@
on:
workflow_dispatch:
push:
branches:
- master
pull_request:
branches:
- master
name: "Flatpak"
jobs:
flatpak:
name: "Flatpak"
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
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
with:
submodules: recursive
- name: Build
uses: flatpak/flatpak-github-actions/flatpak-builder@master
with:
bundle: com.github.rafostar.Clapper.flatpak
manifest-path: pkgs/flatpak/com.github.rafostar.Clapper.json
cache-key: flatpak-builder-${{ github.sha }}
arch: ${{ matrix.arch }}
upload-artifact: false
- name: Upload
uses: actions/upload-artifact@v4
with:
name: clapper-flatpak-${{ matrix.arch }}
path: com.github.rafostar.Clapper.flatpak
if-no-files-found: error

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

@@ -1,77 +1,71 @@
# Clapper
[![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 build using [GJS](https://gitlab.gnome.org/GNOME/gjs) with [GTK4](https://www.gtk.org) toolkit.
The media player is using [GStreamer](https://gstreamer.freedesktop.org/) as a media backend and renders everything via [OpenGL](https://www.opengl.org).
<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
## 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).
List of patches used in this version can be found [here](https://github.com/Rafostar/clapper/issues/35).
Additionally it also has a few patches, thus some functionalities work better (or are only available) in `Flatpak` version (until my changes are accepted upstream). List of patches used in this version can be found [here](https://github.com/Rafostar/clapper/issues/35).
<a href='https://flathub.org/apps/details/com.github.rafostar.Clapper'>
<img width='240' alt='Download on Flathub' src='https://flathub.org/assets/badges/flathub-badge-en.png'/>
</a>
<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)
**Important:** If you have been using the flatpak package from my custom 3rd party repo, please remove it and replace your installation with version from Flathub. That repository will not be maintained any longer. Thank you for understanding.
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.
## Packages
The [pkgs folder](https://github.com/Rafostar/clapper/tree/master/pkgs) in this repository contains build scripts for various package formats. You can use them to build package yourself or download one of pre-built packages:
## Installation from Source Code
#### Debian, Fedora & openSUSE
Pre-built packages are available in [my repo](https://software.opensuse.org//download.html?project=home%3ARafostar&package=clapper) ([see status](https://build.opensuse.org/package/show/home:Rafostar/clapper)).<br>
Those are automatically build 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
```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.
## Q&A
**Q:** Does using `GJS` negatively impact video performance?<br>
**A:** Absolutely not. `GJS` here is used to put together the GUI during startup.
It has nothing to do with video rendering. All used `GTK4` and `GStreamer` libraries are in C.
Even the custom video widget that I prepared for this player (based on original `GTK3` implementation) is a compiled C code.
All these libs are acting "on their own" and no function calls from `GJS` related to video decoding and rendering are performed during playback.
## Questions?
**Q:** What settings should I set to maximize performance?<br>
**A:** As of now, player works best on `Wayland` session. `Wayland` users can try enabling highly experimental `vah264dec` plugin for improved performance (this plugin does not work on `Xorg` right now) for standard (8-bit) `H.264` videos.
It can be enabled from inside player preferences dialog inside `Advanced -> GStreamer` tab using customizable `Plugin Ranking` feature.
Since the whole app is rendered using your GPU, users of VERY weak GPUs might want to disable the "render window shadows" option to have more GPU power available for non-fullscreen video rendering.
## Other Questions?
Feel free to ask me any questions. Come and talk on Matrix: [#clapper-player:matrix.org](https://matrix.to/#/#clapper-player:matrix.org)
## Translations
Preferred translation method is to use [Clapper Crowdin](https://crowdin.com/project/clapper) web page.
Crowdin does not require any additional tools and translating can be done through web browser.
You can login using GitHub account or create a new one. Only I can add new languages to this project,
so if your language is not available, please contact me first.
## Special Thanks
Many thanks to [sp1ritCS](https://github.com/sp1ritCS) for creating and maintaining package build files.
Big thanks to [bridadan](https://github.com/bridadan) and [Uniformbuffer3](https://github.com/Uniformbuffer3) for helping
with testing V4L2 and NVDEC hardware acceleration methods.
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
- [ ] Integration with the top bar
- [ ] MPRIS support
- [ ] Controls in the notifications panel
- [ ] Progress bar in the notifications panel (maybe via extension)

15
_service Normal file
View File

@@ -0,0 +1,15 @@
<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>
<param name="extract">pkgs/deb/clapper.dsc</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,17 @@
#!@GJS@
/* pkg init enforces the imports path to the folder
* named after the pkg name, but I would prefer to have
* the bundled subprocess stored in the same directory */
imports.searchPath.unshift('@datadir@/@PACKAGE_NAME@');
const Package = imports.package;
Package.init({
name: '@PACKAGE_NAME@.@ID_POSTFIX@',
version: '@PACKAGE_VERSION@',
prefix: '@prefix@',
libdir: '@libdir@',
datadir: '@datadir@',
});
Package.run(imports.src.main@ID_POSTFIX@);

View File

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

24
bin/meson.build Normal file
View File

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

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 +0,0 @@
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

324
css/styles.css Normal file
View File

@@ -0,0 +1,324 @@
/* Defaults */
scale marks {
color: currentColor;
}
radio {
margin-left: -2px;
}
/* Adwaita is missing osd ListBox */
.osd list {
background: none;
}
.osd list row image {
-gtk-icon-shadow: none;
}
.gtk402 trough highlight {
border-color: transparent;
}
.gtk402 .osd trough highlight {
border-color: inherit;
}
.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;
}
/* Non-osd style for popover menu */
.menupopover label {
color: @theme_text_color;
}
.menupopover arrow {
background: @theme_base_color;
border-color: @insensitive_base_color;
}
.menupopover contents {
background: @theme_base_color;
border-color: @insensitive_base_color;
}
.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;
}
.adwthemedark scale trough highlight {
filter: brightness(120%);
}
.videowidget {
min-width: 320px;
min-height: 180px;
}
.fullscreen.tvmode popover box {
text-shadow: none;
font-size: 21px;
font-weight: 500;
}
.adwicons .playercontrols {
margin-bottom: -1px;
}
.playercontrols {
margin-left: 2px;
margin-right: 2px;
}
.playercontrols button {
margin: 3px;
margin-left: 1px;
margin-right: 1px;
}
.fullscreen.tvmode .playercontrols button {
min-width: 32px;
min-height: 32px;
margin: 5px;
margin-left: 3px;
margin-right: 3px;
}
.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;
}
.fullscreen.tvmode .playercontrols button image {
-gtk-icon-size: 24px;
}
.adwicons .playbackicon {
-gtk-icon-size: 20px;
}
.adwicons.fullscreen.tvmode .playbackicon {
-gtk-icon-size: 28px;
}
.labelbuttonlabel {
margin-left: -4px;
margin-right: -4px;
min-width: 8px;
font-family: 'Cantarell', sans-serif;
font-variant-numeric: tabular-nums;
font-weight: 600;
}
.fullscreen.tvmode .labelbuttonlabel {
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;
}
/* Button Inside Popover */
.popoverbutton {
min-width: 24px;
min-height: 24px;
}
/* Position Scale */
.positionscale {
margin: -2px;
margin-left: -4px;
margin-right: -4px;
}
.positionscale trough highlight {
min-height: 4px;
}
.osd .positionscale trough highlight {
min-height: 6px;
}
.fullscreen.tvmode .positionscale trough slider {
color: transparent;
background: transparent;
border-color: transparent;
box-shadow: 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;
}
.fullscreen.tvmode .volumescale trough highlight {
min-width: 6px;
}
.overamp trough highlight {
background: @error_color;
}
/* Elapsed Popover */
.elapsedpopoverbox {
min-width: 260px;
}
.elapsedpopoverbox box separator {
background: @insensitive_fg_color;
}
.fullscreen.tvmode .elapsedpopoverbox {
min-width: 360px;
}
.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;
}
/* Preferences */
.prefsnotebook grid {
margin: 10px;
}
.prefssubpage header {
background: none;
}
.prefssubpage header tabs tab {
box-shadow: none;
margin: 0px;
margin-right: 1px;
}
.prefssubpage header tabs tab:checked {
color: initial;
background: @theme_selected_bg_color;
}
/* Open URI Dialog */
.uridialogbox {
margin: 12px;
}
/* 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;
}

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,122 @@
<?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-initial" type="s">
<default>"restore"</default>
<summary>Mode used for startup volume value</summary>
</key>
<key name="volume-value" type="i">
<default>100</default>
<summary>Custom initial volume value in percentage after startup</summary>
</key>
<key name="close-auto" type="b">
<default>false</default>
<summary>Automatically close the app after playback finishes</summary>
</key>
<!-- Behaviour -->
<key name="seeking-mode" type="s">
<default>"normal"</default>
<summary>Mode used for seeking</summary>
</key>
<key name="seeking-value" type="i">
<default>10</default>
<summary>Time amount to seek with single press of arrow keys</summary>
</key>
<key name="seeking-unit" type="s">
<default>"second"</default>
<summary>Unit to use with seeking value</summary>
</key>
<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="d">
<default>0</default>
<summary>Offset time for audio tracks relative to video (milliseconds)</summary>
</key>
<!-- Subtitles -->
<key name="subtitle-offset" type="d">
<default>0</default>
<summary>Offset time for subtitle tracks relative to video (milliseconds)</summary>
</key>
<key name="subtitle-font" type="s">
<default>"Sans 12"</default>
<summary>The subtitles font description</summary>
</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>'[{"apply":false,"name":"vah264dec","rank":300}]'</default>
<summary>Custom values for GStreamer plugin ranking</summary>
</key>
<key name="play-flags" type="i">
<default>1687</default>
<summary>Set PlayFlags for playbin</summary>
</key>
<!-- YouTube -->
<key name="yt-adaptive-enabled" type="b">
<default>false</default>
<summary>Enable to use adaptive streaming for YouTube</summary>
</key>
<key name="yt-quality-type" type="s">
<default>"hfr"</default>
<summary>Max YouTube 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,109 @@
<?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 build using GJS with GTK4 toolkit.
The media player is using GStreamer as a media backend and renders
everything via OpenGL. Player works natively on both Xorg and Wayland.
It also supports VA-API on AMD/Intel GPUs.
</p>
<p>
The media player has an adaptive GUI. When viewing videos in "Windowed Mode",
Clapper will use mostly unmodified GTK widgets to match your OS look nicely.
When player enters "Fullscreen Mode" all GUI elements will become darker, bigger
and semi-transparent for your viewing comfort. It also has a "Floating Mode" which
displays video only on top of all other windows for a PiP-like viewing experience.
Mobile friendly transitions are also supported.
</p>
<p>
For best stability Wayland session is recommended. Wayland users with AMD/Intel GPUs
can try enabling HIGHLY EXPERIMENTAL "vah264dec" plugin inside player preferences
for reduced CPU and GPU usage on standard (8-bit) H.264 videos.
</p>
</description>
<developer_name>Rafał Dzięgiel</developer_name>
<url type="homepage">https://rafostar.github.io/clapper</url>
<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.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" />
<custom>
<value key="Purism::form_factor">workstation</value>
<value key="Purism::form_factor">mobile</value>
</custom>
</component>

View File

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

After

Width:  |  Height:  |  Size: 3.4 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>

18
data/meson.build Normal file
View File

@@ -0,0 +1,18 @@
sharedir = join_paths(get_option('prefix'), 'share')
iconsdir = join_paths(sharedir, 'icons', 'hicolor')
install_data('com.github.rafostar.Clapper.svg',
install_dir: join_paths(iconsdir, 'scalable', 'apps')
)
install_data('com.github.rafostar.Clapper.gschema.xml',
install_dir: join_paths(sharedir, 'glib-2.0', 'schemas')
)
install_data('com.github.rafostar.Clapper.xml',
install_dir: join_paths(sharedir, 'mime', 'packages')
)
install_data('com.github.rafostar.Clapper.desktop',
install_dir: join_paths(sharedir, 'applications')
)
install_data('com.github.rafostar.Clapper.metainfo.xml',
install_dir: join_paths(sharedir, 'metainfo')
)

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

36
lib/gst/clapper/clapper.h vendored Normal file
View File

@@ -0,0 +1,36 @@
/* 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-playlist.h>
#include <gst/clapper/gstclapper-playlist-item.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,788 @@
/*
* 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_WRITABLE | 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_WRITABLE | 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_WRITABLE | 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_WRITABLE | 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_WRITABLE | 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_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);
GstClapperPlaylist *playlist;
GstClapperPlaylistItem *item;
GST_DEBUG ("Handle OpenUri");
playlist = gst_clapper_playlist_new ();
item = gst_clapper_playlist_item_new (uri);
gst_clapper_playlist_append (playlist, item);
gst_clapper_set_playlist (clapper, playlist);
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)
{
GstClapperMpris *self;
self = g_object_new (GST_TYPE_CLAPPER,
"own-name", own_name, "id_path", id_path,
"identity", identity, "desktop-entry", desktop_entry,
"default-art-url", default_art_url, NULL);
return self;
}

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,49 @@
/*
* 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_PLAYLIST_ITEM_PRIVATE_H__
#define __GST_CLAPPER_PLAYLIST_ITEM_PRIVATE_H__
#include "gstclapper-playlist.h"
struct _GstClapperPlaylistItem
{
GstObject parent;
/* ID of the playlist this item belongs to */
gchar *owner_uuid;
gint id;
gchar *uri;
gchar *suburi;
gchar *custom_title;
/* Signals */
gulong activated_signal_id;
};
struct _GstClapperPlaylistItemClass
{
GstObjectClass parent_class;
};
G_GNUC_INTERNAL
void gst_clapper_playlist_item_mark_added (GstClapperPlaylistItem *item, GstClapperPlaylist *playlist);
#endif /* __GST_CLAPPER_PLAYLIST_ITEM_PRIVATE_H__ */

View File

@@ -0,0 +1,281 @@
/*
* 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-playlist-item.h"
#include "gstclapper-playlist-item-private.h"
#include "gstclapper-playlist-private.h"
enum
{
PROP_0,
PROP_URI,
PROP_SUBURI,
PROP_CUSTOM_TITLE,
PROP_LAST
};
enum
{
SIGNAL_ACTIVATED,
SIGNAL_LAST
};
#define parent_class gst_clapper_playlist_item_parent_class
G_DEFINE_TYPE (GstClapperPlaylistItem, gst_clapper_playlist_item, GST_TYPE_OBJECT);
static guint signals[SIGNAL_LAST] = { 0, };
static GParamSpec *param_specs[PROP_LAST] = { NULL, };
static void gst_clapper_playlist_item_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec);
static void gst_clapper_playlist_item_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
static void gst_clapper_playlist_item_dispose (GObject * object);
static void gst_clapper_playlist_item_finalize (GObject * object);
static void
gst_clapper_playlist_item_init (GstClapperPlaylistItem * self)
{
self->owner_uuid = NULL;
self->id = -1;
self->uri = NULL;
self->suburi = NULL;
self->custom_title = NULL;
}
static void
gst_clapper_playlist_item_class_init (GstClapperPlaylistItemClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
gobject_class->set_property = gst_clapper_playlist_item_set_property;
gobject_class->get_property = gst_clapper_playlist_item_get_property;
gobject_class->dispose = gst_clapper_playlist_item_dispose;
gobject_class->finalize = gst_clapper_playlist_item_finalize;
param_specs[PROP_URI] = g_param_spec_string ("uri",
"URI", "Playlist Item URI", NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
param_specs[PROP_SUBURI] = g_param_spec_string ("suburi",
"Subtitle URI", "Playlist Item Subtitle URI", NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
param_specs[PROP_CUSTOM_TITLE] = g_param_spec_string ("custom-title",
"Custom Title", "Playlist Item Custom Title", NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, PROP_LAST, param_specs);
signals[SIGNAL_ACTIVATED] =
g_signal_new ("activated", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
NULL, NULL, G_TYPE_NONE, 0, G_TYPE_INVALID);
}
static void
gst_clapper_playlist_item_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec)
{
GstClapperPlaylistItem *self = GST_CLAPPER_PLAYLIST_ITEM (object);
switch (prop_id) {
case PROP_URI:
self->uri = g_value_dup_string (value);
break;
case PROP_SUBURI:
g_free (self->suburi);
self->suburi = g_value_dup_string (value);
break;
case PROP_CUSTOM_TITLE:
self->custom_title = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_clapper_playlist_item_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec)
{
GstClapperPlaylistItem *self = GST_CLAPPER_PLAYLIST_ITEM (object);
switch (prop_id) {
case PROP_URI:
g_value_set_string (value, self->uri);
break;
case PROP_SUBURI:
g_value_set_string (value, self->suburi);
break;
case PROP_CUSTOM_TITLE:
g_value_set_string (value, self->custom_title);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_clapper_playlist_item_dispose (GObject * object)
{
GstClapperPlaylistItem *self = GST_CLAPPER_PLAYLIST_ITEM (object);
if (self->activated_signal_id) {
g_signal_handler_disconnect (self, self->activated_signal_id);
self->activated_signal_id = 0;
}
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
gst_clapper_playlist_item_finalize (GObject * object)
{
GstClapperPlaylistItem *self = GST_CLAPPER_PLAYLIST_ITEM (object);
g_free (self->owner_uuid);
g_free (self->uri);
g_free (self->suburi);
g_free (self->custom_title);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
item_activate_cb (GstClapperPlaylistItem * self, GParamSpec * pspec,
GstClapperPlaylist * playlist)
{
gst_clapper_playlist_emit_item_activated (playlist, self);
}
void
gst_clapper_playlist_item_mark_added (GstClapperPlaylistItem * self,
GstClapperPlaylist * playlist)
{
GST_OBJECT_LOCK (self);
self->owner_uuid = g_strdup (playlist->uuid);
self->id = playlist->id_count;
self->activated_signal_id = g_signal_connect (self, "activated",
G_CALLBACK (item_activate_cb), playlist);
GST_OBJECT_UNLOCK (self);
}
/**
* gst_clapper_playlist_item_new:
*
* Creates a new #GstClapperPlaylistItem.
*
* Returns: (transfer full): a new #GstClapperPlaylistItem object.
*/
GstClapperPlaylistItem *
gst_clapper_playlist_item_new (const gchar * uri)
{
return g_object_new (GST_TYPE_CLAPPER_PLAYLIST_ITEM, "uri", uri, NULL);
}
/**
* gst_clapper_playlist_item_new_titled:
* @uri: An URI pointing to media
* @custom_title: A custom title for this item
*
* Creates a new #GstClapperPlaylistItem with a custom title.
*
* Normally item title is obtained from media info or local filename,
* use this function for online sources where media title cannot be
* determined or if you want to override original title for some reason.
*
* Returns: (transfer full): a new #GstClapperPlaylistItem object.
*/
GstClapperPlaylistItem *
gst_clapper_playlist_item_new_titled (const gchar * uri,
const gchar * custom_title)
{
return g_object_new (GST_TYPE_CLAPPER_PLAYLIST_ITEM, "uri", uri,
"custom_title", custom_title, NULL);
}
/**
* gst_clapper_playlist_item_copy:
* @item: #GstClapperPlaylistItem
*
* Duplicates a #GstClapperPlaylistItem.
*
* Duplicated items do not belong to any playlist.
* Use this function if you want to append the same
* media into another #GstClapperPlaylist instance.
*
* Returns: (transfer full): a new #GstClapperPlaylistItem object.
*/
GstClapperPlaylistItem *
gst_clapper_playlist_item_copy (GstClapperPlaylistItem * source)
{
g_return_val_if_fail (GST_IS_CLAPPER_PLAYLIST_ITEM (source), NULL);
return g_object_new (GST_TYPE_CLAPPER_PLAYLIST_ITEM, "uri", source->uri,
"suburi", source->suburi, "custom-title", source->custom_title, NULL);
}
/**
* gst_clapper_playlist_item_set_suburi:
* @item: #GstClapperPlaylistItem
* @suburi: subtitle URI
*
* Sets the external subtitle URI.
*/
void
gst_clapper_playlist_item_set_suburi (GstClapperPlaylistItem * self,
const gchar * suburi)
{
/* TODO: When setting this property for an item that is currently active,
* it should be combined with a call to
* gst_clapper_set_subtitle_track_enabled(Clapper, TRUE),
* so the subtitles are actually rendered.
*/
g_return_if_fail (GST_IS_CLAPPER_PLAYLIST_ITEM (self));
g_object_set (self, "suburi", suburi, NULL);
}
/**
* gst_clapper_playlist_item_activate:
* @item: #GstClapperPlaylistItem
*
* Activates the #GstClapperPlaylistItem.
*/
void
gst_clapper_playlist_item_activate (GstClapperPlaylistItem * self)
{
g_return_if_fail (GST_IS_CLAPPER_PLAYLIST_ITEM (self));
g_signal_emit (self, signals[SIGNAL_ACTIVATED], 0);
}

View File

@@ -0,0 +1,62 @@
/*
* 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_PLAYLIST_ITEM_H__
#define __GST_CLAPPER_PLAYLIST_ITEM_H__
#include <gst/clapper/clapper-prelude.h>
G_BEGIN_DECLS
typedef struct _GstClapperPlaylistItem GstClapperPlaylistItem;
typedef struct _GstClapperPlaylistItemClass GstClapperPlaylistItemClass;
#define GST_TYPE_CLAPPER_PLAYLIST_ITEM (gst_clapper_playlist_item_get_type ())
#define GST_IS_CLAPPER_PLAYLIST_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CLAPPER_PLAYLIST_ITEM))
#define GST_IS_CLAPPER_PLAYLIST_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CLAPPER_PLAYLIST_ITEM))
#define GST_CLAPPER_PLAYLIST_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CLAPPER_PLAYLIST_ITEM, GstClapperPlaylistItemClass))
#define GST_CLAPPER_PLAYLIST_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CLAPPER_PLAYLIST_ITEM, GstClapperPlaylistItem))
#define GST_CLAPPER_PLAYLIST_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_CLAPPER_PLAYLIST_ITEM, GstClapperPlaylistItemClass))
#define GST_CLAPPER_PLAYLIST_ITEM_CAST(obj) ((GstClapperPlaylistItem*)(obj))
#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstClapperPlaylistItem, gst_object_unref)
#endif
GST_CLAPPER_API
GType gst_clapper_playlist_item_get_type (void);
GST_CLAPPER_API
GstClapperPlaylistItem * gst_clapper_playlist_item_new (const gchar *uri);
GST_CLAPPER_API
GstClapperPlaylistItem * gst_clapper_playlist_item_new_titled (const gchar *uri, const gchar *custom_title);
GST_CLAPPER_API
GstClapperPlaylistItem * gst_clapper_playlist_item_copy (GstClapperPlaylistItem *item);
GST_CLAPPER_API
void gst_clapper_playlist_item_set_suburi (GstClapperPlaylistItem *item, const gchar *suburi);
GST_CLAPPER_API
void gst_clapper_playlist_item_activate (GstClapperPlaylistItem *item);
G_END_DECLS
#endif /* __GST_CLAPPER_PLAYLIST_ITEM_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_PLAYLIST_PRIVATE_H__
#define __GST_CLAPPER_PLAYLIST_PRIVATE_H__
#include "gstclapper-playlist.h"
struct _GstClapperPlaylist
{
GstObject parent;
gchar *uuid;
gint id_count;
GArray *items;
gint active_index;
};
struct _GstClapperPlaylistClass
{
GstObjectClass parent_class;
};
G_GNUC_INTERNAL
void gst_clapper_playlist_emit_item_activated (GstClapperPlaylist *playlist, GstClapperPlaylistItem *item);
#endif /* __GST_CLAPPER_PLAYLIST_PRIVATE_H__ */

275
lib/gst/clapper/gstclapper-playlist.c vendored Normal file
View File

@@ -0,0 +1,275 @@
/*
* 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-playlist.h"
#include "gstclapper-playlist-private.h"
#include "gstclapper-playlist-item.h"
#include "gstclapper-playlist-item-private.h"
enum
{
SIGNAL_ITEM_ACTIVATED,
SIGNAL_LAST
};
#define parent_class gst_clapper_playlist_parent_class
G_DEFINE_TYPE (GstClapperPlaylist, gst_clapper_playlist, GST_TYPE_OBJECT);
static guint signals[SIGNAL_LAST] = { 0, };
static void gst_clapper_playlist_dispose (GObject * object);
static void gst_clapper_playlist_finalize (GObject * object);
static void
gst_clapper_playlist_init (GstClapperPlaylist * self)
{
self->uuid = g_uuid_string_random ();
self->id_count = 0;
self->items = g_array_new (FALSE, FALSE, sizeof (GstClapperPlaylistItem));
self->active_index = -1;
g_array_set_clear_func (self->items, (GDestroyNotify) gst_object_unref);
}
static void
gst_clapper_playlist_class_init (GstClapperPlaylistClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
gobject_class->dispose = gst_clapper_playlist_dispose;
gobject_class->finalize = gst_clapper_playlist_finalize;
signals[SIGNAL_ITEM_ACTIVATED] =
g_signal_new ("item-activated", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_CLAPPER_PLAYLIST_ITEM);
}
static void
gst_clapper_playlist_dispose (GObject * object)
{
GstClapperPlaylist *self = GST_CLAPPER_PLAYLIST (object);
/* FIXME: Need this for something? */
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
gst_clapper_playlist_finalize (GObject * object)
{
GstClapperPlaylist *self = GST_CLAPPER_PLAYLIST (object);
g_free (self->uuid);
g_array_unref (self->items);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
void
gst_clapper_playlist_emit_item_activated (GstClapperPlaylist * self,
GstClapperPlaylistItem * item)
{
g_signal_emit (self, signals[SIGNAL_ITEM_ACTIVATED], 0, item);
}
/**
* gst_clapper_playlist_new:
*
* Creates a new #GstClapperPlaylist.
*
* Returns: (transfer full): a new #GstClapperPlaylist instance.
*/
GstClapperPlaylist *
gst_clapper_playlist_new (void)
{
return g_object_new (GST_TYPE_CLAPPER_PLAYLIST, NULL);
}
/**
* gst_clapper_playlist_append:
* @playlist: #GstClapperPlaylist
* @item: #GstClapperPlaylistItem to append
*
* Adds a new #GstClapperPlaylistItem to the end of playlist.
*
* Returns: %TRUE if the item was added successfully.
*/
gboolean
gst_clapper_playlist_append (GstClapperPlaylist * self, GstClapperPlaylistItem * item)
{
gboolean added = FALSE;
g_return_val_if_fail (GST_IS_CLAPPER_PLAYLIST (self), FALSE);
g_return_val_if_fail (GST_IS_CLAPPER_PLAYLIST_ITEM (item), FALSE);
g_return_val_if_fail (item->owner_uuid == NULL, FALSE);
GST_OBJECT_LOCK (self);
added = g_array_append_val (self->items, item) != NULL;
if (added) {
gst_clapper_playlist_item_mark_added (item, self);
self->id_count++;
}
GST_OBJECT_UNLOCK (self);
return added;
}
/**
* gst_clapper_playlist_get_length:
* @playlist: #GstClapperPlaylist
*
* Returns: Amount of items in playlist.
*/
guint
gst_clapper_playlist_get_length (GstClapperPlaylist * self)
{
guint len;
g_return_val_if_fail (GST_IS_CLAPPER_PLAYLIST (self), 0);
GST_OBJECT_LOCK (self);
len = self->items->len;
GST_OBJECT_UNLOCK (self);
return len;
}
/**
* gst_clapper_playlist_get_item_at_index:
* @playlist: #GstClapperPlaylist
*
* Returns: (transfer none): A #GstClapperPlaylistItem at given index.
*/
GstClapperPlaylistItem *
gst_clapper_playlist_get_item_at_index (GstClapperPlaylist * self, gint index)
{
GstClapperPlaylistItem *item = NULL;
g_return_val_if_fail (GST_IS_CLAPPER_PLAYLIST (self), NULL);
GST_OBJECT_LOCK (self);
if (index < self->items->len)
goto out;
item = &g_array_index (self->items, GstClapperPlaylistItem, index);
out:
GST_OBJECT_UNLOCK (self);
return item;
}
/**
* gst_clapper_playlist_get_active_item:
* @playlist: #GstClapperPlaylist
*
* Returns: (transfer none): A #GstClapperPlaylistItem that is
* currently playing.
*/
GstClapperPlaylistItem *
gst_clapper_playlist_get_active_item (GstClapperPlaylist * self)
{
gint active_index;
GST_OBJECT_LOCK (self);
active_index = self->active_index;
GST_OBJECT_UNLOCK (self);
return gst_clapper_playlist_get_item_at_index (self, active_index);
}
/**
* gst_clapper_playlist_remove_item_at_index:
* @playlist: #GstClapperPlaylist
* @index: Index of #GstClapperPlaylistItem to remove
*
* Removes item at given index from playlist.
*
* Returns: %TRUE if the item was removed successfully.
*/
gboolean
gst_clapper_playlist_remove_item_at_index (GstClapperPlaylist * self, guint index)
{
gboolean removed = FALSE;
g_return_val_if_fail (GST_IS_CLAPPER_PLAYLIST (self), FALSE);
GST_OBJECT_LOCK (self);
if (index >= self->items->len || index == self->active_index)
goto out;
removed = g_array_remove_index (self->items, index) != NULL;
out:
GST_OBJECT_UNLOCK (self);
return removed;
}
/**
* gst_clapper_playlist_remove_item:
* @playlist: #GstClapperPlaylist
* @item: #GstClapperPlaylistItem object to remove
*
* Removes given playlist item from playlist.
*
* Returns: %TRUE if the item was removed successfully.
*/
gboolean
gst_clapper_playlist_remove_item (GstClapperPlaylist * self,
GstClapperPlaylistItem * item)
{
gint i;
gboolean removed = FALSE;
g_return_val_if_fail (GST_IS_CLAPPER_PLAYLIST (self), FALSE);
g_return_val_if_fail (GST_IS_CLAPPER_PLAYLIST_ITEM (item), FALSE);
GST_OBJECT_LOCK (self);
if (strcmp (self->uuid, item->owner_uuid) != 0)
goto out;
for (i = 0; i < self->items->len; i++) {
GstClapperPlaylistItem *curr_item;
curr_item = &g_array_index (self->items, GstClapperPlaylistItem, i);
if (!curr_item)
goto out;
if (item->id == curr_item->id) {
removed = g_array_remove_index (self->items, i) != NULL;
break;
}
}
out:
GST_OBJECT_UNLOCK (self);
return removed;
}

71
lib/gst/clapper/gstclapper-playlist.h vendored Normal file
View File

@@ -0,0 +1,71 @@
/*
* 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_PLAYLIST_H__
#define __GST_CLAPPER_PLAYLIST_H__
#include <gst/clapper/clapper-prelude.h>
#include <gst/clapper/gstclapper-playlist-item.h>
G_BEGIN_DECLS
typedef struct _GstClapperPlaylist GstClapperPlaylist;
typedef struct _GstClapperPlaylistClass GstClapperPlaylistClass;
#define GST_TYPE_CLAPPER_PLAYLIST (gst_clapper_playlist_get_type ())
#define GST_IS_CLAPPER_PLAYLIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CLAPPER_PLAYLIST))
#define GST_IS_CLAPPER_PLAYLIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CLAPPER_PLAYLIST))
#define GST_CLAPPER_PLAYLIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CLAPPER_PLAYLIST, GstClapperPlaylistClass))
#define GST_CLAPPER_PLAYLIST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CLAPPER_PLAYLIST, GstClapperPlaylist))
#define GST_CLAPPER_PLAYLIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_CLAPPER_PLAYLIST, GstClapperPlaylistClass))
#define GST_CLAPPER_PLAYLIST_CAST(obj) ((GstClapperPlaylist*)(obj))
#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstClapperPlaylist, g_object_unref)
#endif
GST_CLAPPER_API
GType gst_clapper_playlist_get_type (void);
GST_CLAPPER_API
GstClapperPlaylist * gst_clapper_playlist_new (void);
GST_CLAPPER_API
gboolean gst_clapper_playlist_append (GstClapperPlaylist *playlist, GstClapperPlaylistItem *item);
GST_CLAPPER_API
guint gst_clapper_playlist_get_length (GstClapperPlaylist *playlist);
GST_CLAPPER_API
GstClapperPlaylistItem *
gst_clapper_playlist_get_item_at_index (GstClapperPlaylist *playlist, gint index);
GST_CLAPPER_API
GstClapperPlaylistItem *
gst_clapper_playlist_get_active_item (GstClapperPlaylist *playlist);
GST_CLAPPER_API
gboolean gst_clapper_playlist_remove_item_at_index (GstClapperPlaylist *playlist, guint index);
GST_CLAPPER_API
gboolean gst_clapper_playlist_remove_item (GstClapperPlaylist *playlist, GstClapperPlaylistItem *item);
G_END_DECLS
#endif /* __GST_CLAPPER_PLAYLIST_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__ */

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

File diff suppressed because it is too large Load Diff

308
lib/gst/clapper/gstclapper.h vendored Normal file
View File

@@ -0,0 +1,308 @@
/* 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-playlist.h>
#include <gst/clapper/gstclapper-playlist-item.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
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
void gst_clapper_set_playlist (GstClapper *clapper, GstClapperPlaylist *playlist);
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,732 @@
/*
* 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 DEFAULT_FORCE_ASPECT_RATIO TRUE
#define DEFAULT_PAR_N 0
#define DEFAULT_PAR_D 1
static GstStaticPadTemplate gst_clapper_gl_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
(GST_CAPS_FEATURE_MEMORY_GL_MEMORY, "RGBA") "; "
GST_VIDEO_CAPS_MAKE_WITH_FEATURES
(GST_CAPS_FEATURE_MEMORY_GL_MEMORY ", "
GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION, "RGBA")));
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 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);
enum
{
PROP_0,
PROP_WIDGET,
PROP_FORCE_ASPECT_RATIO,
PROP_PIXEL_ASPECT_RATIO,
};
#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;
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));
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));
gobject_class->finalize = gst_clapper_gl_sink_finalize;
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;
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;
}
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 ();
clapper_sink->bind_aspect_ratio =
g_object_bind_property (clapper_sink, "force-aspect-ratio", clapper_sink->widget,
"force-aspect-ratio", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
clapper_sink->bind_pixel_aspect_ratio =
g_object_bind_property (clapper_sink, "pixel-aspect-ratio", clapper_sink->widget,
"pixel-aspect-ratio", 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;
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;
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))
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:
{
if (gst_gl_handle_context_query ((GstElement *) clapper_sink, query,
clapper_sink->display, clapper_sink->context, clapper_sink->gtk_context))
return TRUE;
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);
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 = TRUE;
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);
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;
}
GST_OBJECT_UNLOCK (clapper_sink);
return TRUE;
}
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,106 @@
/*
* 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;
/* properties */
gboolean force_aspect_ratio;
GBinding *bind_aspect_ratio;
gint par_n, par_d;
GBinding *bind_pixel_aspect_ratio;
gboolean ignore_textures;
GBinding *bind_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,71 @@
/*
* GStreamer
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
* Copyright (C) 2015 Thibault Saunier <tsaunier@gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "gstgtkutils.h"
struct invoke_context
{
GThreadFunc func;
gpointer data;
GMutex lock;
GCond cond;
gboolean fired;
gpointer res;
};
static gboolean
gst_gtk_invoke_func (struct invoke_context *info)
{
g_mutex_lock (&info->lock);
info->res = info->func (info->data);
info->fired = TRUE;
g_cond_signal (&info->cond);
g_mutex_unlock (&info->lock);
return G_SOURCE_REMOVE;
}
gpointer
gst_gtk_invoke_on_main (GThreadFunc func, gpointer data)
{
GMainContext *main_context = g_main_context_default ();
struct invoke_context info;
g_mutex_init (&info.lock);
g_cond_init (&info.cond);
info.fired = FALSE;
info.func = func;
info.data = data;
g_main_context_invoke (main_context, (GSourceFunc) gst_gtk_invoke_func,
&info);
g_mutex_lock (&info.lock);
while (!info.fired)
g_cond_wait (&info.cond, &info.lock);
g_mutex_unlock (&info.lock);
g_mutex_clear (&info.lock);
g_cond_clear (&info.cond);
return info.res;
}

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,16 @@
* 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__
#include <glib.h>
#include <gtk/gtk.h>
#include <gst/video/video.h>
#include "gst/plugin/clapper-gst-visibility.h"
gpointer gst_gtk_invoke_on_main (GThreadFunc func, gpointer data);
G_BEGIN_DECLS
CLAPPER_GST_API
gpointer gst_gtk_invoke_on_main (GThreadFunc func, gpointer data);
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,111 @@
/*
* 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;
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);
G_END_DECLS
#endif /* __GTK_CLAPPER_GL_WIDGET_H__ */

111
lib/gst/clapper/meson.build vendored Normal file
View File

@@ -0,0 +1,111 @@
gnome = import('gnome')
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-playlist.c',
'gstclapper-playlist-item.c',
'gstclapper-mpris.c',
'gstclapper-gtk4-plugin.c',
'gtk4/gstclapperglsink.c',
'gtk4/gstgtkutils.c',
'gtk4/gtkclapperglwidget.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-playlist.h',
'gstclapper-playlist-item.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 : clapper_libdir,
dependencies : [gtk4_dep, glib_dep, gio_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(clapper_libdir, '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')

284
lib/meson.build vendored Normal file
View File

@@ -0,0 +1,284 @@
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')
clapper_libdir = join_paths(
get_option('prefix'), get_option('libdir'), meson.project_name()
)
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', clapper_libdir)
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'])
cdata.set('DISABLE_ORC', 1)
cdata.set('GST_ENABLE_EXTRA_CHECKS', get_option('devel-checks'))
cdata.set_quoted('GST_PACKAGE_RELEASE_DATETIME', 'Unknown')
message('GStreamer debug system is disabled')
if cc.has_argument('-Wno-unused')
add_project_arguments('-Wno-unused', language: 'c')
endif
if cxx.has_argument ('-Wno-unused')
add_project_arguments('-Wno-unused', language: 'cpp')
endif
configinc = include_directories('.')
libsinc = include_directories('gst')
gnome = import('gnome')
gir = find_program('g-ir-scanner', required : true)
if not gir.found()
error('Clapper requires GI bindings to be compiled')
endif
gir_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,33 @@
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.2.1',
meson_version: '>= 0.50.0',
license: 'GPL3',
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'
python = import('python')
python_bin = python.find_installation('python3')
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')
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')
clapper_libdir = join_paths(prefix, libdir, clapper_api_name)
build_optimized = optimization in ['2', '3', 's']
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,
)
# Optional
peas_dep = dependency('libpeas-2',
required: false,
)
cgraph_dep = dependency('libcgraph',
required: false,
)
gvc_dep = dependency('libgvc',
required: false,
)
cc = meson.get_compiler('c')
libm = cc.find_library('m', required: false)
warning_flags = [
'-Wmissing-declarations',
'-Wredundant-decls',
'-Wwrite-strings',
'-Wformat',
'-Wformat-security',
'-Winit-self',
'-Wmissing-include-dirs',
'-Waddress',
'-Wno-multichar',
'-Wvla',
'-Wpointer-arith',
'-Wmissing-prototypes',
'-Wdeclaration-after-statement',
'-Wold-style-definition',
'-Wsign-compare',
]
foreach extra_arg : warning_flags
if cc.has_argument (extra_arg)
add_project_arguments([extra_arg], language: 'c')
endif
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')
if not python_bin.found()
error('No valid python3 binary found')
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
if get_option('clapper-lib')
subdir('lib')
endif
if build_clapperapp
foreach name : clapperapp_possible_functionalities
summary(name, clapperapp_available_functionalities.contains(name) ? 'Yes' : 'No', section: 'Functionalities')
endforeach
if get_option('clapper-player')
subdir('bin')
subdir('data')
installdir = join_paths(get_option('prefix'), 'share', meson.project_name())
install_subdir('src', install_dir : installdir)
install_subdir('extras', install_dir : installdir)
install_subdir('css', install_dir : installdir)
install_subdir('ui', install_dir : installdir)
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('clapper-player',
type : 'boolean',
value : true,
description: 'Build Clapper player'
)
option('clapper-gtk',
type: 'feature',
value: 'auto',
description: 'Build Clapper GTK integration library'
option('clapper-lib',
type : 'boolean',
value : true,
description: 'Build Clapper libs (including API)'
)
option('clapper-app',
type: 'feature',
value: 'auto',
description: 'Build Clapper application'
option('devel-checks',
type : 'boolean',
value : false,
description: 'GStreamer GLib checks and asserts such as API guards (disable for stable releases)'
)
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',
type: 'boolean',
value: false,
description: 'Build documentation'
)
# 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'
)

29
pkgs/arch/.SRCINFO Normal file
View File

@@ -0,0 +1,29 @@
pkgbase = clapper-git
pkgdesc = A GNOME media player built using GJS with GTK4 toolkit and powered by GStreamer with OpenGL rendering.
pkgver = r393.bf04af2
pkgrel = 1
url = https://github.com/Rafostar/clapper
arch = any
license = GPL-3.0
makedepends = meson>=0.50
makedepends = git
depends = gtk4
depends = gjs
depends = glib2>=2.56.0
depends = gobject-introspection
depends = wayland-protocols
depends = hicolor-icon-theme
depends = gstreamer>=1.18.0
depends = gst-plugins-base-libs>=1.18.0
depends = gst-plugins-good>=1.18.0
depends = gst-plugins-bad-libs>=1.18.0
optdepends = gst-libav>=1.18.0: Popular video decoders
optdepends = gstreamer-vaapi>=1.18.0: Intel/AMD video acceleration
provides = clapper
conflicts = clapper
replaces = clapper
source = clapper::git+https://github.com/Rafostar/clapper.git
md5sums = SKIP
pkgname = clapper-git

4
pkgs/arch/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
clapper-*/
clapper-*.pkg.tar.*
pkg/
src/

74
pkgs/arch/PKGBUILD Normal file
View File

@@ -0,0 +1,74 @@
#
# PKGBUILD file for package clapper
#
# Copyright (C) 2020/21 sp1rit
# Copyright (C) 2020 Rafostar
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# Maintainer: sp1rit <sp1ritCS@protonmail.com>
_basename=clapper
pkgname="${_basename}-git"
pkgver=r393.bf04af2
pkgrel=1
pkgdesc="A GNOME media player built using GJS with GTK4 toolkit and powered by GStreamer with OpenGL rendering."
arch=(any)
url="https://github.com/Rafostar/clapper"
license=("GPL-3.0")
depends=(
"gtk4"
"gjs"
"glib2>=2.56.0" # glib-2.0, gmodule-2.0, gio-2.0
"gobject-introspection" # /usr/sbin/g-ir-scanner
"wayland-protocols" # gtk4 non-default runtime dep
"hicolor-icon-theme"
"gstreamer>=1.18.0" # gstreamer-1.0, gstreamer-base-1.0
"gst-plugins-base-libs>=1.18.0" # gstreamer-pbutils-1.0, gstreamer-audio-1.0, gstreamer-tag-1.0, gstreamer-video-1.0, gstreamer-gl-1.0, gstreamer-gl-prototypes-1.0, gstreamer-gl-x11-1.0, gstreamer-gl-wayland-1.0, gstreamer-gl-egl-1.0,
"gst-plugins-good>=1.18.0"
"gst-plugins-bad-libs>=1.18.0"
)
makedepends=(
"meson>=0.50"
"git"
)
optdepends=(
"gst-libav>=1.18.0: Popular video decoders"
"gstreamer-vaapi>=1.18.0: Intel/AMD video acceleration"
)
source=("${_basename}::git+https://github.com/Rafostar/${_basename}.git")
provides=("${_basename}")
replaces=("${_basename}")
conflicts=("${_basename}")
md5sums=("SKIP")
pkgver() {
cd "${srcdir}/${_basename}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${_basename}"
arch-meson . _build
}
build() {
cd "${srcdir}/${_basename}"
ninja -C _build
}
package() {
cd "${srcdir}/${_basename}"
DESTDIR="$pkgdir" meson install -C _build/
}

28
pkgs/deb/clapper.dsc Normal file
View File

@@ -0,0 +1,28 @@
Format: 3.0 (quilt)
Source: clapper
Binary: clapper
Architecture: any
Version: 0.2.1
Maintainer: Rafostar <rafostar.github@gmail.com>
Build-Depends: debhelper (>= 10),
meson (>= 0.50),
gjs,
gobject-introspection,
libgtk-4-dev (>= 4.0.0),
libgstreamer1.0-dev (>= 1.18),
libgstreamer-plugins-base1.0-dev (>= 1.18),
libgstreamer-gl1.0-0 (>= 1.18),
libgles-dev,
libglib2.0-dev,
libglib2.0-bin,
desktop-file-utils,
hicolor-icon-theme,
brz,
libfontconfig1-dev,
libpam-systemd
Package-List:
clapper deb gnome optional arch=any
Files:
0 0 debian.tar.xz
Description: Simple and modern GNOME media player
A GNOME media player built using GJS with GTK4 toolkit and powered by GStreamer with OpenGL rendering.

View File

@@ -0,0 +1,5 @@
clapper (0.2.1) unstable; urgency=low
* New version
-- Rafostar <rafostar.github@gmail.com> Mon, 19 Apr 2021 09:39:00 +0100

1
pkgs/deb/debian/compat Normal file
View File

@@ -0,0 +1 @@
10

37
pkgs/deb/debian/control Normal file
View File

@@ -0,0 +1,37 @@
Source: clapper
Section: gnome
Priority: optional
Maintainer: Rafostar <rafostar.github@gmail.com>
Standards-Version: 4.4.0
Build-Depends: debhelper (>= 10),
meson (>= 0.50),
gjs,
gobject-introspection,
libgtk-4-dev (>= 4.0.0),
libgstreamer1.0-dev (>= 1.18),
libgstreamer-plugins-base1.0-dev (>= 1.18),
libgstreamer-gl1.0-0 (>= 1.18),
libgles-dev,
libglib2.0-dev,
libglib2.0-bin,
desktop-file-utils,
hicolor-icon-theme
Package: clapper
Architecture: any
Depends: gjs,
gir1.2-gtk-4.0 (>= 4.0.0),
hicolor-icon-theme,
libgstreamer1.0-0 (>= 1.18),
gstreamer1.0-plugins-base (>= 1.18),
gstreamer1.0-plugins-good (>= 1.18),
gstreamer1.0-plugins-bad (>= 1.18),
gstreamer1.0-gl (>= 1.18)
Recommends: gstreamer1.0-libav,
gstreamer1.0-pulseaudio
Suggests: gstreamer1.0-plugins-ugly,
gstreamer1.0-vaapi
Description: Simple and modern GNOME media player
A GNOME media player built using GJS with GTK4 toolkit and powered by GStreamer with OpenGL rendering.
.
More codecs/features and video acceleration can be enabled by installing the suggested packages.

27
pkgs/deb/debian/copyright Normal file
View File

@@ -0,0 +1,27 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: clapper
Source: https://github.com/Rafostar/clapper
Files: *
Copyright: 2020 Rafostar <rafostar.github@gmail.com>
License: GPL-3.0+
Files: debian/*
Copyright: 2020 Rafostar <rafostar.github@gmail.com>
License: GPL-3.0+
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
.
On Debian systems, the complete text of the GNU General Public License
Version 3 can be found in `/usr/share/common-licenses/GPL-3'.

4
pkgs/deb/debian/rules Executable file
View File

@@ -0,0 +1,4 @@
#!/usr/bin/make -f
%:
dh $@

View File

@@ -0,0 +1 @@
3.0 (quilt)

View File

@@ -1,86 +0,0 @@
{
"app-id": "com.github.rafostar.Clapper",
"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,
"finish-args": [
"--share=ipc",
"--socket=fallback-x11",
"--socket=wayland",
"--device=dri",
"--socket=pulseaudio",
"--share=network",
"--device=all",
"--filesystem=xdg-run/pipewire-0:ro",
"--filesystem=xdg-videos",
"--filesystem=xdg-run/gvfsd",
"--own-name=org.mpris.MediaPlayer2.Clapper.*",
"--talk-name=org.gtk.vfs.*",
"--env=GST_PLUGIN_SYSTEM_PATH=/app/lib/gstreamer-1.0",
"--env=CLAPPER_ENHANCERS_PATH=/app/extensions/clapper/enhancers/plugins",
"--env=PYTHONPATH=/app/extensions/clapper/enhancers/python/site-packages"
],
"build-options": {
"append-path": "/usr/lib/sdk/rust-stable/bin:/usr/lib/sdk/llvm18/bin",
"prepend-ld-library-path": "/usr/lib/sdk/llvm18/lib",
"env": {
"CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER": "clang",
"CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUSTFLAGS": "-C link-arg=-fuse-ld=/usr/lib/sdk/rust-stable/bin/mold",
"CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER": "clang",
"CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUSTFLAGS": "-C link-arg=-fuse-ld=/usr/lib/sdk/rust-stable/bin/mold"
}
},
"modules": [
"flathub/shared-modules/gudev/gudev.json",
"flathub/lib/liba52.json",
"flathub/lib/libmpeg2.json",
"flathub/lib/libdv.json",
"flathub/lib/libdvdcss.json",
"flathub/lib/libdvdread.json",
"flathub/lib/libdvdnav.json",
"flathub/lib/libass.json",
"flathub/lib/libmicrodns.json",
"flathub/lib/libpeas.json",
"testing/dav1d.json",
"testing/gstreamer.json",
"testing/gst-plugins-rs.json",
"testing/graphviz.json",
{
"name": "clapper",
"buildsystem": "meson",
"sources": [
{
"type": "dir",
"path": "../../."
}
]
}
],
"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",
@@ -29,29 +12,34 @@
"--socket=pulseaudio",
"--share=network",
"--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/lib/glib-networking.json",
"flathub/shared-modules/gudev/gudev.json",
"flathub/lib/pango.json",
"flathub/lib/libsass.json",
"flathub/lib/sassc.json",
"flathub/lib/gtk4.json",
"flathub/lib/liba52.json",
"flathub/lib/libmpeg2.json",
"flathub/lib/libdv.json",
"flathub/lib/libdvdcss.json",
"flathub/lib/libdvdread.json",
"flathub/lib/libdvdnav.json",
"flathub/lib/libass.json",
"flathub/lib/ffmpeg.json",
"flathub/lib/uchardet.json",
"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",
{
"name": "clapper",
"buildsystem": "meson",
@@ -62,10 +50,5 @@
}
]
}
],
"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/"
]
}

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