Compare commits

...

23 commits

Author SHA1 Message Date
Seungha Yang 209621552a Merge branch 'h264-ccextractor' into 'main'
closedcaption: Add closed caption extractor element for H.264 stream

See merge request gstreamer/gstreamer!6580
2024-04-27 16:03:27 +00:00
Nirbheek Chauhan d7eeb62f38 meson: Fix Python library searching on Windows
Neither LIBDIR nor LIBPL are set with the native windows Python
(unlike MSYS2), so we need to use `prefix` which takes us to the
rootdir of the Python installation.

The name is also different: it's python312.dll, not python3.12.dll.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6734>
2024-04-27 01:30:21 +00:00
Nirbheek Chauhan 753aeccde7 meson: Fix Python library name fetching on Windows
`python.get_variable('FOO', [])` becomes `python.get_variable('FOO')`
due to how Meson treats empty arrays in arguments, which breaks the
fallback feature of get_variable().

So we need to actually check whether the variable exists before trying
to fetch it.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6734>
2024-04-27 01:30:21 +00:00
Tim-Philipp Müller 7074849c5c exif: add debug category
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6741>
2024-04-27 00:19:30 +00:00
Xavier Claessens f0ef33d018 unixfd: Close file descriptors on error
After calling g_unix_fd_list_steal_fds() and before calling
gst_fd_allocator_alloc(), we are responsible for closing those fds.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6532>
2024-04-26 18:52:19 +00:00
Xavier Claessens 1f8accbc8d unixfdsink: Take segment into account when converting timestamps
Also rename `calculate_timestamp()` to `to_monotonic()` and
`from_monotonic()` which better describe what it does.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6532>
2024-04-26 18:52:19 +00:00
Xavier Claessens 7f47dba299 unixfd: Allow sending buffers with no memories
There is no reason to not allow it, and it is useful for simple unit
test.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6532>
2024-04-26 18:52:18 +00:00
Víctor Manuel Jáquez Leal 1f080391ed vulkan: replace gst_vulkan_queue_create_decoder() with gst_vulkan_decoder_new_from_queue()
The purpose of this refactor is to hide decoding code from public API.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6723>
2024-04-26 16:24:22 +00:00
Víctor Manuel Jáquez Leal 18c32272bd vulkan: conceal unused decoder symbols
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6723>
2024-04-26 16:24:22 +00:00
Víctor Manuel Jáquez Leal 668b395a38 vulkan: conceal decoder from public API
Since we don't want to expose video decoding API outside of GStreamer, the
header is removed from installation and both source files are renamed as
-private.

The header must remain in gst-libs because is referred by GstVulkanQueue,
which's the decoder factory.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6723>
2024-04-26 16:24:22 +00:00
Víctor Manuel Jáquez Leal 547e2899d1 vaallocator: disable derived all together for Mesa <23.3
First it derived mapping was disabled for P010 formats, but also there's an
issue with interlaced frames.

It would be possible to disable derived mapping only for interlaced (H.264
decoder and vadeinterlace) but it would spread the hacks along the code. It's
simpler and contained to disable derived completely for Mesa <23.3

Fixes: #3450
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6729>
2024-04-26 15:41:39 +00:00
Víctor Manuel Jáquez Leal 7eb08feeee va: videoformat: use video library to get DRM fourcc
Instead of duplicating the GStreamer format to DRM fourcc mapping, this patch
uses the GstVideo library helpers. This duplicates the big O of looking for,
since the two lists are traversed, but it's less error prone.

Partially reverts commit 547f3e8622.

Fixes: #3354
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6731>
2024-04-26 15:10:36 +02:00
Edward Hervey 8737b9ca84 playbin3: Handle combiner update in case of errors
The assertion that was present before is a bit too harsh, since there is now
a (understandable) use-case where this could happen.

In gapless use-case, with two files containing the same type (ex:audio). The
first one *does* expose a collection with an audio stream, but decoding
fails (for whatever reason).

That would cause us to have configured a audio combiner, which was never
used (i.e. not active).

Then the second file plays and we (wrongly) assume it should be activated
... whereas the combiner was indeed present.

Demote the assertion to a warning and properly handle it

Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/3389

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6737>
2024-04-26 11:31:32 +00:00
Tim Blechmann ff7b41ac86 soup: fix thread name
thread names should be below 16char, otherwise they won't be shown on
linux.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6736>
2024-04-26 09:45:49 +08:00
Hou Qi be7ba5ac51 wlwindow: free staged buffer when do gst_wl_window_finalize
If waylandsink received buffer rate is high which causes frame
drop, the cached staged buffer will be replaced when next buffer
needs to be rendered and be freed after redraw. But there is
chance to get memory leak if ended without redraw. So need to
free staged buffer when do gst_wl_window_finalize().

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6670>
2024-04-25 23:55:42 +00:00
Seungha Yang 4ac46ce82b d3d12screencapturesrc: Performance improvement
Process captured frame using d3d11 instead of d3d12, and use shared
fence when copying processed d3d11 texture to d3d12 resource.
In this way, capture CPU thread does not need to wait for fence signal.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6733>
2024-04-25 22:51:01 +00:00
Xavier Claessens 364d0ff45d pad: gst_pad_set_offset is only reliable on source pads
Setting an offset on sink pads won't repush segment event which means
buffer running time won't be adjusted. Better warn about this than being
silently not working.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6464>
2024-04-25 13:49:03 +00:00
Nirbheek Chauhan e7598ed521 rsvg: Disable deprecations instead of porting to new librsvg API
`rsvg_handle_get_dimensions()` and `rsvg_handle_render_cairo()` are
deprecated, and the replacement librsvg functions as specified in the
migration guide are `rsvg_handle_get_intrinsic_size_in_pixels()` and
`rsvg_handle_render_document()`.

However, those are not drop-in replacements, and actually have
breaking semantics for our use-case:

1. `intrinsic_size_in_pixels()` requires SVGs to have width+height or
   the viewBox attribute, but `get_dimensions()` does not. It will
   calculate the geometry based on element extents recursively.
2. `render_cairo()` simply renders the SVG at its intrinsic size on
   the specified surface starting at the top-left, maintaining
   whatever transformations have been applied to the cairo surface,
   including distorted aspect ratio.
   However, `render_document()` does not do that, it is specifically
   for rendering at the specified aspect ratio inside the specified
   viewport, and if you specify a viewPort that does not match the
   aspect ratio of the SVG, librsvg will center it.

Matching the old behaviour with the new APIs is a lot of work for no
benefit. We'd be duplicating code that is already there in librsvg in
one case and undoing work that librsvg is doing in the other case.

The aspect ratio handling in this element is also kinda atrocious.
There is no option to scale the SVG while maintaining the aspect
ratio. Overall, element needs a rewrite.

Let's just disable deprecations. The API is not going anywhere.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6726>
2024-04-25 12:43:07 +00:00
Nirbheek Chauhan 49f9a1e224 Revert "rsvgdec: Fix uses of librsvg functions deprecated since 2.52"
This reverts commit b8db473955.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6726>
2024-04-25 12:43:07 +00:00
Jordan Petridis 83694a1094 ci: Remove pip install version limits for meson/hotdoc
We used to have them pinned to avoid unexpected issues
when we wanted to update the image, however we haven't
needed them lately and we should be good to install the
latest stable version always.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6656>
2024-04-24 15:01:27 +00:00
Jordan Petridis 472d1b52d3 ci: Add a simple build job based on debian
The gstreamer-rs repos use debian based images already,
which we can later base on this one. Additionally it's
good to have another distro target so we avoid weird
fedoraisms when possible.

It will also be simpler to keep it up to date, as we
don't need to run the test suite against this build as
well.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6656>
2024-04-24 15:01:27 +00:00
Víctor Manuel Jáquez Leal d2c8593b2e vkswapper: choose color space according with format
The swapper surfaces contains the color space for each supported format. Instead
of hard coding the color space, it returns the value associated with the
negotiated vulkan format.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6725>
2024-04-24 13:53:18 +00:00
Seungha Yang 118e673165 closedcaption: Add closed caption extractor element for H.264 stream
Adding new h264ccextractor element. This element will extract
closed caption meta from H.264 stream, and output in display order.
For the frame reordering, this element is implemented as a subclass
of h264decoder but without actual frame decoding.
2024-04-11 19:03:03 +09:00
43 changed files with 1922 additions and 1244 deletions

View file

@ -33,6 +33,7 @@ variables:
value: ""
FEDORA_AMD64_SUFFIX: 'amd64/fedora'
DEBIAN_AMD64_SUFFIX: 'amd64/debian'
INDENT_AMD64_SUFFIX: 'amd64/gst-indent'
COMMITLINT_AMD64_SUFFIX: 'amd64/commitlint'
WINDOWS_AMD64_SUFFIX: 'amd64/windows'
@ -124,6 +125,7 @@ trigger:
.fedora image:
variables:
CCACHE_DIR: '/cache/gstreamer/gstreamer/ccache/'
FDO_BASE_IMAGE: 'registry.fedoraproject.org/fedora-toolbox:34'
FDO_DISTRIBUTION_VERSION: '34'
FDO_REPO_SUFFIX: "$FEDORA_AMD64_SUFFIX"
@ -140,6 +142,25 @@ fedora amd64 docker:
# (which has faster network connectivity to the registry).
tags: [ 'placeholder-job' ]
.debian image:
variables:
CCACHE_DIR: '/cache/gstreamer/gstreamer/ccache_debian/'
FDO_BASE_IMAGE: "quay.io/toolbx-images/debian-toolbox:12"
FDO_DISTRIBUTION_VERSION: '12'
FDO_REPO_SUFFIX: "$DEBIAN_AMD64_SUFFIX"
FDO_DISTRIBUTION_TAG: "$DEBIAN_TAG-$GST_UPSTREAM_BRANCH"
FDO_DISTRIBUTION_EXEC: 'GIT_BRANCH=$CI_COMMIT_REF_NAME GIT_URL=$CI_REPOSITORY_URL bash ci/docker/debian/prepare.sh'
debian amd64 docker:
extends:
- '.debian image'
- '.fdo.container-build@debian'
stage: 'preparation'
needs: []
# Note: assumption is that placeholder jobs run on a packet runner
# (which has faster network connectivity to the registry).
tags: [ 'placeholder-job' ]
.gst-indent image:
tags: [ 'placeholder-job' ]
variables:
@ -264,7 +285,6 @@ commitlint:
CCACHE_COMPILERCHECK: 'content'
CCACHE_COMPRESS: 'true'
CCACHE_BASEDIR: '/cache/gstreamer/gstreamer'
CCACHE_DIR: '/cache/gstreamer/gstreamer/ccache/'
# shared across everything really
CCACHE_MAXSIZE: '10G'
@ -329,15 +349,10 @@ commitlint:
- changes:
- subprojects/gstreamer-vaapi/**/*
.build fedora x86_64:
.build simple:
extends:
- '.fedora image'
- '.fdo.suffixed-image@fedora'
- '.build'
- '.build_ccache_vars'
needs:
- "trigger"
- "fedora amd64 docker"
variables:
GST_WERROR: "true"
MESON_ARGS: "${SIMPLE_BUILD}"
@ -350,6 +365,15 @@ commitlint:
- meson install --destdir $CI_PROJECT_DIR/destdir -C build
- rm -rf $CI_PROJECT_DIR/destdir
.build fedora x86_64:
extends:
- '.fedora image'
- '.fdo.suffixed-image@fedora'
- '.build simple'
needs:
- "trigger"
- "fedora amd64 docker"
build fedora gcc:
extends: '.build fedora x86_64'
variables:
@ -405,6 +429,18 @@ build fedora clang:
-Dgstreamer-sharp:tests=disabled
--force-fallback-for=glib
build debian x86_64:
extends:
- '.debian image'
- '.fdo.suffixed-image@debian'
- '.build simple'
needs:
- "trigger"
- "debian amd64 docker"
variables:
BUILD_TYPE: "--default-library=shared"
BUILD_GST_DEBUG: "-Dgstreamer:gst_debug=true"
.build windows:
image: $WINDOWS_IMAGE
stage: 'build'

View file

@ -5,7 +5,9 @@ variables:
# If you are hacking on them or need a them to rebuild, its enough
# to change any part of the string of the image you want.
###
FEDORA_TAG: '2024-04-10.0'
FEDORA_TAG: '2024-04-22.4'
DEBIAN_TAG: '2024-04-22.4'
INDENT_TAG: '2023-08-24.3'

283
ci/docker/debian/deps.txt Normal file
View file

@ -0,0 +1,283 @@
apertium-regtest
appstream-util
autopoint
bash-completion
bat
bison
bubblewrap
busybox
ccache
clang
clang-tools
cmake
coinor-libcgl-dev
curl
desktop-file-utils
docutils-common
doxygen
dwz
elfutils
emscripten
ffmpeg
flex
flite1-dev
g++
gcc
gdb
gettext
git
git-lfs
glslc
googletest
graphviz
gtk-doc-tools
guile-cairo-dev
iproute2
iso-codes
itstool
ladspa-sdk
liba52-0.7.4-dev
libaa1-dev
liballeggl4-dev
libaom-dev
libasound2-dev
libass-dev
libatk1.0-dev
libavahi-client-dev
libavahi-common-dev
libavc1394-dev
libavcodec-dev
libavdevice-dev
libavfilter-dev
libavformat-dev
libavif-dev
libavutil-dev
libbluetooth-dev
libboost-system-dev
libbs2b-dev
libcaca-dev
libcairo2-dev
libcamera-dev
libcanberra-dev
libcap-dev
libcdio-dev
libcdparanoia-dev
libchromaprint-dev
libclang-dev
libcoap3-dev
libcurl4-openssl-dev
libdbus-glib2.0-cil-dev
libdca-dev
libde265-dev
libdirectfb-dev
libdrm-dev
libdrumstick-dev
libdv4-dev
libdvdnav-dev
libdvdread-dev
libdw-dev
libebur128-dev
libegl-dev
libespeak-ng-dev
libespeak-ng-libespeak-dev
libevdev-dev
libevent-dev
libexempi-dev
libexif-dev
libfaad-dev
libfftw3-bin
libfftw3-dev
libflac-dev
libfluidsynth-dev
libframe-dev
libfreeaptx-dev
libftgl-dev
libgbm-dev
libgdk-pixbuf-2.0-dev
libgeocode-glib-dev
libgirepository1.0-dev
libgl-dev
libgl1-mesa-dev
libgles-dev
libglib2.0-dev
libglib2.0-doc
libglx-dev
libgme-dev
libgnutls28-dev
libgraphene-1.0-dev
libgridsite-dev
libgsl-dev
libgsm1-dev
libgssdp-1.6-dev
libgtest-dev
libgtk-3-dev
libgtk-4-dev
libgtkmm-3.0-dev
libgudev-1.0-dev
libgupnp-igd-1.0-dev
libiec61883-dev
libinput-dev
libiptcdata0-dev
libjack-jackd2-dev
libjpeg62-turbo-dev
libjson-glib-dev
libjwt-gnutls-dev
libkate-dev
liblc3-dev
liblcms2-dev
libldacbt-abr-dev
libldacbt-enc-dev
liblilv-dev
liblogg4-dev
libltc-dev
liblttng-ust-dev
liblxi-dev
libmfx-dev
libmjpegtools-dev
libmodplug-dev
libmono-cil-dev
libmp3lame-dev
libmpcdec-dev
libmpeg2-4-dev
libmpeg3-dev
libmpg123-dev
libneon27-dev
libngtcp2-crypto-gnutls-dev
libnice-dev
libnx-x11-dev
libogg-dev
libopenal-dev
libopencore-amrnb-dev
libopencore-amrwb-dev
libopencv-dev
libopenexr-dev
libopengl-dev
libopenh264-dev
libopenjp2-7-dev
libopenmpt-dev
libopenni2-dev
libopus-dev
libpango1.0-dev
libpng-dev
libpolkit-gobject-1-dev
libpulse-dev
libpython3-all-dev
libqrencode-dev
libqt5waylandclient5-dev
libqt5x11extras5-dev
libraw1394-dev
librsvg2-dev
librtmp-dev
librust-wayland-protocols-dev
libsbc-dev
libsdl2-dev
libshaderc1
libshout-dev
libsidplay1-dev
libsigc++-2.0-dev
libsndfile1-dev
libsndifsdl2-dev
libsoundtouch-dev
libsoup-3.0-dev
libsoup2.4-dev
libspandsp-dev
libspeex-dev
libsphinxbase-dev
libspice-client-glib-2.0-dev
libsrt-openssl-dev
libsrtp2-dev
libssh2-1-dev
libssl-dev
libsvtav1-dev
libsvtav1dec-dev
libsvtav1enc-dev
libsysprof-4-dev
libtag1-dev
libtaoframework-openal-cil-dev
libtaoframework-opengl-cil-dev
libtheora-dev
libtwolame-dev
libudev-dev
libunwind-dev
liburcu-dev
libusb-1.0-0-dev
libv4l-dev
libva-dev
libvisual-0.4-dev
libvo-aacenc-dev
libvo-amrwbenc-dev
libvorbis-dev
libvpx-dev
libvulkan-dev
libwacom-dev
libwavpack-dev
libwayland-dev
libwebp-dev
libwebrtc-audio-processing-dev
libwildmidi-dev
libwpe-1.0-dev
libwpebackend-fdo-1.0-dev
libwpewebkit-1.1-dev
libx11-dev
libx11-xcb-dev
libx264-dev
libx265-dev
libxcb-dri3-dev
libxcb-glx0-dev
libxcb-xfixes0-dev
libxcb-xv0-dev
libxcb1-dev
libxdamage-dev
libxext-dev
libxfixes-dev
libxi-dev
libxkbcommon-dev
libxkbcommon-x11-dev
libxml2-dev
libxmlsec1-dev
libxrandr-dev
libxslt1-dev
libxtst-dev
libxv-dev
libxvidcore-dev
libyajl-dev
libyaml-dev
libz-mingw-w64-dev
libzbar-dev
libzita-convolver-dev
libzvbi-dev
libzxing-dev
libzxingcore-dev
llvm-dev
lua-zlib-dev
make
modemmanager-dev
mono-complete
mono-devel
nasm
nettle-dev
ninja-build
patch
python-gi-dev
python3-all-dev
python3-cairo-dev
python3-dev
python3-pip
qconf
qt5-qmake
qtbase5-dev
qtbase5-private-dev
qtdeclarative5-dev
qtdeclarative5-dev-tools
qttools5-dev-tools
sudo
svt-av1
valgrind
wayland-protocols
x11-xserver-utils
xdg-utils
xfonts-jmk
xfonts-kaname
xvfb
yasm
zlib1g-dev

View file

@ -0,0 +1,10 @@
#! /bin/bash
set -eux
apt update -y && apt full-upgrade -y
apt install -y $(<./ci/docker/debian/deps.txt)
pip3 install --break-system-packages meson hotdoc python-gitlab tomli junitparser
apt clean all

View file

@ -0,0 +1,13 @@
#! /bin/bash
set -eux
bash ./ci/docker/debian/install-deps.sh
bash ./ci/scripts/install-rust.sh
# Configure git for various usage
git config --global user.email "gstreamer@gstreamer.net"
git config --global user.name "Gstbuild Runner"
bash ./ci/scripts/create-subprojects-cache.sh

View file

@ -32,7 +32,7 @@ dnf builddep -y gstreamer1 \
python3-gstreamer1
dnf remove -y meson -x ninja-build
pip3 install meson==1.2.3 hotdoc==0.16 python-gitlab tomli junitparser
pip3 install meson hotdoc python-gitlab tomli junitparser
# Remove gst-devel packages installed by builddep above
dnf remove -y "gstreamer1*devel"

View file

@ -12,8 +12,8 @@ bash ./ci/docker/fedora/install-gdk-pixbuf.sh
bash ./ci/docker/fedora/install-wayland-protocols.sh
bash ./ci/docker/fedora/install-rust.sh
bash ./ci/scripts/install-rust.sh
bash ./ci/docker/fedora/virtme-fluster-setup.sh
bash ./ci/docker/fedora/create-subprojects-cache.sh
bash ./ci/scripts/create-subprojects-cache.sh

View file

@ -30985,7 +30985,10 @@ of the peer sink pad, if present.</doc>
</parameters>
</method>
<method name="set_offset" c:identifier="gst_pad_set_offset">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstpad.c">Set the offset that will be applied to the running time of @pad.</doc>
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstpad.c">Set the offset that will be applied to the running time of @pad. Upon next
buffer, every sticky events (notably segment) will be pushed again with
their running time adjusted. For that reason this is only reliable on
source pads.</doc>
<source-position filename="../subprojects/gstreamer/gst/gstpad.h"/>
<return-value transfer-ownership="none">
<type name="none" c:type="void"/>

View file

@ -1314,21 +1314,6 @@ need to use this function.</doc>
<record name="VulkanCommandPoolPrivate" c:type="GstVulkanCommandPoolPrivate" disguised="1">
<source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/vulkan/vulkan_fwd.h"/>
</record>
<record name="VulkanDecoder" c:type="GstVulkanDecoder" disguised="1">
<source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/vulkan/vulkan_fwd.h"/>
</record>
<record name="VulkanDecoderClass" c:type="GstVulkanDecoderClass" disguised="1">
<source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/vulkan/vulkan_fwd.h"/>
</record>
<union name="VulkanDecoderParameters" c:type="GstVulkanDecoderParameters">
<source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/vulkan/vulkan_fwd.h"/>
</union>
<record name="VulkanDecoderPicture" c:type="GstVulkanDecoderPicture" disguised="1">
<source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/vulkan/vulkan_fwd.h"/>
</record>
<record name="VulkanDecoderPrivate" c:type="GstVulkanDecoderPrivate" disguised="1">
<source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/vulkan/vulkan_fwd.h"/>
</record>
<class name="VulkanDescriptorCache" c:symbol-prefix="vulkan_descriptor_cache" c:type="GstVulkanDescriptorCache" version="1.18" parent="VulkanHandlePool" glib:type-name="GstVulkanDescriptorCache" glib:get-type="gst_vulkan_descriptor_cache_get_type" glib:type-struct="VulkanDescriptorCacheClass">
<source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkdescriptorcache.h"/>
<constructor name="new" c:identifier="gst_vulkan_descriptor_cache_new" version="1.18">
@ -5178,24 +5163,6 @@ surrounding elements of @element.</doc>
</instance-parameter>
</parameters>
</method>
<method name="create_decoder" c:identifier="gst_vulkan_queue_create_decoder" version="1.24" introspectable="0">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkqueue.c">Creates a #GstVulkanDecoder object if @codec decoding is supported by @queue</doc>
<source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkqueue.h"/>
<return-value transfer-ownership="full" nullable="1">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkqueue.c">the #GstVulkanDecoder object</doc>
<type name="VulkanDecoder" c:type="GstVulkanDecoder*"/>
</return-value>
<parameters>
<instance-parameter name="queue" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkqueue.c">a #GstVulkanQueue</doc>
<type name="VulkanQueue" c:type="GstVulkanQueue*"/>
</instance-parameter>
<parameter name="codec" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkqueue.c">the VkVideoCodecOperationFlagBitsKHR to decode</doc>
<type name="guint" c:type="guint"/>
</parameter>
</parameters>
</method>
<method name="get_device" c:identifier="gst_vulkan_queue_get_device" version="1.18">
<source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkqueue.h"/>
<return-value transfer-ownership="full" nullable="1">

View file

@ -19449,23 +19449,6 @@
"GstVulkanCommandPool.pool",
"GstVulkanCommandPool.queue",
"GstVulkanCommandPoolClass.parent_class",
"GstVulkanDecoder",
"GstVulkanDecoder.codec",
"GstVulkanDecoder.dedicated_dpb",
"GstVulkanDecoder.input_buffer",
"GstVulkanDecoder.layered_buffer",
"GstVulkanDecoder.layered_dpb",
"GstVulkanDecoder.parent",
"GstVulkanDecoder.profile",
"GstVulkanDecoder.queue",
"GstVulkanDecoderClass.parent",
"GstVulkanDecoderPicture",
"GstVulkanDecoderPicture.dpb",
"GstVulkanDecoderPicture.img_view_out",
"GstVulkanDecoderPicture.img_view_ref",
"GstVulkanDecoderPicture.out",
"GstVulkanDecoderPicture.refs",
"GstVulkanDecoderPicture.slice_offs",
"GstVulkanDescriptorCache",
"GstVulkanDescriptorCache.parent",
"GstVulkanDescriptorCache.pool",
@ -44795,22 +44778,6 @@
"gst_vulkan_command_pool_lock",
"gst_vulkan_command_pool_unlock",
"gst_vulkan_create_shader",
"gst_vulkan_decoder_append_slice",
"gst_vulkan_decoder_caps",
"gst_vulkan_decoder_create_dpb_pool",
"gst_vulkan_decoder_decode",
"gst_vulkan_decoder_flush",
"gst_vulkan_decoder_is_started",
"gst_vulkan_decoder_out_format",
"gst_vulkan_decoder_picture_create_view",
"gst_vulkan_decoder_picture_init",
"gst_vulkan_decoder_picture_release",
"gst_vulkan_decoder_profile_caps",
"gst_vulkan_decoder_start",
"gst_vulkan_decoder_stop",
"gst_vulkan_decoder_update_video_session_parameters",
"gst_vulkan_decoder_update_ycbcr_sampler",
"gst_vulkan_decoder_wait",
"gst_vulkan_descriptor_cache_acquire",
"gst_vulkan_descriptor_cache_new",
"gst_vulkan_descriptor_pool_create",
@ -44965,7 +44932,6 @@
"gst_vulkan_physical_device_type_to_string",
"gst_vulkan_present_mode_to_string",
"gst_vulkan_queue_create_command_pool",
"gst_vulkan_queue_create_decoder",
"gst_vulkan_queue_flags_to_string",
"gst_vulkan_queue_get_device",
"gst_vulkan_queue_handle_context_query",

View file

