Commit 7cee5e55 authored by Ziqing Hui's avatar Ziqing Hui Committed by Alexandre Julliard

winegstreamer: Implement wg_muxer_start.

parent 29a8faf1
...@@ -113,6 +113,7 @@ HRESULT wg_transform_flush(wg_transform_t transform); ...@@ -113,6 +113,7 @@ HRESULT wg_transform_flush(wg_transform_t transform);
HRESULT wg_muxer_create(const char *format, wg_muxer_t *muxer); HRESULT wg_muxer_create(const char *format, wg_muxer_t *muxer);
void wg_muxer_destroy(wg_muxer_t muxer); void wg_muxer_destroy(wg_muxer_t muxer);
HRESULT wg_muxer_add_stream(wg_muxer_t muxer, UINT32 stream_id, const struct wg_format *format); HRESULT wg_muxer_add_stream(wg_muxer_t muxer, UINT32 stream_id, const struct wg_format *format);
HRESULT wg_muxer_start(wg_muxer_t muxer);
unsigned int wg_format_get_bytes_for_uncompressed(wg_video_format format, unsigned int width, unsigned int height); unsigned int wg_format_get_bytes_for_uncompressed(wg_video_format format, unsigned int width, unsigned int height);
unsigned int wg_format_get_max_size(const struct wg_format *format); unsigned int wg_format_get_max_size(const struct wg_format *format);
......
...@@ -508,6 +508,21 @@ HRESULT wg_muxer_add_stream(wg_muxer_t muxer, UINT32 stream_id, const struct wg_ ...@@ -508,6 +508,21 @@ HRESULT wg_muxer_add_stream(wg_muxer_t muxer, UINT32 stream_id, const struct wg_
return S_OK; return S_OK;
} }
HRESULT wg_muxer_start(wg_muxer_t muxer)
{
NTSTATUS status;
TRACE("muxer %#I64x.\n", muxer);
if ((status = WINE_UNIX_CALL(unix_wg_muxer_start, &muxer)))
{
WARN("Failed to start muxer, status %#lx.\n", status);
return HRESULT_FROM_NT(status);
}
return S_OK;
}
#define ALIGN(n, alignment) (((n) + (alignment) - 1) & ~((alignment) - 1)) #define ALIGN(n, alignment) (((n) + (alignment) - 1) & ~((alignment) - 1))
unsigned int wg_format_get_stride(const struct wg_format *format) unsigned int wg_format_get_stride(const struct wg_format *format)
......
...@@ -498,7 +498,13 @@ static HRESULT media_sink_queue_stream_event(struct media_sink *media_sink, Medi ...@@ -498,7 +498,13 @@ static HRESULT media_sink_queue_stream_event(struct media_sink *media_sink, Medi
static HRESULT media_sink_start(struct media_sink *media_sink) static HRESULT media_sink_start(struct media_sink *media_sink)
{ {
HRESULT hr;
if (FAILED(hr = wg_muxer_start(media_sink->muxer)))
return hr;
media_sink->state = STATE_STARTED; media_sink->state = STATE_STARTED;
return media_sink_queue_stream_event(media_sink, MEStreamSinkStarted); return media_sink_queue_stream_event(media_sink, MEStreamSinkStarted);
} }
...@@ -1007,7 +1013,8 @@ static HRESULT WINAPI media_sink_callback_Invoke(IMFAsyncCallback *iface, IMFAsy ...@@ -1007,7 +1013,8 @@ static HRESULT WINAPI media_sink_callback_Invoke(IMFAsyncCallback *iface, IMFAsy
switch (command->op) switch (command->op)
{ {
case ASYNC_START: case ASYNC_START:
hr = media_sink_start(media_sink); if (FAILED(hr = media_sink_start(media_sink)))
WARN("Failed to start media sink.\n");
break; break;
case ASYNC_STOP: case ASYNC_STOP:
hr = media_sink_stop(media_sink); hr = media_sink_stop(media_sink);
......
...@@ -68,6 +68,7 @@ extern NTSTATUS wg_transform_flush(void *args) DECLSPEC_HIDDEN; ...@@ -68,6 +68,7 @@ extern NTSTATUS wg_transform_flush(void *args) DECLSPEC_HIDDEN;
extern NTSTATUS wg_muxer_create(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_muxer_create(void *args) DECLSPEC_HIDDEN;
extern NTSTATUS wg_muxer_destroy(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_muxer_destroy(void *args) DECLSPEC_HIDDEN;
extern NTSTATUS wg_muxer_add_stream(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_muxer_add_stream(void *args) DECLSPEC_HIDDEN;
extern NTSTATUS wg_muxer_start(void *args) DECLSPEC_HIDDEN;
/* wg_allocator.c */ /* wg_allocator.c */
......
...@@ -428,6 +428,7 @@ enum unix_funcs ...@@ -428,6 +428,7 @@ enum unix_funcs
unix_wg_muxer_create, unix_wg_muxer_create,
unix_wg_muxer_destroy, unix_wg_muxer_destroy,
unix_wg_muxer_add_stream, unix_wg_muxer_add_stream,
unix_wg_muxer_start,
unix_wg_funcs_count, unix_wg_funcs_count,
}; };
......
...@@ -18,6 +18,27 @@ ...@@ -18,6 +18,27 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
/*
* wg_muxer will autoplug gstreamer muxer and parser elements.
* It creates a pipeline like this:
*
* ------------------- -------
* [my_src 1] ==> |parser 1 (optional)| ==> | |
* ------------------- | |
* | |
* ------------------- | |
* [my_src 2] ==> |parser 2 (optional)| ==> | |
* ------------------- | |
* | muxer | ==> [my_sink]
* | |
* [ ...... ] | |
* | |
* | |
* ------------------- | |
* [my_src n] ==> |parser n (optional)| ==> | |
* ------------------- -------
*/
#if 0 #if 0
#pragma makedep unix #pragma makedep unix
#endif #endif
...@@ -36,6 +57,8 @@ struct wg_muxer ...@@ -36,6 +57,8 @@ struct wg_muxer
{ {
GstElement *container, *muxer; GstElement *container, *muxer;
GstPad *my_sink; GstPad *my_sink;
GstCaps *my_sink_caps;
struct list streams; struct list streams;
}; };
...@@ -48,6 +71,7 @@ struct wg_muxer_stream ...@@ -48,6 +71,7 @@ struct wg_muxer_stream
GstPad *my_src; GstPad *my_src;
GstCaps *my_src_caps, *parser_src_caps; GstCaps *my_src_caps, *parser_src_caps;
GstElement *parser; GstElement *parser;
GstSegment segment;
struct list entry; struct list entry;
}; };
...@@ -57,6 +81,53 @@ static struct wg_muxer *get_muxer(wg_muxer_t muxer) ...@@ -57,6 +81,53 @@ static struct wg_muxer *get_muxer(wg_muxer_t muxer)
return (struct wg_muxer *)(ULONG_PTR)muxer; return (struct wg_muxer *)(ULONG_PTR)muxer;
} }
static bool muxer_try_muxer_factory(struct wg_muxer *muxer, GstElementFactory *muxer_factory)
{
struct wg_muxer_stream *stream;
GST_INFO("Trying %"GST_PTR_FORMAT".", muxer_factory);
LIST_FOR_EACH_ENTRY(stream, &muxer->streams, struct wg_muxer_stream, entry)
{
GstCaps *caps = stream->parser ? stream->parser_src_caps : stream->my_src_caps;
if (!gst_element_factory_can_sink_any_caps(muxer_factory, caps))
{
GST_INFO("%"GST_PTR_FORMAT" cannot sink stream %u %p, caps %"GST_PTR_FORMAT,
muxer_factory, stream->id, stream, caps);
return false;
}
}
return true;
}
static GstElement *muxer_find_muxer(struct wg_muxer *muxer)
{
/* Some muxers are formatter, eg. id3mux. */
GstElementFactoryListType muxer_type = GST_ELEMENT_FACTORY_TYPE_MUXER | GST_ELEMENT_FACTORY_TYPE_FORMATTER;
GstElement *element = NULL;
GList *muxers, *tmp;
GST_DEBUG("muxer %p.", muxer);
muxers = find_element_factories(muxer_type, GST_RANK_NONE, NULL, muxer->my_sink_caps);
for (tmp = muxers; tmp && !element; tmp = tmp->next)
{
GstElementFactory *factory = GST_ELEMENT_FACTORY(tmp->data);
if (muxer_try_muxer_factory(muxer, factory))
element = factory_create_element(factory);
}
gst_plugin_feature_list_free(muxers);
if (!element)
GST_WARNING("Failed to find any compatible muxer element.");
return element;
}
static gboolean muxer_sink_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) static gboolean muxer_sink_query_cb(GstPad *pad, GstObject *parent, GstQuery *query)
{ {
struct wg_muxer *muxer = gst_pad_get_element_private(pad); struct wg_muxer *muxer = gst_pad_get_element_private(pad);
...@@ -87,10 +158,8 @@ static void stream_free(struct wg_muxer_stream *stream) ...@@ -87,10 +158,8 @@ static void stream_free(struct wg_muxer_stream *stream)
NTSTATUS wg_muxer_create(void *args) NTSTATUS wg_muxer_create(void *args)
{ {
struct wg_muxer_create_params *params = args; struct wg_muxer_create_params *params = args;
GstElement *first = NULL, *last = NULL;
NTSTATUS status = STATUS_UNSUCCESSFUL; NTSTATUS status = STATUS_UNSUCCESSFUL;
GstPadTemplate *template = NULL; GstPadTemplate *template = NULL;
GstCaps *sink_caps = NULL;
struct wg_muxer *muxer; struct wg_muxer *muxer;
/* Create wg_muxer object. */ /* Create wg_muxer object. */
...@@ -101,12 +170,12 @@ NTSTATUS wg_muxer_create(void *args) ...@@ -101,12 +170,12 @@ NTSTATUS wg_muxer_create(void *args)
goto out; goto out;
/* Create sink pad. */ /* Create sink pad. */
if (!(sink_caps = gst_caps_from_string(params->format))) if (!(muxer->my_sink_caps = gst_caps_from_string(params->format)))
{ {
GST_ERROR("Failed to get caps from format string: \"%s\".", params->format); GST_ERROR("Failed to get caps from format string: \"%s\".", params->format);
goto out; goto out;
} }
if (!(template = gst_pad_template_new("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sink_caps))) if (!(template = gst_pad_template_new("sink", GST_PAD_SINK, GST_PAD_ALWAYS, muxer->my_sink_caps)))
goto out; goto out;
muxer->my_sink = gst_pad_new_from_template(template, "wg_muxer_sink"); muxer->my_sink = gst_pad_new_from_template(template, "wg_muxer_sink");
if (!muxer->my_sink) if (!muxer->my_sink)
...@@ -114,26 +183,7 @@ NTSTATUS wg_muxer_create(void *args) ...@@ -114,26 +183,7 @@ NTSTATUS wg_muxer_create(void *args)
gst_pad_set_element_private(muxer->my_sink, muxer); gst_pad_set_element_private(muxer->my_sink, muxer);
gst_pad_set_query_function(muxer->my_sink, muxer_sink_query_cb); gst_pad_set_query_function(muxer->my_sink, muxer_sink_query_cb);
/* Create gstreamer muxer element. */
if (!(muxer->muxer = find_element(GST_ELEMENT_FACTORY_TYPE_MUXER | GST_ELEMENT_FACTORY_TYPE_FORMATTER,
NULL, sink_caps)))
goto out;
if (!append_element(muxer->container, muxer->muxer, &first, &last))
goto out;
/* Link muxer to sink pad. */
if (!link_element_to_sink(muxer->muxer, muxer->my_sink))
goto out;
if (!gst_pad_set_active(muxer->my_sink, 1))
goto out;
/* Set to pause state. */
gst_element_set_state(muxer->container, GST_STATE_PAUSED);
if (!gst_element_get_state(muxer->container, NULL, NULL, -1))
goto out;
gst_object_unref(template); gst_object_unref(template);
gst_caps_unref(sink_caps);
GST_INFO("Created winegstreamer muxer %p.", muxer); GST_INFO("Created winegstreamer muxer %p.", muxer);
params->muxer = (wg_transform_t)(ULONG_PTR)muxer; params->muxer = (wg_transform_t)(ULONG_PTR)muxer;
...@@ -145,13 +195,10 @@ out: ...@@ -145,13 +195,10 @@ out:
gst_object_unref(muxer->my_sink); gst_object_unref(muxer->my_sink);
if (template) if (template)
gst_object_unref(template); gst_object_unref(template);
if (sink_caps) if (muxer->my_sink_caps)
gst_caps_unref(sink_caps); gst_caps_unref(muxer->my_sink_caps);
if (muxer->container) if (muxer->container)
{
gst_element_set_state(muxer->container, GST_STATE_NULL);
gst_object_unref(muxer->container); gst_object_unref(muxer->container);
}
free(muxer); free(muxer);
return status; return status;
...@@ -168,6 +215,7 @@ NTSTATUS wg_muxer_destroy(void *args) ...@@ -168,6 +215,7 @@ NTSTATUS wg_muxer_destroy(void *args)
stream_free(stream); stream_free(stream);
} }
gst_object_unref(muxer->my_sink); gst_object_unref(muxer->my_sink);
gst_caps_unref(muxer->my_sink_caps);
gst_element_set_state(muxer->container, GST_STATE_NULL); gst_element_set_state(muxer->container, GST_STATE_NULL);
gst_object_unref(muxer->container); gst_object_unref(muxer->container);
free(muxer); free(muxer);
...@@ -184,7 +232,7 @@ NTSTATUS wg_muxer_add_stream(void *args) ...@@ -184,7 +232,7 @@ NTSTATUS wg_muxer_add_stream(void *args)
struct wg_muxer_stream *stream; struct wg_muxer_stream *stream;
char src_pad_name[64]; char src_pad_name[64];
GST_DEBUG("muxer %p, stream_id %u, format %p.", muxer, params->stream_id, params->format); GST_DEBUG("muxer %p, stream %u, format %p.", muxer, params->stream_id, params->format);
/* Create stream object. */ /* Create stream object. */
if (!(stream = calloc(1, sizeof(*stream)))) if (!(stream = calloc(1, sizeof(*stream))))
...@@ -241,3 +289,57 @@ out: ...@@ -241,3 +289,57 @@ out:
return status; return status;
} }
NTSTATUS wg_muxer_start(void *args)
{
struct wg_muxer *muxer = get_muxer(*(wg_muxer_t *)args);
NTSTATUS status = STATUS_UNSUCCESSFUL;
struct wg_muxer_stream *stream;
GST_DEBUG("muxer %p.", muxer);
/* Create muxer element. */
if (!(muxer->muxer = muxer_find_muxer(muxer))
|| !gst_bin_add(GST_BIN(muxer->container), muxer->muxer))
return status;
/* Link muxer element to my_sink */
if (!link_element_to_sink(muxer->muxer, muxer->my_sink)
|| !gst_pad_set_active(muxer->my_sink, 1))
return status;
/* Link each stream to muxer element. */
LIST_FOR_EACH_ENTRY(stream, &muxer->streams, struct wg_muxer_stream, entry)
{
bool link_ok = stream->parser ?
gst_element_link(stream->parser, muxer->muxer) :
link_src_to_element(stream->my_src, muxer->muxer);
if (!link_ok)
return status;
}
/* Set to pause state. */
if (gst_element_set_state(muxer->container, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE
|| gst_element_get_state(muxer->container, NULL, NULL, -1) == GST_STATE_CHANGE_FAILURE)
return status;
/* Active stream my_src pad and push events to prepare for streaming. */
LIST_FOR_EACH_ENTRY(stream, &muxer->streams, struct wg_muxer_stream, entry)
{
char buffer[64];
sprintf(buffer, "wg_muxer_stream_src_%u", stream->id);
gst_segment_init(&stream->segment, GST_FORMAT_BYTES);
if (!gst_pad_set_active(stream->my_src, 1))
return status;
if (!push_event(stream->my_src, gst_event_new_stream_start(buffer))
|| !push_event(stream->my_src, gst_event_new_caps(stream->my_src_caps))
|| !push_event(stream->my_src, gst_event_new_segment(&stream->segment)))
return status;
}
GST_DEBUG("Started muxer %p.", muxer);
return STATUS_SUCCESS;
}
...@@ -1922,6 +1922,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = ...@@ -1922,6 +1922,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
X(wg_muxer_create), X(wg_muxer_create),
X(wg_muxer_destroy), X(wg_muxer_destroy),
X(wg_muxer_add_stream), X(wg_muxer_add_stream),
X(wg_muxer_start),
}; };
C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs) == unix_wg_funcs_count); C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs) == unix_wg_funcs_count);
...@@ -2209,6 +2210,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = ...@@ -2209,6 +2210,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
X64(wg_muxer_create), X64(wg_muxer_create),
X(wg_muxer_destroy), X(wg_muxer_destroy),
X64(wg_muxer_add_stream), X64(wg_muxer_add_stream),
X(wg_muxer_start),
}; };
C_ASSERT(ARRAYSIZE(__wine_unix_call_wow64_funcs) == unix_wg_funcs_count); C_ASSERT(ARRAYSIZE(__wine_unix_call_wow64_funcs) == unix_wg_funcs_count);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment