On PE internal functions.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v3: Remove DECLSPEC_HIDDEN and add a patch first to make it consistent.
Reorder patches and improve error handling, prefer NTSTATUS values for error codes.
dlls/winegstreamer/gst_private.h | 64 ++++++++++++++++---------------- 1 file changed, 32 insertions(+), 32 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 222bce3b2c7..3584f465218 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -39,7 +39,7 @@
#include "unixlib.h"
-bool array_reserve(void **elements, size_t *capacity, size_t count, size_t size) DECLSPEC_HIDDEN; +bool array_reserve(void **elements, size_t *capacity, size_t count, size_t size);
static inline const char *debugstr_time(REFERENCE_TIME time) { @@ -64,60 +64,60 @@ static inline const char *debugstr_time(REFERENCE_TIME time)
#define MEDIATIME_FROM_BYTES(x) ((LONGLONG)(x) * 10000000)
-struct wg_parser *wg_parser_create(enum wg_parser_type type, bool unlimited_buffering) DECLSPEC_HIDDEN; -void wg_parser_destroy(struct wg_parser *parser) DECLSPEC_HIDDEN; +struct wg_parser *wg_parser_create(enum wg_parser_type type, bool unlimited_buffering); +void wg_parser_destroy(struct wg_parser *parser);
-HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size) DECLSPEC_HIDDEN; -void wg_parser_disconnect(struct wg_parser *parser) DECLSPEC_HIDDEN; +HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size); +void wg_parser_disconnect(struct wg_parser *parser);
-void wg_parser_begin_flush(struct wg_parser *parser) DECLSPEC_HIDDEN; -void wg_parser_end_flush(struct wg_parser *parser) DECLSPEC_HIDDEN; +void wg_parser_begin_flush(struct wg_parser *parser); +void wg_parser_end_flush(struct wg_parser *parser);
-bool wg_parser_get_next_read_offset(struct wg_parser *parser, uint64_t *offset, uint32_t *size) DECLSPEC_HIDDEN; -void wg_parser_push_data(struct wg_parser *parser, const void *data, uint32_t size) DECLSPEC_HIDDEN; +bool wg_parser_get_next_read_offset(struct wg_parser *parser, uint64_t *offset, uint32_t *size); +void wg_parser_push_data(struct wg_parser *parser, const void *data, uint32_t size);
-uint32_t wg_parser_get_stream_count(struct wg_parser *parser) DECLSPEC_HIDDEN; -struct wg_parser_stream *wg_parser_get_stream(struct wg_parser *parser, uint32_t index) DECLSPEC_HIDDEN; +uint32_t wg_parser_get_stream_count(struct wg_parser *parser); +struct wg_parser_stream *wg_parser_get_stream(struct wg_parser *parser, uint32_t index);
-void wg_parser_stream_get_preferred_format(struct wg_parser_stream *stream, struct wg_format *format) DECLSPEC_HIDDEN; -void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format) DECLSPEC_HIDDEN; -void wg_parser_stream_disable(struct wg_parser_stream *stream) DECLSPEC_HIDDEN; +void wg_parser_stream_get_preferred_format(struct wg_parser_stream *stream, struct wg_format *format); +void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format); +void wg_parser_stream_disable(struct wg_parser_stream *stream);
-bool wg_parser_stream_get_event(struct wg_parser_stream *stream, struct wg_parser_event *event) DECLSPEC_HIDDEN; +bool wg_parser_stream_get_event(struct wg_parser_stream *stream, struct wg_parser_event *event); bool wg_parser_stream_copy_buffer(struct wg_parser_stream *stream, - void *data, uint32_t offset, uint32_t size) DECLSPEC_HIDDEN; -void wg_parser_stream_release_buffer(struct wg_parser_stream *stream) DECLSPEC_HIDDEN; + void *data, uint32_t offset, uint32_t size); +void wg_parser_stream_release_buffer(struct wg_parser_stream *stream); void wg_parser_stream_notify_qos(struct wg_parser_stream *stream, - bool underflow, double proportion, int64_t diff, uint64_t timestamp) DECLSPEC_HIDDEN; + bool underflow, double proportion, int64_t diff, uint64_t timestamp);
/* Returns the duration in 100-nanosecond units. */ -uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream) DECLSPEC_HIDDEN; +uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream); /* 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) DECLSPEC_HIDDEN; + uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags);
unsigned int wg_format_get_max_size(const struct wg_format *format);
-HRESULT avi_splitter_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN; -HRESULT decodebin_parser_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN; -HRESULT mpeg_splitter_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN; -HRESULT wave_parser_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN; -HRESULT wma_decoder_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN; +HRESULT avi_splitter_create(IUnknown *outer, IUnknown **out); +HRESULT decodebin_parser_create(IUnknown *outer, IUnknown **out); +HRESULT mpeg_splitter_create(IUnknown *outer, IUnknown **out); +HRESULT wave_parser_create(IUnknown *outer, IUnknown **out); +HRESULT wma_decoder_create(IUnknown *outer, IUnknown **out);
bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool wm); bool amt_to_wg_format(const AM_MEDIA_TYPE *mt, struct wg_format *format);
-BOOL init_gstreamer(void) DECLSPEC_HIDDEN; +BOOL init_gstreamer(void);
-extern HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) DECLSPEC_HIDDEN; -extern HRESULT mfplat_DllRegisterServer(void) DECLSPEC_HIDDEN; +extern HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj); +extern HRESULT mfplat_DllRegisterServer(void);
-IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format) DECLSPEC_HIDDEN; -void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) DECLSPEC_HIDDEN; +IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format); +void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format);
-HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HIDDEN; +HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj);
-HRESULT audio_converter_create(REFIID riid, void **ret) DECLSPEC_HIDDEN; +HRESULT audio_converter_create(REFIID riid, void **ret);
struct wm_stream {
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/unix_private.h | 32 +++ dlls/winegstreamer/wg_format.c | 436 ++++++++++++++++++++++++++++++ dlls/winegstreamer/wg_parser.c | 397 +-------------------------- 4 files changed, 471 insertions(+), 395 deletions(-) create mode 100644 dlls/winegstreamer/unix_private.h create mode 100644 dlls/winegstreamer/wg_format.c
diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index c53e914e246..d9805e3d797 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -12,6 +12,7 @@ C_SRCS = \ media_source.c \ mfplat.c \ quartz_parser.c \ + wg_format.c \ wg_parser.c \ wm_asyncreader.c \ wm_reader.c \ diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h new file mode 100644 index 00000000000..b483638403d --- /dev/null +++ b/dlls/winegstreamer/unix_private.h @@ -0,0 +1,32 @@ +/* + * winegstreamer Unix library interface + * + * Copyright 2020-2021 Zebediah Figura for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_WINEGSTREAMER_UNIX_PRIVATE_H +#define __WINE_WINEGSTREAMER_UNIX_PRIVATE_H + +#include "unixlib.h" + +#include <gst/gst.h> + +extern void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) DECLSPEC_HIDDEN; +extern bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) DECLSPEC_HIDDEN; +extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDEN; + +#endif /* __WINE_WINEGSTREAMER_UNIX_PRIVATE_H */ diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c new file mode 100644 index 00000000000..8952acc1c2e --- /dev/null +++ b/dlls/winegstreamer/wg_format.c @@ -0,0 +1,436 @@ +/* + * GStreamer format helpers + * + * Copyright 2010 Maarten Lankhorst for CodeWeavers + * Copyright 2010 Aric Stewart for CodeWeavers + * Copyright 2019-2020 Zebediah Figura + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#include <assert.h> +#include <stdarg.h> +#include <stdio.h> + +#include <gst/gst.h> +#include <gst/video/video.h> +#include <gst/audio/audio.h> + +#include "winternl.h" +#include "dshow.h" + +#include "unix_private.h" + +GST_DEBUG_CATEGORY_EXTERN(wine); +#define GST_CAT_DEFAULT wine + +static enum wg_audio_format wg_audio_format_from_gst(GstAudioFormat format) +{ + switch (format) + { + case GST_AUDIO_FORMAT_U8: + return WG_AUDIO_FORMAT_U8; + case GST_AUDIO_FORMAT_S16LE: + return WG_AUDIO_FORMAT_S16LE; + case GST_AUDIO_FORMAT_S24LE: + return WG_AUDIO_FORMAT_S24LE; + case GST_AUDIO_FORMAT_S32LE: + return WG_AUDIO_FORMAT_S32LE; + case GST_AUDIO_FORMAT_F32LE: + return WG_AUDIO_FORMAT_F32LE; + case GST_AUDIO_FORMAT_F64LE: + return WG_AUDIO_FORMAT_F64LE; + default: + return WG_AUDIO_FORMAT_UNKNOWN; + } +} + +static uint32_t wg_channel_position_from_gst(GstAudioChannelPosition position) +{ + static const uint32_t position_map[] = + { + SPEAKER_FRONT_LEFT, + SPEAKER_FRONT_RIGHT, + SPEAKER_FRONT_CENTER, + SPEAKER_LOW_FREQUENCY, + SPEAKER_BACK_LEFT, + SPEAKER_BACK_RIGHT, + SPEAKER_FRONT_LEFT_OF_CENTER, + SPEAKER_FRONT_RIGHT_OF_CENTER, + SPEAKER_BACK_CENTER, + 0, + SPEAKER_SIDE_LEFT, + SPEAKER_SIDE_RIGHT, + SPEAKER_TOP_FRONT_LEFT, + SPEAKER_TOP_FRONT_RIGHT, + SPEAKER_TOP_FRONT_CENTER, + SPEAKER_TOP_CENTER, + SPEAKER_TOP_BACK_LEFT, + SPEAKER_TOP_BACK_RIGHT, + 0, + 0, + SPEAKER_TOP_BACK_CENTER, + }; + + if (position == GST_AUDIO_CHANNEL_POSITION_MONO) + return SPEAKER_FRONT_CENTER; + + if (position >= 0 && position < ARRAY_SIZE(position_map)) + return position_map[position]; + return 0; +} + +static uint32_t wg_channel_mask_from_gst(const GstAudioInfo *info) +{ + uint32_t mask = 0, position; + unsigned int i; + + for (i = 0; i < GST_AUDIO_INFO_CHANNELS(info); ++i) + { + if (!(position = wg_channel_position_from_gst(GST_AUDIO_INFO_POSITION(info, i)))) + { + GST_WARNING("Unsupported channel %#x.", GST_AUDIO_INFO_POSITION(info, i)); + return 0; + } + /* Make sure it's also in WinMM order. WinMM mandates that channels be + * ordered, as it were, from least to most significant SPEAKER_* bit. + * Hence we fail if the current channel was already specified, or if any + * higher bit was already specified. */ + if (mask & ~(position - 1)) + { + GST_WARNING("Unsupported channel order."); + return 0; + } + mask |= position; + } + return mask; +} + +static void wg_format_from_audio_info(struct wg_format *format, const GstAudioInfo *info) +{ + format->major_type = WG_MAJOR_TYPE_AUDIO; + format->u.audio.format = wg_audio_format_from_gst(GST_AUDIO_INFO_FORMAT(info)); + format->u.audio.channels = GST_AUDIO_INFO_CHANNELS(info); + format->u.audio.channel_mask = wg_channel_mask_from_gst(info); + format->u.audio.rate = GST_AUDIO_INFO_RATE(info); +} + +static enum wg_video_format wg_video_format_from_gst(GstVideoFormat format) +{ + switch (format) + { + case GST_VIDEO_FORMAT_BGRA: + return WG_VIDEO_FORMAT_BGRA; + case GST_VIDEO_FORMAT_BGRx: + return WG_VIDEO_FORMAT_BGRx; + case GST_VIDEO_FORMAT_BGR: + return WG_VIDEO_FORMAT_BGR; + case GST_VIDEO_FORMAT_RGB15: + return WG_VIDEO_FORMAT_RGB15; + case GST_VIDEO_FORMAT_RGB16: + return WG_VIDEO_FORMAT_RGB16; + case GST_VIDEO_FORMAT_AYUV: + return WG_VIDEO_FORMAT_AYUV; + case GST_VIDEO_FORMAT_I420: + return WG_VIDEO_FORMAT_I420; + case GST_VIDEO_FORMAT_NV12: + return WG_VIDEO_FORMAT_NV12; + case GST_VIDEO_FORMAT_UYVY: + return WG_VIDEO_FORMAT_UYVY; + case GST_VIDEO_FORMAT_YUY2: + return WG_VIDEO_FORMAT_YUY2; + case GST_VIDEO_FORMAT_YV12: + return WG_VIDEO_FORMAT_YV12; + case GST_VIDEO_FORMAT_YVYU: + return WG_VIDEO_FORMAT_YVYU; + default: + return WG_VIDEO_FORMAT_UNKNOWN; + } +} + +static void wg_format_from_video_info(struct wg_format *format, const GstVideoInfo *info) +{ + format->major_type = WG_MAJOR_TYPE_VIDEO; + format->u.video.format = wg_video_format_from_gst(GST_VIDEO_INFO_FORMAT(info)); + format->u.video.width = GST_VIDEO_INFO_WIDTH(info); + format->u.video.height = GST_VIDEO_INFO_HEIGHT(info); + format->u.video.fps_n = GST_VIDEO_INFO_FPS_N(info); + format->u.video.fps_d = GST_VIDEO_INFO_FPS_D(info); +} + +static void wg_format_from_caps_audio_mpeg(struct wg_format *format, const GstCaps *caps) +{ + const GstStructure *structure = gst_caps_get_structure(caps, 0); + gint layer, channels, rate; + + if (!gst_structure_get_int(structure, "layer", &layer)) + { + GST_WARNING("Missing "layer" value."); + return; + } + if (!gst_structure_get_int(structure, "channels", &channels)) + { + GST_WARNING("Missing "channels" value."); + return; + } + if (!gst_structure_get_int(structure, "rate", &rate)) + { + GST_WARNING("Missing "rate" value."); + return; + } + + format->major_type = WG_MAJOR_TYPE_AUDIO; + + if (layer == 1) + format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER1; + else if (layer == 2) + format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER2; + else if (layer == 3) + format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER3; + + format->u.audio.channels = channels; + format->u.audio.rate = rate; +} + +static void wg_format_from_caps_video_cinepak(struct wg_format *format, const GstCaps *caps) +{ + const GstStructure *structure = gst_caps_get_structure(caps, 0); + gint width, height, fps_n, fps_d; + + if (!gst_structure_get_int(structure, "width", &width)) + { + GST_WARNING("Missing "width" value."); + return; + } + if (!gst_structure_get_int(structure, "height", &height)) + { + GST_WARNING("Missing "height" value."); + return; + } + if (!gst_structure_get_fraction(structure, "framerate", &fps_n, &fps_d)) + { + fps_n = 0; + fps_d = 1; + } + + format->major_type = WG_MAJOR_TYPE_VIDEO; + format->u.video.format = WG_VIDEO_FORMAT_CINEPAK; + format->u.video.width = width; + format->u.video.height = height; + format->u.video.fps_n = fps_n; + format->u.video.fps_d = fps_d; +} + +void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) +{ + const GstStructure *structure = gst_caps_get_structure(caps, 0); + const char *name = gst_structure_get_name(structure); + + memset(format, 0, sizeof(*format)); + + if (!strcmp(name, "audio/x-raw")) + { + GstAudioInfo info; + + if (gst_audio_info_from_caps(&info, caps)) + wg_format_from_audio_info(format, &info); + } + else if (!strcmp(name, "video/x-raw")) + { + GstVideoInfo info; + + if (gst_video_info_from_caps(&info, caps)) + wg_format_from_video_info(format, &info); + } + else if (!strcmp(name, "audio/mpeg")) + { + wg_format_from_caps_audio_mpeg(format, caps); + } + else if (!strcmp(name, "video/x-cinepak")) + { + wg_format_from_caps_video_cinepak(format, caps); + } + else + { + gchar *str = gst_caps_to_string(caps); + + GST_FIXME("Unhandled caps %s.", str); + g_free(str); + } +} + +static GstAudioFormat wg_audio_format_to_gst(enum wg_audio_format format) +{ + switch (format) + { + case WG_AUDIO_FORMAT_U8: return GST_AUDIO_FORMAT_U8; + case WG_AUDIO_FORMAT_S16LE: return GST_AUDIO_FORMAT_S16LE; + case WG_AUDIO_FORMAT_S24LE: return GST_AUDIO_FORMAT_S24LE; + case WG_AUDIO_FORMAT_S32LE: return GST_AUDIO_FORMAT_S32LE; + case WG_AUDIO_FORMAT_F32LE: return GST_AUDIO_FORMAT_F32LE; + case WG_AUDIO_FORMAT_F64LE: return GST_AUDIO_FORMAT_F64LE; + default: return GST_AUDIO_FORMAT_UNKNOWN; + } +} + +static void wg_channel_mask_to_gst(GstAudioChannelPosition *positions, uint32_t mask, uint32_t channel_count) +{ + const uint32_t orig_mask = mask; + unsigned int i; + DWORD bit; + + static const GstAudioChannelPosition position_map[] = + { + GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, + GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, + GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, + GST_AUDIO_CHANNEL_POSITION_LFE1, + GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, + GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, + GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, + GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, + GST_AUDIO_CHANNEL_POSITION_REAR_CENTER, + GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, + GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT, + GST_AUDIO_CHANNEL_POSITION_TOP_CENTER, + GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT, + GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER, + GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT, + GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT, + GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER, + GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT, + }; + + for (i = 0; i < channel_count; ++i) + { + positions[i] = GST_AUDIO_CHANNEL_POSITION_NONE; + if (BitScanForward(&bit, mask)) + { + if (bit < ARRAY_SIZE(position_map)) + positions[i] = position_map[bit]; + else + GST_WARNING("Invalid channel mask %#x.\n", orig_mask); + mask &= ~(1 << bit); + } + else + { + GST_WARNING("Incomplete channel mask %#x.\n", orig_mask); + } + } +} + +static GstCaps *wg_format_to_caps_audio(const struct wg_format *format) +{ + GstAudioChannelPosition positions[32]; + GstAudioFormat audio_format; + GstAudioInfo info; + + if ((audio_format = wg_audio_format_to_gst(format->u.audio.format)) == GST_AUDIO_FORMAT_UNKNOWN) + return NULL; + + wg_channel_mask_to_gst(positions, format->u.audio.channel_mask, format->u.audio.channels); + gst_audio_info_set_format(&info, audio_format, format->u.audio.rate, format->u.audio.channels, positions); + return gst_audio_info_to_caps(&info); +} + +static GstVideoFormat wg_video_format_to_gst(enum wg_video_format format) +{ + switch (format) + { + case WG_VIDEO_FORMAT_BGRA: return GST_VIDEO_FORMAT_BGRA; + case WG_VIDEO_FORMAT_BGRx: return GST_VIDEO_FORMAT_BGRx; + case WG_VIDEO_FORMAT_BGR: return GST_VIDEO_FORMAT_BGR; + case WG_VIDEO_FORMAT_RGB15: return GST_VIDEO_FORMAT_RGB15; + case WG_VIDEO_FORMAT_RGB16: return GST_VIDEO_FORMAT_RGB16; + case WG_VIDEO_FORMAT_AYUV: return GST_VIDEO_FORMAT_AYUV; + case WG_VIDEO_FORMAT_I420: return GST_VIDEO_FORMAT_I420; + case WG_VIDEO_FORMAT_NV12: return GST_VIDEO_FORMAT_NV12; + case WG_VIDEO_FORMAT_UYVY: return GST_VIDEO_FORMAT_UYVY; + case WG_VIDEO_FORMAT_YUY2: return GST_VIDEO_FORMAT_YUY2; + case WG_VIDEO_FORMAT_YV12: return GST_VIDEO_FORMAT_YV12; + case WG_VIDEO_FORMAT_YVYU: return GST_VIDEO_FORMAT_YVYU; + default: return GST_VIDEO_FORMAT_UNKNOWN; + } +} + +static GstCaps *wg_format_to_caps_video(const struct wg_format *format) +{ + GstVideoFormat video_format; + GstVideoInfo info; + unsigned int i; + GstCaps *caps; + + if ((video_format = wg_video_format_to_gst(format->u.video.format)) == GST_VIDEO_FORMAT_UNKNOWN) + return NULL; + + gst_video_info_set_format(&info, video_format, format->u.video.width, abs(format->u.video.height)); + if ((caps = gst_video_info_to_caps(&info))) + { + /* Clear some fields that shouldn't prevent us from connecting. */ + for (i = 0; i < gst_caps_get_size(caps); ++i) + { + gst_structure_remove_fields(gst_caps_get_structure(caps, i), + "framerate", "pixel-aspect-ratio", "colorimetry", "chroma-site", NULL); + } + } + return caps; +} + +GstCaps *wg_format_to_caps(const struct wg_format *format) +{ + switch (format->major_type) + { + case WG_MAJOR_TYPE_UNKNOWN: + return NULL; + case WG_MAJOR_TYPE_AUDIO: + return wg_format_to_caps_audio(format); + case WG_MAJOR_TYPE_VIDEO: + return wg_format_to_caps_video(format); + } + assert(0); + return NULL; +} + +bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) +{ + if (a->major_type != b->major_type) + return false; + + switch (a->major_type) + { + case WG_MAJOR_TYPE_UNKNOWN: + return false; + + case WG_MAJOR_TYPE_AUDIO: + return a->u.audio.format == b->u.audio.format + && a->u.audio.channels == b->u.audio.channels + && a->u.audio.rate == b->u.audio.rate; + + case WG_MAJOR_TYPE_VIDEO: + /* Do not compare FPS. */ + return a->u.video.format == b->u.video.format + && a->u.video.width == b->u.video.width + && abs(a->u.video.height) == abs(b->u.video.height); + } + + assert(0); + return false; +} diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 013566b25e9..a73685a2e69 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -37,7 +37,7 @@ #include "winternl.h" #include "dshow.h"
-#include "unixlib.h" +#include "unix_private.h"
typedef enum { @@ -51,7 +51,7 @@ typedef enum * debug logging instead of Wine debug logging. In order to be safe we forbid * any use of Wine debug logging in this entire file. */
-GST_DEBUG_CATEGORY_STATIC(wine); +GST_DEBUG_CATEGORY(wine); #define GST_CAT_DEFAULT wine
typedef BOOL (*init_gst_cb)(struct wg_parser *parser); @@ -111,399 +111,6 @@ struct wg_parser_stream uint64_t duration; };
-static enum wg_audio_format wg_audio_format_from_gst(GstAudioFormat format) -{ - switch (format) - { - case GST_AUDIO_FORMAT_U8: - return WG_AUDIO_FORMAT_U8; - case GST_AUDIO_FORMAT_S16LE: - return WG_AUDIO_FORMAT_S16LE; - case GST_AUDIO_FORMAT_S24LE: - return WG_AUDIO_FORMAT_S24LE; - case GST_AUDIO_FORMAT_S32LE: - return WG_AUDIO_FORMAT_S32LE; - case GST_AUDIO_FORMAT_F32LE: - return WG_AUDIO_FORMAT_F32LE; - case GST_AUDIO_FORMAT_F64LE: - return WG_AUDIO_FORMAT_F64LE; - default: - return WG_AUDIO_FORMAT_UNKNOWN; - } -} - -static uint32_t wg_channel_position_from_gst(GstAudioChannelPosition position) -{ - static const uint32_t position_map[] = - { - SPEAKER_FRONT_LEFT, - SPEAKER_FRONT_RIGHT, - SPEAKER_FRONT_CENTER, - SPEAKER_LOW_FREQUENCY, - SPEAKER_BACK_LEFT, - SPEAKER_BACK_RIGHT, - SPEAKER_FRONT_LEFT_OF_CENTER, - SPEAKER_FRONT_RIGHT_OF_CENTER, - SPEAKER_BACK_CENTER, - 0, - SPEAKER_SIDE_LEFT, - SPEAKER_SIDE_RIGHT, - SPEAKER_TOP_FRONT_LEFT, - SPEAKER_TOP_FRONT_RIGHT, - SPEAKER_TOP_FRONT_CENTER, - SPEAKER_TOP_CENTER, - SPEAKER_TOP_BACK_LEFT, - SPEAKER_TOP_BACK_RIGHT, - 0, - 0, - SPEAKER_TOP_BACK_CENTER, - }; - - if (position == GST_AUDIO_CHANNEL_POSITION_MONO) - return SPEAKER_FRONT_CENTER; - - if (position >= 0 && position < ARRAY_SIZE(position_map)) - return position_map[position]; - return 0; -} - -static uint32_t wg_channel_mask_from_gst(const GstAudioInfo *info) -{ - uint32_t mask = 0, position; - unsigned int i; - - for (i = 0; i < GST_AUDIO_INFO_CHANNELS(info); ++i) - { - if (!(position = wg_channel_position_from_gst(GST_AUDIO_INFO_POSITION(info, i)))) - { - GST_WARNING("Unsupported channel %#x.", GST_AUDIO_INFO_POSITION(info, i)); - return 0; - } - /* Make sure it's also in WinMM order. WinMM mandates that channels be - * ordered, as it were, from least to most significant SPEAKER_* bit. - * Hence we fail if the current channel was already specified, or if any - * higher bit was already specified. */ - if (mask & ~(position - 1)) - { - GST_WARNING("Unsupported channel order."); - return 0; - } - mask |= position; - } - return mask; -} - -static void wg_format_from_audio_info(struct wg_format *format, const GstAudioInfo *info) -{ - format->major_type = WG_MAJOR_TYPE_AUDIO; - format->u.audio.format = wg_audio_format_from_gst(GST_AUDIO_INFO_FORMAT(info)); - format->u.audio.channels = GST_AUDIO_INFO_CHANNELS(info); - format->u.audio.channel_mask = wg_channel_mask_from_gst(info); - format->u.audio.rate = GST_AUDIO_INFO_RATE(info); -} - -static enum wg_video_format wg_video_format_from_gst(GstVideoFormat format) -{ - switch (format) - { - case GST_VIDEO_FORMAT_BGRA: - return WG_VIDEO_FORMAT_BGRA; - case GST_VIDEO_FORMAT_BGRx: - return WG_VIDEO_FORMAT_BGRx; - case GST_VIDEO_FORMAT_BGR: - return WG_VIDEO_FORMAT_BGR; - case GST_VIDEO_FORMAT_RGB15: - return WG_VIDEO_FORMAT_RGB15; - case GST_VIDEO_FORMAT_RGB16: - return WG_VIDEO_FORMAT_RGB16; - case GST_VIDEO_FORMAT_AYUV: - return WG_VIDEO_FORMAT_AYUV; - case GST_VIDEO_FORMAT_I420: - return WG_VIDEO_FORMAT_I420; - case GST_VIDEO_FORMAT_NV12: - return WG_VIDEO_FORMAT_NV12; - case GST_VIDEO_FORMAT_UYVY: - return WG_VIDEO_FORMAT_UYVY; - case GST_VIDEO_FORMAT_YUY2: - return WG_VIDEO_FORMAT_YUY2; - case GST_VIDEO_FORMAT_YV12: - return WG_VIDEO_FORMAT_YV12; - case GST_VIDEO_FORMAT_YVYU: - return WG_VIDEO_FORMAT_YVYU; - default: - return WG_VIDEO_FORMAT_UNKNOWN; - } -} - -static void wg_format_from_video_info(struct wg_format *format, const GstVideoInfo *info) -{ - format->major_type = WG_MAJOR_TYPE_VIDEO; - format->u.video.format = wg_video_format_from_gst(GST_VIDEO_INFO_FORMAT(info)); - format->u.video.width = GST_VIDEO_INFO_WIDTH(info); - format->u.video.height = GST_VIDEO_INFO_HEIGHT(info); - format->u.video.fps_n = GST_VIDEO_INFO_FPS_N(info); - format->u.video.fps_d = GST_VIDEO_INFO_FPS_D(info); -} - -static void wg_format_from_caps_audio_mpeg(struct wg_format *format, const GstCaps *caps) -{ - const GstStructure *structure = gst_caps_get_structure(caps, 0); - gint layer, channels, rate; - - if (!gst_structure_get_int(structure, "layer", &layer)) - { - GST_WARNING("Missing "layer" value."); - return; - } - if (!gst_structure_get_int(structure, "channels", &channels)) - { - GST_WARNING("Missing "channels" value."); - return; - } - if (!gst_structure_get_int(structure, "rate", &rate)) - { - GST_WARNING("Missing "rate" value."); - return; - } - - format->major_type = WG_MAJOR_TYPE_AUDIO; - - if (layer == 1) - format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER1; - else if (layer == 2) - format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER2; - else if (layer == 3) - format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER3; - - format->u.audio.channels = channels; - format->u.audio.rate = rate; -} - -static void wg_format_from_caps_video_cinepak(struct wg_format *format, const GstCaps *caps) -{ - const GstStructure *structure = gst_caps_get_structure(caps, 0); - gint width, height, fps_n, fps_d; - - if (!gst_structure_get_int(structure, "width", &width)) - { - GST_WARNING("Missing "width" value."); - return; - } - if (!gst_structure_get_int(structure, "height", &height)) - { - GST_WARNING("Missing "height" value."); - return; - } - if (!gst_structure_get_fraction(structure, "framerate", &fps_n, &fps_d)) - { - fps_n = 0; - fps_d = 1; - } - - format->major_type = WG_MAJOR_TYPE_VIDEO; - format->u.video.format = WG_VIDEO_FORMAT_CINEPAK; - format->u.video.width = width; - format->u.video.height = height; - format->u.video.fps_n = fps_n; - format->u.video.fps_d = fps_d; -} - -static void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) -{ - const GstStructure *structure = gst_caps_get_structure(caps, 0); - const char *name = gst_structure_get_name(structure); - - memset(format, 0, sizeof(*format)); - - if (!strcmp(name, "audio/x-raw")) - { - GstAudioInfo info; - - if (gst_audio_info_from_caps(&info, caps)) - wg_format_from_audio_info(format, &info); - } - else if (!strcmp(name, "video/x-raw")) - { - GstVideoInfo info; - - if (gst_video_info_from_caps(&info, caps)) - wg_format_from_video_info(format, &info); - } - else if (!strcmp(name, "audio/mpeg")) - { - wg_format_from_caps_audio_mpeg(format, caps); - } - else if (!strcmp(name, "video/x-cinepak")) - { - wg_format_from_caps_video_cinepak(format, caps); - } - else - { - gchar *str = gst_caps_to_string(caps); - - GST_FIXME("Unhandled caps %s.", str); - g_free(str); - } -} - -static GstAudioFormat wg_audio_format_to_gst(enum wg_audio_format format) -{ - switch (format) - { - case WG_AUDIO_FORMAT_U8: return GST_AUDIO_FORMAT_U8; - case WG_AUDIO_FORMAT_S16LE: return GST_AUDIO_FORMAT_S16LE; - case WG_AUDIO_FORMAT_S24LE: return GST_AUDIO_FORMAT_S24LE; - case WG_AUDIO_FORMAT_S32LE: return GST_AUDIO_FORMAT_S32LE; - case WG_AUDIO_FORMAT_F32LE: return GST_AUDIO_FORMAT_F32LE; - case WG_AUDIO_FORMAT_F64LE: return GST_AUDIO_FORMAT_F64LE; - default: return GST_AUDIO_FORMAT_UNKNOWN; - } -} - -static void wg_channel_mask_to_gst(GstAudioChannelPosition *positions, uint32_t mask, uint32_t channel_count) -{ - const uint32_t orig_mask = mask; - unsigned int i; - DWORD bit; - - static const GstAudioChannelPosition position_map[] = - { - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, - GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, - GST_AUDIO_CHANNEL_POSITION_LFE1, - GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, - GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, - GST_AUDIO_CHANNEL_POSITION_REAR_CENTER, - GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, - GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT, - GST_AUDIO_CHANNEL_POSITION_TOP_CENTER, - GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER, - GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT, - GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT, - GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER, - GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT, - }; - - for (i = 0; i < channel_count; ++i) - { - positions[i] = GST_AUDIO_CHANNEL_POSITION_NONE; - if (BitScanForward(&bit, mask)) - { - if (bit < ARRAY_SIZE(position_map)) - positions[i] = position_map[bit]; - else - GST_WARNING("Invalid channel mask %#x.\n", orig_mask); - mask &= ~(1 << bit); - } - else - { - GST_WARNING("Incomplete channel mask %#x.\n", orig_mask); - } - } -} - -static GstCaps *wg_format_to_caps_audio(const struct wg_format *format) -{ - GstAudioChannelPosition positions[32]; - GstAudioFormat audio_format; - GstAudioInfo info; - - if ((audio_format = wg_audio_format_to_gst(format->u.audio.format)) == GST_AUDIO_FORMAT_UNKNOWN) - return NULL; - - wg_channel_mask_to_gst(positions, format->u.audio.channel_mask, format->u.audio.channels); - gst_audio_info_set_format(&info, audio_format, format->u.audio.rate, format->u.audio.channels, positions); - return gst_audio_info_to_caps(&info); -} - -static GstVideoFormat wg_video_format_to_gst(enum wg_video_format format) -{ - switch (format) - { - case WG_VIDEO_FORMAT_BGRA: return GST_VIDEO_FORMAT_BGRA; - case WG_VIDEO_FORMAT_BGRx: return GST_VIDEO_FORMAT_BGRx; - case WG_VIDEO_FORMAT_BGR: return GST_VIDEO_FORMAT_BGR; - case WG_VIDEO_FORMAT_RGB15: return GST_VIDEO_FORMAT_RGB15; - case WG_VIDEO_FORMAT_RGB16: return GST_VIDEO_FORMAT_RGB16; - case WG_VIDEO_FORMAT_AYUV: return GST_VIDEO_FORMAT_AYUV; - case WG_VIDEO_FORMAT_I420: return GST_VIDEO_FORMAT_I420; - case WG_VIDEO_FORMAT_NV12: return GST_VIDEO_FORMAT_NV12; - case WG_VIDEO_FORMAT_UYVY: return GST_VIDEO_FORMAT_UYVY; - case WG_VIDEO_FORMAT_YUY2: return GST_VIDEO_FORMAT_YUY2; - case WG_VIDEO_FORMAT_YV12: return GST_VIDEO_FORMAT_YV12; - case WG_VIDEO_FORMAT_YVYU: return GST_VIDEO_FORMAT_YVYU; - default: return GST_VIDEO_FORMAT_UNKNOWN; - } -} - -static GstCaps *wg_format_to_caps_video(const struct wg_format *format) -{ - GstVideoFormat video_format; - GstVideoInfo info; - unsigned int i; - GstCaps *caps; - - if ((video_format = wg_video_format_to_gst(format->u.video.format)) == GST_VIDEO_FORMAT_UNKNOWN) - return NULL; - - gst_video_info_set_format(&info, video_format, format->u.video.width, abs(format->u.video.height)); - if ((caps = gst_video_info_to_caps(&info))) - { - /* Clear some fields that shouldn't prevent us from connecting. */ - for (i = 0; i < gst_caps_get_size(caps); ++i) - { - gst_structure_remove_fields(gst_caps_get_structure(caps, i), - "framerate", "pixel-aspect-ratio", "colorimetry", "chroma-site", NULL); - } - } - return caps; -} - -static GstCaps *wg_format_to_caps(const struct wg_format *format) -{ - switch (format->major_type) - { - case WG_MAJOR_TYPE_UNKNOWN: - return NULL; - case WG_MAJOR_TYPE_AUDIO: - return wg_format_to_caps_audio(format); - case WG_MAJOR_TYPE_VIDEO: - return wg_format_to_caps_video(format); - } - assert(0); - return NULL; -} - -static bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) -{ - if (a->major_type != b->major_type) - return false; - - switch (a->major_type) - { - case WG_MAJOR_TYPE_UNKNOWN: - return false; - - case WG_MAJOR_TYPE_AUDIO: - return a->u.audio.format == b->u.audio.format - && a->u.audio.channels == b->u.audio.channels - && a->u.audio.rate == b->u.audio.rate; - - case WG_MAJOR_TYPE_VIDEO: - /* Do not compare FPS. */ - return a->u.video.format == b->u.video.format - && a->u.video.width == b->u.video.width - && abs(a->u.video.height) == abs(b->u.video.height); - } - - assert(0); - return false; -} - static NTSTATUS wg_parser_get_stream_count(void *args) { struct wg_parser_get_stream_count_params *params = args;
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winegstreamer/mfplat.c | 109 +++++++++++++++++++++++------ dlls/winegstreamer/quartz_parser.c | 8 +++ dlls/winegstreamer/unixlib.h | 12 ++++ dlls/winegstreamer/wg_format.c | 7 ++ dlls/winegstreamer/wm_reader.c | 8 +++ dlls/winegstreamer/wma_decoder.c | 18 +++++ 6 files changed, 141 insertions(+), 21 deletions(-)
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index a111bbe196d..9b3fc429d32 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -635,6 +635,10 @@ IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format) case WG_MAJOR_TYPE_UNKNOWN: return NULL;
+ case WG_MAJOR_TYPE_WMA: + FIXME("WMA format not implemented!\n"); + return NULL; + case WG_MAJOR_TYPE_AUDIO: return mf_media_type_from_wg_format_audio(format);
@@ -646,17 +650,11 @@ IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format) return NULL; }
-static void mf_media_type_to_wg_format_audio(IMFMediaType *type, struct wg_format *format) +static void mf_media_type_to_wg_format_audio(IMFMediaType *type, const GUID *subtype, struct wg_format *format) { UINT32 rate, channels, channel_mask, depth; unsigned int i; - GUID subtype;
- if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) - { - FIXME("Subtype is not set.\n"); - return; - } if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate))) { FIXME("Sample rate is not set.\n"); @@ -692,26 +690,20 @@ static void mf_media_type_to_wg_format_audio(IMFMediaType *type, struct wg_forma
for (i = 0; i < ARRAY_SIZE(audio_formats); ++i) { - if (IsEqualGUID(&subtype, audio_formats[i].subtype) && depth == audio_formats[i].depth) + if (IsEqualGUID(subtype, audio_formats[i].subtype) && depth == audio_formats[i].depth) { format->u.audio.format = audio_formats[i].format; return; } } - FIXME("Unrecognized audio subtype %s, depth %u.\n", debugstr_guid(&subtype), depth); + FIXME("Unrecognized audio subtype %s, depth %u.\n", debugstr_guid(subtype), depth); }
-static void mf_media_type_to_wg_format_video(IMFMediaType *type, struct wg_format *format) +static void mf_media_type_to_wg_format_video(IMFMediaType *type, const GUID *subtype, struct wg_format *format) { UINT64 frame_rate, frame_size; unsigned int i; - GUID subtype;
- if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) - { - FIXME("Subtype is not set.\n"); - return; - } if (FAILED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) { FIXME("Frame size is not set.\n"); @@ -732,18 +724,80 @@ static void mf_media_type_to_wg_format_video(IMFMediaType *type, struct wg_forma
for (i = 0; i < ARRAY_SIZE(video_formats); ++i) { - if (IsEqualGUID(&subtype, video_formats[i].subtype)) + if (IsEqualGUID(subtype, video_formats[i].subtype)) { format->u.video.format = video_formats[i].format; return; } } - FIXME("Unrecognized video subtype %s.\n", debugstr_guid(&subtype)); + FIXME("Unrecognized video subtype %s.\n", debugstr_guid(subtype)); +} + +static void mf_media_type_to_wg_format_wma(IMFMediaType *type, const GUID *subtype, struct wg_format *format) +{ + UINT32 rate, depth, channels, block_align, bytes_per_second, codec_data_len; + BYTE codec_data[64]; + UINT32 version; + + if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate))) + { + FIXME("Sample rate is not set.\n"); + return; + } + if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &channels))) + { + FIXME("Channel count is not set.\n"); + return; + } + if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_align))) + { + FIXME("Block alignment is not set.\n"); + return; + } + if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &depth))) + { + FIXME("Depth is not set.\n"); + return; + } + if (FAILED(IMFMediaType_GetBlob(type, &MF_MT_USER_DATA, codec_data, sizeof(codec_data), &codec_data_len))) + { + FIXME("Codec data is not set.\n"); + return; + } + if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &bytes_per_second))) + { + FIXME("Bitrate is not set.\n"); + bytes_per_second = 0; + } + + if (IsEqualGUID(subtype, &MEDIASUBTYPE_MSAUDIO1)) + version = 1; + else if (IsEqualGUID(subtype, &MFAudioFormat_WMAudioV8)) + version = 2; + else if (IsEqualGUID(subtype, &MFAudioFormat_WMAudioV9)) + version = 3; + else if (IsEqualGUID(subtype, &MFAudioFormat_WMAudio_Lossless)) + version = 4; + else + { + assert(0); + return; + } + + format->major_type = WG_MAJOR_TYPE_WMA; + format->u.wma.version = version; + format->u.wma.bitrate = bytes_per_second * 8; + format->u.wma.rate = rate; + format->u.wma.depth = depth; + format->u.wma.channels = channels; + format->u.wma.block_align = block_align; + format->u.wma.codec_data_len = codec_data_len; + memcpy(format->u.wma.codec_data, codec_data, codec_data_len); }
void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) { - GUID major_type; + GUID major_type, subtype;
memset(format, 0, sizeof(*format));
@@ -752,11 +806,24 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) FIXME("Major type is not set.\n"); return; } + if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) + { + FIXME("Subtype is not set.\n"); + return; + }
if (IsEqualGUID(&major_type, &MFMediaType_Audio)) - mf_media_type_to_wg_format_audio(type, format); + { + if (IsEqualGUID(&subtype, &MEDIASUBTYPE_MSAUDIO1) || + IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV8) || + IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV9) || + IsEqualGUID(&subtype, &MFAudioFormat_WMAudio_Lossless)) + mf_media_type_to_wg_format_wma(type, &subtype, format); + else + mf_media_type_to_wg_format_audio(type, &subtype, format); + } else if (IsEqualGUID(&major_type, &MFMediaType_Video)) - mf_media_type_to_wg_format_video(type, format); + mf_media_type_to_wg_format_video(type, &subtype, format); else FIXME("Unrecognized major type %s.\n", debugstr_guid(&major_type)); } diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 45313ebda27..e06c55ccfe0 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -319,6 +319,10 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) break; }
+ case WG_MAJOR_TYPE_WMA: + FIXME("WMA format not implemented!\n"); + return 0; + case WG_MAJOR_TYPE_UNKNOWN: FIXME("Cannot guess maximum sample size for unknown format.\n"); return 0; @@ -413,6 +417,10 @@ bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool case WG_MAJOR_TYPE_UNKNOWN: return false;
+ case WG_MAJOR_TYPE_WMA: + FIXME("WMA format not implemented!\n"); + return false; + case WG_MAJOR_TYPE_AUDIO: return amt_from_wg_format_audio(mt, format);
diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 82bb534b938..45ec606fc6a 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -37,6 +37,7 @@ struct wg_format WG_MAJOR_TYPE_UNKNOWN, WG_MAJOR_TYPE_VIDEO, WG_MAJOR_TYPE_AUDIO, + WG_MAJOR_TYPE_WMA, } major_type;
union @@ -88,6 +89,17 @@ struct wg_format uint32_t channel_mask; /* In WinMM format. */ uint32_t rate; } audio; + struct + { + uint32_t version; + uint32_t bitrate; + uint32_t rate; + uint32_t depth; + uint32_t channels; + uint32_t block_align; + uint32_t codec_data_len; + unsigned char codec_data[64]; + } wma; } u; };
diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 8952acc1c2e..8f771bb8abd 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -400,6 +400,9 @@ GstCaps *wg_format_to_caps(const struct wg_format *format) { case WG_MAJOR_TYPE_UNKNOWN: return NULL; + case WG_MAJOR_TYPE_WMA: + GST_FIXME("WMA format not implemented!\n"); + return NULL; case WG_MAJOR_TYPE_AUDIO: return wg_format_to_caps_audio(format); case WG_MAJOR_TYPE_VIDEO: @@ -419,6 +422,10 @@ bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) case WG_MAJOR_TYPE_UNKNOWN: return false;
+ case WG_MAJOR_TYPE_WMA: + GST_FIXME("WMA format not implemented!\n"); + return false; + case WG_MAJOR_TYPE_AUDIO: return a->u.audio.format == b->u.audio.format && a->u.audio.channels == b->u.audio.channels diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index d40afb66afd..01518c6b9a8 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1687,6 +1687,9 @@ HRESULT wm_reader_get_output_format_count(struct wm_reader *reader, DWORD output *count = ARRAY_SIZE(video_formats); break;
+ case WG_MAJOR_TYPE_WMA: + FIXME("WMA format not implemented!\n"); + /* fallthrough */ case WG_MAJOR_TYPE_AUDIO: case WG_MAJOR_TYPE_UNKNOWN: *count = 1; @@ -1733,6 +1736,9 @@ HRESULT wm_reader_get_output_format(struct wm_reader *reader, DWORD output, format.u.audio.format = WG_AUDIO_FORMAT_S16LE; break;
+ case WG_MAJOR_TYPE_WMA: + FIXME("WMA format not implemented!\n"); + break; case WG_MAJOR_TYPE_UNKNOWN: break; } @@ -1808,6 +1814,8 @@ static const char *get_major_type_string(enum wg_major_type type) return "video"; case WG_MAJOR_TYPE_UNKNOWN: return "unknown"; + case WG_MAJOR_TYPE_WMA: + return "wma"; } assert(0); return NULL; diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index 78316059052..31f735a5b1d 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -60,6 +60,21 @@ static inline struct wma_decoder *impl_from_IUnknown(IUnknown *iface) return CONTAINING_RECORD(iface, struct wma_decoder, IUnknown_inner); }
+static HRESULT try_create_wg_transform(struct wma_decoder *decoder) +{ + struct wg_format input_format, output_format; + + mf_media_type_to_wg_format(decoder->input_type, &input_format); + if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + return MF_E_INVALIDMEDIATYPE; + + mf_media_type_to_wg_format(decoder->output_type, &output_format); + if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + return MF_E_INVALIDMEDIATYPE; + + return S_OK; +} + static HRESULT WINAPI unknown_QueryInterface(IUnknown *iface, REFIID iid, void **out) { struct wma_decoder *decoder = impl_from_IUnknown(iface); @@ -438,6 +453,9 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)decoder->output_type))) goto failed;
+ if (FAILED(hr = try_create_wg_transform(decoder))) + goto failed; + return S_OK;
failed:
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/gst_private.h | 3 ++ dlls/winegstreamer/main.c | 14 +++++ dlls/winegstreamer/unix_private.h | 5 ++ dlls/winegstreamer/unixlib.h | 8 +++ dlls/winegstreamer/wg_parser.c | 13 ++++- dlls/winegstreamer/wg_transform.c | 88 +++++++++++++++++++++++++++++++ dlls/winegstreamer/wma_decoder.c | 11 ++++ 8 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 dlls/winegstreamer/wg_transform.c
diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index d9805e3d797..0bcdb3eec65 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -14,6 +14,7 @@ C_SRCS = \ quartz_parser.c \ wg_format.c \ wg_parser.c \ + wg_transform.c \ wm_asyncreader.c \ wm_reader.c \ wm_syncreader.c \ diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 3584f465218..8bc9f838d29 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -96,6 +96,9 @@ uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream); 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);
+struct wg_transform *wg_transform_create(void); +void wg_transform_destroy(struct wg_transform *transform); + unsigned int wg_format_get_max_size(const struct wg_format *format);
HRESULT avi_splitter_create(IUnknown *outer, IUnknown **out); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 260dd208e2f..f23fa3abcdf 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -254,6 +254,20 @@ void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, __wine_unix_call(unix_handle, unix_wg_parser_stream_seek, ¶ms); }
+struct wg_transform *wg_transform_create(void) +{ + struct wg_transform_create_params params = {0}; + + if (__wine_unix_call(unix_handle, unix_wg_transform_create, ¶ms)) + return NULL; + return params.transform; +} + +void wg_transform_destroy(struct wg_transform *transform) +{ + __wine_unix_call(unix_handle, unix_wg_transform_destroy, transform); +} + BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) { if (reason == DLL_PROCESS_ATTACH) diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index b483638403d..f9c4da2f6ea 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -25,8 +25,13 @@
#include <gst/gst.h>
+extern bool init_gstreamer(void) DECLSPEC_HIDDEN; + extern void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) DECLSPEC_HIDDEN; extern bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) DECLSPEC_HIDDEN; extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDEN;
+extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; +extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN; + #endif /* __WINE_WINEGSTREAMER_UNIX_PRIVATE_H */ diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 45ec606fc6a..8e3f5e84bfb 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -229,6 +229,11 @@ struct wg_parser_stream_seek_params DWORD start_flags, stop_flags; };
+struct wg_transform_create_params +{ + struct wg_transform *transform; +}; + enum unix_funcs { unix_wg_parser_create, @@ -257,6 +262,9 @@ enum unix_funcs
unix_wg_parser_stream_get_duration, unix_wg_parser_stream_seek, + + unix_wg_transform_create, + unix_wg_transform_destroy, };
#endif /* __WINE_WINEGSTREAMER_UNIXLIB_H */ diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index a73685a2e69..5a2e970a4dd 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1570,6 +1570,13 @@ static void init_gstreamer_once(void) gst_version_string(), GST_VERSION_MAJOR, GST_VERSION_MINOR, GST_VERSION_MICRO); }
+bool init_gstreamer(void) +{ + static pthread_once_t init_once = PTHREAD_ONCE_INIT; + + return !pthread_once(&init_once, init_gstreamer_once); +} + static NTSTATUS wg_parser_create(void *args) { static const init_gst_cb init_funcs[] = @@ -1580,11 +1587,10 @@ static NTSTATUS wg_parser_create(void *args) [WG_PARSER_WAVPARSE] = wave_parser_init_gst, };
- static pthread_once_t once = PTHREAD_ONCE_INIT; struct wg_parser_create_params *params = args; struct wg_parser *parser;
- if (pthread_once(&once, init_gstreamer_once)) + if (!init_gstreamer()) return E_FAIL;
if (!(parser = calloc(1, sizeof(*parser)))) @@ -1651,4 +1657,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
X(wg_parser_stream_get_duration), X(wg_parser_stream_seek), + + X(wg_transform_create), + X(wg_transform_destroy), }; diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c new file mode 100644 index 00000000000..2f225e5bc55 --- /dev/null +++ b/dlls/winegstreamer/wg_transform.c @@ -0,0 +1,88 @@ +/* + * GStreamer transform backend + * + * Copyright 2022 Rémi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#include <assert.h> +#include <stdarg.h> +#include <stdio.h> + +#include <gst/gst.h> +#include <gst/video/video.h> +#include <gst/audio/audio.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "winternl.h" +#include "dshow.h" + +#include "unix_private.h" + +GST_DEBUG_CATEGORY_EXTERN(wine); +#define GST_CAT_DEFAULT wine + +struct wg_transform +{ + int dummy; +}; + +NTSTATUS wg_transform_destroy(void *args) +{ + struct wg_transform *transform = args; + + free(transform); + return STATUS_SUCCESS; +} + +NTSTATUS wg_transform_create(void *args) +{ + struct wg_transform_create_params *params = args; + struct wg_transform *transform; + NTSTATUS status; + + if (!init_gstreamer()) + return STATUS_UNSUCCESSFUL; + + status = STATUS_NO_MEMORY; + + if (!(transform = calloc(1, sizeof(*transform)))) + goto done; + + status = STATUS_SUCCESS; + +done: + if (status) + { + GST_ERROR("Failed to create winegstreamer transform."); + if (transform) + wg_transform_destroy(transform); + } + else + { + GST_INFO("Created winegstreamer transform %p.", transform); + params->transform = transform; + } + + return status; +} diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index 31f735a5b1d..b14261706a7 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -53,6 +53,8 @@ struct wma_decoder LONG refcount; IMFMediaType *input_type; IMFMediaType *output_type; + + struct wg_transform *wg_transform; };
static inline struct wma_decoder *impl_from_IUnknown(IUnknown *iface) @@ -64,6 +66,10 @@ static HRESULT try_create_wg_transform(struct wma_decoder *decoder) { struct wg_format input_format, output_format;
+ if (decoder->wg_transform) + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = NULL; + mf_media_type_to_wg_format(decoder->input_type, &input_format); if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) return MF_E_INVALIDMEDIATYPE; @@ -72,6 +78,9 @@ static HRESULT try_create_wg_transform(struct wma_decoder *decoder) if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) return MF_E_INVALIDMEDIATYPE;
+ if (!(decoder->wg_transform = wg_transform_create())) + return E_FAIL; + return S_OK; }
@@ -119,6 +128,8 @@ static ULONG WINAPI unknown_Release(IUnknown *iface)
if (!refcount) { + if (decoder->wg_transform) + wg_transform_destroy(decoder->wg_transform); if (decoder->input_type) IMFMediaType_Release(decoder->input_type); if (decoder->output_type)
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
With caps created from the input / output formats.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winegstreamer/gst_private.h | 3 +- dlls/winegstreamer/main.c | 9 ++++-- dlls/winegstreamer/unixlib.h | 2 ++ dlls/winegstreamer/wg_format.c | 40 ++++++++++++++++++++++-- dlls/winegstreamer/wg_transform.c | 51 ++++++++++++++++++++++++++++++- dlls/winegstreamer/wma_decoder.c | 2 +- 6 files changed, 100 insertions(+), 7 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 8bc9f838d29..a63daaf04b9 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -96,7 +96,8 @@ uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream); 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);
-struct wg_transform *wg_transform_create(void); +struct wg_transform *wg_transform_create(const struct wg_format *input_format, + const struct wg_format *output_format); void wg_transform_destroy(struct wg_transform *transform);
unsigned int wg_format_get_max_size(const struct wg_format *format); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index f23fa3abcdf..f85e9995525 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -254,9 +254,14 @@ void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, __wine_unix_call(unix_handle, unix_wg_parser_stream_seek, ¶ms); }
-struct wg_transform *wg_transform_create(void) +struct wg_transform *wg_transform_create(const struct wg_format *input_format, + const struct wg_format *output_format) { - struct wg_transform_create_params params = {0}; + struct wg_transform_create_params params = + { + .input_format = input_format, + .output_format = output_format, + };
if (__wine_unix_call(unix_handle, unix_wg_transform_create, ¶ms)) return NULL; diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 8e3f5e84bfb..4adbb694766 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -232,6 +232,8 @@ struct wg_parser_stream_seek_params struct wg_transform_create_params { struct wg_transform *transform; + const struct wg_format *input_format; + const struct wg_format *output_format; };
enum unix_funcs diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 8f771bb8abd..40b9acfefff 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -394,6 +394,43 @@ static GstCaps *wg_format_to_caps_video(const struct wg_format *format) return caps; }
+static GstCaps *wg_format_to_caps_wma(const struct wg_format *format) +{ + GstBuffer *buffer; + GstCaps *caps; + + if (!(caps = gst_caps_new_empty_simple("audio/x-wma"))) + return NULL; + if (format->u.wma.version) + gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, format->u.wma.version, NULL); + + if (format->u.wma.bitrate) + gst_caps_set_simple(caps, "bitrate", G_TYPE_INT, format->u.wma.bitrate, NULL); + if (format->u.wma.rate) + gst_caps_set_simple(caps, "rate", G_TYPE_INT, format->u.wma.rate, NULL); + if (format->u.wma.depth) + gst_caps_set_simple(caps, "depth", G_TYPE_INT, format->u.wma.depth, NULL); + if (format->u.wma.channels) + gst_caps_set_simple(caps, "channels", G_TYPE_INT, format->u.wma.channels, NULL); + if (format->u.wma.block_align) + gst_caps_set_simple(caps, "block_align", G_TYPE_INT, format->u.wma.block_align, NULL); + + if (format->u.wma.codec_data_len) + { + if (!(buffer = gst_buffer_new_and_alloc(format->u.wma.codec_data_len))) + { + gst_caps_unref(caps); + return NULL; + } + + gst_buffer_fill(buffer, 0, format->u.wma.codec_data, format->u.wma.codec_data_len); + gst_caps_set_simple(caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL); + gst_buffer_unref(buffer); + } + + return caps; +} + GstCaps *wg_format_to_caps(const struct wg_format *format) { switch (format->major_type) @@ -401,8 +438,7 @@ GstCaps *wg_format_to_caps(const struct wg_format *format) case WG_MAJOR_TYPE_UNKNOWN: return NULL; case WG_MAJOR_TYPE_WMA: - GST_FIXME("WMA format not implemented!\n"); - return NULL; + return wg_format_to_caps_wma(format); case WG_MAJOR_TYPE_AUDIO: return wg_format_to_caps_audio(format); case WG_MAJOR_TYPE_VIDEO: diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 2f225e5bc55..e4545774428 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -44,13 +44,29 @@ GST_DEBUG_CATEGORY_EXTERN(wine);
struct wg_transform { - int dummy; + GstPad *my_src, *my_sink; };
+static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *buffer) +{ + struct wg_transform *transform = gst_pad_get_element_private(pad); + + GST_INFO("transform %p, buffer %p.", transform, buffer); + + gst_buffer_unref(buffer); + + return GST_FLOW_OK; +} + NTSTATUS wg_transform_destroy(void *args) { struct wg_transform *transform = args;
+ if (transform->my_sink) + g_object_unref(transform->my_sink); + if (transform->my_src) + g_object_unref(transform->my_src); + free(transform); return STATUS_SUCCESS; } @@ -58,6 +74,10 @@ NTSTATUS wg_transform_destroy(void *args) NTSTATUS wg_transform_create(void *args) { struct wg_transform_create_params *params = args; + struct wg_format output_format = *params->output_format; + struct wg_format input_format = *params->input_format; + GstCaps *src_caps = NULL, *sink_caps = NULL; + GstPadTemplate *template = NULL; struct wg_transform *transform; NTSTATUS status;
@@ -69,9 +89,38 @@ NTSTATUS wg_transform_create(void *args) if (!(transform = calloc(1, sizeof(*transform)))) goto done;
+ if (!(src_caps = wg_format_to_caps(&input_format))) + goto done; + if (!(sink_caps = wg_format_to_caps(&output_format))) + goto done; + + if (!(template = gst_pad_template_new("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps))) + goto done; + if (!(transform->my_src = gst_pad_new_from_template(template, "src"))) + goto done; + g_object_unref(template); + template = NULL; + + if (!(template = gst_pad_template_new("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sink_caps))) + goto done; + if (!(transform->my_sink = gst_pad_new_from_template(template, "sink"))) + goto done; + g_object_unref(template); + template = NULL; + + gst_pad_set_element_private(transform->my_sink, transform); + gst_pad_set_chain_function(transform->my_sink, transform_sink_chain_cb); + status = STATUS_SUCCESS;
done: + if (template) + g_object_unref(template); + if (sink_caps) + gst_caps_unref(sink_caps); + if (src_caps) + gst_caps_unref(src_caps); + if (status) { GST_ERROR("Failed to create winegstreamer transform."); diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index b14261706a7..6c198706944 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -78,7 +78,7 @@ static HRESULT try_create_wg_transform(struct wma_decoder *decoder) if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) return MF_E_INVALIDMEDIATYPE;
- if (!(decoder->wg_transform = wg_transform_create())) + if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format))) return E_FAIL;
return S_OK;
Signed-off-by: Zebediah Figura zfigura@codeweavers.com