@ -7997,6 +7997,33 @@
},
"rank": "none"
},
"h264ccextractor": {
"author": "Seungha Yang <seungha@centricular.com>",
"description": "Extract GstVideoCaptionMeta from input H.264 stream",
"hierarchy": [
"GstH264CCExtractor",
"GstH264Decoder",
"GstVideoDecoder",
"GstElement",
"GstObject",
"GInitiallyUnowned",
"GObject"
],
"klass": "Codec/Video/Filter",
"pad-templates": {
"sink": {
"caps": "video/x-h264:\n alignment: au\n parsed: true\n",
"direction": "sink",
"presence": "always"
},
"src": {
"caps": "closedcaption/x-cea-608:\n format: { raw, s334-1a }\nclosedcaption/x-cea-708:\n format: { cc_data, cdp }\n",
"direction": "src",
"presence": "always"
}
},
"rank": "none"
},
"line21decoder": {
"author": "Edward Hervey <edward@centricular.com>",
"description": "Extract line21 CC from SD video streams",

View file

@ -33,6 +33,7 @@
#include "gstceaccoverlay.h"
#include "gstline21enc.h"
#include "ccutils.h"
#include "gsth264ccextractor.h"
static gboolean
closedcaption_init (GstPlugin * plugin)
@ -49,6 +50,7 @@ closedcaption_init (GstPlugin * plugin)
ret |= GST_ELEMENT_REGISTER (line21decoder, plugin);
ret |= GST_ELEMENT_REGISTER (cc708overlay, plugin);
ret |= GST_ELEMENT_REGISTER (line21encoder, plugin);
ret |= GST_ELEMENT_REGISTER (h264ccextractor, plugin);
return ret;
}

View file

@ -0,0 +1,451 @@
/* GStreamer
* Copyright (C) 2024 Seungha Yang <seungha@centricular.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 "gsth264ccextractor.h"
#include <gst/base/gstqueuearray.h>
GST_DEBUG_CATEGORY_STATIC (gst_h264_cc_extractor_debug);
#define GST_CAT_DEFAULT gst_h264_cc_extractor_debug
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-h264, alignment=(string) au, "
"parsed=(boolean) true"));
static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS
("closedcaption/x-cea-608,format={ (string) raw, (string) s334-1a}; "
"closedcaption/x-cea-708,format={ (string) cc_data, (string) cdp }"));
static void gst_h264_cc_extractor_finalize (GObject * object);
static gboolean gst_h264_cc_extractor_set_format (GstVideoDecoder * decoder,
GstVideoCodecState * state);
static gboolean gst_h264_cc_extractor_negotiate (GstVideoDecoder * decoder);
static gboolean gst_h264_cc_extractor_transform_meta (GstVideoDecoder * decoder,
GstVideoCodecFrame * frame, GstMeta * meta);
static GstFlowReturn
gst_h264_cc_extractor_handle_frame (GstVideoDecoder * decoder,
GstVideoCodecFrame * frame);
static GstFlowReturn gst_h264_cc_extractor_finish (GstVideoDecoder * decoder);
static GstFlowReturn
gst_h264_cc_extractor_new_sequence (GstH264Decoder * decoder,
const GstH264SPS * sps, gint max_dpb_size);
static GstFlowReturn
gst_h264_cc_extractor_new_picture (GstH264Decoder * decoder,
GstVideoCodecFrame * frame, GstH264Picture * picture);
static GstFlowReturn
gst_h264_cc_extractor_new_field_picture (GstH264Decoder * decoder,
GstH264Picture * first_field, GstH264Picture * second_field);
static GstFlowReturn
gst_h264_cc_extractor_start_picture (GstH264Decoder * decoder,
GstH264Picture * picture, GstH264Slice * slice, GstH264Dpb * dpb);
static GstFlowReturn
gst_h264_cc_extractor_decode_slice (GstH264Decoder * decoder,
GstH264Picture * picture, GstH264Slice * slice, GArray * ref_pic_list0,
GArray * ref_pic_list1);
static GstFlowReturn
gst_h264_cc_extractor_output_picture (GstH264Decoder * decoder,
GstVideoCodecFrame * frame, GstH264Picture * picture);
typedef struct _CaptionData
{
GstVideoCaptionType caption_type;
GstBuffer *buffer;
} CaptionData;
struct _GstH264CCExtractor
{
GstH264Decoder parent;
GstVideoCaptionType caption_type;
GstQueueArray *cur_data;
GstQueueArray *out_data;
gboolean on_eos;
gint fps_n;
gint fps_d;
};
#define gst_h264_cc_extractor_parent_class parent_class
G_DEFINE_TYPE (GstH264CCExtractor, gst_h264_cc_extractor,
GST_TYPE_H264_DECODER);
GST_ELEMENT_REGISTER_DEFINE (h264ccextractor, "h264ccextractor",
GST_RANK_NONE, GST_TYPE_H264_CC_EXTRACTOR);
static void
gst_h264_cc_extractor_class_init (GstH264CCExtractorClass * klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass);
GstH264DecoderClass *h264_class = GST_H264_DECODER_CLASS (klass);
object_class->finalize = gst_h264_cc_extractor_finalize;
gst_element_class_set_static_metadata (element_class,
"H.264 Closed Caption Extractor",
"Codec/Video/Filter",
"Extract GstVideoCaptionMeta from input H.264 stream",
"Seungha Yang <seungha@centricular.com>");
gst_element_class_add_static_pad_template (element_class, &sink_template);
gst_element_class_add_static_pad_template (element_class, &src_template);
decoder_class->set_format =
GST_DEBUG_FUNCPTR (gst_h264_cc_extractor_set_format);
decoder_class->negotiate =
GST_DEBUG_FUNCPTR (gst_h264_cc_extractor_negotiate);
decoder_class->transform_meta =
GST_DEBUG_FUNCPTR (gst_h264_cc_extractor_transform_meta);
decoder_class->handle_frame =
GST_DEBUG_FUNCPTR (gst_h264_cc_extractor_handle_frame);
decoder_class->finish = GST_DEBUG_FUNCPTR (gst_h264_cc_extractor_finish);
h264_class->new_sequence =
GST_DEBUG_FUNCPTR (gst_h264_cc_extractor_new_sequence);
h264_class->new_picture =
GST_DEBUG_FUNCPTR (gst_h264_cc_extractor_new_picture);
h264_class->new_field_picture =
GST_DEBUG_FUNCPTR (gst_h264_cc_extractor_new_field_picture);
h264_class->start_picture =
GST_DEBUG_FUNCPTR (gst_h264_cc_extractor_start_picture);
h264_class->decode_slice =
GST_DEBUG_FUNCPTR (gst_h264_cc_extractor_decode_slice);
h264_class->output_picture =
GST_DEBUG_FUNCPTR (gst_h264_cc_extractor_output_picture);
GST_DEBUG_CATEGORY_INIT (gst_h264_cc_extractor_debug, "h264ccextractor",
0, "h264ccextractor");
}
static void
caption_data_clear_func (CaptionData * data)
{
data->caption_type = GST_VIDEO_CAPTION_TYPE_UNKNOWN;
gst_clear_buffer (&data->buffer);
}
static GstQueueArray *
caption_data_queue_new (void)
{
GstQueueArray *array =
gst_queue_array_new_for_struct (sizeof (CaptionData), 2);
gst_queue_array_set_clear_func (array,
(GDestroyNotify) caption_data_clear_func);
return array;
}
static void
gst_h264_cc_extractor_init (GstH264CCExtractor * self)
{
self->cur_data = caption_data_queue_new ();
self->out_data = gst_queue_array_new_for_struct (sizeof (CaptionData), 2);
self->caption_type = GST_VIDEO_CAPTION_TYPE_UNKNOWN;
self->fps_n = 0;
self->fps_d = 1;
}
static void
gst_h264_cc_extractor_finalize (GObject * object)
{
GstH264CCExtractor *self = GST_H264_CC_EXTRACTOR (object);
if (self->cur_data)
gst_queue_array_free (self->cur_data);
gst_queue_array_free (self->out_data);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static gboolean
gst_h264_cc_extractor_set_format (GstVideoDecoder * decoder,
GstVideoCodecState * state)
{
GstH264CCExtractor *self = GST_H264_CC_EXTRACTOR (decoder);
GstVideoCodecState *out_state;
GstCaps *caps;
gboolean ret;
/* Assume caption type is cea708 raw which is common cc type
* embedded in SEI */
if (self->caption_type == GST_VIDEO_CAPTION_TYPE_UNKNOWN)
self->caption_type = GST_VIDEO_CAPTION_TYPE_CEA708_RAW;
/* Create dummy output state. Otherwise decoder baseclass will try to create
* video caps on GAP event */
out_state = gst_video_decoder_set_output_state (decoder,
GST_VIDEO_FORMAT_NV12, state->info.width, state->info.height, NULL);
caps = gst_video_caption_type_to_caps (self->caption_type);
gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION,
state->info.fps_n, state->info.fps_d, NULL);
out_state->caps = caps;
gst_video_codec_state_unref (out_state);
ret = GST_VIDEO_DECODER_CLASS (parent_class)->set_format (decoder, state);
gst_video_decoder_negotiate (decoder);
return ret;
}
static gboolean
gst_h264_cc_extractor_negotiate (GstVideoDecoder * decoder)
{
GstH264CCExtractor *self = GST_H264_CC_EXTRACTOR (decoder);
GstCaps *caps = gst_video_caption_type_to_caps (self->caption_type);
gst_caps_set_simple (caps,
"framerate", GST_TYPE_FRACTION, self->fps_n, self->fps_d, NULL);
gst_pad_set_caps (decoder->srcpad, caps);
gst_caps_unref (caps);
return TRUE;
}
static gboolean
gst_h264_cc_extractor_transform_meta (GstVideoDecoder * decoder,
GstVideoCodecFrame * frame, GstMeta * meta)
{
/* do not copy any meta */
return FALSE;
}
static GstFlowReturn
gst_h264_cc_extractor_handle_frame (GstVideoDecoder * decoder,
GstVideoCodecFrame * frame)
{
GstH264CCExtractor *self = GST_H264_CC_EXTRACTOR (decoder);
GstVideoTimeCodeMeta *tc_meta;
GstVideoCaptionMeta *cc_meta;
gpointer iter = NULL;
GstFlowReturn ret;
if (self->cur_data)
gst_queue_array_clear (self->cur_data);
tc_meta = gst_buffer_get_video_time_code_meta (frame->input_buffer);
while ((cc_meta = (GstVideoCaptionMeta *)
gst_buffer_iterate_meta_filtered (frame->input_buffer, &iter,
GST_VIDEO_CAPTION_META_API_TYPE))) {
CaptionData data;
data.caption_type = cc_meta->caption_type;
data.buffer = gst_buffer_new_memdup (cc_meta->data, cc_meta->size);
GST_BUFFER_DTS (data.buffer) = GST_CLOCK_TIME_NONE;
GST_BUFFER_PTS (data.buffer) = GST_BUFFER_PTS (frame->input_buffer);
GST_BUFFER_DURATION (data.buffer) =
GST_BUFFER_DURATION (frame->input_buffer);
if (tc_meta)
gst_buffer_add_video_time_code_meta (data.buffer, &tc_meta->tc);
if (!self->cur_data)
self->cur_data = caption_data_queue_new ();
gst_queue_array_push_tail_struct (self->cur_data, &data);
}
GST_DEBUG_OBJECT (self, "Queued captions %u",
self->cur_data ? gst_queue_array_get_length (self->cur_data) : 0);
ret = GST_VIDEO_DECODER_CLASS (parent_class)->handle_frame (decoder, frame);
if (self->cur_data)
gst_queue_array_clear (self->cur_data);
return ret;
}
static GstFlowReturn
gst_h264_cc_extractor_finish (GstVideoDecoder * decoder)
{
GST_VIDEO_DECODER_CLASS (parent_class)->finish (decoder);
/* baseclass will post error message if there was no output buffer
* and subclass returns OK. Return flow EOS to avoid the error message */
return GST_FLOW_EOS;
}
static GstFlowReturn
gst_h264_cc_extractor_new_sequence (GstH264Decoder * decoder,
const GstH264SPS * sps, gint max_dpb_size)
{
return GST_FLOW_OK;
}
static GstFlowReturn
gst_h264_cc_extractor_new_picture (GstH264Decoder * decoder,
GstVideoCodecFrame * frame, GstH264Picture * picture)
{
return GST_FLOW_OK;
}
static GstFlowReturn
gst_h264_cc_extractor_new_field_picture (GstH264Decoder * decoder,
GstH264Picture * first_field, GstH264Picture * second_field)
{
return GST_FLOW_OK;
}
static GstFlowReturn
gst_h264_cc_extractor_start_picture (GstH264Decoder * decoder,
GstH264Picture * picture, GstH264Slice * slice, GstH264Dpb * dpb)
{
GstH264CCExtractor *self = GST_H264_CC_EXTRACTOR (decoder);
GstH264Picture *target_pic = picture;
GstQueueArray *pic_data;
GST_LOG_OBJECT (self, "Start %s field picture", picture->second_field ?
"second" : "first");
if (!self->cur_data || !gst_queue_array_get_length (self->cur_data))
return GST_FLOW_OK;
/* Baseclass will output only the first field's codec frame.
* If this second field picture's codec frame is different from
* the first one, attach */
if (picture->second_field && picture->other_field &&
GST_CODEC_PICTURE_FRAME_NUMBER (picture) !=
GST_CODEC_PICTURE_FRAME_NUMBER (picture->other_field)) {
target_pic = picture->other_field;
GST_DEBUG_OBJECT (self, "Found second field picture");
}
pic_data = gst_h264_picture_get_user_data (target_pic);
if (!pic_data) {
GST_DEBUG_OBJECT (self, "Creating new picture data, caption size: %u",
gst_queue_array_get_length (self->cur_data));
gst_h264_picture_set_user_data (target_pic,
g_steal_pointer (&self->cur_data),
(GDestroyNotify) gst_queue_array_free);
} else {
gpointer caption_data;
GST_DEBUG_OBJECT (self, "Appending %u caption buffers, prev size: %u",
gst_queue_array_get_length (self->cur_data),
gst_queue_array_get_length (pic_data));
while ((caption_data = gst_queue_array_pop_head_struct (self->cur_data)))
gst_queue_array_push_tail_struct (pic_data, caption_data);
}
return GST_FLOW_OK;
}
static GstFlowReturn
gst_h264_cc_extractor_decode_slice (GstH264Decoder * decoder,
GstH264Picture * picture, GstH264Slice * slice, GArray * ref_pic_list0,
GArray * ref_pic_list1)
{
return GST_FLOW_OK;
}
static GstFlowReturn
gst_h264_cc_extractor_output_picture (GstH264Decoder * decoder,
GstVideoCodecFrame * frame, GstH264Picture * picture)
{
GstVideoDecoder *videodec = GST_VIDEO_DECODER (decoder);
GstH264CCExtractor *self = GST_H264_CC_EXTRACTOR (decoder);
gint fps_n = 0;
gint fps_d = 1;
gboolean updated = FALSE;
GstCodecPicture *codec_pic = GST_CODEC_PICTURE (picture);
GstQueueArray *pic_data;
CaptionData *caption_data = NULL;
GstBuffer *front_buf = NULL;
GstClockTime pts, dur;
GstFlowReturn ret = GST_FLOW_OK;
pic_data = gst_h264_picture_get_user_data (picture);
/* Move caption buffer to our temporary storage */
if (pic_data) {
while ((caption_data = gst_queue_array_pop_head_struct (pic_data)))
gst_queue_array_push_tail_struct (self->out_data, caption_data);
}
fps_n = decoder->input_state->info.fps_n;
fps_d = decoder->input_state->info.fps_d;
if (codec_pic->discont_state) {
fps_n = codec_pic->discont_state->info.fps_n;
fps_d = codec_pic->discont_state->info.fps_d;
}
if (fps_n != self->fps_n || fps_d != self->fps_d) {
updated = TRUE;
self->fps_n = fps_n;
self->fps_d = fps_d;
}
GST_DEBUG_OBJECT (self, "picture is holding %u caption buffers",
gst_queue_array_get_length (self->out_data));
if (gst_queue_array_get_length (self->out_data)) {
caption_data = gst_queue_array_pop_head_struct (self->out_data);
front_buf = caption_data->buffer;
if (caption_data->caption_type != self->caption_type) {
GST_DEBUG_OBJECT (self, "Caption type changed, need new caps");
self->caption_type = caption_data->caption_type;
updated = TRUE;
}
}
if (updated)
gst_video_decoder_negotiate (videodec);
gst_h264_picture_unref (picture);
pts = GST_BUFFER_PTS (frame->input_buffer);
dur = GST_BUFFER_DURATION (frame->input_buffer);
if (!front_buf) {
GstEvent *gap;
GST_VIDEO_CODEC_FRAME_SET_DECODE_ONLY (frame);
ret = gst_video_decoder_finish_frame (videodec, frame);
gap = gst_event_new_gap (pts, dur);
gst_pad_push_event (videodec->srcpad, gap);
return ret;
}
frame->output_buffer = front_buf;
ret = gst_video_decoder_finish_frame (videodec, frame);
/* Drain other caption data */
while ((caption_data = gst_queue_array_pop_head_struct (self->out_data))) {
if (ret == GST_FLOW_OK)
ret = gst_pad_push (videodec->srcpad, caption_data->buffer);
else
gst_buffer_unref (caption_data->buffer);
}
return ret;
}

