mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-06 09:17:14 +00:00
winegstreamer: Query stream tags and set MF_SD_LANGUAGE attribute.
Loosely based on a patch by Derek Lesho and Rémi Bernon.
This commit is contained in:
parent
2dad3edf7c
commit
3dd56dd606
|
@ -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, ¶ms) != 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, ¶ms))
|
||||
{
|
||||
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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue