2 * winegstreamer Unix library interface
4 * Copyright 2020-2021 Zebediah Figura for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
32 #include <gst/video/video.h>
33 #include <gst/audio/audio.h>
34 #include <gst/tag/tag.h>
37 #define WIN32_NO_STATUS
41 #include "unix_private.h"
43 /* GStreamer callbacks may be called on threads not created by Wine, and
44 * therefore cannot access the Wine TEB. This means that we must use GStreamer
45 * debug logging instead of Wine debug logging. In order to be safe we forbid
46 * any use of Wine debug logging in this entire file. */
48 GST_DEBUG_CATEGORY(wine
);
50 GstStreamType
stream_type_from_caps(GstCaps
*caps
)
52 const gchar
*media_type
;
54 if (!caps
|| !gst_caps_get_size(caps
))
55 return GST_STREAM_TYPE_UNKNOWN
;
57 media_type
= gst_structure_get_name(gst_caps_get_structure(caps
, 0));
58 if (g_str_has_prefix(media_type
, "video/")
59 || g_str_has_prefix(media_type
, "image/"))
60 return GST_STREAM_TYPE_VIDEO
;
61 if (g_str_has_prefix(media_type
, "audio/"))
62 return GST_STREAM_TYPE_AUDIO
;
63 if (g_str_has_prefix(media_type
, "text/")
64 || g_str_has_prefix(media_type
, "subpicture/")
65 || g_str_has_prefix(media_type
, "closedcaption/"))
66 return GST_STREAM_TYPE_TEXT
;
68 return GST_STREAM_TYPE_UNKNOWN
;
71 GstElement
*create_element(const char *name
, const char *plugin_set
)
75 if (!(element
= gst_element_factory_make(name
, NULL
)))
76 fprintf(stderr
, "winegstreamer: failed to create %s, are %u-bit GStreamer \"%s\" plugins installed?\n",
77 name
, 8 * (unsigned int)sizeof(void *), plugin_set
);
81 GstElement
*find_element(GstElementFactoryListType type
, GstCaps
*src_caps
, GstCaps
*sink_caps
)
83 GstElement
*element
= NULL
;
84 GList
*tmp
, *transforms
;
87 if (!(transforms
= gst_element_factory_list_get_elements(type
, GST_RANK_MARGINAL
)))
90 tmp
= gst_element_factory_list_filter(transforms
, src_caps
, GST_PAD_SINK
, FALSE
);
91 gst_plugin_feature_list_free(transforms
);
92 if (!(transforms
= tmp
))
95 tmp
= gst_element_factory_list_filter(transforms
, sink_caps
, GST_PAD_SRC
, FALSE
);
96 gst_plugin_feature_list_free(transforms
);
97 if (!(transforms
= tmp
))
100 transforms
= g_list_sort(transforms
, gst_plugin_feature_rank_compare_func
);
101 for (tmp
= transforms
; tmp
!= NULL
&& element
== NULL
; tmp
= tmp
->next
)
103 name
= gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(tmp
->data
));
105 if (!strcmp(name
, "vaapidecodebin"))
107 /* vaapidecodebin adds asynchronicity which breaks wg_transform synchronous drain / flush
108 * requirements. Ignore it and use VA-API decoders directly instead.
110 GST_WARNING("Ignoring vaapidecodebin decoder.");
114 if (!(element
= gst_element_factory_create(GST_ELEMENT_FACTORY(tmp
->data
), NULL
)))
115 GST_WARNING("Failed to create %s element.", name
);
117 gst_plugin_feature_list_free(transforms
);
122 GST_DEBUG("Created %s element %p.", name
, element
);
126 gchar
*src_str
= gst_caps_to_string(src_caps
), *sink_str
= gst_caps_to_string(sink_caps
);
127 GST_WARNING("Failed to create element matching caps %s / %s.", src_str
, sink_str
);
135 bool append_element(GstElement
*container
, GstElement
*element
, GstElement
**first
, GstElement
**last
)
137 gchar
*name
= gst_element_get_name(element
);
138 bool success
= false;
140 if (!gst_bin_add(GST_BIN(container
), element
) ||
141 !gst_element_sync_state_with_parent(element
) ||
142 (*last
&& !gst_element_link(*last
, element
)))
144 GST_ERROR("Failed to link %s element.", name
);
148 GST_DEBUG("Linked %s element %p.", name
, element
);
159 bool link_src_to_element(GstPad
*src_pad
, GstElement
*element
)
161 GstPadLinkReturn ret
;
164 if (!(sink_pad
= gst_element_get_static_pad(element
, "sink")))
166 gchar
*name
= gst_element_get_name(element
);
167 GST_ERROR("Failed to find sink pad on %s", name
);
171 if ((ret
= gst_pad_link(src_pad
, sink_pad
)))
173 gchar
*src_name
= gst_pad_get_name(src_pad
), *sink_name
= gst_pad_get_name(sink_pad
);
174 GST_ERROR("Failed to link element pad %s with pad %s", src_name
, sink_name
);
178 gst_object_unref(sink_pad
);
182 bool link_element_to_sink(GstElement
*element
, GstPad
*sink_pad
)
184 GstPadLinkReturn ret
;
187 if (!(src_pad
= gst_element_get_static_pad(element
, "src")))
189 gchar
*name
= gst_element_get_name(element
);
190 GST_ERROR("Failed to find src pad on %s", name
);
194 if ((ret
= gst_pad_link(src_pad
, sink_pad
)))
196 gchar
*src_name
= gst_pad_get_name(src_pad
), *sink_name
= gst_pad_get_name(sink_pad
);
197 GST_ERROR("Failed to link pad %s with element pad %s", src_name
, sink_name
);
201 gst_object_unref(src_pad
);
205 NTSTATUS
wg_init_gstreamer(void *arg
)
207 char arg0
[] = "wine";
208 char arg1
[] = "--gst-disable-registry-fork";
209 char *args
[] = {arg0
, arg1
, NULL
};
210 int argc
= ARRAY_SIZE(args
) - 1;
214 if (!gst_init_check(&argc
, &argv
, &err
))
216 fprintf(stderr
, "winegstreamer: failed to initialize GStreamer: %s\n", err
->message
);
218 return STATUS_UNSUCCESSFUL
;
221 GST_DEBUG_CATEGORY_INIT(wine
, "WINE", GST_DEBUG_FG_RED
, "Wine GStreamer support");
223 GST_INFO("GStreamer library version %s; wine built with %d.%d.%d.",
224 gst_version_string(), GST_VERSION_MAJOR
, GST_VERSION_MINOR
, GST_VERSION_MICRO
);
225 return STATUS_SUCCESS
;