View file

@ -0,0 +1,34 @@
/* GStreamer
* Copyright (C) 2024 Seungha Yang <seungha@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/codecs/gsth264decoder.h>
G_BEGIN_DECLS
#define GST_TYPE_H264_CC_EXTRACTOR (gst_h264_cc_extractor_get_type())
G_DECLARE_FINAL_TYPE (GstH264CCExtractor, gst_h264_cc_extractor,
GST, H264_CC_EXTRACTOR, GstH264Decoder);
GST_ELEMENT_REGISTER_DECLARE (h264ccextractor);
G_END_DECLS

View file

@ -9,15 +9,30 @@ zvbi_sources = [
'io-sim.c',
]
closedcaption_sources = [
'gstcccombiner.c',
'gstccextractor.c',
'gstccconverter.c',
'gstcea608mux.c',
'gstclosedcaption.c',
'gstline21dec.c',
'gstcea708decoder.c',
'gstceaccoverlay.c',
'gstline21enc.c',
'ccutils.c',
'gsth264ccextractor.c',
]
extra_args = ['-DGST_USE_UNSTABLE_API']
if closedcaption_dep.found()
gstclosedcaption = library('gstclosedcaption',
'gstcccombiner.c', 'gstccextractor.c', 'gstccconverter.c', 'gstcea608mux.c', 'gstclosedcaption.c',
'gstline21dec.c', 'gstcea708decoder.c', 'gstceaccoverlay.c', 'gstline21enc.c', 'ccutils.c',
zvbi_sources,
c_args : gst_plugins_bad_args,
closedcaption_sources, zvbi_sources,
c_args : gst_plugins_bad_args + extra_args,
link_args : noseh_link_args,
include_directories : [configinc],
dependencies : [gstvideo_dep, gstbase_dep, gst_dep, closedcaption_dep, libm],
dependencies : [gstvideo_dep, gstbase_dep, gst_dep, closedcaption_dep, libm,
gstcodecs_dep],
install : true,
install_dir : plugins_install_dir,
)

View file

@ -145,12 +145,8 @@ gst_rsvg_decode_image (GstRsvgDec * rsvg, GstBuffer * buffer,
cairo_surface_t *surface;
RsvgHandle *handle;
GError *error = NULL;
#if LIBRSVG_MAJOR_VERSION > (2) || (LIBRSVG_MAJOR_VERSION == (2) && LIBRSVG_MINOR_VERSION > (52))
RsvgRectangle viewport;
#else
RsvgDimensionData dimension;
gdouble scalex, scaley;
#endif
GstRsvgDimension dimension;
GstMapInfo minfo;
GstVideoFrame vframe;
GstVideoCodecState *output_state;
@ -167,12 +163,10 @@ gst_rsvg_decode_image (GstRsvgDec * rsvg, GstBuffer * buffer,
g_error_free (error);
return GST_FLOW_ERROR;
}
#if LIBRSVG_MAJOR_VERSION > (2) || (LIBRSVG_MAJOR_VERSION == (2) && LIBRSVG_MINOR_VERSION > (52))
rsvg_handle_get_intrinsic_size_in_pixels (handle, &dimension.width,
&dimension.height);
#else
G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
rsvg_handle_get_dimensions (handle, &dimension);
#endif
G_GNUC_END_IGNORE_DEPRECATIONS;
output_state = gst_video_decoder_get_output_state (decoder);
if ((output_state == NULL)
@ -188,9 +182,8 @@ gst_rsvg_decode_image (GstRsvgDec * rsvg, GstBuffer * buffer,
gst_pad_peer_query_caps (GST_VIDEO_DECODER_SRC_PAD (rsvg), templ_caps);
GST_DEBUG_OBJECT (rsvg,
"Trying to negotiate for SVG resolution %" G_GUINT64_FORMAT "x %"
G_GUINT64_FORMAT " with downstream caps %" GST_PTR_FORMAT,
(guint64) dimension.width, (guint64) dimension.height, peer_caps);
"Trying to negotiate for SVG resolution %ux%u with downstream caps %"
GST_PTR_FORMAT, dimension.width, dimension.height, peer_caps);
source_caps = gst_caps_make_writable (g_steal_pointer (&templ_caps));
gst_caps_set_simple (source_caps, "width", G_TYPE_INT, dimension.width,
@ -272,21 +265,6 @@ gst_rsvg_decode_image (GstRsvgDec * rsvg, GstBuffer * buffer,
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0);
#if LIBRSVG_MAJOR_VERSION > (2) || (LIBRSVG_MAJOR_VERSION == (2) && LIBRSVG_MINOR_VERSION > (52))
viewport.x = 0;
viewport.y = 0;
viewport.width = GST_VIDEO_INFO_WIDTH (&output_state->info);
viewport.height = GST_VIDEO_INFO_HEIGHT (&output_state->info);
if (!rsvg_handle_render_document (handle, cr, &viewport, &error)) {
GST_ERROR_OBJECT (rsvg, "Failed to render SVG image: %s", error->message);
g_error_free (error);
g_object_unref (handle);
cairo_destroy (cr);
cairo_surface_destroy (surface);
gst_video_codec_state_unref (output_state);
return GST_FLOW_ERROR;
}
#else
scalex = scaley = 1.0;
if (GST_VIDEO_INFO_WIDTH (&output_state->info) != dimension.width) {
scalex =
@ -300,8 +278,9 @@ gst_rsvg_decode_image (GstRsvgDec * rsvg, GstBuffer * buffer,
}
cairo_scale (cr, scalex, scaley);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
rsvg_handle_render_cairo (handle, cr);
#endif
G_GNUC_END_IGNORE_DEPRECATIONS;
g_object_unref (handle);
cairo_destroy (cr);

View file

@ -44,15 +44,6 @@ G_BEGIN_DECLS
typedef struct _GstRsvgDec GstRsvgDec;
typedef struct _GstRsvgDecClass GstRsvgDecClass;
#if LIBRSVG_MAJOR_VERSION > (2) || (LIBRSVG_MAJOR_VERSION == (2) && LIBRSVG_MINOR_VERSION > (52))
typedef struct
{
gdouble width, height;
} GstRsvgDimension;
#else
typedef RsvgDimensionData GstRsvgDimension;
#endif
struct _GstRsvgDec
{
GstVideoDecoder decoder;
@ -66,7 +57,7 @@ struct _GstRsvgDec
guint64 frame_count;
GstVideoCodecState *input_state;
GstRsvgDimension dimension;
RsvgDimensionData dimension;
GstSegment segment;
gboolean need_newsegment;

View file

@ -163,7 +163,9 @@ gst_rsvg_overlay_set_svg_data (GstRsvgOverlay * overlay, const gchar * data,
} else {
/* Get SVG dimension. */
RsvgDimensionData svg_dimension;
G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
rsvg_handle_get_dimensions (overlay->handle, &svg_dimension);
G_GNUC_END_IGNORE_DEPRECATIONS;
overlay->svg_width = svg_dimension.width;
overlay->svg_height = svg_dimension.height;
gst_base_transform_set_passthrough (btrans, FALSE);
@ -421,7 +423,9 @@ gst_rsvg_overlay_transform_frame_ip (GstVideoFilter * vfilter,
cairo_scale (cr, (double) applied_width / overlay->svg_width,
(double) applied_height / overlay->svg_height);
}
G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
rsvg_handle_render_cairo (overlay->handle, cr);
G_GNUC_END_IGNORE_DEPRECATIONS;
GST_RSVG_UNLOCK (overlay);
cairo_destroy (cr);

View file

