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 @@ ...@@ -33,7 +33,6 @@
#define NONAMELESSUNION #define NONAMELESSUNION
#include "dshow.h" #include "dshow.h"
#include "mfidl.h" #include "mfidl.h"
#include "wmsdk.h"
#include "wine/debug.h" #include "wine/debug.h"
#include "wine/strmbase.h" #include "wine/strmbase.h"
...@@ -96,6 +95,7 @@ void wg_parser_stream_notify_qos(struct wg_parser_stream *stream, ...@@ -96,6 +95,7 @@ void wg_parser_stream_notify_qos(struct wg_parser_stream *stream,
/* Returns the duration in 100-nanosecond units. */ /* Returns the duration in 100-nanosecond units. */
uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream); 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. */ /* start_pos and stop_pos are in 100-nanosecond units. */
void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, 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); uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags);
......
...@@ -21,6 +21,9 @@ ...@@ -21,6 +21,9 @@
#define WINE_NO_NAMELESS_EXTENSION #define WINE_NO_NAMELESS_EXTENSION
#define EXTERN_GUID DEFINE_GUID #define EXTERN_GUID DEFINE_GUID
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "initguid.h" #include "initguid.h"
#include "gst_private.h" #include "gst_private.h"
#include "winternl.h" #include "winternl.h"
...@@ -273,6 +276,34 @@ uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream) ...@@ -273,6 +276,34 @@ uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream)
return params.duration; 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, 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) 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_ ...@@ -1481,7 +1481,37 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_
descriptors = malloc(object->stream_count * sizeof(IMFStreamDescriptor *)); descriptors = malloc(object->stream_count * sizeof(IMFStreamDescriptor *));
for (i = 0; i < object->stream_count; i++) 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]); 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))) if (FAILED(hr = MFCreatePresentationDescriptor(object->stream_count, descriptors, &object->pres_desc)))
......
...@@ -252,6 +252,20 @@ struct wg_parser_stream_get_duration_params ...@@ -252,6 +252,20 @@ struct wg_parser_stream_get_duration_params
UINT64 duration; 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_seek_params
{ {
struct wg_parser_stream *stream; struct wg_parser_stream *stream;
...@@ -312,6 +326,7 @@ enum unix_funcs ...@@ -312,6 +326,7 @@ enum unix_funcs
unix_wg_parser_stream_notify_qos, unix_wg_parser_stream_notify_qos,
unix_wg_parser_stream_get_duration, unix_wg_parser_stream_get_duration,
unix_wg_parser_stream_get_tag,
unix_wg_parser_stream_seek, unix_wg_parser_stream_seek,
unix_wg_transform_create, unix_wg_transform_create,
......
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
#include <gst/video/video.h> #include <gst/video/video.h>
#include <gst/audio/audio.h> #include <gst/audio/audio.h>
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "winternl.h" #include "winternl.h"
#include "dshow.h" #include "dshow.h"
...@@ -107,9 +109,10 @@ struct wg_parser_stream ...@@ -107,9 +109,10 @@ struct wg_parser_stream
GstBuffer *buffer; GstBuffer *buffer;
GstMapInfo map_info; GstMapInfo map_info;
bool flushing, eos, enabled, has_caps; bool flushing, eos, enabled, has_caps, has_tags, has_buffer;
uint64_t duration; uint64_t duration;
gchar *tags[WG_PARSER_TAG_COUNT];
}; };
static NTSTATUS wg_parser_get_stream_count(void *args) static NTSTATUS wg_parser_get_stream_count(void *args)
...@@ -397,6 +400,24 @@ static NTSTATUS wg_parser_stream_get_duration(void *args) ...@@ -397,6 +400,24 @@ static NTSTATUS wg_parser_stream_get_duration(void *args)
return S_OK; 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) static NTSTATUS wg_parser_stream_seek(void *args)
{ {
GstSeekType start_type = GST_SEEK_TYPE_SET, stop_type = GST_SEEK_TYPE_SET; 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) ...@@ -574,6 +595,13 @@ static gboolean sink_event_cb(GstPad *pad, GstObject *parent, GstEvent *event)
break; 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: default:
GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event)); 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 ...@@ -590,6 +618,12 @@ static GstFlowReturn sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *bu
pthread_mutex_lock(&parser->mutex); 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 /* Allow this buffer to be flushed by GStreamer. We are effectively
* implementing a queue object here. */ * implementing a queue object here. */
...@@ -756,6 +790,8 @@ static struct wg_parser_stream *create_stream(struct wg_parser *parser) ...@@ -756,6 +790,8 @@ static struct wg_parser_stream *create_stream(struct wg_parser *parser)
static void free_stream(struct wg_parser_stream *stream) static void free_stream(struct wg_parser_stream *stream)
{ {
unsigned int i;
if (stream->their_src) if (stream->their_src)
{ {
if (stream->post_sink) if (stream->post_sink)
...@@ -771,6 +807,11 @@ static void free_stream(struct wg_parser_stream *stream) ...@@ -771,6 +807,11 @@ static void free_stream(struct wg_parser_stream *stream)
pthread_cond_destroy(&stream->event_cond); pthread_cond_destroy(&stream->event_cond);
pthread_cond_destroy(&stream->event_empty_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); free(stream);
} }
...@@ -1232,6 +1273,19 @@ static gboolean src_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) ...@@ -1232,6 +1273,19 @@ static gboolean src_event_cb(GstPad *pad, GstObject *parent, GstEvent *event)
return ret; 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) static NTSTATUS wg_parser_connect(void *args)
{ {
GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("quartz_src", GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("quartz_src",
...@@ -1290,7 +1344,8 @@ static NTSTATUS wg_parser_connect(void *args) ...@@ -1290,7 +1344,8 @@ static NTSTATUS wg_parser_connect(void *args)
struct wg_parser_stream *stream = parser->streams[i]; struct wg_parser_stream *stream = parser->streams[i];
gint64 duration; 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); pthread_cond_wait(&parser->init_cond, &parser->mutex);
/* GStreamer doesn't actually provide any guarantees about when duration /* GStreamer doesn't actually provide any guarantees about when duration
...@@ -1354,6 +1409,8 @@ static NTSTATUS wg_parser_connect(void *args) ...@@ -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 /* Now that we're fully initialized, enable the stream so that further
* samples get queued instead of being discarded. We don't actually need * samples get queued instead of being discarded. We don't actually need
* the samples (in particular, the frontend should seek before * the samples (in particular, the frontend should seek before
...@@ -1676,6 +1733,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = ...@@ -1676,6 +1733,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
X(wg_parser_stream_notify_qos), X(wg_parser_stream_notify_qos),
X(wg_parser_stream_get_duration), X(wg_parser_stream_get_duration),
X(wg_parser_stream_get_tag),
X(wg_parser_stream_seek), X(wg_parser_stream_seek),
X(wg_transform_create), X(wg_transform_create),
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
*/ */
#include "gst_private.h" #include "gst_private.h"
#include "initguid.h"
#include "wmsdk.h"
WINE_DEFAULT_DEBUG_CHANNEL(wmvcore); 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