Commit 3dd56dd6 authored by Paul Gofman's avatar Paul Gofman Committed by Alexandre Julliard

winegstreamer: Query stream tags and set MF_SD_LANGUAGE attribute.

Loosely based on a patch by Derek Lesho and Rémi Bernon.
parent 2dad3edf
......@@ -33,7 +33,6 @@
#define NONAMELESSUNION
#include "dshow.h"
#include "mfidl.h"
#include "wmsdk.h"
#include "wine/debug.h"
#include "wine/strmbase.h"
......@@ -96,6 +95,7 @@ void wg_parser_stream_notify_qos(struct wg_parser_stream *stream,
/* Returns the duration in 100-nanosecond units. */
uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream);
char *wg_parser_stream_get_tag(struct wg_parser_stream *stream, enum wg_parser_tag tag);
/* 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);
......
......@@ -21,6 +21,9 @@
#define WINE_NO_NAMELESS_EXTENSION
#define EXTERN_GUID DEFINE_GUID
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "initguid.h"
#include "gst_private.h"
#include "winternl.h"
......@@ -273,6 +276,34 @@ uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream)
return params.duration;
}
char *wg_parser_stream_get_tag(struct wg_parser_stream *stream, enum wg_parser_tag tag)
{
uint32_t size = 0;
struct wg_parser_stream_get_tag_params params =
{
.stream = stream,
.tag = tag,
.size = &size,
};
char *buffer;
if (WINE_UNIX_CALL(unix_wg_parser_stream_get_tag, &params) != STATUS_BUFFER_TOO_SMALL)
return NULL;
if (!(buffer = malloc(size)))
{
ERR("No memory.\n");
return NULL;
}
params.buffer = buffer;
if (WINE_UNIX_CALL(unix_wg_parser_stream_get_tag, &params))
{
ERR("wg_parser_stream_get_tag failed unexpectedly.\n");
free(buffer);
return NULL;
}
return buffer;
}
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)
{
......
......@@ -1481,7 +1481,37 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_
descriptors = malloc(object->stream_count * sizeof(IMFStreamDescriptor *));
for (i = 0; i < object->stream_count; i++)
{
static const struct
{
enum wg_parser_tag tag;
const GUID *mf_attr;
}
tags[] =
{
{WG_PARSER_TAG_LANGUAGE, &MF_SD_LANGUAGE},
};
unsigned int j;
WCHAR *strW;
DWORD len;
char *str;
IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, &descriptors[i]);
for (j = 0; j < ARRAY_SIZE(tags); ++j)
{
if (!(str = wg_parser_stream_get_tag(object->streams[i]->wg_stream, tags[j].tag)))
continue;
if (!(len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)))
{
free(str);
continue;
}
strW = malloc(len * sizeof(*strW));
if (MultiByteToWideChar(CP_UTF8, 0, str, -1, strW, len))
IMFStreamDescriptor_SetString(descriptors[i], tags[j].mf_attr, strW);
free(strW);
free(str);
}
}
if (FAILED(hr = MFCreatePresentationDescriptor(object->stream_count, descriptors, &object->pres_desc)))
......
......@@ -252,6 +252,20 @@ struct wg_parser_stream_get_duration_params
UINT64 duration;
};
enum wg_parser_tag
{
WG_PARSER_TAG_LANGUAGE,
WG_PARSER_TAG_COUNT
};
struct wg_parser_stream_get_tag_params
{
struct wg_parser_stream *stream;
enum wg_parser_tag tag;
char *buffer;
UINT32 *size;
};
struct wg_parser_stream_seek_params
{
struct wg_parser_stream *stream;
......@@ -312,6 +326,7 @@ enum unix_funcs
unix_wg_parser_stream_notify_qos,
unix_wg_parser_stream_get_duration,
unix_wg_parser_stream_get_tag,
unix_wg_parser_stream_seek,
unix_wg_transform_create,
......
......@@ -34,6 +34,8 @@
#include <gst/video/video.h>
#include <gst/audio/audio.h>
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "winternl.h"
#include "dshow.h"
......@@ -107,9 +109,10 @@ struct wg_parser_stream
GstBuffer *buffer;
GstMapInfo map_info;
bool flushing, eos, enabled, has_caps;
bool flushing, eos, enabled, has_caps, has_tags, has_buffer;
uint64_t duration;
gchar *tags[WG_PARSER_TAG_COUNT];
};
static NTSTATUS wg_parser_get_stream_count(void *args)
......@@ -397,6 +400,24 @@ static NTSTATUS wg_parser_stream_get_duration(void *args)
return S_OK;
}
static NTSTATUS wg_parser_stream_get_tag(void *args)
{
struct wg_parser_stream_get_tag_params *params = args;
uint32_t len;
if (params->tag >= WG_PARSER_TAG_COUNT)
return STATUS_INVALID_PARAMETER;
if (!params->stream->tags[params->tag])
return STATUS_NOT_FOUND;
if ((len = strlen(params->stream->tags[params->tag]) + 1) > *params->size)
{
*params->size = len;
return STATUS_BUFFER_TOO_SMALL;
}
memcpy(params->buffer, params->stream->tags[params->tag], len);
return STATUS_SUCCESS;
}
static NTSTATUS wg_parser_stream_seek(void *args)
{
GstSeekType start_type = GST_SEEK_TYPE_SET, stop_type = GST_SEEK_TYPE_SET;
......@@ -574,6 +595,13 @@ static gboolean sink_event_cb(GstPad *pad, GstObject *parent, GstEvent *event)
break;
}
case GST_EVENT_TAG:
pthread_mutex_lock(&parser->mutex);
stream->has_tags = true;
pthread_cond_signal(&parser->init_cond);
pthread_mutex_unlock(&parser->mutex);
break;
default:
GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event));
}
......@@ -590,6 +618,12 @@ static GstFlowReturn sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *bu
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. */
......@@ -756,6 +790,8 @@ static struct wg_parser_stream *create_stream(struct wg_parser *parser)
static void free_stream(struct wg_parser_stream *stream)
{
unsigned int i;
if (stream->their_src)
{
if (stream->post_sink)
......@@ -771,6 +807,11 @@ static void free_stream(struct wg_parser_stream *stream)
pthread_cond_destroy(&stream->event_cond);
pthread_cond_destroy(&stream->event_empty_cond);
for (i = 0; i < ARRAY_SIZE(stream->tags); ++i)
{
if (stream->tags[i])
g_free(stream->tags[i]);
}
free(stream);
}
......@@ -1232,6 +1273,19 @@ static gboolean src_event_cb(GstPad *pad, GstObject *parent, GstEvent *event)
return ret;
}
static void query_tags(struct wg_parser_stream *stream)
{
GstTagList *tag_list;
GstEvent *tag_event;
if (!(tag_event = gst_pad_get_sticky_event(stream->their_src, GST_EVENT_TAG, 0)))
return;
gst_event_parse_tag(tag_event, &tag_list);
gst_tag_list_get_string(tag_list, "language-code", &stream->tags[WG_PARSER_TAG_LANGUAGE]);
gst_event_unref(tag_event);
}
static NTSTATUS wg_parser_connect(void *args)
{
GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("quartz_src",
......@@ -1290,7 +1344,8 @@ static NTSTATUS wg_parser_connect(void *args)
struct wg_parser_stream *stream = parser->streams[i];
gint64 duration;
while (!stream->has_caps && !parser->error)
/* If we receieved a buffer waiting for tags or caps does not make sense anymore. */
while ((!stream->has_caps || !stream->has_tags) && !parser->error && !stream->has_buffer)
pthread_cond_wait(&parser->init_cond, &parser->mutex);
/* GStreamer doesn't actually provide any guarantees about when duration
......@@ -1354,6 +1409,8 @@ static NTSTATUS wg_parser_connect(void *args)
}
}
query_tags(stream);
/* Now that we're fully initialized, enable the stream so that further
* samples get queued instead of being discarded. We don't actually need
* the samples (in particular, the frontend should seek before
......@@ -1676,6 +1733,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
X(wg_parser_stream_notify_qos),
X(wg_parser_stream_get_duration),
X(wg_parser_stream_get_tag),
X(wg_parser_stream_seek),
X(wg_transform_create),
......
......@@ -17,6 +17,8 @@
*/
#include "gst_private.h"
#include "initguid.h"
#include "wmsdk.h"
WINE_DEFAULT_DEBUG_CHANNEL(wmvcore);
......
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