From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/main.c | 13 +++ dlls/winegstreamer/unixlib.h | 7 ++ dlls/winegstreamer/wg_parser.c | 194 +++++++++++++++++++++---------- dlls/winegstreamer/wm_reader.c | 12 ++ 5 files changed, 166 insertions(+), 61 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index d397ab21ca0..ebbbf4e6510 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -100,6 +100,7 @@ char *wg_parser_stream_get_tag(struct wg_parser_stream *stream, enum wg_parser_t /* start_pos and stop_pos are in 100-nanosecond units. */ void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags); +bool wg_parser_stream_set_output_compressed(struct wg_parser_stream *stream, bool compressed);
struct wg_transform *wg_transform_create(const struct wg_format *input_format, const struct wg_format *output_format, const struct wg_transform_attrs *attrs); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 88179feeb56..e93f226ef02 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -317,6 +317,19 @@ char *wg_parser_stream_get_tag(struct wg_parser_stream *stream, enum wg_parser_t return buffer; }
+bool wg_parser_stream_set_output_compressed(struct wg_parser_stream *stream, bool compressed) +{ + struct wg_parser_stream_set_output_compressed_params params = + { + .stream = stream, + .compressed = compressed, + }; + + TRACE("stream %p, compressed %d.\n", stream, compressed); + + return !WINE_UNIX_CALL(unix_wg_parser_stream_set_output_compressed, ¶ms); +} + void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags) { diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index a9892bf9d4f..ee4cbec76c1 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -282,6 +282,12 @@ struct wg_parser_stream_get_duration_params UINT64 duration; };
+struct wg_parser_stream_set_output_compressed_params +{ + struct wg_parser_stream *stream; + bool compressed; +}; + enum wg_parser_tag { WG_PARSER_TAG_LANGUAGE, @@ -376,6 +382,7 @@ enum unix_funcs unix_wg_parser_stream_get_duration, unix_wg_parser_stream_get_tag, unix_wg_parser_stream_seek, + unix_wg_parser_stream_set_output_compressed,
unix_wg_transform_create, unix_wg_transform_destroy, diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index cb2901f484d..2291768db74 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -110,10 +110,10 @@ struct wg_parser_stream struct wg_format preferred_format, current_format, codec_format;
pthread_cond_t event_cond, event_empty_cond; - GstBuffer *buffer; - GstMapInfo map_info; + GstBuffer *buffer, *buffer_compressed; + GstMapInfo map_info, map_info_compressed;
- bool flushing, eos, enabled, has_caps, has_tags, has_buffer, no_more_pads; + bool flushing, eos, enabled, has_caps, has_tags, has_buffer, no_more_pads, output_compressed;
uint64_t duration; gchar *tags[WG_PARSER_TAG_COUNT]; @@ -126,6 +126,73 @@ static bool format_is_compressed(struct wg_format *format) && format->major_type != WG_MAJOR_TYPE_AUDIO; }
+static bool stream_buffer_available(struct wg_parser_stream *stream) +{ + return format_is_compressed(&stream->codec_format) ? + stream->buffer && stream->buffer_compressed : + !!stream->buffer; +} + +static GstFlowReturn stream_set_buffer(struct wg_parser_stream *stream, GstBuffer *buffer, bool compressed) +{ + struct wg_parser *parser = stream->parser; + GstMapInfo *map_info; + + pthread_mutex_lock(&parser->mutex); + + if (!compressed && !stream->has_buffer) + { + stream->has_buffer = true; + pthread_cond_signal(&parser->init_cond); + } + + /* Allow this buffer to be flushed by GStreamer. We are effectively + * implementing a queue object here. */ + + while (stream->enabled && !stream->flushing && (compressed ? stream->buffer_compressed : stream->buffer)) + pthread_cond_wait(&stream->event_empty_cond, &parser->mutex); + + if (!stream->enabled) + { + pthread_mutex_unlock(&parser->mutex); + gst_buffer_unref(buffer); + return GST_FLOW_OK; + } + + if (stream->flushing) + { + pthread_mutex_unlock(&parser->mutex); + GST_DEBUG("Stream is flushing; discarding buffer."); + gst_buffer_unref(buffer); + return GST_FLOW_FLUSHING; + } + + map_info = compressed ? &stream->map_info_compressed : &stream->map_info; + if (!gst_buffer_map(buffer, map_info, GST_MAP_READ)) + { + pthread_mutex_unlock(&parser->mutex); + GST_ERROR("Failed to map buffer.\n"); + gst_buffer_unref(buffer); + return GST_FLOW_ERROR; + } + + if (compressed) + stream->buffer_compressed = buffer; + else + stream->buffer = buffer; + + pthread_mutex_unlock(&parser->mutex); + pthread_cond_signal(&stream->event_cond); + + /* The chain callback is given a reference to the buffer. Transfer that + * reference to the stream object, which will release it in + * wg_parser_stream_release_buffer(). */ + + GST_LOG("Buffer queued."); + + return GST_FLOW_OK; +} + static NTSTATUS wg_parser_get_stream_count(void *args) { struct wg_parser_get_stream_count_params *params = args; @@ -266,15 +333,21 @@ static NTSTATUS wg_parser_stream_disable(void *args)
static GstBuffer *wait_parser_stream_buffer(struct wg_parser *parser, struct wg_parser_stream *stream) { - GstBuffer *buffer = NULL; - /* Note that we can both have a buffer and stream->eos, in which case we * must return the buffer. */
- while (stream->enabled && !(buffer = stream->buffer) && !stream->eos) + while (stream->enabled && !stream_buffer_available(stream) && !stream->eos) pthread_cond_wait(&stream->event_cond, &parser->mutex);
- return buffer; + if (stream->buffer_compressed) + { + if (!GST_BUFFER_PTS_IS_VALID(stream->buffer_compressed) && GST_BUFFER_PTS_IS_VALID(stream->buffer)) + GST_BUFFER_PTS(stream->buffer_compressed) = GST_BUFFER_PTS(stream->buffer); + if (!GST_BUFFER_DURATION_IS_VALID(stream->buffer_compressed) && GST_BUFFER_DURATION_IS_VALID(stream->buffer)) + GST_BUFFER_DURATION(stream->buffer_compressed) = GST_BUFFER_DURATION(stream->buffer); + } + + return stream->output_compressed ? stream->buffer_compressed : stream->buffer; }
static NTSTATUS wg_parser_stream_get_buffer(void *args) @@ -356,18 +429,20 @@ static NTSTATUS wg_parser_stream_copy_buffer(void *args) struct wg_parser *parser = stream->parser; uint32_t offset = params->offset; uint32_t size = params->size; + GstMapInfo *map_info;
pthread_mutex_lock(&parser->mutex);
- if (!stream->buffer) + if (!stream_buffer_available(stream)) { pthread_mutex_unlock(&parser->mutex); return VFW_E_WRONG_STATE; }
- assert(offset < stream->map_info.size); - assert(offset + size <= stream->map_info.size); - memcpy(params->data, stream->map_info.data + offset, size); + map_info = stream->output_compressed ? &stream->map_info_compressed : &stream->map_info; + assert(offset < map_info->size); + assert(offset + size <= map_info->size); + memcpy(params->data, map_info->data + offset, size);
pthread_mutex_unlock(&parser->mutex); return S_OK; @@ -381,11 +456,17 @@ static NTSTATUS wg_parser_stream_release_buffer(void *args) pthread_mutex_lock(&parser->mutex);
assert(stream->buffer); - gst_buffer_unmap(stream->buffer, &stream->map_info); gst_buffer_unref(stream->buffer); stream->buffer = NULL;
+ if (stream->buffer_compressed) + { + gst_buffer_unmap(stream->buffer_compressed, &stream->map_info_compressed); + gst_buffer_unref(stream->buffer_compressed); + stream->buffer_compressed = NULL; + } + pthread_mutex_unlock(&parser->mutex); pthread_cond_signal(&stream->event_empty_cond);
@@ -473,6 +554,19 @@ static NTSTATUS wg_parser_stream_notify_qos(void *args) return S_OK; }
+static NTSTATUS wg_parser_stream_set_output_compressed(void *args) +{ + const struct wg_parser_stream_set_output_compressed_params *params = args; + struct wg_parser_stream *stream = params->stream; + struct wg_parser *parser = stream->parser; + + pthread_mutex_lock(&parser->mutex); + stream->output_compressed = params->compressed; + pthread_mutex_unlock(&parser->mutex); + + return S_OK; +} + static bool parser_no_more_pads(struct wg_parser *parser) { unsigned int i; @@ -586,6 +680,12 @@ static gboolean sink_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) gst_buffer_unref(stream->buffer); stream->buffer = NULL; } + if (stream->buffer_compressed) + { + gst_buffer_unmap(stream->buffer_compressed, &stream->map_info_compressed); + gst_buffer_unref(stream->buffer_compressed); + stream->buffer_compressed = NULL; + } }
pthread_mutex_unlock(&parser->mutex); @@ -640,58 +740,10 @@ static gboolean sink_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) static GstFlowReturn sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *buffer) { struct wg_parser_stream *stream = gst_pad_get_element_private(pad); - struct wg_parser *parser = stream->parser;
GST_LOG("stream %p, buffer %p.", stream, buffer);
- pthread_mutex_lock(&parser->mutex); - - if (!stream->has_buffer) - { - stream->has_buffer = true; - pthread_cond_signal(&parser->init_cond); - } - - /* Allow this buffer to be flushed by GStreamer. We are effectively - * implementing a queue object here. */ - - while (stream->enabled && !stream->flushing && stream->buffer) - pthread_cond_wait(&stream->event_empty_cond, &parser->mutex); - - if (!stream->enabled) - { - pthread_mutex_unlock(&parser->mutex); - gst_buffer_unref(buffer); - return GST_FLOW_OK; - } - - if (stream->flushing) - { - pthread_mutex_unlock(&parser->mutex); - GST_DEBUG("Stream is flushing; discarding buffer."); - gst_buffer_unref(buffer); - return GST_FLOW_FLUSHING; - } - - if (!gst_buffer_map(buffer, &stream->map_info, GST_MAP_READ)) - { - pthread_mutex_unlock(&parser->mutex); - GST_ERROR("Failed to map buffer.\n"); - gst_buffer_unref(buffer); - return GST_FLOW_ERROR; - } - - stream->buffer = buffer; - - pthread_mutex_unlock(&parser->mutex); - pthread_cond_signal(&stream->event_cond); - - /* The chain callback is given a reference to the buffer. Transfer that - * reference to the stream object, which will release it in - * wg_parser_stream_release_buffer(). */ - - GST_LOG("Buffer queued."); - return GST_FLOW_OK; + return stream_set_buffer(stream, buffer, FALSE); }
static gboolean sink_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) @@ -775,6 +827,17 @@ static gboolean sink_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) } }
+static GstPadProbeReturn compressed_data_buffer_cb(GstPad *pad, GstPadProbeInfo *info, gpointer user_data) +{ + GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info); + struct wg_parser_stream *stream = user_data; + + gst_buffer_ref(buffer); + stream_set_buffer(stream, buffer, TRUE); + + return GST_PAD_PROBE_OK; +} + static struct wg_parser_stream *create_stream(struct wg_parser *parser) { struct wg_parser_stream *stream, **new_array; @@ -819,6 +882,12 @@ static void free_stream(struct wg_parser_stream *stream) gst_buffer_unref(stream->buffer); stream->buffer = NULL; } + if (stream->buffer_compressed) + { + gst_buffer_unmap(stream->buffer_compressed, &stream->map_info_compressed); + gst_buffer_unref(stream->buffer_compressed); + stream->buffer_compressed = NULL; + }
pthread_cond_destroy(&stream->event_cond); pthread_cond_destroy(&stream->event_empty_cond); @@ -969,6 +1038,8 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) /* For compressed stream, create an extra decodebin to decode it. */ if (format_is_compressed(&stream->codec_format)) { + gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER, compressed_data_buffer_cb, stream, NULL); + if (!stream_decodebin_create(stream)) { GST_ERROR("Failed to create decodebin for stream %u.", stream->number); @@ -1931,6 +2002,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_parser_stream_get_duration), X(wg_parser_stream_get_tag), X(wg_parser_stream_seek), + X(wg_parser_stream_set_output_compressed),
X(wg_transform_create), X(wg_transform_destroy), diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 02237933905..3d279b96d0b 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -2338,6 +2338,18 @@ static HRESULT WINAPI reader_SetReadStreamSamples(IWMSyncReader2 *iface, WORD st return E_INVALIDARG; }
+ if (stream->read_compressed == compressed) + { + LeaveCriticalSection(&reader->cs); + return S_OK; + } + + if (!wg_parser_stream_set_output_compressed(stream->wg_stream, compressed)) + { + LeaveCriticalSection(&reader->cs); + return E_FAIL; + } + stream->read_compressed = compressed;
LeaveCriticalSection(&reader->cs);