Compare commits

...

18 commits

Author SHA1 Message Date
Seungha Yang 06a92667ac Merge branch 'deinit-callback' into 'main'
gst: Add gst_register_deinit_notify() API

See merge request gstreamer/gstreamer!6381
2024-04-27 15:02:58 +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
Seungha Yang 47ff3ea50a d3d11: Report live object on gst_deinit()
This would be useful for tracing D3D11 resource leaks
2024-03-21 19:10:18 +09:00
Seungha Yang b5a7d0ae48 gst: Add gst_deinit_register_notify() API
Add an API so that user can install a callback function to be
called when gst_deinit() is executed, then performs library specific
teardown operations such as clearing resources or reporting live
objects.
2024-03-21 19:07:18 +09:00
28 changed files with 1192 additions and 1188 deletions

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

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

@ -203,10 +203,10 @@ gst_d3d11_device_enable_d3d11_debug (void)
/* If all below libraries are unavailable, d3d11 device would fail with
* D3D11_CREATE_DEVICE_DEBUG flag */
static const gchar *sdk_dll_names[] = {
"d3d11sdklayers.dll",
"d3d11_1sdklayers.dll",
"d3d11_2sdklayers.dll",
"d3d11_3sdklayers.dll",
"d3d11_2sdklayers.dll",
"d3d11_1sdklayers.dll",
"d3d11sdklayers.dll",
};
GST_D3D11_CALL_ONCE_BEGIN {
@ -289,6 +289,78 @@ gst_d3d11_device_d3d11_debug (GstD3D11Device * device,
return;
}
/* *INDENT-OFF* */
static ID3D11Debug *g_debug_device = nullptr;
static ID3D11InfoQueue *g_debug_info_queue = nullptr;
static std::recursive_mutex g_sdk_debug_lock;
/* *INDENT-ON* */
static void
gst_d3d11_device_sdk_debug_init (ID3D11Debug * dbg, ID3D11InfoQueue * queue)
{
std::lock_guard < std::recursive_mutex > lk (g_sdk_debug_lock);
if (g_debug_device)
return;
g_debug_device = dbg;
g_debug_device->AddRef ();
g_debug_info_queue = queue;
g_debug_info_queue->AddRef ();
}
static void
gst_d3d11_device_sdk_debug_deinit (gpointer user_data)
{
std::lock_guard < std::recursive_mutex > lk (g_sdk_debug_lock);
if (!g_debug_device)
return;
GST_CAT_INFO (gst_d3d11_debug_layer_debug, "Begin live object report");
auto hr = g_debug_device->ReportLiveDeviceObjects ((D3D11_RLDO_FLAGS)
GST_D3D11_RLDO_FLAGS);
if (SUCCEEDED (hr)) {
UINT64 num_msg = g_debug_info_queue->GetNumStoredMessages ();
for (UINT64 i = 0; num_msg; i++) {
GstDebugLevel level;
SIZE_T msg_len;
hr = g_debug_info_queue->GetMessage (i, nullptr, &msg_len);
if (FAILED (hr))
break;
if (msg_len == 0)
continue;
auto msg = (D3D11_MESSAGE *) g_malloc0 (msg_len);
hr = g_debug_info_queue->GetMessage (i, msg, &msg_len);
if (FAILED (hr)) {
g_free (msg);
break;
}
level = d3d11_message_severity_to_gst (msg->Severity);
if (msg->Category == D3D11_MESSAGE_CATEGORY_STATE_CREATION &&
level > GST_LEVEL_ERROR) {
level = GST_LEVEL_INFO;
}
gst_debug_log (gst_d3d11_debug_layer_debug, level, __FILE__, GST_FUNCTION,
__LINE__, nullptr, "D3D11InfoQueue: Severity (%d), %s",
msg->Severity, msg->pDescription);
g_free (msg);
}
}
g_debug_info_queue->ClearStoredMessages ();
GST_CAT_INFO (gst_d3d11_debug_layer_debug, "End live object report");
GST_D3D11_CLEAR_COM (g_debug_info_queue);
GST_D3D11_CLEAR_COM (g_debug_device);
}
#else
void
gst_d3d11_device_d3d11_debug (GstD3D11Device * device,
@ -456,6 +528,10 @@ gst_d3d11_device_class_init (GstD3D11DeviceClass * klass)
pspec_removed_reason);
gst_d3d11_memory_init_once ();
#if HAVE_D3D11SDKLAYERS_H
gst_deinit_register_notify (gst_d3d11_device_sdk_debug_deinit, nullptr);
#endif
}
static void
@ -994,6 +1070,7 @@ gst_d3d11_device_setup_debug_layer (GstD3D11Device * self)
GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self,
"ID3D11InfoQueue interface available");
priv->d3d11_info_queue = info_queue;
gst_d3d11_device_sdk_debug_init (debug, info_queue);
}
}
}

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

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

