[PATCH 3/5] winegstreamer: Move GST_Connect() to the Unix library.
Zebediah Figura
z.figura12 at gmail.com
Sat Feb 13 11:33:04 CST 2021
Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
dlls/winegstreamer/gst_private.h | 2 +
dlls/winegstreamer/gstdemux.c | 372 +------------------------------
dlls/winegstreamer/wg_parser.c | 372 +++++++++++++++++++++++++++++++
3 files changed, 375 insertions(+), 371 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index 15a20749786..ce500a92356 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -211,6 +211,8 @@ struct unix_funcs
struct wg_parser *(CDECL *wg_mpeg_audio_parser_create)(void);
struct wg_parser *(CDECL *wg_wave_parser_create)(void);
void (CDECL *wg_parser_destroy)(struct wg_parser *parser);
+
+ HRESULT (CDECL *wg_parser_connect)(struct wg_parser *parser, uint64_t file_size);
};
extern const struct unix_funcs *unix_funcs;
diff --git a/dlls/winegstreamer/gstdemux.c b/dlls/winegstreamer/gstdemux.c
index 8b63aa57702..9a74e09f5dd 100644
--- a/dlls/winegstreamer/gstdemux.c
+++ b/dlls/winegstreamer/gstdemux.c
@@ -42,9 +42,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(gstreamer);
-GST_DEBUG_CATEGORY_STATIC(wine);
-#define GST_CAT_DEFAULT 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}};
@@ -569,133 +566,6 @@ static bool amt_to_wg_format(const AM_MEDIA_TYPE *mt, struct wg_format *format)
return false;
}
-static gboolean gst_base_src_perform_seek(struct wg_parser *parser, GstEvent *event)
-{
- gboolean res = TRUE;
- gdouble rate;
- GstFormat seek_format;
- GstSeekFlags flags;
- GstSeekType cur_type, stop_type;
- gint64 cur, stop;
- gboolean flush;
- guint32 seqnum;
- GstEvent *tevent;
- BOOL thread = !!parser->push_thread;
-
- gst_event_parse_seek(event, &rate, &seek_format, &flags,
- &cur_type, &cur, &stop_type, &stop);
-
- if (seek_format != GST_FORMAT_BYTES)
- {
- GST_FIXME("Unhandled format \"%s\".", gst_format_get_name(seek_format));
- return FALSE;
- }
-
- flush = flags & GST_SEEK_FLAG_FLUSH;
- seqnum = gst_event_get_seqnum(event);
-
- /* send flush start */
- if (flush) {
- tevent = gst_event_new_flush_start();
- gst_event_set_seqnum(tevent, seqnum);
- gst_pad_push_event(parser->my_src, tevent);
- if (thread)
- gst_pad_set_active(parser->my_src, 1);
- }
-
- parser->next_offset = parser->start_offset = cur;
-
- /* and prepare to continue streaming */
- if (flush) {
- tevent = gst_event_new_flush_stop(TRUE);
- gst_event_set_seqnum(tevent, seqnum);
- gst_pad_push_event(parser->my_src, tevent);
- if (thread)
- gst_pad_set_active(parser->my_src, 1);
- }
-
- return res;
-}
-
-static gboolean event_src(GstPad *pad, GstObject *parent, GstEvent *event)
-{
- struct wg_parser *parser = gst_pad_get_element_private(pad);
- gboolean ret = TRUE;
-
- GST_LOG("parser %p, type \"%s\".", parser, GST_EVENT_TYPE_NAME(event));
-
- switch (event->type)
- {
- case GST_EVENT_SEEK:
- ret = gst_base_src_perform_seek(parser, event);
- break;
-
- case GST_EVENT_FLUSH_START:
- case GST_EVENT_FLUSH_STOP:
- case GST_EVENT_QOS:
- case GST_EVENT_RECONFIGURE:
- break;
-
- default:
- GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event));
- ret = FALSE;
- break;
- }
- gst_event_unref(event);
- return ret;
-}
-
-static GstFlowReturn request_buffer_src(GstPad *pad, GstObject *parent, guint64 offset, guint size, GstBuffer **buffer);
-
-static void *push_data(void *arg)
-{
- struct wg_parser *parser = arg;
- GstBuffer *buffer;
- LONGLONG maxlen;
-
- GST_DEBUG("Starting push thread.");
-
- if (!(buffer = gst_buffer_new_allocate(NULL, 16384, NULL)))
- {
- GST_ERROR("Failed to allocate memory.");
- return NULL;
- }
-
- maxlen = parser->stop_offset ? parser->stop_offset : parser->file_size;
-
- for (;;) {
- ULONG len;
- int ret;
-
- if (parser->next_offset >= maxlen)
- break;
- len = min(16384, maxlen - parser->next_offset);
-
- if ((ret = request_buffer_src(parser->my_src, NULL, parser->next_offset, len, &buffer)) < 0)
- {
- GST_ERROR("Failed to read data, ret %s.", gst_flow_get_name(ret));
- break;
- }
-
- parser->next_offset += len;
-
- buffer->duration = buffer->pts = -1;
- if ((ret = gst_pad_push(parser->my_src, buffer)) < 0)
- {
- GST_ERROR("Failed to push data, ret %s.", gst_flow_get_name(ret));
- break;
- }
- }
-
- gst_buffer_unref(buffer);
-
- gst_pad_push_event(parser->my_src, gst_event_new_eos());
-
- GST_DEBUG("Stopping push thread.");
-
- return NULL;
-}
-
/* 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)
@@ -890,45 +760,6 @@ static DWORD CALLBACK stream_thread(void *arg)
return 0;
}
-static GstFlowReturn request_buffer_src(GstPad *pad, GstObject *parent, guint64 offset, guint size, GstBuffer **buffer)
-{
- struct wg_parser *parser = gst_pad_get_element_private(pad);
- GstBuffer *new_buffer = NULL;
- GstFlowReturn ret;
-
- GST_LOG("pad %p, offset %" G_GINT64_MODIFIER "u, length %u, buffer %p.", pad, offset, size, *buffer);
-
- if (!*buffer)
- *buffer = new_buffer = gst_buffer_new_and_alloc(size);
-
- pthread_mutex_lock(&parser->mutex);
-
- assert(!parser->read_request.buffer);
- parser->read_request.buffer = *buffer;
- parser->read_request.offset = offset;
- parser->read_request.size = size;
- parser->read_request.done = false;
- pthread_cond_signal(&parser->read_cond);
-
- /* Note that we don't unblock this wait on GST_EVENT_FLUSH_START. We expect
- * the upstream pin to flush if necessary. We should never be blocked on
- * read_thread() not running. */
-
- while (!parser->read_request.done)
- pthread_cond_wait(&parser->read_done_cond, &parser->mutex);
-
- ret = parser->read_request.ret;
-
- pthread_mutex_unlock(&parser->mutex);
-
- GST_LOG("Request returned %s.", gst_flow_get_name(ret));
-
- if (ret != GST_FLOW_OK && new_buffer)
- gst_buffer_unref(new_buffer);
-
- return ret;
-}
-
static GstFlowReturn read_buffer(struct parser *This, guint64 ofs, guint len, GstBuffer *buffer)
{
HRESULT hr;
@@ -989,206 +820,6 @@ static DWORD CALLBACK read_thread(void *arg)
return 0;
}
-static gboolean query_function(GstPad *pad, GstObject *parent, GstQuery *query)
-{
- struct wg_parser *parser = gst_pad_get_element_private(pad);
- GstFormat format;
-
- GST_LOG("parser %p, type %s.", parser, GST_QUERY_TYPE_NAME(query));
-
- switch (GST_QUERY_TYPE(query)) {
- case GST_QUERY_DURATION:
- gst_query_parse_duration(query, &format, NULL);
- if (format == GST_FORMAT_PERCENT)
- {
- gst_query_set_duration(query, GST_FORMAT_PERCENT, GST_FORMAT_PERCENT_MAX);
- return TRUE;
- }
- else if (format == GST_FORMAT_BYTES)
- {
- gst_query_set_duration(query, GST_FORMAT_BYTES, parser->file_size);
- return TRUE;
- }
- return FALSE;
- case GST_QUERY_SEEKING:
- gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
- if (format != GST_FORMAT_BYTES)
- {
- GST_WARNING("Cannot seek using format \"%s\".", gst_format_get_name(format));
- return FALSE;
- }
- gst_query_set_seeking(query, GST_FORMAT_BYTES, 1, 0, parser->file_size);
- return TRUE;
- case GST_QUERY_SCHEDULING:
- gst_query_set_scheduling(query, GST_SCHEDULING_FLAG_SEEKABLE, 1, -1, 0);
- gst_query_add_scheduling_mode(query, GST_PAD_MODE_PUSH);
- gst_query_add_scheduling_mode(query, GST_PAD_MODE_PULL);
- return TRUE;
- default:
- GST_WARNING("Unhandled query type %s.", GST_QUERY_TYPE_NAME(query));
- return FALSE;
- }
-}
-
-static gboolean activate_push(GstPad *pad, gboolean activate)
-{
- struct wg_parser *parser = gst_pad_get_element_private(pad);
-
- if (!activate) {
- if (parser->push_thread) {
- pthread_join(parser->push_thread, NULL);
- parser->push_thread = 0;
- }
- } else if (!parser->push_thread) {
- int ret;
-
- if ((ret = pthread_create(&parser->push_thread, NULL, push_data, parser)))
- {
- GST_ERROR("Failed to create push thread: %s", strerror(errno));
- parser->push_thread = 0;
- return FALSE;
- }
- }
- return TRUE;
-}
-
-static gboolean activate_mode(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate)
-{
- struct wg_parser *parser = gst_pad_get_element_private(pad);
-
- GST_DEBUG("%s source pad for parser %p in %s mode.",
- activate ? "Activating" : "Deactivating", parser, gst_pad_mode_get_name(mode));
-
- switch (mode) {
- case GST_PAD_MODE_PULL:
- return TRUE;
- case GST_PAD_MODE_PUSH:
- return activate_push(pad, activate);
- default:
- return FALSE;
- }
- return FALSE;
-}
-
-static GstBusSyncReply watch_bus(GstBus *bus, GstMessage *msg, gpointer user)
-{
- struct wg_parser *parser = user;
- GError *err = NULL;
- gchar *dbg_info = NULL;
-
- GST_DEBUG("parser %p, message type %s.", parser, GST_MESSAGE_TYPE_NAME(msg));
-
- switch (msg->type)
- {
- case GST_MESSAGE_ERROR:
- gst_message_parse_error(msg, &err, &dbg_info);
- fprintf(stderr, "winegstreamer: error: %s: %s\n", GST_OBJECT_NAME(msg->src), err->message);
- fprintf(stderr, "winegstreamer: error: %s: %s\n", GST_OBJECT_NAME(msg->src), dbg_info);
- g_error_free(err);
- g_free(dbg_info);
- pthread_mutex_lock(&parser->mutex);
- parser->error = true;
- pthread_mutex_unlock(&parser->mutex);
- pthread_cond_signal(&parser->init_cond);
- break;
-
- case GST_MESSAGE_WARNING:
- gst_message_parse_warning(msg, &err, &dbg_info);
- fprintf(stderr, "winegstreamer: warning: %s: %s\n", GST_OBJECT_NAME(msg->src), err->message);
- fprintf(stderr, "winegstreamer: warning: %s: %s\n", GST_OBJECT_NAME(msg->src), dbg_info);
- g_error_free(err);
- g_free(dbg_info);
- break;
-
- case GST_MESSAGE_DURATION_CHANGED:
- pthread_mutex_lock(&parser->mutex);
- parser->has_duration = true;
- pthread_mutex_unlock(&parser->mutex);
- pthread_cond_signal(&parser->init_cond);
- break;
-
- default:
- break;
- }
- gst_message_unref(msg);
- return GST_BUS_DROP;
-}
-
-static LONGLONG query_duration(GstPad *pad)
-{
- gint64 duration, byte_length;
-
- if (gst_pad_query_duration(pad, GST_FORMAT_TIME, &duration))
- return duration / 100;
-
- WARN("Failed to query time duration; trying to convert from byte length.\n");
-
- /* To accurately get a duration for the stream, we want to only consider the
- * length of that stream. Hence, query for the pad duration, instead of
- * using the file duration. */
- if (gst_pad_query_duration(pad, GST_FORMAT_BYTES, &byte_length)
- && gst_pad_query_convert(pad, GST_FORMAT_BYTES, byte_length, GST_FORMAT_TIME, &duration))
- return duration / 100;
-
- ERR("Failed to query duration.\n");
- return 0;
-}
-
-static HRESULT GST_Connect(struct wg_parser *parser, LONGLONG file_size)
-{
- unsigned int i;
- GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE(
- "quartz_src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS_ANY);
-
- parser->file_size = file_size;
- parser->sink_connected = true;
-
- if (!parser->bus)
- {
- parser->bus = gst_bus_new();
- gst_bus_set_sync_handler(parser->bus, watch_bus, parser, NULL);
- }
-
- parser->container = gst_bin_new(NULL);
- gst_element_set_bus(parser->container, parser->bus);
-
- parser->my_src = gst_pad_new_from_static_template(&src_template, "quartz-src");
- gst_pad_set_getrange_function(parser->my_src, request_buffer_src);
- gst_pad_set_query_function(parser->my_src, query_function);
- gst_pad_set_activatemode_function(parser->my_src, activate_mode);
- gst_pad_set_event_function(parser->my_src, event_src);
- gst_pad_set_element_private(parser->my_src, parser);
-
- parser->start_offset = parser->next_offset = parser->stop_offset = 0;
-
- if (!parser->init_gst(parser))
- return E_FAIL;
-
- pthread_mutex_lock(&parser->mutex);
-
- for (i = 0; i < parser->stream_count; ++i)
- {
- struct wg_parser_stream *stream = parser->streams[i];
-
- stream->duration = query_duration(stream->their_src);
- while (!stream->has_caps && !parser->error)
- pthread_cond_wait(&parser->init_cond, &parser->mutex);
- if (parser->error)
- {
- pthread_mutex_unlock(&parser->mutex);
- return E_FAIL;
- }
- }
-
- pthread_mutex_unlock(&parser->mutex);
-
- parser->next_offset = 0;
- return S_OK;
-}
-
static inline struct parser_source *impl_from_IMediaSeeking(IMediaSeeking *iface)
{
return CONTAINING_RECORD(iface, struct parser_source, seek.IMediaSeeking_iface);
@@ -1363,7 +994,7 @@ static HRESULT parser_sink_connect(struct strmbase_sink *iface, IPin *peer, cons
filter->read_thread = CreateThread(NULL, 0, read_thread, filter, 0, NULL);
filter->next_pull_offset = 0;
- if (FAILED(hr = GST_Connect(filter->wg_parser, filter->file_size)))
+ if (FAILED(hr = unix_funcs->wg_parser_connect(filter->wg_parser, filter->file_size)))
goto err;
if (!filter->init_gst(filter))
@@ -1485,7 +1116,6 @@ static BOOL parser_init_gstreamer(void)
{
if (!init_gstreamer())
return FALSE;
- GST_DEBUG_CATEGORY_INIT(wine, "WINE", GST_DEBUG_FG_RED, "Wine GStreamer support");
return TRUE;
}
diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c
index 071694f77cc..3e7c41d644d 100644
--- a/dlls/winegstreamer/wg_parser.c
+++ b/dlls/winegstreamer/wg_parser.c
@@ -757,6 +757,376 @@ static void removed_decoded_pad(GstElement *element, GstPad *pad, gpointer user)
g_free(name);
}
+static GstFlowReturn request_buffer_src(GstPad *pad, GstObject *parent, guint64 offset, guint size, GstBuffer **buffer)
+{
+ struct wg_parser *parser = gst_pad_get_element_private(pad);
+ GstBuffer *new_buffer = NULL;
+ GstFlowReturn ret;
+
+ GST_LOG("pad %p, offset %" G_GINT64_MODIFIER "u, length %u, buffer %p.", pad, offset, size, *buffer);
+
+ if (!*buffer)
+ *buffer = new_buffer = gst_buffer_new_and_alloc(size);
+
+ pthread_mutex_lock(&parser->mutex);
+
+ assert(!parser->read_request.buffer);
+ parser->read_request.buffer = *buffer;
+ parser->read_request.offset = offset;
+ parser->read_request.size = size;
+ parser->read_request.done = false;
+ pthread_cond_signal(&parser->read_cond);
+
+ /* Note that we don't unblock this wait on GST_EVENT_FLUSH_START. We expect
+ * the upstream pin to flush if necessary. We should never be blocked on
+ * read_thread() not running. */
+
+ while (!parser->read_request.done)
+ pthread_cond_wait(&parser->read_done_cond, &parser->mutex);
+
+ ret = parser->read_request.ret;
+
+ pthread_mutex_unlock(&parser->mutex);
+
+ GST_LOG("Request returned %s.", gst_flow_get_name(ret));
+
+ if (ret != GST_FLOW_OK && new_buffer)
+ gst_buffer_unref(new_buffer);
+
+ return ret;
+}
+
+static gboolean query_function(GstPad *pad, GstObject *parent, GstQuery *query)
+{
+ struct wg_parser *parser = gst_pad_get_element_private(pad);
+ GstFormat format;
+
+ GST_LOG("parser %p, type %s.", parser, GST_QUERY_TYPE_NAME(query));
+
+ switch (GST_QUERY_TYPE(query))
+ {
+ case GST_QUERY_DURATION:
+ gst_query_parse_duration(query, &format, NULL);
+ if (format == GST_FORMAT_PERCENT)
+ {
+ gst_query_set_duration(query, GST_FORMAT_PERCENT, GST_FORMAT_PERCENT_MAX);
+ return TRUE;
+ }
+ else if (format == GST_FORMAT_BYTES)
+ {
+ gst_query_set_duration(query, GST_FORMAT_BYTES, parser->file_size);
+ return TRUE;
+ }
+ return FALSE;
+
+ case GST_QUERY_SEEKING:
+ gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
+ if (format != GST_FORMAT_BYTES)
+ {
+ GST_WARNING("Cannot seek using format \"%s\".", gst_format_get_name(format));
+ return FALSE;
+ }
+ gst_query_set_seeking(query, GST_FORMAT_BYTES, 1, 0, parser->file_size);
+ return TRUE;
+
+ case GST_QUERY_SCHEDULING:
+ gst_query_set_scheduling(query, GST_SCHEDULING_FLAG_SEEKABLE, 1, -1, 0);
+ gst_query_add_scheduling_mode(query, GST_PAD_MODE_PUSH);
+ gst_query_add_scheduling_mode(query, GST_PAD_MODE_PULL);
+ return TRUE;
+
+ default:
+ GST_WARNING("Unhandled query type %s.", GST_QUERY_TYPE_NAME(query));
+ return FALSE;
+ }
+}
+
+static void *push_data(void *arg)
+{
+ struct wg_parser *parser = arg;
+ GstBuffer *buffer;
+ guint max_size;
+
+ GST_DEBUG("Starting push thread.");
+
+ if (!(buffer = gst_buffer_new_allocate(NULL, 16384, NULL)))
+ {
+ GST_ERROR("Failed to allocate memory.");
+ return NULL;
+ }
+
+ max_size = parser->stop_offset ? parser->stop_offset : parser->file_size;
+
+ for (;;)
+ {
+ ULONG size;
+ int ret;
+
+ if (parser->next_offset >= max_size)
+ break;
+ size = min(16384, max_size - parser->next_offset);
+
+ if ((ret = request_buffer_src(parser->my_src, NULL, parser->next_offset, size, &buffer)) < 0)
+ {
+ GST_ERROR("Failed to read data, ret %s.", gst_flow_get_name(ret));
+ break;
+ }
+
+ parser->next_offset += size;
+
+ buffer->duration = buffer->pts = -1;
+ if ((ret = gst_pad_push(parser->my_src, buffer)) < 0)
+ {
+ GST_ERROR("Failed to push data, ret %s.", gst_flow_get_name(ret));
+ break;
+ }
+ }
+
+ gst_buffer_unref(buffer);
+
+ gst_pad_push_event(parser->my_src, gst_event_new_eos());
+
+ GST_DEBUG("Stopping push thread.");
+
+ return NULL;
+}
+
+static gboolean activate_push(GstPad *pad, gboolean activate)
+{
+ struct wg_parser *parser = gst_pad_get_element_private(pad);
+
+ if (!activate)
+ {
+ if (parser->push_thread)
+ {
+ pthread_join(parser->push_thread, NULL);
+ parser->push_thread = 0;
+ }
+ }
+ else if (!parser->push_thread)
+ {
+ int ret;
+
+ if ((ret = pthread_create(&parser->push_thread, NULL, push_data, parser)))
+ {
+ GST_ERROR("Failed to create push thread: %s", strerror(errno));
+ parser->push_thread = 0;
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static gboolean activate_mode(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate)
+{
+ struct wg_parser *parser = gst_pad_get_element_private(pad);
+
+ GST_DEBUG("%s source pad for parser %p in %s mode.",
+ activate ? "Activating" : "Deactivating", parser, gst_pad_mode_get_name(mode));
+
+ switch (mode)
+ {
+ case GST_PAD_MODE_PULL:
+ return TRUE;
+ case GST_PAD_MODE_PUSH:
+ return activate_push(pad, activate);
+ case GST_PAD_MODE_NONE:
+ break;
+ }
+ return FALSE;
+}
+
+static GstBusSyncReply watch_bus(GstBus *bus, GstMessage *msg, gpointer user)
+{
+ struct wg_parser *parser = user;
+ gchar *dbg_info = NULL;
+ GError *err = NULL;
+
+ GST_DEBUG("parser %p, message type %s.", parser, GST_MESSAGE_TYPE_NAME(msg));
+
+ switch (msg->type)
+ {
+ case GST_MESSAGE_ERROR:
+ gst_message_parse_error(msg, &err, &dbg_info);
+ fprintf(stderr, "winegstreamer: error: %s: %s\n", GST_OBJECT_NAME(msg->src), err->message);
+ fprintf(stderr, "winegstreamer: error: %s: %s\n", GST_OBJECT_NAME(msg->src), dbg_info);
+ g_error_free(err);
+ g_free(dbg_info);
+ pthread_mutex_lock(&parser->mutex);
+ parser->error = true;
+ pthread_mutex_unlock(&parser->mutex);
+ pthread_cond_signal(&parser->init_cond);
+ break;
+
+ case GST_MESSAGE_WARNING:
+ gst_message_parse_warning(msg, &err, &dbg_info);
+ fprintf(stderr, "winegstreamer: warning: %s: %s\n", GST_OBJECT_NAME(msg->src), err->message);
+ fprintf(stderr, "winegstreamer: warning: %s: %s\n", GST_OBJECT_NAME(msg->src), dbg_info);
+ g_error_free(err);
+ g_free(dbg_info);
+ break;
+
+ case GST_MESSAGE_DURATION_CHANGED:
+ pthread_mutex_lock(&parser->mutex);
+ parser->has_duration = true;
+ pthread_mutex_unlock(&parser->mutex);
+ pthread_cond_signal(&parser->init_cond);
+ break;
+
+ default:
+ break;
+ }
+ gst_message_unref(msg);
+ return GST_BUS_DROP;
+}
+
+static gboolean gst_base_src_perform_seek(struct wg_parser *parser, GstEvent *event)
+{
+ BOOL thread = !!parser->push_thread;
+ GstSeekType cur_type, stop_type;
+ GstFormat seek_format;
+ GstEvent *flush_event;
+ GstSeekFlags flags;
+ gint64 cur, stop;
+ guint32 seqnum;
+ gdouble rate;
+
+ gst_event_parse_seek(event, &rate, &seek_format, &flags,
+ &cur_type, &cur, &stop_type, &stop);
+
+ if (seek_format != GST_FORMAT_BYTES)
+ {
+ GST_FIXME("Unhandled format \"%s\".", gst_format_get_name(seek_format));
+ return FALSE;
+ }
+
+ seqnum = gst_event_get_seqnum(event);
+
+ /* send flush start */
+ if (flags & GST_SEEK_FLAG_FLUSH)
+ {
+ flush_event = gst_event_new_flush_start();
+ gst_event_set_seqnum(flush_event, seqnum);
+ gst_pad_push_event(parser->my_src, flush_event);
+ if (thread)
+ gst_pad_set_active(parser->my_src, 1);
+ }
+
+ parser->next_offset = parser->start_offset = cur;
+
+ /* and prepare to continue streaming */
+ if (flags & GST_SEEK_FLAG_FLUSH)
+ {
+ flush_event = gst_event_new_flush_stop(TRUE);
+ gst_event_set_seqnum(flush_event, seqnum);
+ gst_pad_push_event(parser->my_src, flush_event);
+ if (thread)
+ gst_pad_set_active(parser->my_src, 1);
+ }
+
+ return TRUE;
+}
+
+static gboolean event_src(GstPad *pad, GstObject *parent, GstEvent *event)
+{
+ struct wg_parser *parser = gst_pad_get_element_private(pad);
+ gboolean ret = TRUE;
+
+ GST_LOG("parser %p, type \"%s\".", parser, GST_EVENT_TYPE_NAME(event));
+
+ switch (event->type)
+ {
+ case GST_EVENT_SEEK:
+ ret = gst_base_src_perform_seek(parser, event);
+ break;
+
+ case GST_EVENT_FLUSH_START:
+ case GST_EVENT_FLUSH_STOP:
+ case GST_EVENT_QOS:
+ case GST_EVENT_RECONFIGURE:
+ break;
+
+ default:
+ GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event));
+ ret = FALSE;
+ break;
+ }
+ gst_event_unref(event);
+ return ret;
+}
+
+static LONGLONG query_duration(GstPad *pad)
+{
+ gint64 duration, byte_length;
+
+ if (gst_pad_query_duration(pad, GST_FORMAT_TIME, &duration))
+ return duration / 100;
+
+ WARN("Failed to query time duration; trying to convert from byte length.\n");
+
+ /* To accurately get a duration for the stream, we want to only consider the
+ * length of that stream. Hence, query for the pad duration, instead of
+ * using the file duration. */
+ if (gst_pad_query_duration(pad, GST_FORMAT_BYTES, &byte_length)
+ && gst_pad_query_convert(pad, GST_FORMAT_BYTES, byte_length, GST_FORMAT_TIME, &duration))
+ return duration / 100;
+
+ ERR("Failed to query duration.\n");
+ return 0;
+}
+
+static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_size)
+{
+ GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("quartz_src",
+ GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY);
+ unsigned int i;
+
+ parser->file_size = file_size;
+ parser->sink_connected = true;
+
+ if (!parser->bus)
+ {
+ parser->bus = gst_bus_new();
+ gst_bus_set_sync_handler(parser->bus, watch_bus, parser, NULL);
+ }
+
+ parser->container = gst_bin_new(NULL);
+ gst_element_set_bus(parser->container, parser->bus);
+
+ parser->my_src = gst_pad_new_from_static_template(&src_template, "quartz-src");
+ gst_pad_set_getrange_function(parser->my_src, request_buffer_src);
+ gst_pad_set_query_function(parser->my_src, query_function);
+ gst_pad_set_activatemode_function(parser->my_src, activate_mode);
+ gst_pad_set_event_function(parser->my_src, event_src);
+ gst_pad_set_element_private(parser->my_src, parser);
+
+ parser->start_offset = parser->next_offset = parser->stop_offset = 0;
+
+ if (!parser->init_gst(parser))
+ return E_FAIL;
+
+ pthread_mutex_lock(&parser->mutex);
+
+ for (i = 0; i < parser->stream_count; ++i)
+ {
+ struct wg_parser_stream *stream = parser->streams[i];
+
+ stream->duration = query_duration(stream->their_src);
+ while (!stream->has_caps && !parser->error)
+ pthread_cond_wait(&parser->init_cond, &parser->mutex);
+ if (parser->error)
+ {
+ pthread_mutex_unlock(&parser->mutex);
+ return E_FAIL;
+ }
+ }
+
+ pthread_mutex_unlock(&parser->mutex);
+
+ parser->next_offset = 0;
+ return S_OK;
+}
+
static BOOL decodebin_parser_init_gst(struct wg_parser *parser)
{
GstElement *element = gst_element_factory_make("decodebin", NULL);
@@ -1034,6 +1404,8 @@ static const struct unix_funcs funcs =
wg_mpeg_audio_parser_create,
wg_wave_parser_create,
wg_parser_destroy,
+
+ wg_parser_connect,
};
NTSTATUS CDECL __wine_init_unix_lib(HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out)
--
2.30.0
More information about the wine-devel
mailing list