[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