@ -172,6 +172,23 @@ static gboolean parse_goption_arg (const gchar * s_opt,
GSList *_priv_gst_preload_plugins = NULL;
/* deinit callbacks */
static GList *_gst_deinit_notifies = NULL;
typedef struct _GstDeinitNotify
{
GstDeinitNotifyFunc func;
gpointer user_data;
} GstDeinitNotify;
static void
gst_deinit_notify_free (GstDeinitNotify * cb)
{
if (cb->func)
cb->func (cb->user_data);
g_free (cb);
}
enum
{
ARG_VERSION = 1,
@ -1092,6 +1109,10 @@ gst_deinit (void)
}
GST_INFO ("deinitializing GStreamer");
g_list_free_full (_gst_deinit_notifies,
(GDestroyNotify) gst_deinit_notify_free);
g_thread_pool_set_max_unused_threads (0);
bin_class = (GstBinClass *) g_type_class_peek (gst_bin_get_type ());
if (bin_class && bin_class->pool != NULL) {
@ -1326,3 +1347,40 @@ gst_segtrap_set_enabled (gboolean enabled)
{
_gst_disable_segtrap = !enabled;
}
/**
* gst_deinit_register_notify:
* @func: (scope async): a #GstDeinitNotifyFunc
* @user_data: (nullable): private user data
*
* Registers a callback notified when gst_deinit() is called.
* This could be useful for a GStreamer library where the library holds
* persistent resources but prefers the resources to be released
* when gst_deinit() is called, so that any expected resource leaks
* (either GStreamer object or native handle/memory) can be addressed.
*
* Applications or GStreamer components can register callbacks
* before GStreamer is initialized, but installing notify after gst_deinit()
* is not allowed.
*
* Since: 1.26
*/
void
gst_deinit_register_notify (GstDeinitNotifyFunc func, gpointer user_data)
{
GstDeinitNotify *cb;
g_rec_mutex_lock (&init_lock);
if (gst_deinitialized) {
g_warning ("GStreamer was deinitialized already.");
g_rec_mutex_unlock (&init_lock);
return;
}
cb = g_new0 (GstDeinitNotify, 1);
cb->func = func;
cb->user_data = user_data;
_gst_deinit_notifies = g_list_prepend (_gst_deinit_notifies, cb);
g_rec_mutex_unlock (&init_lock);
}

View file

@ -144,6 +144,18 @@ gboolean gst_update_registry (void);
GST_API
const gchar * gst_get_main_executable_path (void);
/**
* GstDeinitNotifyFunc:
* @user_data: User data registered along with this function via gst_deinit_register_notify()
*
* Since: 1.26
*/
typedef void (*GstDeinitNotifyFunc) (gpointer user_data);
GST_API
void gst_deinit_register_notify (GstDeinitNotifyFunc func,
gpointer user_data);
G_END_DECLS
#endif /* __GST_H__ */

View file

@ -0,0 +1,49 @@
/* 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 <gst/gst.h>
static void
deinit_cb (guint * cb_count)
{
*cb_count += 1;
}
int
main (int argc, char **argv)
{
guint cb_count = 0;
/* Installing callback before gst_init() is allowed */
gst_deinit_register_notify ((GstDeinitNotifyFunc) deinit_cb, &cb_count);
gst_init (NULL, NULL);
/* Install callback again */
gst_deinit_register_notify ((GstDeinitNotifyFunc) deinit_cb, &cb_count);
gst_deinit ();
g_assert (cb_count == 2);
return 0;
}

View file

@ -16,6 +16,7 @@ core_tests = [
[ 'gst/gstcapsfeatures.c' ],
[ 'gst/gstdatetime.c' ],
[ 'gst/gstdeinit.c' ],
[ 'gst/gstdeinit2.c' ],
[ 'gst/gstdevice.c' ],
[ 'gst/gstelement.c', not gst_registry or not gst_parse],
[ 'gst/gstelementfactory.c', not gst_registry ],