@ -26,6 +26,7 @@
#include <gst/video/video.h>
#include <gst/vulkan/vulkan.h>
#include "gst/vulkan/gstvkdecoder-private.h"
#include "gstvulkanelements.h"
typedef struct _GstVulkanH264Decoder GstVulkanH264Decoder;
@ -161,7 +162,7 @@ gst_vulkan_h264_decoder_open (GstVideoDecoder * decoder)
return FALSE;
}
self->decoder = gst_vulkan_queue_create_decoder (self->decode_queue,
self->decoder = gst_vulkan_decoder_new_from_queue (self->decode_queue,
VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR);
if (!self->decoder) {
GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,

View file

@ -25,6 +25,7 @@
#include <gst/video/video.h>
#include <gst/vulkan/vulkan.h>
#include "gst/vulkan/gstvkdecoder-private.h"
#include "gstvulkanelements.h"
@ -219,7 +220,7 @@ gst_vulkan_h265_decoder_open (GstVideoDecoder * decoder)
return FALSE;
}
self->decoder = gst_vulkan_queue_create_decoder (self->decode_queue,
self->decoder = gst_vulkan_decoder_new_from_queue (self->decode_queue,
VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR);
if (!self->decoder) {
GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,

View file

@ -1327,7 +1327,7 @@ static inline gboolean
_is_old_mesa (GstVaAllocator * va_allocator)
{
return GST_VA_DISPLAY_IS_IMPLEMENTATION (va_allocator->display, MESA_GALLIUM)
&& !gst_va_display_check_version (va_allocator->display, 23, 2);
&& !gst_va_display_check_version (va_allocator->display, 23, 3);
}
#endif /* G_OS_WIN32 */
@ -1376,13 +1376,15 @@ _update_image_info (GstVaAllocator * va_allocator,
}
va_allocator->use_derived = FALSE;
#else
/* XXX: Derived in Mesa <23.3 can't use derived images for P010 format
/* XXX: Derived in radeonsi Mesa <23.3 can't use derived images for several
* cases
* https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24381
* https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26174
*/
if (va_allocator->img_format == GST_VIDEO_FORMAT_P010_10LE
&& _is_old_mesa (va_allocator)) {
if (_is_old_mesa (va_allocator)) {
if (feat_use_derived != GST_VA_FEATURE_DISABLED) {
GST_INFO_OBJECT (va_allocator, "Disable image derive on old Mesa.");
GST_INFO_OBJECT (va_allocator,
"Disable image derive on old Mesa (< 23.3).");
feat_use_derived = GST_VA_FEATURE_DISABLED;
}
va_allocator->use_derived = FALSE;

View file

@ -23,9 +23,6 @@
#endif
#include "gstvavideoformat.h"
#ifndef G_OS_WIN32
#include <libdrm/drm_fourcc.h>
#endif
#define GST_CAT_DEFAULT gst_va_display_debug
GST_DEBUG_CATEGORY_EXTERN (gst_va_display_debug);
@ -38,73 +35,62 @@ static struct FormatMap
GstVideoFormat format;
guint va_rtformat;
VAImageFormat va_format;
/* The drm fourcc may have different definition from VA */
guint drm_fourcc;
} format_map[] = {
#ifndef G_OS_WIN32
#define F(format, drm, fourcc, rtformat, order, bpp, depth, r, g, b, a) { \
#define F(format, fourcc, rtformat, order, bpp, depth, r, g, b, a) { \
G_PASTE (GST_VIDEO_FORMAT_, format), \
G_PASTE (VA_RT_FORMAT_, rtformat), \
{ VA_FOURCC fourcc, G_PASTE (G_PASTE (VA_, order), _FIRST), \
bpp, depth, r, g, b, a }, G_PASTE (DRM_FORMAT_, drm) }
#else
#define F(format, drm, fourcc, rtformat, order, bpp, depth, r, g, b, a) { \
G_PASTE (GST_VIDEO_FORMAT_, format), \
G_PASTE (VA_RT_FORMAT_, rtformat), \
{ VA_FOURCC fourcc, G_PASTE (G_PASTE (VA_, order), _FIRST), \
bpp, depth, r, g, b, a }, 0 /* DRM_FORMAT_INVALID */ }
#endif
#define G(format, drm, fourcc, rtformat, order, bpp) \
F (format, drm, fourcc, rtformat, order, bpp, 0, 0, 0 ,0, 0)
G (NV12, NV12, ('N', 'V', '1', '2'), YUV420, NSB, 12),
G (NV21, NV21, ('N', 'V', '2', '1'), YUV420, NSB, 21),
G (VUYA, AYUV, ('A', 'Y', 'U', 'V'), YUV444, LSB, 32),
F (RGBA, RGBA8888, ('R', 'G', 'B', 'A'), RGB32, LSB, 32, 32, 0x000000ff,
bpp, depth, r, g, b, a } }
#define G(format, fourcc, rtformat, order, bpp) \
F (format, fourcc, rtformat, order, bpp, 0, 0, 0 ,0, 0)
G (NV12, ('N', 'V', '1', '2'), YUV420, NSB, 12),
G (NV21, ('N', 'V', '2', '1'), YUV420, NSB, 21),
G (VUYA, ('A', 'Y', 'U', 'V'), YUV444, LSB, 32),
F (RGBA, ('R', 'G', 'B', 'A'), RGB32, LSB, 32, 32, 0x000000ff,
0x0000ff00, 0x00ff0000, 0xff000000),
F (RGBx, RGBX8888, ('R', 'G', 'B', 'X'), RGB32, LSB, 32, 24, 0x000000ff,
F (RGBx, ('R', 'G', 'B', 'X'), RGB32, LSB, 32, 24, 0x000000ff,
0x0000ff00, 0x00ff0000, 0x00000000),
F (BGRA, BGRA8888, ('B', 'G', 'R', 'A'), RGB32, LSB, 32, 32, 0x00ff0000,
F (BGRA, ('B', 'G', 'R', 'A'), RGB32, LSB, 32, 32, 0x00ff0000,
0x0000ff00, 0x000000ff, 0xff000000),
F (ARGB, ARGB8888, ('A', 'R', 'G', 'B'), RGB32, LSB, 32, 32, 0x0000ff00,
F (ARGB, ('A', 'R', 'G', 'B'), RGB32, LSB, 32, 32, 0x0000ff00,
0x00ff0000, 0xff000000, 0x000000ff),
F (xRGB, XRGB8888, ('X', 'R', 'G', 'B'), RGB32, LSB, 32, 24, 0x0000ff00,
F (xRGB, ('X', 'R', 'G', 'B'), RGB32, LSB, 32, 24, 0x0000ff00,
0x00ff0000, 0xff000000, 0x00000000),
F (ABGR, ABGR8888, ('A', 'B', 'G', 'R'), RGB32, LSB, 32, 32, 0xff000000,
F (ABGR, ('A', 'B', 'G', 'R'), RGB32, LSB, 32, 32, 0xff000000,
0x00ff0000, 0x0000ff00, 0x000000ff),
F (xBGR, XBGR8888, ('X', 'B', 'G', 'R'), RGB32, LSB, 32, 24, 0xff000000,
F (xBGR, ('X', 'B', 'G', 'R'), RGB32, LSB, 32, 24, 0xff000000,
0x00ff0000, 0x0000ff00, 0x00000000),
F (BGRx, BGRX8888, ('B', 'G', 'R', 'X'), RGB32, LSB, 32, 24, 0x00ff0000,
F (BGRx, ('B', 'G', 'R', 'X'), RGB32, LSB, 32, 24, 0x00ff0000,
0x0000ff00, 0x000000ff, 0x00000000),
G (UYVY, UYVY, ('U', 'Y', 'V', 'Y'), YUV422, NSB, 16),
G (YUY2, YUYV, ('Y', 'U', 'Y', '2'), YUV422, NSB, 16),
G (AYUV, AYUV, ('A', 'Y', 'U', 'V'), YUV444, LSB, 32),
G (UYVY, ('U', 'Y', 'V', 'Y'), YUV422, NSB, 16),
G (YUY2, ('Y', 'U', 'Y', '2'), YUV422, NSB, 16),
G (AYUV, ('A', 'Y', 'U', 'V'), YUV444, LSB, 32),
/* F (????, NV11), */
G (YV12, YVU420, ('Y', 'V', '1', '2'), YUV420, NSB, 12),
G (YV12, ('Y', 'V', '1', '2'), YUV420, NSB, 12),
/* F (????, P208), */
G (I420, YUV420, ('I', '4', '2', '0'), YUV420, NSB, 12),
G (I420, ('I', '4', '2', '0'), YUV420, NSB, 12),
/* F (????, YV24), */
/* F (????, YV32), */
/* F (????, Y800), */
/* F (????, IMC3), */
/* F (????, 411P), */
/* F (????, 411R), */
G (Y42B, YUV422, ('4', '2', '2', 'H'), YUV422, LSB, 16),
G (Y42B, ('4', '2', '2', 'H'), YUV422, LSB, 16),
/* F (????, 422V), */
/* F (????, 444P), */
/* No RGBP support in drm fourcc */
G (RGBP, INVALID, ('R', 'G', 'B', 'P'), RGBP, LSB, 8),
G (RGBP, ('R', 'G', 'B', 'P'), RGBP, LSB, 8),
/* F (????, BGRP), */
/* F (????, RGB565), */
/* F (????, BGR565), */
G (Y210, Y210, ('Y', '2', '1', '0'), YUV422_10, NSB, 32),
G (Y210, ('Y', '2', '1', '0'), YUV422_10, NSB, 32),
/* F (????, Y216), */
G (Y410, Y410, ('Y', '4', '1', '0'), YUV444_10, NSB, 32),
G (Y212_LE, Y212, ('Y', '2', '1', '2'), YUV422_12, NSB, 32),
G (Y412_LE, Y412, ('Y', '4', '1', '2'), YUV444_12, NSB, 32),
G (Y410, ('Y', '4', '1', '0'), YUV444_10, NSB, 32),
G (Y212_LE, ('Y', '2', '1', '2'), YUV422_12, NSB, 32),
G (Y412_LE, ('Y', '4', '1', '2'), YUV444_12, NSB, 32),
/* F (????, Y416), */
/* F (????, YV16), */
G (P010_10LE, P010, ('P', '0', '1', '0'), YUV420_10, NSB, 24),
G (P012_LE, P012, ('P', '0', '1', '2'), YUV420_12, NSB, 24),
G (P010_10LE, ('P', '0', '1', '0'), YUV420_10, NSB, 24),
G (P012_LE, ('P', '0', '1', '2'), YUV420_12, NSB, 24),
/* F (P016_LE, P016, ????), */
/* F (????, I010), */
/* F (????, IYUV), */
@ -112,20 +98,19 @@ static struct FormatMap
/* F (????, A2B10G10R10), */
/* F (????, X2R10G10B10), */
/* F (????, X2B10G10R10), */
/* No GRAY8 support in drm fourcc */
G (GRAY8, INVALID, ('Y', '8', '0', '0'), YUV400, NSB, 8),
G (Y444, YUV444, ('4', '4', '4', 'P'), YUV444, NSB, 24),
G (GRAY8, ('Y', '8', '0', '0'), YUV400, NSB, 8),
G (Y444, ('4', '4', '4', 'P'), YUV444, NSB, 24),
/* F (????, Y16), */
/* G (VYUY, VYUY, YUV422), */
/* G (YVYU, YVYU, YUV422), */
/* F (ARGB64, ARGB64, ????), */
/* F (????, ABGR64), */
F (RGB16, RGB565, ('R', 'G', '1', '6'), RGB16, NSB, 16, 16, 0x0000f800,
F (RGB16, ('R', 'G', '1', '6'), RGB16, NSB, 16, 16, 0x0000f800,
0x000007e0, 0x0000001f, 0x00000000),
F (RGB, RGB888, ('R', 'G', '2', '4'), RGB32, NSB, 32, 24, 0x00ff0000,
F (RGB, ('R', 'G', '2', '4'), RGB32, NSB, 32, 24, 0x00ff0000,
0x0000ff00, 0x000000ff, 0x00000000),
F (BGR10A2_LE, ARGB2101010, ('A', 'R', '3', '0'), RGB32, LSB, 32, 30,
0x3ff00000, 0x000ffc00, 0x000003ff, 0x30000000),
F (BGR10A2_LE, ('A', 'R', '3', '0'), RGB32, LSB, 32, 30, 0x3ff00000,
0x000ffc00, 0x000003ff, 0x30000000),
#undef F
#undef G
};
@ -133,54 +118,47 @@ static struct FormatMap
static const struct RBG32FormatMap
{
GstVideoFormat format;
guint drm_fourcc;
VAImageFormat va_format[2];
} rgb32_format_map[] = {
#define F(fourcc, order, bpp, depth, r, g, b, a) \
{ VA_FOURCC fourcc, G_PASTE (G_PASTE (VA_, order), _FIRST), bpp, depth, r, g, b, a }
#define A(fourcc, order, r, g, b, a) F (fourcc, order, 32, 32, r, g, b, a)
#define X(fourcc, order, r, g, b) F (fourcc, order, 32, 24, r, g, b, 0x0)
#ifndef G_OS_WIN32
#define D(format, drm_fourcc) G_PASTE (GST_VIDEO_FORMAT_, format), G_PASTE (DRM_FORMAT_, drm_fourcc)
#else
#define D(format, drm_fourcc) G_PASTE (GST_VIDEO_FORMAT_, format), 0 /* DRM_FORMAT_INVALID */
#endif
{ D (ARGB, BGRA8888), {
{ GST_VIDEO_FORMAT_ARGB, {
A (('B', 'G', 'R', 'A'), LSB, 0x0000ff00, 0x00ff0000, 0xff000000, 0x000000ff),
A (('A', 'R', 'G', 'B'), MSB, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000),
} },
{ D (RGBA, ABGR8888), {
{ GST_VIDEO_FORMAT_RGBA, {
A (('A', 'B', 'G', 'R'), LSB, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000),
A (('R', 'G', 'B', 'A'), MSB, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff),
} },
{ D (ABGR, RGBA8888), {
{ GST_VIDEO_FORMAT_ABGR, {
A (('R', 'G', 'B', 'A'), LSB, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff),
A (('A', 'B', 'G', 'R'), MSB, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000),
} },
{ D (BGRA, ARGB8888), {
{ GST_VIDEO_FORMAT_BGRA, {
A (('A', 'R', 'G', 'B'), LSB, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000),
A (('B', 'G', 'R', 'A'), MSB, 0x0000ff00, 0x00ff0000, 0xff000000, 0x000000ff),
} },
{ D (xRGB, BGRX8888), {
{ GST_VIDEO_FORMAT_xRGB, {
X (('B', 'G', 'R', 'X'), LSB, 0x0000ff00, 0x00ff0000, 0xff000000),
X (('X', 'R', 'G', 'B'), MSB, 0x00ff0000, 0x0000ff00, 0x000000ff),
} },
{ D (RGBx, XBGR8888), {
{ GST_VIDEO_FORMAT_RGBx, {
X (('X', 'B', 'G', 'R'), LSB, 0x000000ff, 0x0000ff00, 0x00ff0000),
X (('R', 'G', 'B', 'X'), MSB, 0xff000000, 0x00ff0000, 0x0000ff00),
} },
{ D (xBGR, RGBX8888), {
{ GST_VIDEO_FORMAT_xBGR, {
X (('R', 'G', 'B', 'X'), LSB, 0xff000000, 0x00ff0000, 0x0000ff00),
X (('X', 'B', 'G', 'R'), MSB, 0x000000ff, 0x0000ff00, 0x00ff0000),
} },
{ D (BGRx, XRGB8888), {
{ GST_VIDEO_FORMAT_BGRx, {
X (('X', 'R', 'G', 'B'), LSB, 0x00ff0000, 0x0000ff00, 0x000000ff),
X (('B', 'G', 'R', 'X'), MSB, 0x0000ff00, 0x00ff0000, 0xff000000),
} },
#undef X
#undef A
#undef F
#undef D
};
/* *INDENT-ON* */
@ -201,9 +179,11 @@ static const struct FormatMap *
get_format_map_from_drm_fourcc (guint drm_fourcc)
{
int i;
GstVideoFormat format;
format = gst_video_dma_drm_fourcc_to_format (drm_fourcc);
for (i = 0; i < G_N_ELEMENTS (format_map); i++) {
if (format_map[i].drm_fourcc == drm_fourcc)
if (format_map[i].format == format)
return &format_map[i];
}
@ -263,6 +243,20 @@ get_format_map_from_va_image_format (const VAImageFormat * va_format)
return NULL;
}
/**
* XXX: there are two potentially different fourcc: the VA and the DRM.
*
* Normally they should be the same, but there are a couple formats where VA's
* fourcc is different from the DRM's fourcc. One example is
* GST_VIDEO_FORMAT_I420, where VA's fourcc is ('I', '4', '2', '0') while DRM's
* is ('Y', 'U', '1', '2').
*
* That's the reason there are two functions:
* gst_va_video_format_from_va_fourcc() and
* gst_va_video_format_from_drm_fourcc() They should be used depending where the
* value is going to be used: for VA concerns the first should be used, for
* DMABuf exportation, the last.
*/
GstVideoFormat
gst_va_video_format_from_va_fourcc (guint fourcc)
{
@ -292,7 +286,7 @@ gst_va_drm_fourcc_from_video_format (GstVideoFormat format)
{
const struct FormatMap *map = get_format_map_from_video_format (format);
return map ? map->drm_fourcc : 0;
return map ? gst_video_dma_drm_fourcc_from_format (format) : 0;
}
guint
@ -406,15 +400,13 @@ gst_va_dma_drm_info_to_video_info (const GstVideoInfoDmaDrm * drm_info,
}
static GstVideoFormat
find_gst_video_format_in_rgb32_map (VAImageFormat * image_format,
guint * drm_fourcc)
find_gst_video_format_in_rgb32_map (VAImageFormat * image_format)
{
guint i, j;
for (i = 0; i < G_N_ELEMENTS (rgb32_format_map); i++) {
for (j = 0; j < G_N_ELEMENTS (rgb32_format_map[i].va_format); j++) {
if (va_format_is_same (&rgb32_format_map[i].va_format[j], image_format)) {
*drm_fourcc = rgb32_format_map[i].drm_fourcc;
return rgb32_format_map[i].format;
}
}
@ -436,14 +428,13 @@ fix_map (gpointer data)
GstVideoFormat format;
VAImageFormat *image_format;
struct FormatMap *map;
guint drm_fourcc = 0;
guint i;
for (i = 0; i < args->len; i++) {
image_format = &args->image_formats[i];
if (!va_format_is_rgb (image_format))
continue;
format = find_gst_video_format_in_rgb32_map (image_format, &drm_fourcc);
format = find_gst_video_format_in_rgb32_map (image_format);
if (format == GST_VIDEO_FORMAT_UNKNOWN)
continue;
map = get_format_map_from_video_format (format);
@ -453,14 +444,11 @@ fix_map (gpointer data)
continue;
map->va_format = *image_format;
map->drm_fourcc = drm_fourcc;
GST_INFO ("GST_VIDEO_FORMAT_%s => { fourcc %" GST_FOURCC_FORMAT ", "
"drm fourcc %" GST_FOURCC_FORMAT ", %s, bpp %d, depth %d, "
"R %#010x, G %#010x, B %#010x, A %#010x }",
gst_video_format_to_string (map->format),
GST_INFO ("GST_VIDEO_FORMAT_%s => { fourcc %"
GST_FOURCC_FORMAT ", %s, bpp %d, depth %d, R %#010x, G %#010x, "
"B %#010x, A %#010x }", gst_video_format_to_string (map->format),
GST_FOURCC_ARGS (map->va_format.fourcc),
GST_FOURCC_ARGS (map->drm_fourcc),
(map->va_format.byte_order == 1) ? "LSB" : "MSB",
map->va_format.bits_per_pixel, map->va_format.depth,
map->va_format.red_mask, map->va_format.green_mask,

View file

@ -22,7 +22,7 @@
#include "config.h"
#endif
#include "gstvkdecoder.h"
#include "gstvkdecoder-private.h"
#include "gstvkoperation.h"
#include "gstvkphysicaldevice-private.h"
@ -39,6 +39,7 @@
* Since: 1.24
*/
typedef struct _GstVulkanDecoderPrivate GstVulkanDecoderPrivate;
struct _GstVulkanDecoderPrivate
{
GstVulkanHandle *empty_params;
@ -1309,3 +1310,72 @@ gst_vulkan_decoder_wait (GstVulkanDecoder * self)
return TRUE;
}
/**
* gst_vulkan_decoder_new_from_queue:
* @queue: a #GstVulkanQueue
* @codec: (type guint): the VkVideoCodecOperationFlagBitsKHR to decode
*
* Creates a #GstVulkanDecoder object if @codec decoding is supported by @queue
*
* Returns: (transfer full) (nullable): the #GstVulkanDecoder object
*/
GstVulkanDecoder *
gst_vulkan_decoder_new_from_queue (GstVulkanQueue * queue, guint codec)
{
GstVulkanPhysicalDevice *device;
GstVulkanDecoder *decoder;
guint flags, expected_flag, supported_video_ops;
const char *extension;
g_return_val_if_fail (GST_IS_VULKAN_QUEUE (queue), NULL);
device = queue->device->physical_device;
expected_flag = VK_QUEUE_VIDEO_DECODE_BIT_KHR;
flags = device->queue_family_props[queue->family].queueFlags;
supported_video_ops = device->queue_family_ops[queue->family].video;
if (device->properties.apiVersion < VK_MAKE_VERSION (1, 3, 238)) {
GST_WARNING_OBJECT (queue,
"Driver API version [%d.%d.%d] doesn't support Video extensions",
VK_VERSION_MAJOR (device->properties.apiVersion),
VK_VERSION_MINOR (device->properties.apiVersion),
VK_VERSION_PATCH (device->properties.apiVersion));
return NULL;
}
switch (codec) {
case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR:
extension = VK_KHR_VIDEO_DECODE_H264_EXTENSION_NAME;
break;
case VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR:
extension = VK_KHR_VIDEO_DECODE_H265_EXTENSION_NAME;
break;
default:
GST_WARNING_OBJECT (queue, "Unsupported codec %u", codec);
return NULL;
}
if ((flags & expected_flag) != expected_flag) {
GST_WARNING_OBJECT (queue, "Queue doesn't support decoding");
return NULL;
}
if ((supported_video_ops & codec) != codec) {
GST_WARNING_OBJECT (queue, "Queue doesn't support codec %u decoding",
codec);
return NULL;
}
if (!(gst_vulkan_device_is_extension_enabled (queue->device,
VK_KHR_VIDEO_QUEUE_EXTENSION_NAME)
&& gst_vulkan_device_is_extension_enabled (queue->device,
VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME)
&& gst_vulkan_device_is_extension_enabled (queue->device, extension)))
return NULL;
decoder = g_object_new (GST_TYPE_VULKAN_DECODER, NULL);
gst_object_ref_sink (decoder);
decoder->queue = gst_object_ref (queue);
decoder->codec = codec;
return decoder;
}

View file

@ -21,7 +21,6 @@
#pragma once
#include <gst/vulkan/gstvkqueue.h>
#include <gst/vulkan/gstvkvideoutils.h>
G_BEGIN_DECLS
@ -34,6 +33,11 @@ G_BEGIN_DECLS
GST_VULKAN_API
GType gst_vulkan_decoder_get_type (void);
typedef struct _GstVulkanDecoder GstVulkanDecoder;
typedef struct _GstVulkanDecoderClass GstVulkanDecoderClass;
typedef struct _GstVulkanDecoderPicture GstVulkanDecoderPicture;
typedef union _GstVulkanDecoderParameters GstVulkanDecoderParameters;
/**
* GstVulkanDecoderPicture:
* @out: output buffer
@ -132,6 +136,9 @@ union _GstVulkanDecoderParameters
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GstVulkanDecoder, gst_object_unref)
GST_VULKAN_API
GstVulkanDecoder * gst_vulkan_decoder_new_from_queue (GstVulkanQueue * queue,
guint codec);
GST_VULKAN_API
gboolean gst_vulkan_decoder_start (GstVulkanDecoder * self,
GstVulkanVideoProfile * profile,

View file

@ -23,6 +23,9 @@
#endif
#include "gstvkqueue.h"
#if GST_VULKAN_HAVE_VIDEO_EXTENSIONS
#include "gstvkdecoder-private.h"
#endif
/**
* SECTION:vkqueue
@ -154,81 +157,6 @@ error:
return NULL;
}
/**
* gst_vulkan_queue_create_decoder:
* @queue: a #GstVulkanQueue
* @codec: (type guint): the VkVideoCodecOperationFlagBitsKHR to decode
*
* Creates a #GstVulkanDecoder object if @codec decoding is supported by @queue
*
* Returns: (transfer full) (nullable): the #GstVulkanDecoder object
*
* Since: 1.24
*/
GstVulkanDecoder *
gst_vulkan_queue_create_decoder (GstVulkanQueue * queue, guint codec)
{
#if GST_VULKAN_HAVE_VIDEO_EXTENSIONS
GstVulkanPhysicalDevice *device;
GstVulkanDecoder *decoder;
guint flags, expected_flag, supported_video_ops;
const char *extension;
g_return_val_if_fail (GST_IS_VULKAN_QUEUE (queue), NULL);
device = queue->device->physical_device;
expected_flag = VK_QUEUE_VIDEO_DECODE_BIT_KHR;
flags = device->queue_family_props[queue->family].queueFlags;
supported_video_ops = device->queue_family_ops[queue->family].video;
if (device->properties.apiVersion < VK_MAKE_VERSION (1, 3, 238)) {
GST_WARNING_OBJECT (queue,
"Driver API version [%d.%d.%d] doesn't support Video extensions",
VK_VERSION_MAJOR (device->properties.apiVersion),
VK_VERSION_MINOR (device->properties.apiVersion),
VK_VERSION_PATCH (device->properties.apiVersion));
return NULL;
}
switch (codec) {
case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR:
extension = VK_KHR_VIDEO_DECODE_H264_EXTENSION_NAME;
break;
case VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR:
extension = VK_KHR_VIDEO_DECODE_H265_EXTENSION_NAME;
break;
default:
GST_WARNING_OBJECT (queue, "Unsupported codec %u", codec);
return NULL;
}
if ((flags & expected_flag) != expected_flag) {
GST_WARNING_OBJECT (queue, "Queue doesn't support decoding");
return NULL;
}
if ((supported_video_ops & codec) != codec) {
GST_WARNING_OBJECT (queue, "Queue doesn't support codec %u decoding",
codec);
return NULL;
}
if (!(gst_vulkan_device_is_extension_enabled (queue->device,
VK_KHR_VIDEO_QUEUE_EXTENSION_NAME)
&& gst_vulkan_device_is_extension_enabled (queue->device,
VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME)
&& gst_vulkan_device_is_extension_enabled (queue->device, extension)))
return NULL;
decoder = g_object_new (GST_TYPE_VULKAN_DECODER, NULL);
gst_object_ref_sink (decoder);
decoder->queue = gst_object_ref (queue);
decoder->codec = codec;
return decoder;
#else
return NULL;
#endif
}
/**
* gst_context_set_vulkan_queue:
* @context: a #GstContext

View file

@ -23,9 +23,6 @@
#include <gst/vulkan/gstvkdevice.h>
#include <gst/vulkan/gstvkcommandpool.h>
#if GST_VULKAN_HAVE_VIDEO_EXTENSIONS
#include <gst/vulkan/gstvkdecoder.h>
#endif
#define GST_TYPE_VULKAN_QUEUE (gst_vulkan_queue_get_type())
#define GST_VULKAN_QUEUE(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GST_TYPE_VULKAN_QUEUE, GstVulkanQueue))
@ -83,15 +80,12 @@ struct _GstVulkanQueueClass
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GstVulkanQueue, gst_object_unref)
GST_VULKAN_API
GST_VULKAN_API
GstVulkanDevice * gst_vulkan_queue_get_device (GstVulkanQueue * queue);
GST_VULKAN_API
GstVulkanCommandPool * gst_vulkan_queue_create_command_pool (GstVulkanQueue * queue,
GError ** error);
GST_VULKAN_API
GstVulkanDecoder * gst_vulkan_queue_create_decoder (GstVulkanQueue * queue,
guint codec);
GST_VULKAN_API
void gst_vulkan_queue_submit_lock (GstVulkanQueue * queue);

View file

@ -178,8 +178,18 @@ _get_function_table (GstVulkanSwapper * swapper)
}
static VkColorSpaceKHR
_vk_color_space_from_video_info (GstVideoInfo * v_info)
_vk_color_space_from_vk_format (GstVulkanSwapper * swapper, VkFormat format)
{
GstVulkanSwapperPrivate *priv = GET_PRIV (swapper);
int i;
for (i = 0; i < priv->n_surf_formats; i++) {
if (format != priv->surf_formats[i].format)
continue;
return priv->surf_formats[i].colorSpace;
}
GST_WARNING_OBJECT (swapper, "unsupported format for swapper's colospaces");
return VK_COLORSPACE_SRGB_NONLINEAR_KHR;
}
@ -790,7 +800,7 @@ _allocate_swapchain (GstVulkanSwapper * swapper, GstCaps * caps,
}
format = gst_vulkan_format_from_video_info (&priv->v_info, 0);
color_space = _vk_color_space_from_video_info (&priv->v_info);
color_space = _vk_color_space_from_vk_format (swapper, format);
if ((priv->surf_props.supportedCompositeAlpha &
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) != 0) {

View file

@ -333,12 +333,9 @@ static StdVideoH265PictureParameterSet h265_pps;
endif
if have_vk_video
vulkan_conf.set('GST_VULKAN_HAVE_VIDEO_EXTENSIONS', 1)
vulkan_priv_sources += files('gstvkvideo-private.c')
vulkan_sources += files(
'gstvkdecoder.c',
)
vulkan_headers += files(
'gstvkdecoder.h'
vulkan_priv_sources += files(
'gstvkvideo-private.c',
'gstvkdecoder-private.c',
)
elif get_option('vulkan-video').enabled()
error('Vulkan Video extensions headers not found')
@ -501,4 +498,3 @@ if enabled_vulkan_winsys.contains('wayland')
sources : vulkan_wayland_gir)
meson.override_dependency('gstreamer-vulkan-wayland-1.0', gstvulkanwayland_dep)
endif

View file

@ -119,12 +119,6 @@ typedef struct _GstVulkanOperation GstVulkanOperation;
typedef struct _GstVulkanOperationClass GstVulkanOperationClass;
typedef struct _GstVulkanOperationPrivate GstVulkanOperationPrivate;
typedef struct _GstVulkanDecoder GstVulkanDecoder;
typedef struct _GstVulkanDecoderClass GstVulkanDecoderClass;
typedef struct _GstVulkanDecoderPrivate GstVulkanDecoderPrivate;
typedef union _GstVulkanDecoderParameters GstVulkanDecoderParameters;
typedef struct _GstVulkanDecoderPicture GstVulkanDecoderPicture;
G_END_DECLS
#endif /* __GST_VULKAN_FWD_H__ */

View file

@ -196,6 +196,9 @@ gst_wl_window_finalize (GObject * gobject)
gst_wl_display_callback_destroy (priv->display, &priv->frame_callback);
gst_wl_display_callback_destroy (priv->display, &priv->commit_callback);
if (priv->staged_buffer)
gst_wl_buffer_unref_buffer (priv->staged_buffer);
g_cond_clear (&priv->configure_cond);
g_mutex_clear (&priv->configure_mutex);
g_mutex_clear (&priv->window_lock);

View file

@ -428,12 +428,22 @@ send_command_to_all (GstUnixFdSink * self, CommandType type, GUnixFDList * fds,
}
static GstClockTime
calculate_timestamp (GstClockTime timestamp, GstClockTime base_time,
GstClockTime latency, GstClockTimeDiff clock_diff)
to_monotonic (GstClockTime timestamp, const GstSegment * segment,
GstClockTime base_time, GstClockTime latency, GstClockTimeDiff clock_diff)
{
if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
/* Convert running time to pipeline clock time */
timestamp += base_time;
gint res =
gst_segment_to_running_time_full (segment, GST_FORMAT_TIME, timestamp,
&timestamp);
if (res == 0)
return GST_CLOCK_TIME_NONE;
else if (res > 0)
timestamp += base_time;
else if (base_time > timestamp)
timestamp = base_time - timestamp;
else
timestamp = 0;
if (GST_CLOCK_TIME_IS_VALID (latency))
timestamp += latency;
/* Convert to system monotonic clock time */
@ -485,11 +495,11 @@ gst_unix_fd_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
* id so we know which buffer to unref. */
new_buffer->id = (guint64) buffer;
new_buffer->pts =
calculate_timestamp (GST_BUFFER_PTS (buffer), base_time, latency,
clock_diff);
to_monotonic (GST_BUFFER_PTS (buffer),
&GST_BASE_SINK_CAST (self)->segment, base_time, latency, clock_diff);
new_buffer->dts =
calculate_timestamp (GST_BUFFER_DTS (buffer), base_time, latency,
clock_diff);
to_monotonic (GST_BUFFER_DTS (buffer),
&GST_BASE_SINK_CAST (self)->segment, base_time, latency, clock_diff);
new_buffer->duration = GST_BUFFER_DURATION (buffer);
new_buffer->offset = GST_BUFFER_OFFSET (buffer);
new_buffer->offset_end = GST_BUFFER_OFFSET_END (buffer);
@ -498,6 +508,15 @@ gst_unix_fd_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
new_buffer->n_memory = n_memory;
new_buffer->n_meta = n_meta;
if ((GST_BUFFER_PTS_IS_VALID (buffer)
&& !GST_CLOCK_TIME_IS_VALID (new_buffer->pts))
|| (GST_BUFFER_DTS_IS_VALID (buffer)
&& !GST_CLOCK_TIME_IS_VALID (new_buffer->dts))) {
GST_ERROR_OBJECT (self,
"Could not convert buffer timestamp to running time");
return GST_FLOW_ERROR;
}
gboolean dmabuf_count = 0;
GUnixFDList *fds = g_unix_fd_list_new ();
for (int i = 0; i < n_memory; i++) {

View file

@ -89,31 +89,34 @@ typedef struct
guint n_memory;
} BufferContext;
static void
release_buffer (GstUnixFdSrc * self, guint64 id)
{
/* Notify that we are not using this buffer anymore */
ReleaseBufferPayload payload = { id };
GError *error = NULL;
if (!gst_unix_fd_send_command (self->socket, COMMAND_TYPE_RELEASE_BUFFER,
NULL, (guint8 *) & payload, sizeof (payload), &error)) {
GST_WARNING_OBJECT (self, "Failed to send release-buffer command: %s",
error->message);
g_clear_error (&error);
}
}
static void
memory_weak_ref_cb (GstUnixFdSrc * self, GstMemory * mem)
{
GST_OBJECT_LOCK (self);
BufferContext *ctx = g_hash_table_lookup (self->memories, mem);
if (ctx == NULL)
goto out;
if (--ctx->n_memory == 0) {
/* Notify that we are not using this buffer anymore */
ReleaseBufferPayload payload = { ctx->id };
GError *error = NULL;
if (!gst_unix_fd_send_command (self->socket, COMMAND_TYPE_RELEASE_BUFFER,
NULL, (guint8 *) & payload, sizeof (payload), &error)) {
GST_WARNING_OBJECT (self, "Failed to send release-buffer command: %s",
error->message);
g_clear_error (&error);
if (ctx != NULL) {
if (--ctx->n_memory == 0) {
release_buffer (self, ctx->id);
g_free (ctx);
}
g_free (ctx);
g_hash_table_remove (self->memories, mem);
}
g_hash_table_remove (self->memories, mem);
out:
GST_OBJECT_UNLOCK (self);
}
@ -279,7 +282,7 @@ gst_unix_fd_src_unlock_stop (GstBaseSrc * bsrc)
}
static GstClockTime
calculate_timestamp (GstClockTime timestamp, GstClockTime base_time,
from_monotonic (GstClockTime timestamp, GstClockTime base_time,
GstClockTimeDiff clock_diff)
{
if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
@ -295,6 +298,14 @@ calculate_timestamp (GstClockTime timestamp, GstClockTime base_time,
return timestamp;
}
static void
close_and_free_fds (gint * fds, gint fds_len)
{
for (int i = 0; i < fds_len; i++)
g_close (fds[i], NULL);
g_free (fds);
}
static GstFlowReturn
gst_unix_fd_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
{
@ -335,33 +346,26 @@ again:
goto on_error;
}
if (fds == NULL) {
GST_ERROR_OBJECT (self,
"Received new buffer command without file descriptors");
return GST_FLOW_ERROR;
}
if (g_unix_fd_list_get_length (fds) != new_buffer->n_memory) {
gint fds_arr_len = 0;
gint *fds_arr =
(fds != NULL) ? g_unix_fd_list_steal_fds (fds, &fds_arr_len) : NULL;
if (fds_arr_len != new_buffer->n_memory) {
GST_ERROR_OBJECT (self,
"Received new buffer command with %d file descriptors instead of "
"%d", g_unix_fd_list_get_length (fds), new_buffer->n_memory);
"%d", fds_arr_len, new_buffer->n_memory);
ret = GST_FLOW_ERROR;
close_and_free_fds (fds_arr, fds_arr_len);
goto on_error;
}
if (new_buffer->type >= MEMORY_TYPE_LAST) {
GST_ERROR_OBJECT (self, "Unknown buffer type %d", new_buffer->type);
ret = GST_FLOW_ERROR;
close_and_free_fds (fds_arr, fds_arr_len);
goto on_error;
}
GstAllocator *allocator = self->allocators[new_buffer->type];
gint *fds_arr = g_unix_fd_list_steal_fds (fds, NULL);
BufferContext *ctx = g_new0 (BufferContext, 1);
ctx->id = new_buffer->id;
ctx->n_memory = new_buffer->n_memory;
*outbuf = gst_buffer_new ();
GstClockTime base_time =
@ -373,9 +377,9 @@ again:
}
GST_BUFFER_PTS (*outbuf) =
calculate_timestamp (new_buffer->pts, base_time, clock_diff);
from_monotonic (new_buffer->pts, base_time, clock_diff);
GST_BUFFER_DTS (*outbuf) =
calculate_timestamp (new_buffer->dts, base_time, clock_diff);
from_monotonic (new_buffer->dts, base_time, clock_diff);
GST_BUFFER_DURATION (*outbuf) = new_buffer->duration;
GST_BUFFER_OFFSET (*outbuf) = new_buffer->offset;
GST_BUFFER_OFFSET_END (*outbuf) = new_buffer->offset_end;
@ -388,24 +392,35 @@ again:
if (consumed == 0) {
GST_ERROR_OBJECT (self, "Malformed meta serialization");
ret = GST_FLOW_ERROR;
close_and_free_fds (fds_arr, fds_arr_len);
gst_clear_buffer (outbuf);
goto on_error;
}
payload_off += consumed;
}
GST_OBJECT_LOCK (self);
for (int i = 0; i < new_buffer->n_memory; i++) {
GstMemory *mem = gst_fd_allocator_alloc (allocator, fds_arr[i],
new_buffer->memories[i].size, GST_FD_MEMORY_FLAG_NONE);
gst_memory_resize (mem, new_buffer->memories[i].offset,
new_buffer->memories[i].size);
GST_MINI_OBJECT_FLAG_SET (mem, GST_MEMORY_FLAG_READONLY);
if (new_buffer->n_memory > 0) {
BufferContext *ctx = g_new0 (BufferContext, 1);
ctx->id = new_buffer->id;
ctx->n_memory = new_buffer->n_memory;
for (int i = 0; i < new_buffer->n_memory; i++) {
GstMemory *mem = gst_fd_allocator_alloc (allocator, fds_arr[i],
new_buffer->memories[i].size, GST_FD_MEMORY_FLAG_NONE);
gst_memory_resize (mem, new_buffer->memories[i].offset,
new_buffer->memories[i].size);
GST_MINI_OBJECT_FLAG_SET (mem, GST_MEMORY_FLAG_READONLY);
g_hash_table_insert (self->memories, mem, ctx);
gst_mini_object_weak_ref (GST_MINI_OBJECT_CAST (mem),
(GstMiniObjectNotify) memory_weak_ref_cb, self);
g_hash_table_insert (self->memories, mem, ctx);
gst_mini_object_weak_ref (GST_MINI_OBJECT_CAST (mem),
(GstMiniObjectNotify) memory_weak_ref_cb, self);
gst_buffer_append_memory (*outbuf, mem);
gst_buffer_append_memory (*outbuf, mem);
}
} else {
/* This buffer has no memories, we can release it immediately otherwise
* it gets leaked. */
release_buffer (self, new_buffer->id);
}
GST_OBJECT_UNLOCK (self);

File diff suppressed because it is too large Load diff

View file

@ -777,11 +777,13 @@ gst_d3d12_screen_capture_src_decide_allocation (GstBaseSrc * bsrc,
if (!params) {
params = gst_d3d12_allocation_params_new (self->device, &vinfo,
GST_D3D12_ALLOCATION_FLAG_DEFAULT, resource_flags,
D3D12_HEAP_FLAG_NONE);
D3D12_HEAP_FLAG_SHARED);
} else {
gst_d3d12_allocation_params_set_resource_flags (params, resource_flags);
gst_d3d12_allocation_params_unset_resource_flags (params,
D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE);
gst_d3d12_allocation_params_set_heap_flags (params,
D3D12_HEAP_FLAG_SHARED);
}
gst_buffer_pool_config_set_d3d12_allocation_params (config, params);
@ -815,7 +817,7 @@ gst_d3d12_screen_capture_src_decide_allocation (GstBaseSrc * bsrc,
auto params = gst_d3d12_allocation_params_new (self->device, &vinfo,
GST_D3D12_ALLOCATION_FLAG_DEFAULT, resource_flags,
D3D12_HEAP_FLAG_NONE);
D3D12_HEAP_FLAG_SHARED);
gst_buffer_pool_config_set_d3d12_allocation_params (config, params);
gst_d3d12_allocation_params_free (params);

View file

@ -25,6 +25,7 @@
#include <gst/gst.h>
#include <gst/check/gstcheck.h>
#include <gst/app/app.h>
#include <glib/gstdio.h>
static void
@ -134,6 +135,92 @@ GST_START_TEST (test_unixfd_videotestsrc)
GST_END_TEST;
GST_START_TEST (test_unixfd_segment)
{
GError *error = NULL;
/* Ensure we don't have socket from previous failed test */
gchar *socket_path =
g_strdup_printf ("%s/unixfd-test-socket", g_get_user_runtime_dir ());
if (g_file_test (socket_path, G_FILE_TEST_EXISTS)) {
g_unlink (socket_path);
}
GstCaps *caps = gst_caps_new_empty_simple ("video/x-raw");
/* Setup service */
gchar *pipeline_str =
g_strdup_printf
("appsrc name=src format=time handle-segment-change=true ! unixfdsink socket-path=%s sync=false async=false",
socket_path);
GstElement *pipeline_service = gst_parse_launch (pipeline_str, &error);
g_assert_no_error (error);
fail_unless (gst_element_set_state (pipeline_service,
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
GstElement *appsrc = gst_bin_get_by_name (GST_BIN (pipeline_service), "src");
gst_object_unref (appsrc);
g_free (pipeline_str);
/* Setup client */
pipeline_str =
g_strdup_printf
("unixfdsrc socket-path=%s ! appsink name=sink sync=false async=false",
socket_path);
GstElement *pipeline_client = gst_parse_launch (pipeline_str, &error);
g_assert_no_error (error);
fail_unless (gst_element_set_state (pipeline_client,
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
GstElement *appsink = gst_bin_get_by_name (GST_BIN (pipeline_client), "sink");
gst_object_unref (appsink);
g_free (pipeline_str);
/* Send a buffer with PTS=30s */
GstSegment segment;
gst_segment_init (&segment, GST_FORMAT_TIME);
GstBuffer *buf = gst_buffer_new ();
GST_BUFFER_PTS (buf) = 30 * GST_SECOND;
GstSample *sample = gst_sample_new (buf, caps, &segment, NULL);
gst_app_src_push_sample (GST_APP_SRC (appsrc), sample);
gst_sample_unref (sample);
gst_buffer_unref (buf);
/* Wait for it */
sample = gst_app_sink_pull_sample (GST_APP_SINK (appsink));
buf = gst_sample_get_buffer (sample);
GstClockTime first_pts = GST_BUFFER_PTS (buf);
gst_sample_unref (sample);
/* Send a buffer with PTS=1s but with 30s offset in the segment */
segment.base = 30 * GST_SECOND;
buf = gst_buffer_new ();
GST_BUFFER_PTS (buf) = 1 * GST_SECOND;
sample = gst_sample_new (buf, caps, &segment, NULL);
gst_app_src_push_sample (GST_APP_SRC (appsrc), sample);
gst_sample_unref (sample);
gst_buffer_unref (buf);
/* Wait for it */
sample = gst_app_sink_pull_sample (GST_APP_SINK (appsink));
buf = gst_sample_get_buffer (sample);
GstClockTime second_pts = GST_BUFFER_PTS (buf);
gst_sample_unref (sample);
/* They should be 1s appart */
fail_unless_equals_uint64 (second_pts - first_pts, GST_SECOND);
/* Teardown */
fail_unless (gst_element_set_state (pipeline_client,
GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
fail_unless (gst_element_set_state (pipeline_service,
GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
gst_object_unref (pipeline_service);
gst_object_unref (pipeline_client);
g_free (socket_path);
gst_caps_unref (caps);
}
GST_END_TEST;
static Suite *
unixfd_suite (void)
{
@ -142,6 +229,7 @@ unixfd_suite (void)
suite_add_tcase (s, tc);
tcase_add_test (tc, test_unixfd_videotestsrc);
tcase_add_test (tc, test_unixfd_segment);
return s;
}

View file

@ -26,6 +26,8 @@
#include <gst/check/gstcheck.h>
#include <gst/vulkan/vulkan.h>
#include "gst/vulkan/gstvkdecoder-private.h"
static GstVulkanInstance *instance;
static GstVulkanDevice *device;
static GstVulkanQueue *video_queue = NULL;
@ -327,7 +329,7 @@ GST_START_TEST (test_h264_decoder)
return;
}
dec = gst_vulkan_queue_create_decoder (video_queue,
dec = gst_vulkan_decoder_new_from_queue (video_queue,
VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR);
if (!dec) {
GST_WARNING ("Unable to create a vulkan decoder");
@ -495,7 +497,7 @@ GST_START_TEST (test_h265_decoder)
return;
}
dec = gst_vulkan_queue_create_decoder (video_queue,
dec = gst_vulkan_decoder_new_from_queue (video_queue,
VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR);
if (!dec) {
GST_WARNING ("Unable to create a vulkan decoder");

View file

@ -65,6 +65,25 @@ typedef struct _GstExifWriter GstExifWriter;
typedef struct _GstExifReader GstExifReader;
typedef struct _GstExifTagData GstExifTagData;
#define GST_CAT_DEFAULT gst_exif_tag_ensure_debug_category()
static GstDebugCategory *
gst_exif_tag_ensure_debug_category (void)
{
static gsize cat_gonce = 0;
if (g_once_init_enter (&cat_gonce)) {
GstDebugCategory *cat = NULL;
GST_DEBUG_CATEGORY_INIT (cat, "exif-tags", 0, "EXIF tag parsing");
g_once_init_leave (&cat_gonce, (gsize) cat);
}
return (GstDebugCategory *) cat_gonce;
}
typedef void (*GstExifSerializationFunc) (GstExifWriter * writer,
const GstTagList * taglist, const GstExifTagMatch * exiftag);

View file

@ -2614,25 +2614,38 @@ reconfigure_output (GstPlayBin3 * playbin)
GST_DEBUG_OBJECT (playbin, "Stream type '%s' is now requested",
gst_stream_type_get_name (combine->stream_type));
g_assert (combine->sinkpad == NULL);
if (combine->sinkpad) {
/* This was previously an assert but is now just a WARNING
*
* This *theoretically* should never happen, but there is the
* possibility where there was a failure within (uri)decodebin3 where
* the collection was posted (by demuxer for ex) but the decoding failed
* (no decoder, bad stream, etc...).
*
* in that case, we could have a combiner already prepared for that type
* but never got activated.
**/
GST_WARNING_OBJECT (playbin, "Combiner already configured");
} else {
/* Request playsink sink pad */
combine->sinkpad =
gst_play_sink_request_pad (playbin->playsink,
gst_play_sink_type_from_stream_type (combine->stream_type));
gst_object_ref (combine->sinkpad);
/* Create combiner if needed and link it */
create_combiner (playbin, combine);
if (combine->combiner) {
res = gst_pad_link (combine->srcpad, combine->sinkpad);
GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d",
gst_stream_type_get_name (combine->stream_type), res);
if (res != GST_PAD_LINK_OK) {
GST_ELEMENT_ERROR (playbin, CORE, PAD,
("Internal playbin error."),
("Failed to link combiner to sink. Error %d", res));
}
/* Request playsink sink pad */
combine->sinkpad =
gst_play_sink_request_pad (playbin->playsink,
gst_play_sink_type_from_stream_type (combine->stream_type));
gst_object_ref (combine->sinkpad);
/* Create combiner if needed and link it */
create_combiner (playbin, combine);
if (combine->combiner) {
res = gst_pad_link (combine->srcpad, combine->sinkpad);
GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d",
gst_stream_type_get_name (combine->stream_type), res);
if (res != GST_PAD_LINK_OK) {
GST_ELEMENT_ERROR (playbin, CORE, PAD,
("Internal playbin error."),
("Failed to link combiner to sink. Error %d", res));
}
}
}
}

View file

@ -1202,7 +1202,7 @@ gst_soup_http_src_session_open (GstSoupHTTPSrc * src)
/* now owned by the loop */
g_main_context_unref (ctx);
src->session->thread = g_thread_try_new ("souphttpsrc-thread",
src->session->thread = g_thread_try_new ("souphttpsrc",
thread_func, src, NULL);
if (!src->session->thread) {

View file

@ -45,35 +45,53 @@ pylib_loc = get_option('libpython-dir')
fsmod = import('fs')
pylib_prefix = 'lib'
pylib_suffix = 'so'
pylib_ver = python_dep.version()
pylib_locs = []
if host_system == 'windows'
if cc.get_argument_syntax() == 'msvc'
pylib_prefix = ''
endif
pylib_suffix = 'dll'
pylib_ver = pylib_ver.replace('.', '')
elif host_system == 'darwin'
pylib_suffix = 'dylib'
endif
pylib_fnames = []
# Library name with soversion, non-devel package
pylib_fnames += python.get_variable('INSTSONAME', [])
if python.has_variable('INSTSONAME')
# For example, libpython3.12.so.1.0 (Linux), libpython3.11.dll.a (MSYS2), etc.
pylib_fnames += python.get_variable('INSTSONAME')
endif
# Library name without soversion, devel package, framework, etc.
pylib_fnames += python.get_variable('LDLIBRARY', [])
if python.has_variable('LDLIBRARY')
# For example, libpython3.12.so (Linux), libpython3.11.dll.a (MSYS2), etc.
pylib_fnames += python.get_variable('LDLIBRARY')
endif
# Manually construct name as a fallback
pylib_fnames += [
pylib_prefix + 'python' + python_dep.version() + python_abi_flags + '.' + pylib_suffix
pylib_prefix + 'python' + pylib_ver + python_abi_flags + '.' + pylib_suffix
]
if pylib_loc != ''
pylib_locs = [pylib_loc]
else
pylib_locs = [
python.get_variable('LIBDIR', ''),
python.get_variable('LIBPL', ''),
]
if python.has_variable('LIBDIR')
pylib_locs += python.get_variable('LIBDIR')
endif
if python.has_variable('LIBPL')
pylib_locs += python.get_variable('LIBPL')
endif
# On Windows, python312.dll is in the rootdir where Python is installed,
# which is configured as the "prefix" in sysconfig.
if host_system == 'windows'
pylib_locs += python.get_variable('prefix')
endif
endif
pylib_fname = ''
foreach loc: pylib_locs
foreach fname: pylib_fnames
if fsmod.exists(loc / fname)
fpath = loc / fname
debug(f'Looking for Python library at: @fpath@')
if fsmod.exists(fpath)
pylib_fname = fname
message(f'PY_LIB_FNAME = @fname@ (@loc@)')
break
@ -81,12 +99,7 @@ foreach loc: pylib_locs
endforeach
endforeach
if pylib_fname == ''
error_msg = 'Could not find python library to load'
if python_opt.enabled()
error(error_msg)
else
message(error_msg)
endif
message('Could not find python library to load, will try loading at runtime')
endif
pygi_override_dir = get_option('pygi-overrides-dir')

View file

@ -4014,13 +4014,24 @@ mark_event_not_received (GstPad * pad, PadEvent * ev, gpointer user_data)
* @pad: a #GstPad
* @offset: the offset
*
* Set the offset that will be applied to the running time of @pad.
* Set the offset that will be applied to the running time of @pad. Upon next
* buffer, every sticky events (notably segment) will be pushed again with
* their running time adjusted. For that reason this is only reliable on
* source pads.
*/
void
gst_pad_set_offset (GstPad * pad, gint64 offset)
{
g_return_if_fail (GST_IS_PAD (pad));
/* Setting pad offset on a sink pad does not work reliably:
* https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6464 */
if (GST_PAD_IS_SINK (pad)) {
/* Make it non fatal warning for backward compatibility. */
GST_WARNING_OBJECT (pad,
"Setting pad offset only works reliably on source pads");
}
GST_OBJECT_LOCK (pad);
/* if nothing changed, do nothing */
if (pad->offset == offset)