[PATCH 2/4] winegstreamer: Move wg_parser object creation to a new Unix library.
Zebediah Figura
z.figura12 at gmail.com
Thu Feb 11 16:18:56 CST 2021
Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
dlls/winegstreamer/Makefile.in | 3 +-
dlls/winegstreamer/gst_cbs.h | 6 -
dlls/winegstreamer/gst_private.h | 88 +++
dlls/winegstreamer/gstdemux.c | 1029 +----------------------------
dlls/winegstreamer/main.c | 3 +
dlls/winegstreamer/wg_parser.c | 1030 ++++++++++++++++++++++++++++++
6 files changed, 1129 insertions(+), 1030 deletions(-)
create mode 100644 dlls/winegstreamer/wg_parser.c
diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in
index 0b3229160b9..c5e4ed1ef42 100644
--- a/dlls/winegstreamer/Makefile.in
+++ b/dlls/winegstreamer/Makefile.in
@@ -16,7 +16,8 @@ C_SRCS = \
mfplat.c \
pin.c \
qualitycontrol.c \
- seeking.c
+ seeking.c \
+ wg_parser.c
IDL_SRCS = \
winegstreamer_classes.idl
diff --git a/dlls/winegstreamer/gst_cbs.h b/dlls/winegstreamer/gst_cbs.h
index fd90373d900..1daebee7906 100644
--- a/dlls/winegstreamer/gst_cbs.h
+++ b/dlls/winegstreamer/gst_cbs.h
@@ -23,12 +23,6 @@
#include "windef.h"
#include <pthread.h>
-typedef enum {
- GST_AUTOPLUG_SELECT_TRY,
- GST_AUTOPLUG_SELECT_EXPOSE,
- GST_AUTOPLUG_SELECT_SKIP
-} GstAutoplugSelectResult;
-
enum CB_TYPE {
BYTESTREAM_WRAPPER_PULL,
BYTESTREAM_QUERY,
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index adef709d8fa..7aaf25e395e 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -43,6 +43,13 @@
#include "wine/heap.h"
#include "wine/strmbase.h"
+typedef enum
+{
+ GST_AUTOPLUG_SELECT_TRY,
+ GST_AUTOPLUG_SELECT_EXPOSE,
+ GST_AUTOPLUG_SELECT_SKIP,
+} GstAutoplugSelectResult;
+
static inline const char *debugstr_time(REFERENCE_TIME time)
{
ULONGLONG abstime = time >= 0 ? time : -time;
@@ -126,6 +133,87 @@ struct wg_format
} u;
};
+struct wg_parser
+{
+ BOOL (*init_gst)(struct wg_parser *parser);
+
+ struct wg_parser_stream **streams;
+ unsigned int stream_count;
+
+ GstElement *container;
+ GstBus *bus;
+ GstPad *my_src, *their_sink;
+
+ guint64 file_size, start_offset, next_offset, stop_offset;
+
+ pthread_t push_thread;
+
+ pthread_mutex_t mutex;
+
+ pthread_cond_t init_cond;
+ bool no_more_pads, has_duration, error;
+
+ pthread_cond_t read_cond, read_done_cond;
+ struct
+ {
+ GstBuffer *buffer;
+ uint64_t offset;
+ uint32_t size;
+ bool done;
+ GstFlowReturn ret;
+ } read_request;
+
+ bool flushing, sink_connected;
+};
+
+enum wg_parser_event_type
+{
+ WG_PARSER_EVENT_NONE = 0,
+ WG_PARSER_EVENT_BUFFER,
+ WG_PARSER_EVENT_EOS,
+ WG_PARSER_EVENT_SEGMENT,
+};
+
+struct wg_parser_event
+{
+ enum wg_parser_event_type type;
+ union
+ {
+ GstBuffer *buffer;
+ struct
+ {
+ uint64_t position, stop;
+ double rate;
+ } segment;
+ } u;
+};
+
+struct wg_parser_stream
+{
+ struct wg_parser *parser;
+
+ GstPad *their_src, *post_sink, *post_src, *my_sink;
+ GstElement *flip;
+ struct wg_format preferred_format, current_format;
+
+ pthread_cond_t event_cond, event_empty_cond;
+ struct wg_parser_event event;
+
+ bool flushing, eos, enabled, has_caps;
+
+ uint64_t duration;
+};
+
+struct unix_funcs
+{
+ struct wg_parser *(CDECL *wg_decodebin_parser_create)(void);
+ struct wg_parser *(CDECL *wg_avi_parser_create)(void);
+ struct wg_parser *(CDECL *wg_mpeg_audio_parser_create)(void);
+ struct wg_parser *(CDECL *wg_wave_parser_create)(void);
+};
+
+extern const struct unix_funcs *unix_funcs;
+
extern LONG object_locks;
HRESULT avi_splitter_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
diff --git a/dlls/winegstreamer/gstdemux.c b/dlls/winegstreamer/gstdemux.c
index 384ba9e6687..b4f95df67da 100644
--- a/dlls/winegstreamer/gstdemux.c
+++ b/dlls/winegstreamer/gstdemux.c
@@ -1,8 +1,9 @@
/*
- * GStreamer splitter + decoder, adapted from parser.c
+ * DirectShow parser filters
*
* Copyright 2010 Maarten Lankhorst for CodeWeavers
* Copyright 2010 Aric Stewart for CodeWeavers
+ * Copyright 2019-2020 Zebediah Figura
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -47,77 +48,6 @@ GST_DEBUG_CATEGORY_STATIC(wine);
static const GUID MEDIASUBTYPE_CVID = {mmioFOURCC('c','v','i','d'), 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
static const GUID MEDIASUBTYPE_MP3 = {WAVE_FORMAT_MPEGLAYER3, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
-struct wg_parser
-{
- BOOL (*init_gst)(struct wg_parser *parser);
-
- struct wg_parser_stream **streams;
- unsigned int stream_count;
-
- GstElement *container;
- GstBus *bus;
- GstPad *my_src, *their_sink;
-
- guint64 file_size, start_offset, next_offset, stop_offset;
-
- pthread_t push_thread;
-
- pthread_mutex_t mutex;
-
- pthread_cond_t init_cond;
- bool no_more_pads, has_duration, error;
-
- pthread_cond_t read_cond, read_done_cond;
- struct
- {
- GstBuffer *buffer;
- uint64_t offset;
- uint32_t size;
- bool done;
- GstFlowReturn ret;
- } read_request;
-
- bool flushing, sink_connected;
-};
-
-enum wg_parser_event_type
-{
- WG_PARSER_EVENT_NONE = 0,
- WG_PARSER_EVENT_BUFFER,
- WG_PARSER_EVENT_EOS,
- WG_PARSER_EVENT_SEGMENT,
-};
-
-struct wg_parser_event
-{
- enum wg_parser_event_type type;
- union
- {
- GstBuffer *buffer;
- struct
- {
- uint64_t position, stop;
- double rate;
- } segment;
- } u;
-};
-
-struct wg_parser_stream
-{
- struct wg_parser *parser;
-
- GstPad *their_src, *post_sink, *post_src, *my_sink;
- GstElement *flip;
- struct wg_format preferred_format, current_format;
-
- pthread_cond_t event_cond, event_empty_cond;
- struct wg_parser_event event;
-
- bool flushing, eos, enabled, has_caps;
-
- uint64_t duration;
-};
-
struct parser
{
struct strmbase_filter filter;
@@ -170,7 +100,6 @@ static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
static const IMediaSeekingVtbl GST_Seeking_Vtbl;
static const IQualityControlVtbl GSTOutPin_QualityControl_Vtbl;
-static struct wg_parser_stream *create_stream(struct wg_parser *parser);
static struct parser_source *create_pin(struct parser *filter,
struct wg_parser_stream *stream, const WCHAR *name);
static HRESULT GST_RemoveOutputPins(struct parser *This);
@@ -178,177 +107,6 @@ static HRESULT WINAPI GST_ChangeCurrent(IMediaSeeking *iface);
static HRESULT WINAPI GST_ChangeStop(IMediaSeeking *iface);
static HRESULT WINAPI GST_ChangeRate(IMediaSeeking *iface);
-static enum wg_audio_format wg_audio_format_from_gst(GstAudioFormat format)
-{
- switch (format)
- {
- case GST_AUDIO_FORMAT_U8:
- return WG_AUDIO_FORMAT_U8;
- case GST_AUDIO_FORMAT_S16LE:
- return WG_AUDIO_FORMAT_S16LE;
- case GST_AUDIO_FORMAT_S24LE:
- return WG_AUDIO_FORMAT_S24LE;
- case GST_AUDIO_FORMAT_S32LE:
- return WG_AUDIO_FORMAT_S32LE;
- case GST_AUDIO_FORMAT_F32LE:
- return WG_AUDIO_FORMAT_F32LE;
- case GST_AUDIO_FORMAT_F64LE:
- return WG_AUDIO_FORMAT_F64LE;
- default:
- return WG_AUDIO_FORMAT_UNKNOWN;
- }
-}
-
-static void wg_format_from_audio_info(struct wg_format *format, const GstAudioInfo *info)
-{
- format->major_type = WG_MAJOR_TYPE_AUDIO;
- format->u.audio.format = wg_audio_format_from_gst(GST_AUDIO_INFO_FORMAT(info));
- format->u.audio.channels = GST_AUDIO_INFO_CHANNELS(info);
- format->u.audio.rate = GST_AUDIO_INFO_RATE(info);
-}
-
-static enum wg_video_format wg_video_format_from_gst(GstVideoFormat format)
-{
- switch (format)
- {
- case GST_VIDEO_FORMAT_BGRA:
- return WG_VIDEO_FORMAT_BGRA;
- case GST_VIDEO_FORMAT_BGRx:
- return WG_VIDEO_FORMAT_BGRx;
- case GST_VIDEO_FORMAT_BGR:
- return WG_VIDEO_FORMAT_BGR;
- case GST_VIDEO_FORMAT_RGB15:
- return WG_VIDEO_FORMAT_RGB15;
- case GST_VIDEO_FORMAT_AYUV:
- return WG_VIDEO_FORMAT_AYUV;
- case GST_VIDEO_FORMAT_I420:
- return WG_VIDEO_FORMAT_I420;
- case GST_VIDEO_FORMAT_NV12:
- return WG_VIDEO_FORMAT_NV12;
- case GST_VIDEO_FORMAT_UYVY:
- return WG_VIDEO_FORMAT_UYVY;
- case GST_VIDEO_FORMAT_YUY2:
- return WG_VIDEO_FORMAT_YUY2;
- case GST_VIDEO_FORMAT_YV12:
- return WG_VIDEO_FORMAT_YV12;
- case GST_VIDEO_FORMAT_YVYU:
- return WG_VIDEO_FORMAT_YVYU;
- default:
- return WG_VIDEO_FORMAT_UNKNOWN;
- }
-}
-
-static void wg_format_from_video_info(struct wg_format *format, const GstVideoInfo *info)
-{
- format->major_type = WG_MAJOR_TYPE_VIDEO;
- format->u.video.format = wg_video_format_from_gst(GST_VIDEO_INFO_FORMAT(info));
- format->u.video.width = GST_VIDEO_INFO_WIDTH(info);
- format->u.video.height = GST_VIDEO_INFO_HEIGHT(info);
- format->u.video.fps_n = GST_VIDEO_INFO_FPS_N(info);
- format->u.video.fps_d = GST_VIDEO_INFO_FPS_D(info);
-}
-
-static void wg_format_from_caps_audio_mpeg(struct wg_format *format, const GstCaps *caps)
-{
- const GstStructure *structure = gst_caps_get_structure(caps, 0);
- gint layer, channels, rate;
-
- if (!gst_structure_get_int(structure, "layer", &layer))
- {
- GST_WARNING("Missing \"layer\" value.");
- return;
- }
- if (!gst_structure_get_int(structure, "channels", &channels))
- {
- GST_WARNING("Missing \"channels\" value.");
- return;
- }
- if (!gst_structure_get_int(structure, "rate", &rate))
- {
- GST_WARNING("Missing \"rate\" value.");
- return;
- }
-
- format->major_type = WG_MAJOR_TYPE_AUDIO;
-
- if (layer == 1)
- format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER1;
- else if (layer == 2)
- format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER2;
- else if (layer == 3)
- format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER3;
-
- format->u.audio.channels = channels;
- format->u.audio.rate = rate;
-}
-
-static void wg_format_from_caps_video_cinepak(struct wg_format *format, const GstCaps *caps)
-{
- const GstStructure *structure = gst_caps_get_structure(caps, 0);
- gint width, height, fps_n, fps_d;
-
- if (!gst_structure_get_int(structure, "width", &width))
- {
- GST_WARNING("Missing \"width\" value.");
- return;
- }
- if (!gst_structure_get_int(structure, "height", &height))
- {
- GST_WARNING("Missing \"height\" value.");
- return;
- }
- if (!gst_structure_get_fraction(structure, "framerate", &fps_n, &fps_d))
- {
- fps_n = 0;
- fps_d = 1;
- }
-
- format->major_type = WG_MAJOR_TYPE_VIDEO;
- format->u.video.format = WG_VIDEO_FORMAT_CINEPAK;
- format->u.video.width = width;
- format->u.video.height = height;
- format->u.video.fps_n = fps_n;
- format->u.video.fps_d = fps_d;
-}
-
-static void wg_format_from_caps(struct wg_format *format, const GstCaps *caps)
-{
- const GstStructure *structure = gst_caps_get_structure(caps, 0);
- const char *name = gst_structure_get_name(structure);
-
- memset(format, 0, sizeof(*format));
-
- if (!strcmp(name, "audio/x-raw"))
- {
- GstAudioInfo info;
-
- if (gst_audio_info_from_caps(&info, caps))
- wg_format_from_audio_info(format, &info);
- }
- else if (!strcmp(name, "video/x-raw"))
- {
- GstVideoInfo info;
-
- if (gst_video_info_from_caps(&info, caps))
- wg_format_from_video_info(format, &info);
- }
- else if (!strcmp(name, "audio/mpeg"))
- {
- wg_format_from_caps_audio_mpeg(format, caps);
- }
- else if (!strcmp(name, "video/x-cinepak"))
- {
- wg_format_from_caps_video_cinepak(format, caps);
- }
- else
- {
- gchar *str = gst_caps_to_string(caps);
-
- GST_FIXME("Unhandled caps %s.", str);
- g_free(str);
- }
-}
-
static DWORD channel_mask_from_count(uint32_t count)
{
switch (count)
@@ -811,177 +569,6 @@ static bool amt_to_wg_format(const AM_MEDIA_TYPE *mt, struct wg_format *format)
return false;
}
-static GstAudioFormat wg_audio_format_to_gst(enum wg_audio_format format)
-{
- switch (format)
- {
- case WG_AUDIO_FORMAT_U8: return GST_AUDIO_FORMAT_U8;
- case WG_AUDIO_FORMAT_S16LE: return GST_AUDIO_FORMAT_S16LE;
- case WG_AUDIO_FORMAT_S24LE: return GST_AUDIO_FORMAT_S24LE;
- case WG_AUDIO_FORMAT_S32LE: return GST_AUDIO_FORMAT_S32LE;
- case WG_AUDIO_FORMAT_F32LE: return GST_AUDIO_FORMAT_F32LE;
- case WG_AUDIO_FORMAT_F64LE: return GST_AUDIO_FORMAT_F64LE;
- default: return GST_AUDIO_FORMAT_UNKNOWN;
- }
-}
-
-static GstCaps *wg_format_to_caps_audio(const struct wg_format *format)
-{
- GstAudioFormat audio_format;
- GstAudioInfo info;
-
- if ((audio_format = wg_audio_format_to_gst(format->u.audio.format)) == GST_AUDIO_FORMAT_UNKNOWN)
- return NULL;
-
- gst_audio_info_set_format(&info, audio_format, format->u.audio.rate, format->u.audio.channels, NULL);
- return gst_audio_info_to_caps(&info);
-}
-
-static GstVideoFormat wg_video_format_to_gst(enum wg_video_format format)
-{
- switch (format)
- {
- case WG_VIDEO_FORMAT_BGRA: return GST_VIDEO_FORMAT_BGRA;
- case WG_VIDEO_FORMAT_BGRx: return GST_VIDEO_FORMAT_BGRx;
- case WG_VIDEO_FORMAT_BGR: return GST_VIDEO_FORMAT_BGR;
- case WG_VIDEO_FORMAT_RGB15: return GST_VIDEO_FORMAT_RGB15;
- case WG_VIDEO_FORMAT_RGB16: return GST_VIDEO_FORMAT_RGB16;
- case WG_VIDEO_FORMAT_AYUV: return GST_VIDEO_FORMAT_AYUV;
- case WG_VIDEO_FORMAT_I420: return GST_VIDEO_FORMAT_I420;
- case WG_VIDEO_FORMAT_NV12: return GST_VIDEO_FORMAT_NV12;
- case WG_VIDEO_FORMAT_UYVY: return GST_VIDEO_FORMAT_UYVY;
- case WG_VIDEO_FORMAT_YUY2: return GST_VIDEO_FORMAT_YUY2;
- case WG_VIDEO_FORMAT_YV12: return GST_VIDEO_FORMAT_YV12;
- case WG_VIDEO_FORMAT_YVYU: return GST_VIDEO_FORMAT_YVYU;
- default: return GST_VIDEO_FORMAT_UNKNOWN;
- }
-}
-
-static GstCaps *wg_format_to_caps_video(const struct wg_format *format)
-{
- GstVideoFormat video_format;
- GstVideoInfo info;
- unsigned int i;
- GstCaps *caps;
-
- if ((video_format = wg_video_format_to_gst(format->u.video.format)) == GST_VIDEO_FORMAT_UNKNOWN)
- return NULL;
-
- gst_video_info_set_format(&info, video_format, format->u.video.width, format->u.video.height);
- if ((caps = gst_video_info_to_caps(&info)))
- {
- /* Clear some fields that shouldn't prevent us from connecting. */
- for (i = 0; i < gst_caps_get_size(caps); ++i)
- {
- gst_structure_remove_fields(gst_caps_get_structure(caps, i),
- "framerate", "pixel-aspect-ratio", "colorimetry", "chroma-site", NULL);
- }
- }
- return caps;
-}
-
-static GstCaps *wg_format_to_caps(const struct wg_format *format)
-{
- switch (format->major_type)
- {
- case WG_MAJOR_TYPE_UNKNOWN:
- return NULL;
- case WG_MAJOR_TYPE_AUDIO:
- return wg_format_to_caps_audio(format);
- case WG_MAJOR_TYPE_VIDEO:
- return wg_format_to_caps_video(format);
- }
- assert(0);
- return NULL;
-}
-
-static bool wg_format_compare(const struct wg_format *a, const struct wg_format *b)
-{
- if (a->major_type != b->major_type)
- return false;
-
- switch (a->major_type)
- {
- case WG_MAJOR_TYPE_UNKNOWN:
- return false;
-
- case WG_MAJOR_TYPE_AUDIO:
- return a->u.audio.format == b->u.audio.format
- && a->u.audio.channels == b->u.audio.channels
- && a->u.audio.rate == b->u.audio.rate;
-
- case WG_MAJOR_TYPE_VIDEO:
- return a->u.video.format == b->u.video.format
- && a->u.video.width == b->u.video.width
- && a->u.video.height == b->u.video.height
- && a->u.video.fps_d * b->u.video.fps_n == a->u.video.fps_n * b->u.video.fps_d;
- }
-
- assert(0);
- return false;
-}
-
-static gboolean query_sink(GstPad *pad, GstObject *parent, GstQuery *query)
-{
- struct wg_parser_stream *stream = gst_pad_get_element_private(pad);
-
- GST_LOG("stream %p, type \"%s\".", stream, gst_query_type_get_name(query->type));
-
- switch (query->type)
- {
- case GST_QUERY_CAPS:
- {
- GstCaps *caps, *filter, *temp;
-
- gst_query_parse_caps(query, &filter);
-
- if (stream->enabled)
- caps = wg_format_to_caps(&stream->current_format);
- else
- caps = gst_caps_new_any();
- if (!caps)
- return FALSE;
-
- if (filter)
- {
- temp = gst_caps_intersect(caps, filter);
- gst_caps_unref(caps);
- caps = temp;
- }
-
- gst_query_set_caps_result(query, caps);
- gst_caps_unref(caps);
- return TRUE;
- }
- case GST_QUERY_ACCEPT_CAPS:
- {
- struct wg_format format;
- gboolean ret = TRUE;
- GstCaps *caps;
-
- if (!stream->enabled)
- {
- gst_query_set_accept_caps_result(query, TRUE);
- return TRUE;
- }
-
- gst_query_parse_accept_caps(query, &caps);
- wg_format_from_caps(&format, caps);
- ret = wg_format_compare(&format, &stream->current_format);
- if (!ret && WARN_ON(gstreamer))
- {
- gchar *str = gst_caps_to_string(caps);
- GST_WARNING("Rejecting caps \"%s\".", str);
- g_free(str);
- }
- gst_query_set_accept_caps_result(query, ret);
- return TRUE;
- }
- default:
- return gst_pad_query_default (pad, parent, query);
- }
-}
-
static gboolean gst_base_src_perform_seek(struct wg_parser *parser, GstEvent *event)
{
gboolean res = TRUE;
@@ -1058,134 +645,6 @@ static gboolean event_src(GstPad *pad, GstObject *parent, GstEvent *event)
return ret;
}
-static GstFlowReturn queue_stream_event(struct wg_parser_stream *stream, const struct wg_parser_event *event)
-{
- struct wg_parser *parser = stream->parser;
-
- /* Unlike request_buffer_src() [q.v.], we need to watch for GStreamer
- * flushes here. The difference is that we can be blocked by the streaming
- * thread not running (or itself flushing on the DirectShow side).
- * request_buffer_src() can only be blocked by the upstream source, and that
- * is solved by flushing the upstream source. */
-
- pthread_mutex_lock(&parser->mutex);
- while (!stream->flushing && stream->event.type != WG_PARSER_EVENT_NONE)
- pthread_cond_wait(&stream->event_empty_cond, &parser->mutex);
- if (stream->flushing)
- {
- pthread_mutex_unlock(&parser->mutex);
- GST_DEBUG("Filter is flushing; discarding event.");
- return GST_FLOW_FLUSHING;
- }
- stream->event = *event;
- pthread_mutex_unlock(&parser->mutex);
- pthread_cond_signal(&stream->event_cond);
- GST_LOG("Event queued.");
- return GST_FLOW_OK;
-}
-
-static gboolean event_sink(GstPad *pad, GstObject *parent, GstEvent *event)
-{
- struct wg_parser_stream *stream = gst_pad_get_element_private(pad);
- struct wg_parser *parser = stream->parser;
-
- GST_LOG("stream %p, type \"%s\".", stream, GST_EVENT_TYPE_NAME(event));
-
- switch (event->type)
- {
- case GST_EVENT_SEGMENT:
- if (stream->enabled)
- {
- struct wg_parser_event stream_event;
- const GstSegment *segment;
-
- gst_event_parse_segment(event, &segment);
-
- if (segment->format != GST_FORMAT_TIME)
- {
- GST_FIXME("Unhandled format \"%s\".", gst_format_get_name(segment->format));
- break;
- }
-
- stream_event.type = WG_PARSER_EVENT_SEGMENT;
- stream_event.u.segment.position = segment->position / 100;
- stream_event.u.segment.stop = segment->stop / 100;
- stream_event.u.segment.rate = segment->rate * segment->applied_rate;
- queue_stream_event(stream, &stream_event);
- }
- break;
-
- case GST_EVENT_EOS:
- if (stream->enabled)
- {
- struct wg_parser_event stream_event;
-
- stream_event.type = WG_PARSER_EVENT_EOS;
- queue_stream_event(stream, &stream_event);
- }
- else
- {
- pthread_mutex_lock(&parser->mutex);
- stream->eos = true;
- pthread_mutex_unlock(&parser->mutex);
- pthread_cond_signal(&parser->init_cond);
- }
- break;
-
- case GST_EVENT_FLUSH_START:
- if (stream->enabled)
- {
- pthread_mutex_lock(&parser->mutex);
-
- stream->flushing = true;
- pthread_cond_signal(&stream->event_empty_cond);
-
- switch (stream->event.type)
- {
- case WG_PARSER_EVENT_NONE:
- case WG_PARSER_EVENT_EOS:
- case WG_PARSER_EVENT_SEGMENT:
- break;
-
- case WG_PARSER_EVENT_BUFFER:
- gst_buffer_unref(stream->event.u.buffer);
- break;
- }
- stream->event.type = WG_PARSER_EVENT_NONE;
-
- pthread_mutex_unlock(&parser->mutex);
- }
- break;
-
- case GST_EVENT_FLUSH_STOP:
- if (stream->enabled)
- {
- pthread_mutex_lock(&parser->mutex);
- stream->flushing = false;
- pthread_mutex_unlock(&parser->mutex);
- }
- break;
-
- case GST_EVENT_CAPS:
- {
- GstCaps *caps;
-
- gst_event_parse_caps(event, &caps);
- pthread_mutex_lock(&parser->mutex);
- wg_format_from_caps(&stream->preferred_format, caps);
- stream->has_caps = true;
- pthread_mutex_unlock(&parser->mutex);
- pthread_cond_signal(&parser->init_cond);
- break;
- }
-
- default:
- GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event));
- }
- gst_event_unref(event);
- return TRUE;
-}
-
static GstFlowReturn request_buffer_src(GstPad *pad, GstObject *parent, guint64 offset, guint size, GstBuffer **buffer);
static void *push_data(void *arg)
@@ -1237,28 +696,6 @@ static void *push_data(void *arg)
return NULL;
}
-static GstFlowReturn got_data_sink(GstPad *pad, GstObject *parent, GstBuffer *buffer)
-{
- struct wg_parser_stream *stream = gst_pad_get_element_private(pad);
- struct wg_parser_event stream_event;
- GstFlowReturn ret;
-
- GST_LOG("stream %p, buffer %p.", stream, buffer);
-
- if (!stream->enabled)
- {
- gst_buffer_unref(buffer);
- return GST_FLOW_OK;
- }
-
- stream_event.type = WG_PARSER_EVENT_BUFFER;
- stream_event.u.buffer = buffer;
- /* Transfer our reference to the buffer to the thread. */
- if ((ret = queue_stream_event(stream, &stream_event)) != GST_FLOW_OK)
- gst_buffer_unref(buffer);
- return ret;
-}
-
/* Fill and send a single IMediaSample. */
static HRESULT send_sample(struct parser_source *pin, IMediaSample *sample,
GstBuffer *buf, GstMapInfo *info, gsize offset, gsize size, DWORD bytes_per_second)
@@ -1552,180 +989,6 @@ static DWORD CALLBACK read_thread(void *arg)
return 0;
}
-static void removed_decoded_pad(GstElement *bin, GstPad *pad, gpointer user)
-{
- struct wg_parser *parser = user;
- unsigned int i;
- char *name;
-
- GST_LOG("parser %p, bin %p, pad %p.", parser, bin, pad);
-
- for (i = 0; i < parser->stream_count; ++i)
- {
- struct wg_parser_stream *stream = parser->streams[i];
-
- if (stream->their_src == pad)
- {
- if (stream->post_sink)
- gst_pad_unlink(stream->their_src, stream->post_sink);
- else
- gst_pad_unlink(stream->their_src, stream->my_sink);
- gst_object_unref(stream->their_src);
- stream->their_src = NULL;
- return;
- }
- }
-
- name = gst_pad_get_name(pad);
- GST_LOG("No pin matching pad \"%s\" found.", name);
- g_free(name);
-}
-
-static void free_stream(struct wg_parser_stream *stream);
-
-static void init_new_decoded_pad(GstElement *bin, GstPad *pad, struct wg_parser *parser)
-{
- struct wg_parser_stream *stream;
- const char *typename;
- GstCaps *caps;
- GstStructure *arg;
- int ret;
-
- caps = gst_pad_query_caps(pad, NULL);
- caps = gst_caps_make_writable(caps);
- arg = gst_caps_get_structure(caps, 0);
- typename = gst_structure_get_name(arg);
-
- if (!(stream = create_stream(parser)))
- goto out;
-
- if (!strcmp(typename, "video/x-raw"))
- {
- GstElement *deinterlace, *vconv, *flip, *vconv2;
-
- /* DirectShow can express interlaced video, but downstream filters can't
- * necessarily consume it. In particular, the video renderer can't. */
- if (!(deinterlace = gst_element_factory_make("deinterlace", NULL)))
- {
- fprintf(stderr, "winegstreamer: failed to create deinterlace, are %u-bit GStreamer \"good\" plugins installed?\n",
- 8 * (int)sizeof(void *));
- goto out;
- }
-
- /* decodebin considers many YUV formats to be "raw", but some quartz
- * filters can't handle those. Also, videoflip can't handle all "raw"
- * formats either. Add a videoconvert to swap color spaces. */
- if (!(vconv = gst_element_factory_make("videoconvert", NULL)))
- {
- fprintf(stderr, "winegstreamer: failed to create videoconvert, are %u-bit GStreamer \"base\" plugins installed?\n",
- 8 * (int)sizeof(void *));
- goto out;
- }
-
- /* GStreamer outputs RGB video top-down, but DirectShow expects bottom-up. */
- if (!(flip = gst_element_factory_make("videoflip", NULL)))
- {
- fprintf(stderr, "winegstreamer: failed to create videoflip, are %u-bit GStreamer \"good\" plugins installed?\n",
- 8 * (int)sizeof(void *));
- goto out;
- }
-
- /* videoflip does not support 15 and 16-bit RGB so add a second videoconvert
- * to do the final conversion. */
- if (!(vconv2 = gst_element_factory_make("videoconvert", NULL)))
- {
- fprintf(stderr, "winegstreamer: failed to create videoconvert, are %u-bit GStreamer \"base\" plugins installed?\n",
- 8 * (int)sizeof(void *));
- goto out;
- }
-
- /* The bin takes ownership of these elements. */
- gst_bin_add(GST_BIN(parser->container), deinterlace);
- gst_element_sync_state_with_parent(deinterlace);
- gst_bin_add(GST_BIN(parser->container), vconv);
- gst_element_sync_state_with_parent(vconv);
- gst_bin_add(GST_BIN(parser->container), flip);
- gst_element_sync_state_with_parent(flip);
- gst_bin_add(GST_BIN(parser->container), vconv2);
- gst_element_sync_state_with_parent(vconv2);
-
- gst_element_link(deinterlace, vconv);
- gst_element_link(vconv, flip);
- gst_element_link(flip, vconv2);
-
- stream->post_sink = gst_element_get_static_pad(deinterlace, "sink");
- stream->post_src = gst_element_get_static_pad(vconv2, "src");
- stream->flip = flip;
- }
- else if (!strcmp(typename, "audio/x-raw"))
- {
- GstElement *convert;
-
- /* Currently our dsound can't handle 64-bit formats or all
- * surround-sound configurations. Native dsound can't always handle
- * 64-bit formats either. Add an audioconvert to allow changing bit
- * depth and channel count. */
- if (!(convert = gst_element_factory_make("audioconvert", NULL)))
- {
- fprintf(stderr, "winegstreamer: failed to create audioconvert, are %u-bit GStreamer \"base\" plugins installed?\n",
- 8 * (int)sizeof(void *));
- goto out;
- }
-
- gst_bin_add(GST_BIN(parser->container), convert);
- gst_element_sync_state_with_parent(convert);
-
- stream->post_sink = gst_element_get_static_pad(convert, "sink");
- stream->post_src = gst_element_get_static_pad(convert, "src");
- }
-
- if (stream->post_sink)
- {
- if ((ret = gst_pad_link(pad, stream->post_sink)) < 0)
- {
- GST_ERROR("Failed to link decodebin source pad to post-processing elements, error %s.",
- gst_pad_link_get_name(ret));
- gst_object_unref(stream->post_sink);
- stream->post_sink = NULL;
- goto out;
- }
-
- if ((ret = gst_pad_link(stream->post_src, stream->my_sink)) < 0)
- {
- GST_ERROR("Failed to link post-processing elements to our sink pad, error %s.",
- gst_pad_link_get_name(ret));
- gst_object_unref(stream->post_src);
- stream->post_src = NULL;
- gst_object_unref(stream->post_sink);
- stream->post_sink = NULL;
- goto out;
- }
- }
- else if ((ret = gst_pad_link(pad, stream->my_sink)) < 0)
- {
- GST_ERROR("Failed to link decodebin source pad to our sink pad, error %s.",
- gst_pad_link_get_name(ret));
- goto out;
- }
-
- gst_pad_set_active(stream->my_sink, 1);
- gst_object_ref(stream->their_src = pad);
-out:
- gst_caps_unref(caps);
-}
-
-static void existing_new_pad(GstElement *bin, GstPad *pad, gpointer user)
-{
- struct wg_parser *This = user;
-
- GST_LOG("parser %p, bin %p, pad %p.", This, bin, pad);
-
- if (gst_pad_is_linked(pad))
- return;
-
- init_new_decoded_pad(bin, pad, This);
-}
-
static gboolean query_function(GstPad *pad, GstObject *parent, GstQuery *query)
{
struct wg_parser *parser = gst_pad_get_element_private(pad);
@@ -1807,37 +1070,6 @@ static gboolean activate_mode(GstPad *pad, GstObject *parent, GstPadMode mode, g
return FALSE;
}
-static void no_more_pads(GstElement *decodebin, gpointer user)
-{
- struct wg_parser *parser = user;
-
- GST_DEBUG("parser %p.", parser);
-
- pthread_mutex_lock(&parser->mutex);
- parser->no_more_pads = true;
- pthread_mutex_unlock(&parser->mutex);
- pthread_cond_signal(&parser->init_cond);
-}
-
-static GstAutoplugSelectResult autoplug_blacklist(GstElement *bin, GstPad *pad, GstCaps *caps, GstElementFactory *fact, gpointer user)
-{
- const char *name = gst_element_factory_get_longname(fact);
-
- GST_TRACE("Using \"%s\".", name);
-
- if (strstr(name, "Player protection"))
- {
- GST_WARNING("Blacklisted a/52 decoder because it only works in Totem.");
- return GST_AUTOPLUG_SELECT_SKIP;
- }
- if (!strcmp(name, "Fluendo Hardware Accelerated Video Decoder"))
- {
- GST_WARNING("Disabled video acceleration since it breaks in wine.");
- return GST_AUTOPLUG_SELECT_SKIP;
- }
- return GST_AUTOPLUG_SELECT_TRY;
-}
-
static GstBusSyncReply watch_bus(GstBus *bus, GstMessage *msg, gpointer data)
{
struct parser *filter = data;
@@ -2191,58 +1423,6 @@ static const struct strmbase_sink_ops sink_ops =
.sink_disconnect = parser_sink_disconnect,
};
-static BOOL decodebin_parser_init_gst(struct wg_parser *parser)
-{
- GstElement *element = gst_element_factory_make("decodebin", NULL);
- int ret;
-
- if (!element)
- {
- ERR("Failed to create decodebin; are %u-bit GStreamer \"base\" plugins installed?\n",
- 8 * (int)sizeof(void*));
- return FALSE;
- }
-
- gst_bin_add(GST_BIN(parser->container), element);
-
- g_signal_connect(element, "pad-added", G_CALLBACK(existing_new_pad), parser);
- g_signal_connect(element, "pad-removed", G_CALLBACK(removed_decoded_pad), parser);
- g_signal_connect(element, "autoplug-select", G_CALLBACK(autoplug_blacklist), parser);
- g_signal_connect(element, "no-more-pads", G_CALLBACK(no_more_pads), parser);
-
- parser->their_sink = gst_element_get_static_pad(element, "sink");
-
- pthread_mutex_lock(&parser->mutex);
- parser->no_more_pads = parser->error = false;
- pthread_mutex_unlock(&parser->mutex);
-
- if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0)
- {
- ERR("Failed to link pads, error %d.\n", ret);
- return FALSE;
- }
-
- gst_element_set_state(parser->container, GST_STATE_PAUSED);
- ret = gst_element_get_state(parser->container, NULL, NULL, -1);
- if (ret == GST_STATE_CHANGE_FAILURE)
- {
- ERR("Failed to play stream.\n");
- return FALSE;
- }
-
- pthread_mutex_lock(&parser->mutex);
- while (!parser->no_more_pads && !parser->error)
- pthread_cond_wait(&parser->init_cond, &parser->mutex);
- if (parser->error)
- {
- pthread_mutex_unlock(&parser->mutex);
- return FALSE;
- }
- pthread_mutex_unlock(&parser->mutex);
-
- return TRUE;
-}
-
static BOOL decodebin_parser_filter_init_gst(struct parser *filter)
{
static const WCHAR formatW[] = {'S','t','r','e','a','m',' ','%','0','2','u',0};
@@ -2328,23 +1508,6 @@ static BOOL parser_init_gstreamer(void)
return TRUE;
}
-static struct wg_parser *wg_parser_create(void)
-{
- struct wg_parser *parser;
-
- if (!(parser = calloc(1, sizeof(*parser))))
- return NULL;
-
- pthread_mutex_init(&parser->mutex, NULL);
- pthread_cond_init(&parser->init_cond, NULL);
- pthread_cond_init(&parser->read_cond, NULL);
- pthread_cond_init(&parser->read_done_cond, NULL);
- parser->flushing = true;
-
- TRACE("Created winegstreamer parser %p.\n", parser);
- return parser;
-}
-
HRESULT decodebin_parser_create(IUnknown *outer, IUnknown **out)
{
struct parser *object;
@@ -2357,12 +1520,11 @@ HRESULT decodebin_parser_create(IUnknown *outer, IUnknown **out)
if (!(object = heap_alloc_zero(sizeof(*object))))
return E_OUTOFMEMORY;
- if (!(object->wg_parser = wg_parser_create()))
+ if (!(object->wg_parser = unix_funcs->wg_decodebin_parser_create()))
{
heap_free(object);
return E_OUTOFMEMORY;
}
- object->wg_parser->init_gst = decodebin_parser_init_gst;
strmbase_filter_init(&object->filter, outer, &CLSID_decodebin_parser, &filter_ops);
strmbase_sink_init(&object->sink, &object->filter, wcsInputPinName, &sink_ops, NULL);
@@ -2827,33 +1989,6 @@ static const struct strmbase_source_ops source_ops =
.source_disconnect = source_disconnect,
};
-static struct wg_parser_stream *create_stream(struct wg_parser *parser)
-{
- struct wg_parser_stream *stream, **new_array;
- char pad_name[19];
-
- if (!(new_array = realloc(parser->streams, (parser->stream_count + 1) * sizeof(*parser->streams))))
- return NULL;
- parser->streams = new_array;
-
- if (!(stream = calloc(1, sizeof(*stream))))
- return NULL;
-
- stream->parser = parser;
- pthread_cond_init(&stream->event_cond, NULL);
- pthread_cond_init(&stream->event_empty_cond, NULL);
-
- sprintf(pad_name, "qz_sink_%u", parser->stream_count);
- stream->my_sink = gst_pad_new(pad_name, GST_PAD_SINK);
- gst_pad_set_element_private(stream->my_sink, stream);
- gst_pad_set_chain_function(stream->my_sink, got_data_sink);
- gst_pad_set_event_function(stream->my_sink, event_sink);
- gst_pad_set_query_function(stream->my_sink, query_sink);
-
- parser->streams[parser->stream_count++] = stream;
- return stream;
-}
-
static struct parser_source *create_pin(struct parser *filter,
struct wg_parser_stream *stream, const WCHAR *name)
{
@@ -2962,51 +2097,6 @@ static const struct strmbase_sink_ops wave_parser_sink_ops =
.sink_disconnect = parser_sink_disconnect,
};
-static BOOL wave_parser_init_gst(struct wg_parser *parser)
-{
- struct wg_parser_stream *stream;
- GstElement *element;
- int ret;
-
- if (!(element = gst_element_factory_make("wavparse", NULL)))
- {
- ERR("Failed to create wavparse; are %u-bit GStreamer \"good\" plugins installed?\n",
- 8 * (int)sizeof(void*));
- return FALSE;
- }
-
- gst_bin_add(GST_BIN(parser->container), element);
-
- parser->their_sink = gst_element_get_static_pad(element, "sink");
- if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0)
- {
- ERR("Failed to link sink pads, error %d.\n", ret);
- return FALSE;
- }
-
- if (!(stream = create_stream(parser)))
- return FALSE;
-
- stream->their_src = gst_element_get_static_pad(element, "src");
- gst_object_ref(stream->their_src);
- if ((ret = gst_pad_link(stream->their_src, stream->my_sink)) < 0)
- {
- ERR("Failed to link source pads, error %d.\n", ret);
- return FALSE;
- }
-
- gst_pad_set_active(stream->my_sink, 1);
- gst_element_set_state(parser->container, GST_STATE_PAUSED);
- ret = gst_element_get_state(parser->container, NULL, NULL, -1);
- if (ret == GST_STATE_CHANGE_FAILURE)
- {
- ERR("Failed to play stream.\n");
- return FALSE;
- }
-
- return TRUE;
-}
-
static BOOL wave_parser_filter_init_gst(struct parser *filter)
{
static const WCHAR source_name[] = {'o','u','t','p','u','t',0};
@@ -3056,12 +2146,11 @@ HRESULT wave_parser_create(IUnknown *outer, IUnknown **out)
if (!(object = heap_alloc_zero(sizeof(*object))))
return E_OUTOFMEMORY;
- if (!(object->wg_parser = wg_parser_create()))
+ if (!(object->wg_parser = unix_funcs->wg_wave_parser_create()))
{
heap_free(object);
return E_OUTOFMEMORY;
}
- object->wg_parser->init_gst = wave_parser_init_gst;
strmbase_filter_init(&object->filter, outer, &CLSID_WAVEParser, &filter_ops);
strmbase_sink_init(&object->sink, &object->filter, sink_name, &wave_parser_sink_ops, NULL);
@@ -3089,57 +2178,6 @@ static const struct strmbase_sink_ops avi_splitter_sink_ops =
.sink_disconnect = parser_sink_disconnect,
};
-static BOOL avi_parser_init_gst(struct wg_parser *parser)
-{
- GstElement *element = gst_element_factory_make("avidemux", NULL);
- int ret;
-
- if (!element)
- {
- ERR("Failed to create avidemux; are %u-bit GStreamer \"good\" plugins installed?\n",
- 8 * (int)sizeof(void*));
- return FALSE;
- }
-
- gst_bin_add(GST_BIN(parser->container), element);
-
- g_signal_connect(element, "pad-added", G_CALLBACK(existing_new_pad), parser);
- g_signal_connect(element, "pad-removed", G_CALLBACK(removed_decoded_pad), parser);
- g_signal_connect(element, "no-more-pads", G_CALLBACK(no_more_pads), parser);
-
- parser->their_sink = gst_element_get_static_pad(element, "sink");
-
- pthread_mutex_lock(&parser->mutex);
- parser->no_more_pads = parser->error = false;
- pthread_mutex_unlock(&parser->mutex);
-
- if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0)
- {
- ERR("Failed to link pads, error %d.\n", ret);
- return FALSE;
- }
-
- gst_element_set_state(parser->container, GST_STATE_PAUSED);
- ret = gst_element_get_state(parser->container, NULL, NULL, -1);
- if (ret == GST_STATE_CHANGE_FAILURE)
- {
- ERR("Failed to play stream.\n");
- return FALSE;
- }
-
- pthread_mutex_lock(&parser->mutex);
- while (!parser->no_more_pads && !parser->error)
- pthread_cond_wait(&parser->init_cond, &parser->mutex);
- if (parser->error)
- {
- pthread_mutex_unlock(&parser->mutex);
- return FALSE;
- }
- pthread_mutex_unlock(&parser->mutex);
-
- return TRUE;
-}
-
static BOOL avi_splitter_filter_init_gst(struct parser *filter)
{
static const WCHAR formatW[] = {'S','t','r','e','a','m',' ','%','0','2','u',0};
@@ -3195,12 +2233,11 @@ HRESULT avi_splitter_create(IUnknown *outer, IUnknown **out)
if (!(object = heap_alloc_zero(sizeof(*object))))
return E_OUTOFMEMORY;
- if (!(object->wg_parser = wg_parser_create()))
+ if (!(object->wg_parser = unix_funcs->wg_avi_parser_create()))
{
heap_free(object);
return E_OUTOFMEMORY;
}
- object->wg_parser->init_gst = avi_parser_init_gst;
strmbase_filter_init(&object->filter, outer, &CLSID_AviSplitter, &filter_ops);
strmbase_sink_init(&object->sink, &object->filter, sink_name, &avi_splitter_sink_ops, NULL);
@@ -3233,59 +2270,6 @@ static const struct strmbase_sink_ops mpeg_splitter_sink_ops =
.sink_disconnect = parser_sink_disconnect,
};
-static BOOL mpeg_audio_parser_init_gst(struct wg_parser *parser)
-{
- struct wg_parser_stream *stream;
- GstElement *element;
- int ret;
-
- if (!(element = gst_element_factory_make("mpegaudioparse", NULL)))
- {
- ERR("Failed to create mpegaudioparse; are %u-bit GStreamer \"good\" plugins installed?\n",
- 8 * (int)sizeof(void*));
- return FALSE;
- }
-
- gst_bin_add(GST_BIN(parser->container), element);
-
- parser->their_sink = gst_element_get_static_pad(element, "sink");
- if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0)
- {
- ERR("Failed to link sink pads, error %d.\n", ret);
- return FALSE;
- }
-
- if (!(stream = create_stream(parser)))
- return FALSE;
-
- gst_object_ref(stream->their_src = gst_element_get_static_pad(element, "src"));
- if ((ret = gst_pad_link(stream->their_src, stream->my_sink)) < 0)
- {
- ERR("Failed to link source pads, error %d.\n", ret);
- return FALSE;
- }
-
- gst_pad_set_active(stream->my_sink, 1);
- gst_element_set_state(parser->container, GST_STATE_PAUSED);
- ret = gst_element_get_state(parser->container, NULL, NULL, -1);
- if (ret == GST_STATE_CHANGE_FAILURE)
- {
- ERR("Failed to play stream.\n");
- return FALSE;
- }
-
- pthread_mutex_lock(&parser->mutex);
- while (!parser->has_duration && !parser->error && !stream->eos)
- pthread_cond_wait(&parser->init_cond, &parser->mutex);
- if (parser->error)
- {
- pthread_mutex_unlock(&parser->mutex);
- return FALSE;
- }
- pthread_mutex_unlock(&parser->mutex);
- return TRUE;
-}
-
static BOOL mpeg_splitter_filter_init_gst(struct parser *filter)
{
static const WCHAR source_name[] = {'A','u','d','i','o',0};
@@ -3358,12 +2342,11 @@ HRESULT mpeg_splitter_create(IUnknown *outer, IUnknown **out)
if (!(object = heap_alloc_zero(sizeof(*object))))
return E_OUTOFMEMORY;
- if (!(object->wg_parser = wg_parser_create()))
+ if (!(object->wg_parser = unix_funcs->wg_mpeg_audio_parser_create()))
{
heap_free(object);
return E_OUTOFMEMORY;
}
- object->wg_parser->init_gst = mpeg_audio_parser_init_gst;
strmbase_filter_init(&object->filter, outer, &CLSID_MPEG1Splitter, &mpeg_splitter_ops);
strmbase_sink_init(&object->sink, &object->filter, sink_name, &mpeg_splitter_sink_ops, NULL);
diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c
index 3c630a1561f..477ed0ad1e6 100644
--- a/dlls/winegstreamer/main.c
+++ b/dlls/winegstreamer/main.c
@@ -40,12 +40,15 @@ static const WCHAR avi_splitterW[] =
static const WCHAR mpeg_splitterW[] =
{'M','P','E','G','-','I',' ','S','t','r','e','a','m',' ','S','p','l','i','t','t','e','r',0};
+const struct unix_funcs *unix_funcs = NULL;
+
BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
{
if (reason == DLL_PROCESS_ATTACH)
{
winegstreamer_instance = instance;
DisableThreadLibraryCalls(instance);
+ __wine_init_unix_lib(instance, reason, NULL, &unix_funcs);
}
return TRUE;
}
diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c
new file mode 100644
index 00000000000..a64c3f83497
--- /dev/null
+++ b/dlls/winegstreamer/wg_parser.c
@@ -0,0 +1,1030 @@
+/*
+ * GStreamer parser backend
+ *
+ * Copyright 2010 Maarten Lankhorst for CodeWeavers
+ * Copyright 2010 Aric Stewart for CodeWeavers
+ * Copyright 2019-2020 Zebediah Figura
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#if 0
+#pragma makedep unix
+#endif
+
+#include "config.h"
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "gst_private.h"
+#include "winternl.h"
+#include <assert.h>
+
+WINE_DEFAULT_DEBUG_CHANNEL(gstreamer);
+
+GST_DEBUG_CATEGORY_STATIC(wine);
+#define GST_CAT_DEFAULT wine
+
+static enum wg_audio_format wg_audio_format_from_gst(GstAudioFormat format)
+{
+ switch (format)
+ {
+ case GST_AUDIO_FORMAT_U8:
+ return WG_AUDIO_FORMAT_U8;
+ case GST_AUDIO_FORMAT_S16LE:
+ return WG_AUDIO_FORMAT_S16LE;
+ case GST_AUDIO_FORMAT_S24LE:
+ return WG_AUDIO_FORMAT_S24LE;
+ case GST_AUDIO_FORMAT_S32LE:
+ return WG_AUDIO_FORMAT_S32LE;
+ case GST_AUDIO_FORMAT_F32LE:
+ return WG_AUDIO_FORMAT_F32LE;
+ case GST_AUDIO_FORMAT_F64LE:
+ return WG_AUDIO_FORMAT_F64LE;
+ default:
+ return WG_AUDIO_FORMAT_UNKNOWN;
+ }
+}
+
+static void wg_format_from_audio_info(struct wg_format *format, const GstAudioInfo *info)
+{
+ format->major_type = WG_MAJOR_TYPE_AUDIO;
+ format->u.audio.format = wg_audio_format_from_gst(GST_AUDIO_INFO_FORMAT(info));
+ format->u.audio.channels = GST_AUDIO_INFO_CHANNELS(info);
+ format->u.audio.rate = GST_AUDIO_INFO_RATE(info);
+}
+
+static enum wg_video_format wg_video_format_from_gst(GstVideoFormat format)
+{
+ switch (format)
+ {
+ case GST_VIDEO_FORMAT_BGRA:
+ return WG_VIDEO_FORMAT_BGRA;
+ case GST_VIDEO_FORMAT_BGRx:
+ return WG_VIDEO_FORMAT_BGRx;
+ case GST_VIDEO_FORMAT_BGR:
+ return WG_VIDEO_FORMAT_BGR;
+ case GST_VIDEO_FORMAT_RGB15:
+ return WG_VIDEO_FORMAT_RGB15;
+ case GST_VIDEO_FORMAT_AYUV:
+ return WG_VIDEO_FORMAT_AYUV;
+ case GST_VIDEO_FORMAT_I420:
+ return WG_VIDEO_FORMAT_I420;
+ case GST_VIDEO_FORMAT_NV12:
+ return WG_VIDEO_FORMAT_NV12;
+ case GST_VIDEO_FORMAT_UYVY:
+ return WG_VIDEO_FORMAT_UYVY;
+ case GST_VIDEO_FORMAT_YUY2:
+ return WG_VIDEO_FORMAT_YUY2;
+ case GST_VIDEO_FORMAT_YV12:
+ return WG_VIDEO_FORMAT_YV12;
+ case GST_VIDEO_FORMAT_YVYU:
+ return WG_VIDEO_FORMAT_YVYU;
+ default:
+ return WG_VIDEO_FORMAT_UNKNOWN;
+ }
+}
+
+static void wg_format_from_video_info(struct wg_format *format, const GstVideoInfo *info)
+{
+ format->major_type = WG_MAJOR_TYPE_VIDEO;
+ format->u.video.format = wg_video_format_from_gst(GST_VIDEO_INFO_FORMAT(info));
+ format->u.video.width = GST_VIDEO_INFO_WIDTH(info);
+ format->u.video.height = GST_VIDEO_INFO_HEIGHT(info);
+ format->u.video.fps_n = GST_VIDEO_INFO_FPS_N(info);
+ format->u.video.fps_d = GST_VIDEO_INFO_FPS_D(info);
+}
+
+static void wg_format_from_caps_audio_mpeg(struct wg_format *format, const GstCaps *caps)
+{
+ const GstStructure *structure = gst_caps_get_structure(caps, 0);
+ gint layer, channels, rate;
+
+ if (!gst_structure_get_int(structure, "layer", &layer))
+ {
+ GST_WARNING("Missing \"layer\" value.");
+ return;
+ }
+ if (!gst_structure_get_int(structure, "channels", &channels))
+ {
+ GST_WARNING("Missing \"channels\" value.");
+ return;
+ }
+ if (!gst_structure_get_int(structure, "rate", &rate))
+ {
+ GST_WARNING("Missing \"rate\" value.");
+ return;
+ }
+
+ format->major_type = WG_MAJOR_TYPE_AUDIO;
+
+ if (layer == 1)
+ format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER1;
+ else if (layer == 2)
+ format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER2;
+ else if (layer == 3)
+ format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER3;
+
+ format->u.audio.channels = channels;
+ format->u.audio.rate = rate;
+}
+
+static void wg_format_from_caps_video_cinepak(struct wg_format *format, const GstCaps *caps)
+{
+ const GstStructure *structure = gst_caps_get_structure(caps, 0);
+ gint width, height, fps_n, fps_d;
+
+ if (!gst_structure_get_int(structure, "width", &width))
+ {
+ GST_WARNING("Missing \"width\" value.");
+ return;
+ }
+ if (!gst_structure_get_int(structure, "height", &height))
+ {
+ GST_WARNING("Missing \"height\" value.");
+ return;
+ }
+ if (!gst_structure_get_fraction(structure, "framerate", &fps_n, &fps_d))
+ {
+ fps_n = 0;
+ fps_d = 1;
+ }
+
+ format->major_type = WG_MAJOR_TYPE_VIDEO;
+ format->u.video.format = WG_VIDEO_FORMAT_CINEPAK;
+ format->u.video.width = width;
+ format->u.video.height = height;
+ format->u.video.fps_n = fps_n;
+ format->u.video.fps_d = fps_d;
+}
+
+static void wg_format_from_caps(struct wg_format *format, const GstCaps *caps)
+{
+ const GstStructure *structure = gst_caps_get_structure(caps, 0);
+ const char *name = gst_structure_get_name(structure);
+
+ memset(format, 0, sizeof(*format));
+
+ if (!strcmp(name, "audio/x-raw"))
+ {
+ GstAudioInfo info;
+
+ if (gst_audio_info_from_caps(&info, caps))
+ wg_format_from_audio_info(format, &info);
+ }
+ else if (!strcmp(name, "video/x-raw"))
+ {
+ GstVideoInfo info;
+
+ if (gst_video_info_from_caps(&info, caps))
+ wg_format_from_video_info(format, &info);
+ }
+ else if (!strcmp(name, "audio/mpeg"))
+ {
+ wg_format_from_caps_audio_mpeg(format, caps);
+ }
+ else if (!strcmp(name, "video/x-cinepak"))
+ {
+ wg_format_from_caps_video_cinepak(format, caps);
+ }
+ else
+ {
+ gchar *str = gst_caps_to_string(caps);
+
+ GST_FIXME("Unhandled caps %s.", str);
+ g_free(str);
+ }
+}
+
+static GstAudioFormat wg_audio_format_to_gst(enum wg_audio_format format)
+{
+ switch (format)
+ {
+ case WG_AUDIO_FORMAT_U8: return GST_AUDIO_FORMAT_U8;
+ case WG_AUDIO_FORMAT_S16LE: return GST_AUDIO_FORMAT_S16LE;
+ case WG_AUDIO_FORMAT_S24LE: return GST_AUDIO_FORMAT_S24LE;
+ case WG_AUDIO_FORMAT_S32LE: return GST_AUDIO_FORMAT_S32LE;
+ case WG_AUDIO_FORMAT_F32LE: return GST_AUDIO_FORMAT_F32LE;
+ case WG_AUDIO_FORMAT_F64LE: return GST_AUDIO_FORMAT_F64LE;
+ default: return GST_AUDIO_FORMAT_UNKNOWN;
+ }
+}
+
+static GstCaps *wg_format_to_caps_audio(const struct wg_format *format)
+{
+ GstAudioFormat audio_format;
+ GstAudioInfo info;
+
+ if ((audio_format = wg_audio_format_to_gst(format->u.audio.format)) == GST_AUDIO_FORMAT_UNKNOWN)
+ return NULL;
+
+ gst_audio_info_set_format(&info, audio_format, format->u.audio.rate, format->u.audio.channels, NULL);
+ return gst_audio_info_to_caps(&info);
+}
+
+static GstVideoFormat wg_video_format_to_gst(enum wg_video_format format)
+{
+ switch (format)
+ {
+ case WG_VIDEO_FORMAT_BGRA: return GST_VIDEO_FORMAT_BGRA;
+ case WG_VIDEO_FORMAT_BGRx: return GST_VIDEO_FORMAT_BGRx;
+ case WG_VIDEO_FORMAT_BGR: return GST_VIDEO_FORMAT_BGR;
+ case WG_VIDEO_FORMAT_RGB15: return GST_VIDEO_FORMAT_RGB15;
+ case WG_VIDEO_FORMAT_RGB16: return GST_VIDEO_FORMAT_RGB16;
+ case WG_VIDEO_FORMAT_AYUV: return GST_VIDEO_FORMAT_AYUV;
+ case WG_VIDEO_FORMAT_I420: return GST_VIDEO_FORMAT_I420;
+ case WG_VIDEO_FORMAT_NV12: return GST_VIDEO_FORMAT_NV12;
+ case WG_VIDEO_FORMAT_UYVY: return GST_VIDEO_FORMAT_UYVY;
+ case WG_VIDEO_FORMAT_YUY2: return GST_VIDEO_FORMAT_YUY2;
+ case WG_VIDEO_FORMAT_YV12: return GST_VIDEO_FORMAT_YV12;
+ case WG_VIDEO_FORMAT_YVYU: return GST_VIDEO_FORMAT_YVYU;
+ default: return GST_VIDEO_FORMAT_UNKNOWN;
+ }
+}
+
+static GstCaps *wg_format_to_caps_video(const struct wg_format *format)
+{
+ GstVideoFormat video_format;
+ GstVideoInfo info;
+ unsigned int i;
+ GstCaps *caps;
+
+ if ((video_format = wg_video_format_to_gst(format->u.video.format)) == GST_VIDEO_FORMAT_UNKNOWN)
+ return NULL;
+
+ gst_video_info_set_format(&info, video_format, format->u.video.width, format->u.video.height);
+ if ((caps = gst_video_info_to_caps(&info)))
+ {
+ /* Clear some fields that shouldn't prevent us from connecting. */
+ for (i = 0; i < gst_caps_get_size(caps); ++i)
+ {
+ gst_structure_remove_fields(gst_caps_get_structure(caps, i),
+ "framerate", "pixel-aspect-ratio", "colorimetry", "chroma-site", NULL);
+ }
+ }
+ return caps;
+}
+
+static GstCaps *wg_format_to_caps(const struct wg_format *format)
+{
+ switch (format->major_type)
+ {
+ case WG_MAJOR_TYPE_UNKNOWN:
+ return NULL;
+ case WG_MAJOR_TYPE_AUDIO:
+ return wg_format_to_caps_audio(format);
+ case WG_MAJOR_TYPE_VIDEO:
+ return wg_format_to_caps_video(format);
+ }
+ assert(0);
+ return NULL;
+}
+
+static bool wg_format_compare(const struct wg_format *a, const struct wg_format *b)
+{
+ if (a->major_type != b->major_type)
+ return false;
+
+ switch (a->major_type)
+ {
+ case WG_MAJOR_TYPE_UNKNOWN:
+ return false;
+
+ case WG_MAJOR_TYPE_AUDIO:
+ return a->u.audio.format == b->u.audio.format
+ && a->u.audio.channels == b->u.audio.channels
+ && a->u.audio.rate == b->u.audio.rate;
+
+ case WG_MAJOR_TYPE_VIDEO:
+ return a->u.video.format == b->u.video.format
+ && a->u.video.width == b->u.video.width
+ && a->u.video.height == b->u.video.height
+ && a->u.video.fps_d * b->u.video.fps_n == a->u.video.fps_n * b->u.video.fps_d;
+ }
+
+ assert(0);
+ return false;
+}
+
+static GstAutoplugSelectResult autoplug_blacklist(GstElement *bin, GstPad *pad, GstCaps *caps, GstElementFactory *fact, gpointer user)
+{
+ const char *name = gst_element_factory_get_longname(fact);
+
+ GST_TRACE("Using \"%s\".", name);
+
+ if (strstr(name, "Player protection"))
+ {
+ GST_WARNING("Blacklisted a/52 decoder because it only works in Totem.");
+ return GST_AUTOPLUG_SELECT_SKIP;
+ }
+ if (!strcmp(name, "Fluendo Hardware Accelerated Video Decoder"))
+ {
+ GST_WARNING("Disabled video acceleration since it breaks in wine.");
+ return GST_AUTOPLUG_SELECT_SKIP;
+ }
+ return GST_AUTOPLUG_SELECT_TRY;
+}
+
+static void no_more_pads(GstElement *element, gpointer user)
+{
+ struct wg_parser *parser = user;
+
+ GST_DEBUG("parser %p.", parser);
+
+ pthread_mutex_lock(&parser->mutex);
+ parser->no_more_pads = true;
+ pthread_mutex_unlock(&parser->mutex);
+ pthread_cond_signal(&parser->init_cond);
+}
+
+static GstFlowReturn queue_stream_event(struct wg_parser_stream *stream, const struct wg_parser_event *event)
+{
+ struct wg_parser *parser = stream->parser;
+
+ /* Unlike request_buffer_src() [q.v.], we need to watch for GStreamer
+ * flushes here. The difference is that we can be blocked by the streaming
+ * thread not running (or itself flushing on the DirectShow side).
+ * request_buffer_src() can only be blocked by the upstream source, and that
+ * is solved by flushing the upstream source. */
+
+ pthread_mutex_lock(&parser->mutex);
+ while (!stream->flushing && stream->event.type != WG_PARSER_EVENT_NONE)
+ pthread_cond_wait(&stream->event_empty_cond, &parser->mutex);
+ if (stream->flushing)
+ {
+ pthread_mutex_unlock(&parser->mutex);
+ GST_DEBUG("Filter is flushing; discarding event.");
+ return GST_FLOW_FLUSHING;
+ }
+ stream->event = *event;
+ pthread_mutex_unlock(&parser->mutex);
+ pthread_cond_signal(&stream->event_cond);
+ GST_LOG("Event queued.");
+ return GST_FLOW_OK;
+}
+
+static gboolean event_sink(GstPad *pad, GstObject *parent, GstEvent *event)
+{
+ struct wg_parser_stream *stream = gst_pad_get_element_private(pad);
+ struct wg_parser *parser = stream->parser;
+
+ GST_LOG("stream %p, type \"%s\".", stream, GST_EVENT_TYPE_NAME(event));
+
+ switch (event->type)
+ {
+ case GST_EVENT_SEGMENT:
+ if (stream->enabled)
+ {
+ struct wg_parser_event stream_event;
+ const GstSegment *segment;
+
+ gst_event_parse_segment(event, &segment);
+
+ if (segment->format != GST_FORMAT_TIME)
+ {
+ GST_FIXME("Unhandled format \"%s\".", gst_format_get_name(segment->format));
+ break;
+ }
+
+ stream_event.type = WG_PARSER_EVENT_SEGMENT;
+ stream_event.u.segment.position = segment->position / 100;
+ stream_event.u.segment.stop = segment->stop / 100;
+ stream_event.u.segment.rate = segment->rate * segment->applied_rate;
+ queue_stream_event(stream, &stream_event);
+ }
+ break;
+
+ case GST_EVENT_EOS:
+ if (stream->enabled)
+ {
+ struct wg_parser_event stream_event;
+
+ stream_event.type = WG_PARSER_EVENT_EOS;
+ queue_stream_event(stream, &stream_event);
+ }
+ else
+ {
+ pthread_mutex_lock(&parser->mutex);
+ stream->eos = true;
+ pthread_mutex_unlock(&parser->mutex);
+ pthread_cond_signal(&parser->init_cond);
+ }
+ break;
+
+ case GST_EVENT_FLUSH_START:
+ if (stream->enabled)
+ {
+ pthread_mutex_lock(&parser->mutex);
+
+ stream->flushing = true;
+ pthread_cond_signal(&stream->event_empty_cond);
+
+ switch (stream->event.type)
+ {
+ case WG_PARSER_EVENT_NONE:
+ case WG_PARSER_EVENT_EOS:
+ case WG_PARSER_EVENT_SEGMENT:
+ break;
+
+ case WG_PARSER_EVENT_BUFFER:
+ gst_buffer_unref(stream->event.u.buffer);
+ break;
+ }
+ stream->event.type = WG_PARSER_EVENT_NONE;
+
+ pthread_mutex_unlock(&parser->mutex);
+ }
+ break;
+
+ case GST_EVENT_FLUSH_STOP:
+ if (stream->enabled)
+ {
+ pthread_mutex_lock(&parser->mutex);
+ stream->flushing = false;
+ pthread_mutex_unlock(&parser->mutex);
+ }
+ break;
+
+ case GST_EVENT_CAPS:
+ {
+ GstCaps *caps;
+
+ gst_event_parse_caps(event, &caps);
+ pthread_mutex_lock(&parser->mutex);
+ wg_format_from_caps(&stream->preferred_format, caps);
+ stream->has_caps = true;
+ pthread_mutex_unlock(&parser->mutex);
+ pthread_cond_signal(&parser->init_cond);
+ break;
+ }
+
+ default:
+ GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event));
+ }
+ gst_event_unref(event);
+ return TRUE;
+}
+
+static GstFlowReturn got_data_sink(GstPad *pad, GstObject *parent, GstBuffer *buffer)
+{
+ struct wg_parser_stream *stream = gst_pad_get_element_private(pad);
+ struct wg_parser_event stream_event;
+ GstFlowReturn ret;
+
+ GST_LOG("stream %p, buffer %p.", stream, buffer);
+
+ if (!stream->enabled)
+ {
+ gst_buffer_unref(buffer);
+ return GST_FLOW_OK;
+ }
+
+ stream_event.type = WG_PARSER_EVENT_BUFFER;
+ stream_event.u.buffer = buffer;
+ /* Transfer our reference to the buffer to the object. */
+ if ((ret = queue_stream_event(stream, &stream_event)) != GST_FLOW_OK)
+ gst_buffer_unref(buffer);
+ return ret;
+}
+
+static gboolean query_sink(GstPad *pad, GstObject *parent, GstQuery *query)
+{
+ struct wg_parser_stream *stream = gst_pad_get_element_private(pad);
+
+ GST_LOG("stream %p, type \"%s\".", stream, gst_query_type_get_name(query->type));
+
+ switch (query->type)
+ {
+ case GST_QUERY_CAPS:
+ {
+ GstCaps *caps, *filter, *temp;
+
+ gst_query_parse_caps(query, &filter);
+
+ if (stream->enabled)
+ caps = wg_format_to_caps(&stream->current_format);
+ else
+ caps = gst_caps_new_any();
+ if (!caps)
+ return FALSE;
+
+ if (filter)
+ {
+ temp = gst_caps_intersect(caps, filter);
+ gst_caps_unref(caps);
+ caps = temp;
+ }
+
+ gst_query_set_caps_result(query, caps);
+ gst_caps_unref(caps);
+ return TRUE;
+ }
+
+ case GST_QUERY_ACCEPT_CAPS:
+ {
+ struct wg_format format;
+ gboolean ret = TRUE;
+ GstCaps *caps;
+
+ if (!stream->enabled)
+ {
+ gst_query_set_accept_caps_result(query, TRUE);
+ return TRUE;
+ }
+
+ gst_query_parse_accept_caps(query, &caps);
+ wg_format_from_caps(&format, caps);
+ ret = wg_format_compare(&format, &stream->current_format);
+ if (!ret && WARN_ON(gstreamer))
+ {
+ gchar *str = gst_caps_to_string(caps);
+ GST_WARNING("Rejecting caps \"%s\".", str);
+ g_free(str);
+ }
+ gst_query_set_accept_caps_result(query, ret);
+ return TRUE;
+ }
+
+ default:
+ return gst_pad_query_default (pad, parent, query);
+ }
+}
+
+static struct wg_parser_stream *create_stream(struct wg_parser *parser)
+{
+ struct wg_parser_stream *stream, **new_array;
+ char pad_name[19];
+
+ if (!(new_array = realloc(parser->streams, (parser->stream_count + 1) * sizeof(*parser->streams))))
+ return NULL;
+ parser->streams = new_array;
+
+ if (!(stream = calloc(1, sizeof(*stream))))
+ return NULL;
+
+ stream->parser = parser;
+ pthread_cond_init(&stream->event_cond, NULL);
+ pthread_cond_init(&stream->event_empty_cond, NULL);
+
+ sprintf(pad_name, "qz_sink_%u", parser->stream_count);
+ stream->my_sink = gst_pad_new(pad_name, GST_PAD_SINK);
+ gst_pad_set_element_private(stream->my_sink, stream);
+ gst_pad_set_chain_function(stream->my_sink, got_data_sink);
+ gst_pad_set_event_function(stream->my_sink, event_sink);
+ gst_pad_set_query_function(stream->my_sink, query_sink);
+
+ parser->streams[parser->stream_count++] = stream;
+ return stream;
+}
+
+static void init_new_decoded_pad(GstElement *element, GstPad *pad, struct wg_parser *parser)
+{
+ struct wg_parser_stream *stream;
+ const char *name;
+ GstCaps *caps;
+ int ret;
+
+ caps = gst_caps_make_writable(gst_pad_query_caps(pad, NULL));
+ name = gst_structure_get_name(gst_caps_get_structure(caps, 0));
+
+ if (!(stream = create_stream(parser)))
+ goto out;
+
+ if (!strcmp(name, "video/x-raw"))
+ {
+ GstElement *deinterlace, *vconv, *flip, *vconv2;
+
+ /* DirectShow can express interlaced video, but downstream filters can't
+ * necessarily consume it. In particular, the video renderer can't. */
+ if (!(deinterlace = gst_element_factory_make("deinterlace", NULL)))
+ {
+ fprintf(stderr, "winegstreamer: failed to create deinterlace, are %u-bit GStreamer \"good\" plugins installed?\n",
+ 8 * (int)sizeof(void *));
+ goto out;
+ }
+
+ /* decodebin considers many YUV formats to be "raw", but some quartz
+ * filters can't handle those. Also, videoflip can't handle all "raw"
+ * formats either. Add a videoconvert to swap color spaces. */
+ if (!(vconv = gst_element_factory_make("videoconvert", NULL)))
+ {
+ fprintf(stderr, "winegstreamer: failed to create videoconvert, are %u-bit GStreamer \"base\" plugins installed?\n",
+ 8 * (int)sizeof(void *));
+ goto out;
+ }
+
+ /* GStreamer outputs RGB video top-down, but DirectShow expects bottom-up. */
+ if (!(flip = gst_element_factory_make("videoflip", NULL)))
+ {
+ fprintf(stderr, "winegstreamer: failed to create videoflip, are %u-bit GStreamer \"good\" plugins installed?\n",
+ 8 * (int)sizeof(void *));
+ goto out;
+ }
+
+ /* videoflip does not support 15 and 16-bit RGB so add a second videoconvert
+ * to do the final conversion. */
+ if (!(vconv2 = gst_element_factory_make("videoconvert", NULL)))
+ {
+ fprintf(stderr, "winegstreamer: failed to create videoconvert, are %u-bit GStreamer \"base\" plugins installed?\n",
+ 8 * (int)sizeof(void *));
+ goto out;
+ }
+
+ /* The bin takes ownership of these elements. */
+ gst_bin_add(GST_BIN(parser->container), deinterlace);
+ gst_element_sync_state_with_parent(deinterlace);
+ gst_bin_add(GST_BIN(parser->container), vconv);
+ gst_element_sync_state_with_parent(vconv);
+ gst_bin_add(GST_BIN(parser->container), flip);
+ gst_element_sync_state_with_parent(flip);
+ gst_bin_add(GST_BIN(parser->container), vconv2);
+ gst_element_sync_state_with_parent(vconv2);
+
+ gst_element_link(deinterlace, vconv);
+ gst_element_link(vconv, flip);
+ gst_element_link(flip, vconv2);
+
+ stream->post_sink = gst_element_get_static_pad(deinterlace, "sink");
+ stream->post_src = gst_element_get_static_pad(vconv2, "src");
+ stream->flip = flip;
+ }
+ else if (!strcmp(name, "audio/x-raw"))
+ {
+ GstElement *convert;
+
+ /* Currently our dsound can't handle 64-bit formats or all
+ * surround-sound configurations. Native dsound can't always handle
+ * 64-bit formats either. Add an audioconvert to allow changing bit
+ * depth and channel count. */
+ if (!(convert = gst_element_factory_make("audioconvert", NULL)))
+ {
+ fprintf(stderr, "winegstreamer: failed to create audioconvert, are %u-bit GStreamer \"base\" plugins installed?\n",
+ 8 * (int)sizeof(void *));
+ goto out;
+ }
+
+ gst_bin_add(GST_BIN(parser->container), convert);
+ gst_element_sync_state_with_parent(convert);
+
+ stream->post_sink = gst_element_get_static_pad(convert, "sink");
+ stream->post_src = gst_element_get_static_pad(convert, "src");
+ }
+
+ if (stream->post_sink)
+ {
+ if ((ret = gst_pad_link(pad, stream->post_sink)) < 0)
+ {
+ GST_ERROR("Failed to link decodebin source pad to post-processing elements, error %s.",
+ gst_pad_link_get_name(ret));
+ gst_object_unref(stream->post_sink);
+ stream->post_sink = NULL;
+ goto out;
+ }
+
+ if ((ret = gst_pad_link(stream->post_src, stream->my_sink)) < 0)
+ {
+ GST_ERROR("Failed to link post-processing elements to our sink pad, error %s.",
+ gst_pad_link_get_name(ret));
+ gst_object_unref(stream->post_src);
+ stream->post_src = NULL;
+ gst_object_unref(stream->post_sink);
+ stream->post_sink = NULL;
+ goto out;
+ }
+ }
+ else if ((ret = gst_pad_link(pad, stream->my_sink)) < 0)
+ {
+ GST_ERROR("Failed to link decodebin source pad to our sink pad, error %s.",
+ gst_pad_link_get_name(ret));
+ goto out;
+ }
+
+ gst_pad_set_active(stream->my_sink, 1);
+ gst_object_ref(stream->their_src = pad);
+out:
+ gst_caps_unref(caps);
+}
+
+static void existing_new_pad(GstElement *element, GstPad *pad, gpointer user)
+{
+ struct wg_parser *parser = user;
+
+ GST_LOG("parser %p, element %p, pad %p.", parser, element, pad);
+
+ if (gst_pad_is_linked(pad))
+ return;
+
+ init_new_decoded_pad(element, pad, parser);
+}
+
+static void removed_decoded_pad(GstElement *element, GstPad *pad, gpointer user)
+{
+ struct wg_parser *parser = user;
+ unsigned int i;
+ char *name;
+
+ GST_LOG("parser %p, element %p, pad %p.", parser, element, pad);
+
+ for (i = 0; i < parser->stream_count; ++i)
+ {
+ struct wg_parser_stream *stream = parser->streams[i];
+
+ if (stream->their_src == pad)
+ {
+ if (stream->post_sink)
+ gst_pad_unlink(stream->their_src, stream->post_sink);
+ else
+ gst_pad_unlink(stream->their_src, stream->my_sink);
+ gst_object_unref(stream->their_src);
+ stream->their_src = NULL;
+ return;
+ }
+ }
+
+ name = gst_pad_get_name(pad);
+ GST_WARNING("No pin matching pad \"%s\" found.", name);
+ g_free(name);
+}
+
+static BOOL decodebin_parser_init_gst(struct wg_parser *parser)
+{
+ GstElement *element = gst_element_factory_make("decodebin", NULL);
+ int ret;
+
+ if (!element)
+ {
+ ERR("Failed to create decodebin; are %u-bit GStreamer \"base\" plugins installed?\n",
+ 8 * (int)sizeof(void*));
+ return FALSE;
+ }
+
+ gst_bin_add(GST_BIN(parser->container), element);
+
+ g_signal_connect(element, "pad-added", G_CALLBACK(existing_new_pad), parser);
+ g_signal_connect(element, "pad-removed", G_CALLBACK(removed_decoded_pad), parser);
+ g_signal_connect(element, "autoplug-select", G_CALLBACK(autoplug_blacklist), parser);
+ g_signal_connect(element, "no-more-pads", G_CALLBACK(no_more_pads), parser);
+
+ parser->their_sink = gst_element_get_static_pad(element, "sink");
+
+ pthread_mutex_lock(&parser->mutex);
+ parser->no_more_pads = parser->error = false;
+ pthread_mutex_unlock(&parser->mutex);
+
+ if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0)
+ {
+ ERR("Failed to link pads, error %d.\n", ret);
+ return FALSE;
+ }
+
+ gst_element_set_state(parser->container, GST_STATE_PAUSED);
+ ret = gst_element_get_state(parser->container, NULL, NULL, -1);
+ if (ret == GST_STATE_CHANGE_FAILURE)
+ {
+ ERR("Failed to play stream.\n");
+ return FALSE;
+ }
+
+ pthread_mutex_lock(&parser->mutex);
+ while (!parser->no_more_pads && !parser->error)
+ pthread_cond_wait(&parser->init_cond, &parser->mutex);
+ if (parser->error)
+ {
+ pthread_mutex_unlock(&parser->mutex);
+ return FALSE;
+ }
+ pthread_mutex_unlock(&parser->mutex);
+
+ return TRUE;
+}
+
+static BOOL avi_parser_init_gst(struct wg_parser *parser)
+{
+ GstElement *element = gst_element_factory_make("avidemux", NULL);
+ int ret;
+
+ if (!element)
+ {
+ ERR("Failed to create avidemux; are %u-bit GStreamer \"good\" plugins installed?\n",
+ 8 * (int)sizeof(void*));
+ return FALSE;
+ }
+
+ gst_bin_add(GST_BIN(parser->container), element);
+
+ g_signal_connect(element, "pad-added", G_CALLBACK(existing_new_pad), parser);
+ g_signal_connect(element, "pad-removed", G_CALLBACK(removed_decoded_pad), parser);
+ g_signal_connect(element, "no-more-pads", G_CALLBACK(no_more_pads), parser);
+
+ parser->their_sink = gst_element_get_static_pad(element, "sink");
+
+ pthread_mutex_lock(&parser->mutex);
+ parser->no_more_pads = parser->error = false;
+ pthread_mutex_unlock(&parser->mutex);
+
+ if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0)
+ {
+ ERR("Failed to link pads, error %d.\n", ret);
+ return FALSE;
+ }
+
+ gst_element_set_state(parser->container, GST_STATE_PAUSED);
+ ret = gst_element_get_state(parser->container, NULL, NULL, -1);
+ if (ret == GST_STATE_CHANGE_FAILURE)
+ {
+ ERR("Failed to play stream.\n");
+ return FALSE;
+ }
+
+ pthread_mutex_lock(&parser->mutex);
+ while (!parser->no_more_pads && !parser->error)
+ pthread_cond_wait(&parser->init_cond, &parser->mutex);
+ if (parser->error)
+ {
+ pthread_mutex_unlock(&parser->mutex);
+ return FALSE;
+ }
+ pthread_mutex_unlock(&parser->mutex);
+
+ return TRUE;
+}
+
+static BOOL mpeg_audio_parser_init_gst(struct wg_parser *parser)
+{
+ struct wg_parser_stream *stream;
+ GstElement *element;
+ int ret;
+
+ if (!(element = gst_element_factory_make("mpegaudioparse", NULL)))
+ {
+ ERR("Failed to create mpegaudioparse; are %u-bit GStreamer \"good\" plugins installed?\n",
+ 8 * (int)sizeof(void*));
+ return FALSE;
+ }
+
+ gst_bin_add(GST_BIN(parser->container), element);
+
+ parser->their_sink = gst_element_get_static_pad(element, "sink");
+ if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0)
+ {
+ ERR("Failed to link sink pads, error %d.\n", ret);
+ return FALSE;
+ }
+
+ if (!(stream = create_stream(parser)))
+ return FALSE;
+
+ gst_object_ref(stream->their_src = gst_element_get_static_pad(element, "src"));
+ if ((ret = gst_pad_link(stream->their_src, stream->my_sink)) < 0)
+ {
+ ERR("Failed to link source pads, error %d.\n", ret);
+ return FALSE;
+ }
+
+ gst_pad_set_active(stream->my_sink, 1);
+ gst_element_set_state(parser->container, GST_STATE_PAUSED);
+ ret = gst_element_get_state(parser->container, NULL, NULL, -1);
+ if (ret == GST_STATE_CHANGE_FAILURE)
+ {
+ ERR("Failed to play stream.\n");
+ return FALSE;
+ }
+
+ pthread_mutex_lock(&parser->mutex);
+ while (!parser->has_duration && !parser->error && !stream->eos)
+ pthread_cond_wait(&parser->init_cond, &parser->mutex);
+ if (parser->error)
+ {
+ pthread_mutex_unlock(&parser->mutex);
+ return FALSE;
+ }
+ pthread_mutex_unlock(&parser->mutex);
+ return TRUE;
+}
+
+static BOOL wave_parser_init_gst(struct wg_parser *parser)
+{
+ struct wg_parser_stream *stream;
+ GstElement *element;
+ int ret;
+
+ if (!(element = gst_element_factory_make("wavparse", NULL)))
+ {
+ ERR("Failed to create wavparse; are %u-bit GStreamer \"good\" plugins installed?\n",
+ 8 * (int)sizeof(void*));
+ return FALSE;
+ }
+
+ gst_bin_add(GST_BIN(parser->container), element);
+
+ parser->their_sink = gst_element_get_static_pad(element, "sink");
+ if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0)
+ {
+ ERR("Failed to link sink pads, error %d.\n", ret);
+ return FALSE;
+ }
+
+ if (!(stream = create_stream(parser)))
+ return FALSE;
+
+ stream->their_src = gst_element_get_static_pad(element, "src");
+ gst_object_ref(stream->their_src);
+ if ((ret = gst_pad_link(stream->their_src, stream->my_sink)) < 0)
+ {
+ ERR("Failed to link source pads, error %d.\n", ret);
+ return FALSE;
+ }
+
+ gst_pad_set_active(stream->my_sink, 1);
+ gst_element_set_state(parser->container, GST_STATE_PAUSED);
+ ret = gst_element_get_state(parser->container, NULL, NULL, -1);
+ if (ret == GST_STATE_CHANGE_FAILURE)
+ {
+ ERR("Failed to play stream.\n");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static struct wg_parser *wg_parser_create(void)
+{
+ struct wg_parser *parser;
+
+ if (!(parser = calloc(1, sizeof(*parser))))
+ return NULL;
+
+ pthread_mutex_init(&parser->mutex, NULL);
+ pthread_cond_init(&parser->init_cond, NULL);
+ pthread_cond_init(&parser->read_cond, NULL);
+ pthread_cond_init(&parser->read_done_cond, NULL);
+ parser->flushing = true;
+
+ TRACE("Created winegstreamer parser %p.\n", parser);
+ return parser;
+}
+
+static struct wg_parser * CDECL wg_decodebin_parser_create(void)
+{
+ struct wg_parser *parser;
+
+ if ((parser = wg_parser_create()))
+ parser->init_gst = decodebin_parser_init_gst;
+ return parser;
+}
+
+static struct wg_parser * CDECL wg_avi_parser_create(void)
+{
+ struct wg_parser *parser;
+
+ if ((parser = wg_parser_create()))
+ parser->init_gst = avi_parser_init_gst;
+ return parser;
+}
+
+static struct wg_parser * CDECL wg_mpeg_audio_parser_create(void)
+{
+ struct wg_parser *parser;
+
+ if ((parser = wg_parser_create()))
+ parser->init_gst = mpeg_audio_parser_init_gst;
+ return parser;
+}
+
+static struct wg_parser * CDECL wg_wave_parser_create(void)
+{
+ struct wg_parser *parser;
+
+ if ((parser = wg_parser_create()))
+ parser->init_gst = wave_parser_init_gst;
+ return parser;
+}
+
+static const struct unix_funcs funcs =
+{
+ wg_decodebin_parser_create,
+ wg_avi_parser_create,
+ wg_mpeg_audio_parser_create,
+ wg_wave_parser_create,
+};
+
+NTSTATUS CDECL __wine_init_unix_lib(HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out)
+{
+ if (reason == DLL_PROCESS_ATTACH)
+ {
+ GST_DEBUG_CATEGORY_INIT(wine, "WINE", GST_DEBUG_FG_RED, "Wine GStreamer support");
+ *(const struct unix_funcs **)ptr_out = &funcs;
+ }
+ return STATUS_SUCCESS;
+}
--
2.30.0
More information about the wine-devel
mailing list