From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winegstreamer/gst_private.h | 2 +- dlls/winegstreamer/main.c | 83 ++++++- dlls/winegstreamer/unix_private.h | 3 +- dlls/winegstreamer/unixlib.h | 6 +- dlls/winegstreamer/video_decoder.c | 20 +- dlls/winegstreamer/wg_media_type.c | 365 +++++++++++++++++++++++++++++ dlls/winegstreamer/wg_parser.c | 19 +- dlls/winegstreamer/wg_transform.c | 15 +- 8 files changed, 476 insertions(+), 37 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 12cd4bcaa30..6525381312d 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -89,7 +89,7 @@ HRESULT wg_transform_create_quartz(const AM_MEDIA_TYPE *input_format, const AM_M const struct wg_transform_attrs *attrs, wg_transform_t *transform); void wg_transform_destroy(wg_transform_t transform); HRESULT wg_transform_get_output_type(wg_transform_t transform, IMFMediaType **media_type); -bool wg_transform_set_output_format(wg_transform_t transform, struct wg_format *format); +HRESULT wg_transform_set_output_type(wg_transform_t transform, IMFMediaType *media_type); bool wg_transform_get_status(wg_transform_t transform, bool *accepts_input); HRESULT wg_transform_drain(wg_transform_t transform); HRESULT wg_transform_flush(wg_transform_t transform); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index e9e8c955d2a..203ac6a7a61 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -70,6 +70,66 @@ bool array_reserve(void **elements, size_t *capacity, size_t count, size_t size) return TRUE; }
+static HRESULT video_format_from_media_type(IMFMediaType *media_type, MFVIDEOFORMAT **format, UINT32 *format_size) +{ + GUID subtype; + HRESULT hr; + + if (FAILED(hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype))) + return hr; + if (FAILED(hr = MFCreateMFVideoFormatFromMFMediaType(media_type, format, format_size))) + return hr; + + /* fixup MPEG video formats here, so we can consistently use MFVIDEOFORMAT internally */ + if (IsEqualGUID(&subtype, &MEDIASUBTYPE_MPEG1Payload) + || IsEqualGUID(&subtype, &MEDIASUBTYPE_MPEG1Packet) + || IsEqualGUID(&subtype, &MEDIASUBTYPE_MPEG2_VIDEO)) + { + struct mpeg_video_format *mpeg; + UINT32 mpeg_size, len; + + if (FAILED(IMFMediaType_GetBlobSize(media_type, &MF_MT_MPEG_SEQUENCE_HEADER, &len))) + len = 0; + mpeg_size = offsetof(struct mpeg_video_format, sequence_header[len]); + + if ((mpeg = CoTaskMemAlloc(mpeg_size))) + { + memset(mpeg, 0, mpeg_size); + mpeg->hdr = **format; + + IMFMediaType_GetBlob(media_type, &MF_MT_MPEG_SEQUENCE_HEADER, mpeg->sequence_header, len, NULL); + IMFMediaType_GetUINT32(media_type, &MF_MT_MPEG_START_TIME_CODE, (UINT32 *)&mpeg->start_time_code); + IMFMediaType_GetUINT32(media_type, &MF_MT_MPEG2_PROFILE, &mpeg->profile); + IMFMediaType_GetUINT32(media_type, &MF_MT_MPEG2_LEVEL, &mpeg->level); + IMFMediaType_GetUINT32(media_type, &MF_MT_MPEG2_FLAGS, &mpeg->flags); + + CoTaskMemFree(*format); + *format = &mpeg->hdr; + *format_size = mpeg_size; + } + } + + return hr; +} + +static HRESULT wg_media_type_from_mf(IMFMediaType *media_type, struct wg_media_type *wg_media_type) +{ + HRESULT hr; + + if (FAILED(hr = IMFMediaType_GetMajorType(media_type, &wg_media_type->major))) + return hr; + + if (IsEqualGUID(&wg_media_type->major, &MFMediaType_Video)) + return video_format_from_media_type(media_type, &wg_media_type->u.video, + &wg_media_type->format_size); + if (IsEqualGUID(&wg_media_type->major, &MFMediaType_Audio)) + return MFCreateWaveFormatExFromMFMediaType(media_type, &wg_media_type->u.audio, + &wg_media_type->format_size, 0); + + FIXME("Unsupported major type %s\n", debugstr_guid(&wg_media_type->major)); + return E_NOTIMPL; +} + static HRESULT media_type_from_video_format(const MFVIDEOFORMAT *format, IMFMediaType **media_type) { HRESULT hr; @@ -514,17 +574,30 @@ HRESULT wg_transform_get_output_type(wg_transform_t transform, IMFMediaType **me return hr; }
-bool wg_transform_set_output_format(wg_transform_t transform, struct wg_format *format) +HRESULT wg_transform_set_output_type(wg_transform_t transform, IMFMediaType *media_type) { - struct wg_transform_set_output_format_params params = + struct wg_transform_set_output_type_params params = { .transform = transform, - .format = format, }; + NTSTATUS status; + HRESULT hr;
- TRACE("transform %#I64x, format %p.\n", transform, format); + TRACE("transform %#I64x, media_type %p.\n", transform, media_type);
- return !WINE_UNIX_CALL(unix_wg_transform_set_output_format, ¶ms); + if (FAILED(hr = wg_media_type_from_mf(media_type, ¶ms.media_type))) + { + WARN("Failed to initialize media type, hr %#lx\n", hr); + return hr; + } + if ((status = WINE_UNIX_CALL(unix_wg_transform_set_output_type, ¶ms))) + { + WARN("Failed to set transform output type, status %#lx\n", status); + hr = HRESULT_FROM_NT(status); + } + + CoTaskMemFree(params.media_type.u.format); + return hr; }
HRESULT wg_transform_drain(wg_transform_t transform) diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 6f23e5f987e..985b70a925c 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -59,7 +59,7 @@ extern uint32_t wg_channel_mask_from_gst(const GstAudioInfo *info); extern NTSTATUS wg_transform_create(void *args); extern NTSTATUS wg_transform_destroy(void *args); extern NTSTATUS wg_transform_get_output_type(void *args); -extern NTSTATUS wg_transform_set_output_format(void *args); +extern NTSTATUS wg_transform_set_output_type(void *args); extern NTSTATUS wg_transform_push_data(void *args); extern NTSTATUS wg_transform_read_data(void *args); extern NTSTATUS wg_transform_get_status(void *args); @@ -69,6 +69,7 @@ extern NTSTATUS wg_transform_notify_qos(void *args);
/* wg_media_type.c */
+extern GstCaps *caps_from_media_type(const struct wg_media_type *media_type); extern NTSTATUS caps_to_media_type(GstCaps *caps, struct wg_media_type *media_type, UINT32 video_plane_align);
diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index a5f693a09de..94b2b8e347b 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -365,10 +365,10 @@ struct wg_transform_get_output_type_params struct wg_media_type media_type; };
-struct wg_transform_set_output_format_params +struct wg_transform_set_output_type_params { wg_transform_t transform; - const struct wg_format *format; + struct wg_media_type media_type; };
struct wg_transform_get_status_params @@ -447,7 +447,7 @@ enum unix_funcs unix_wg_transform_create, unix_wg_transform_destroy, unix_wg_transform_get_output_type, - unix_wg_transform_set_output_format, + unix_wg_transform_set_output_type,
unix_wg_transform_push_data, unix_wg_transform_read_data, diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 9c50743eac7..3e91e55a779 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -694,25 +694,17 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF }
if (decoder->wg_transform) - { - struct wg_format output_format; - mf_media_type_to_wg_format(output_type, &output_format); + hr = wg_transform_set_output_type(decoder->wg_transform, output_type); + else + hr = try_create_wg_transform(decoder, output_type);
- if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN - || !wg_transform_set_output_format(decoder->wg_transform, &output_format)) - { - IMFMediaType_Release(decoder->output_type); - decoder->output_type = NULL; - hr = MF_E_INVALIDMEDIATYPE; - } - } - else if (FAILED(hr = try_create_wg_transform(decoder, output_type))) + IMFMediaType_Release(output_type); + + if (FAILED(hr)) { IMFMediaType_Release(decoder->output_type); decoder->output_type = NULL; } - - IMFMediaType_Release(output_type); return hr; }
diff --git a/dlls/winegstreamer/wg_media_type.c b/dlls/winegstreamer/wg_media_type.c index 21338e89399..14fc1a9cdf4 100644 --- a/dlls/winegstreamer/wg_media_type.c +++ b/dlls/winegstreamer/wg_media_type.c @@ -64,6 +64,371 @@ DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50,MAKEFOURCC('I','V','5','0')); DEFINE_MEDIATYPE_GUID(MFVideoFormat_VC1S,MAKEFOURCC('V','C','1','S')); DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32,D3DFMT_A8B8G8R8);
+static void init_caps_codec_data(GstCaps *caps, const void *codec_data, int codec_data_size) +{ + GstBuffer *buffer; + + if (codec_data_size > 0 && (buffer = gst_buffer_new_and_alloc(codec_data_size))) + { + gst_buffer_fill(buffer, 0, codec_data, codec_data_size); + gst_caps_set_simple(caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL); + gst_buffer_unref(buffer); + } +} + +static void init_caps_from_wave_format_mpeg1(GstCaps *caps, const MPEG1WAVEFORMAT *format, UINT32 format_size) +{ + init_caps_codec_data(caps, &format->wfx + 1, format->wfx.cbSize); + + gst_structure_remove_field(gst_caps_get_structure(caps, 0), "format"); + gst_structure_set_name(gst_caps_get_structure(caps, 0), "audio/mpeg"); + gst_caps_set_simple(caps, "mpegversion", G_TYPE_INT, 1, NULL); + gst_caps_set_simple(caps, "layer", G_TYPE_INT, format->fwHeadLayer, NULL); + gst_caps_set_simple(caps, "parsed", G_TYPE_BOOLEAN, TRUE, NULL); +} + +static void init_caps_from_wave_format_mp3(GstCaps *caps, const MPEGLAYER3WAVEFORMAT *format, UINT32 format_size) +{ + init_caps_codec_data(caps, &format->wfx + 1, format->wfx.cbSize); + + gst_structure_remove_field(gst_caps_get_structure(caps, 0), "format"); + gst_structure_set_name(gst_caps_get_structure(caps, 0), "audio/mpeg"); + gst_caps_set_simple(caps, "mpegversion", G_TYPE_INT, 1, NULL); + gst_caps_set_simple(caps, "layer", G_TYPE_INT, 3, NULL); + gst_caps_set_simple(caps, "parsed", G_TYPE_BOOLEAN, TRUE, NULL); +} + +static void init_caps_from_wave_format_aac(GstCaps *caps, const HEAACWAVEFORMAT *format, UINT32 format_size) +{ + init_caps_codec_data(caps, format->pbAudioSpecificConfig, format_size - sizeof(format->wfInfo)); + + gst_structure_remove_field(gst_caps_get_structure(caps, 0), "format"); + gst_structure_set_name(gst_caps_get_structure(caps, 0), "audio/mpeg"); + gst_caps_set_simple(caps, "mpegversion", G_TYPE_INT, 4, NULL); + + switch (format->wfInfo.wPayloadType) + { + case 0: gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "raw", NULL); break; + case 1: gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "adts", NULL); break; + case 2: gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "adif", NULL); break; + case 3: gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "loas", NULL); break; + } + + /* FIXME: Use gst_codec_utils_aac_caps_set_level_and_profile from GStreamer pbutils library */ +} + +static void init_caps_from_wave_format_aac_raw(GstCaps *caps, const WAVEFORMATEX *format, UINT32 format_size) +{ + init_caps_codec_data(caps, format + 1, format->cbSize); + + gst_structure_remove_field(gst_caps_get_structure(caps, 0), "format"); + gst_structure_set_name(gst_caps_get_structure(caps, 0), "audio/mpeg"); + gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "raw", NULL); + gst_caps_set_simple(caps, "mpegversion", G_TYPE_INT, 4, NULL); +} + +static void init_caps_from_wave_format_wma1(GstCaps *caps, const MSAUDIO1WAVEFORMAT *format, UINT32 format_size) +{ + init_caps_codec_data(caps, &format->wfx + 1, format->wfx.cbSize); + + gst_structure_remove_field(gst_caps_get_structure(caps, 0), "format"); + gst_structure_set_name(gst_caps_get_structure(caps, 0), "audio/x-wma"); + gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, 1, NULL); + gst_caps_set_simple(caps, "block_align", G_TYPE_INT, format->wfx.nBlockAlign, NULL); + gst_caps_set_simple(caps, "depth", G_TYPE_INT, format->wfx.wBitsPerSample, NULL); + gst_caps_set_simple(caps, "bitrate", G_TYPE_INT, format->wfx.nAvgBytesPerSec * 8, NULL); +} + +static void init_caps_from_wave_format_wma2(GstCaps *caps, const WMAUDIO2WAVEFORMAT *format, UINT32 format_size) +{ + init_caps_codec_data(caps, &format->wfx + 1, format->wfx.cbSize); + + gst_structure_remove_field(gst_caps_get_structure(caps, 0), "format"); + gst_structure_set_name(gst_caps_get_structure(caps, 0), "audio/x-wma"); + gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, 2, NULL); + gst_caps_set_simple(caps, "block_align", G_TYPE_INT, format->wfx.nBlockAlign, NULL); + gst_caps_set_simple(caps, "depth", G_TYPE_INT, format->wfx.wBitsPerSample, NULL); + gst_caps_set_simple(caps, "bitrate", G_TYPE_INT, format->wfx.nAvgBytesPerSec * 8, NULL); +} + +static void init_caps_from_wave_format_wma3(GstCaps *caps, const WMAUDIO3WAVEFORMAT *format, UINT32 format_size) +{ + init_caps_codec_data(caps, &format->wfx + 1, format->wfx.cbSize); + + gst_structure_remove_field(gst_caps_get_structure(caps, 0), "format"); + gst_structure_set_name(gst_caps_get_structure(caps, 0), "audio/x-wma"); + gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, 3, NULL); + gst_caps_set_simple(caps, "block_align", G_TYPE_INT, format->wfx.nBlockAlign, NULL); + gst_caps_set_simple(caps, "depth", G_TYPE_INT, format->wfx.wBitsPerSample, NULL); + gst_caps_set_simple(caps, "bitrate", G_TYPE_INT, format->wfx.nAvgBytesPerSec * 8, NULL); +} + +static void init_caps_from_wave_format(GstCaps *caps, const GUID *subtype, + const void *format, UINT32 format_size) +{ + if (IsEqualGUID(subtype, &MFAudioFormat_MPEG)) + return init_caps_from_wave_format_mpeg1(caps, format, format_size); + if (IsEqualGUID(subtype, &MFAudioFormat_MP3)) + return init_caps_from_wave_format_mp3(caps, format, format_size); + if (IsEqualGUID(subtype, &MFAudioFormat_AAC)) + return init_caps_from_wave_format_aac(caps, format, format_size); + if (IsEqualGUID(subtype, &MFAudioFormat_RAW_AAC)) + return init_caps_from_wave_format_aac_raw(caps, format, format_size); + if (IsEqualGUID(subtype, &MFAudioFormat_MSAudio1)) + return init_caps_from_wave_format_wma1(caps, format, format_size); + if (IsEqualGUID(subtype, &MFAudioFormat_WMAudioV8)) + return init_caps_from_wave_format_wma2(caps, format, format_size); + if (IsEqualGUID(subtype, &MFAudioFormat_WMAudioV9) + || IsEqualGUID(subtype, &MFAudioFormat_WMAudio_Lossless)) + return init_caps_from_wave_format_wma3(caps, format, format_size); + + GST_FIXME("Unsupported subtype " WG_GUID_FORMAT, WG_GUID_ARGS(*subtype)); +} + +static GstAudioFormat wave_format_tag_to_gst_audio_format(UINT tag, UINT depth) +{ + switch (tag) + { + case WAVE_FORMAT_PCM: + if (depth == 32) return GST_AUDIO_FORMAT_S32LE; + if (depth == 24) return GST_AUDIO_FORMAT_S24LE; + if (depth == 16) return GST_AUDIO_FORMAT_S16LE; + if (depth == 8) return GST_AUDIO_FORMAT_U8; + break; + + case WAVE_FORMAT_IEEE_FLOAT: + if (depth == 64) return GST_AUDIO_FORMAT_F64LE; + if (depth == 32) return GST_AUDIO_FORMAT_F32LE; + break; + } + + return GST_AUDIO_FORMAT_ENCODED; +} + +static GstCaps *caps_from_wave_format_ex(const WAVEFORMATEX *format, UINT32 format_size, const GUID *subtype, UINT64 channel_mask) +{ + GstAudioFormat audio_format = wave_format_tag_to_gst_audio_format(subtype->Data1, format->wBitsPerSample); + GstCaps *caps; + + if (!(caps = gst_caps_new_simple("audio/x-raw", "format", G_TYPE_STRING, gst_audio_format_to_string(audio_format), + "layout", G_TYPE_STRING, "interleaved", "rate", G_TYPE_INT, format->nSamplesPerSec, + "channels", G_TYPE_INT, format->nChannels, "channel-mask", GST_TYPE_BITMASK, channel_mask, NULL))) + return NULL; + + if (audio_format == GST_AUDIO_FORMAT_ENCODED) + init_caps_from_wave_format(caps, subtype, format, format_size); + + return caps; +} + +static WAVEFORMATEX *strip_wave_format_extensible(const WAVEFORMATEXTENSIBLE *format_ext) +{ + UINT32 extra_size = format_ext->Format.cbSize + sizeof(WAVEFORMATEX) - sizeof(WAVEFORMATEXTENSIBLE); + WAVEFORMATEX *format; + + if (!(format = malloc(sizeof(*format) + extra_size))) + return NULL; + + *format = format_ext->Format; + format->cbSize = extra_size; + format->wFormatTag = format_ext->SubFormat.Data1; + memcpy(format + 1, format_ext + 1, extra_size); + return format; +} + +static GstCaps *caps_from_wave_format_extensible(const WAVEFORMATEXTENSIBLE *format, UINT32 format_size) +{ + WAVEFORMATEX *wfx; + GstCaps *caps; + + GST_TRACE("tag %#x, %u channels, sample rate %u, %u bytes/sec, alignment %u, %u bits/sample, " + "%u valid bps, channel mask %#x, subtype " WG_GUID_FORMAT ".", + format->Format.wFormatTag, format->Format.nChannels, (int)format->Format.nSamplesPerSec, + (int)format->Format.nAvgBytesPerSec, format->Format.nBlockAlign, format->Format.wBitsPerSample, + format->Samples.wValidBitsPerSample, (int)format->dwChannelMask, WG_GUID_ARGS(format->SubFormat)); + if (format->Format.cbSize) + { + guint extra_size = sizeof(WAVEFORMATEX) + format->Format.cbSize - sizeof(WAVEFORMATEXTENSIBLE); + GST_MEMDUMP("extra bytes:", (guint8 *)(format + 1), extra_size); + } + + if (!(wfx = strip_wave_format_extensible(format))) + return NULL; + + caps = caps_from_wave_format_ex(wfx, format_size + sizeof(*wfx) - sizeof(*format), + &format->SubFormat, format->dwChannelMask); + free(wfx); + return caps; +} + +static GstCaps *caps_from_wave_format(const void *format, UINT32 format_size) +{ + const WAVEFORMATEX *wfx = format; + GUID subtype = MFAudioFormat_Base; + UINT channel_mask; + + if (wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) + return caps_from_wave_format_extensible(format, format_size); + + GST_TRACE("tag %#x, %u channels, sample rate %u, %u bytes/sec, alignment %u, %u bits/sample.", + wfx->wFormatTag, wfx->nChannels, (int)wfx->nSamplesPerSec, + (int)wfx->nAvgBytesPerSec, wfx->nBlockAlign, wfx->wBitsPerSample); + if (wfx->cbSize) GST_MEMDUMP("extra bytes:", (guint8 *)(wfx + 1), wfx->cbSize); + + subtype.Data1 = wfx->wFormatTag; + channel_mask = gst_audio_channel_get_fallback_mask(wfx->nChannels); + return caps_from_wave_format_ex(format, format_size, &subtype, channel_mask); +} + +static void init_caps_from_video_cinepak(GstCaps *caps, const MFVIDEOFORMAT *format, UINT format_size) +{ + init_caps_codec_data(caps, format + 1, format_size - sizeof(*format)); + + gst_structure_remove_field(gst_caps_get_structure(caps, 0), "format"); + gst_structure_set_name(gst_caps_get_structure(caps, 0), "video/x-cinepak"); +} + +static void init_caps_from_video_h264(GstCaps *caps, const MFVIDEOFORMAT *format, UINT format_size) +{ + init_caps_codec_data(caps, format + 1, format_size - sizeof(*format)); + + gst_structure_remove_field(gst_caps_get_structure(caps, 0), "format"); + gst_structure_set_name(gst_caps_get_structure(caps, 0), "video/x-h264"); + gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "byte-stream", NULL); + gst_caps_set_simple(caps, "alignment", G_TYPE_STRING, "au", NULL); +} + +static void init_caps_from_video_wmv(GstCaps *caps, const MFVIDEOFORMAT *format, UINT format_size, + int wmv_version, const char *wmv_format) +{ + init_caps_codec_data(caps, format + 1, format_size - sizeof(*format)); + + gst_structure_remove_field(gst_caps_get_structure(caps, 0), "format"); + gst_structure_set_name(gst_caps_get_structure(caps, 0), "video/x-wmv"); + gst_caps_set_simple(caps, "wmvversion", G_TYPE_INT, wmv_version, NULL); + gst_caps_set_simple(caps, "format", G_TYPE_STRING, wmv_format, NULL); +} + +static void init_caps_from_video_indeo(GstCaps *caps, const MFVIDEOFORMAT *format, UINT format_size) +{ + init_caps_codec_data(caps, format + 1, format_size - sizeof(*format)); + + gst_structure_remove_field(gst_caps_get_structure(caps, 0), "format"); + gst_structure_set_name(gst_caps_get_structure(caps, 0), "video/x-indeo"); + gst_caps_set_simple(caps, "indeoversion", G_TYPE_INT, 5, NULL); +} + +static void init_caps_from_video_mpeg(GstCaps *caps, const struct mpeg_video_format *format, UINT format_size) +{ + init_caps_codec_data(caps, format->sequence_header, format->sequence_header_count); + + gst_structure_remove_field(gst_caps_get_structure(caps, 0), "format"); + gst_structure_set_name(gst_caps_get_structure(caps, 0), "video/mpeg"); + gst_caps_set_simple(caps, "mpegversion", G_TYPE_INT, 1, NULL); + gst_caps_set_simple(caps, "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); + gst_caps_set_simple(caps, "parsed", G_TYPE_BOOLEAN, TRUE, NULL); +} + +static void init_caps_from_video_subtype(GstCaps *caps, const GUID *subtype, const void *format, UINT format_size) +{ + if (IsEqualGUID(subtype, &MFVideoFormat_CVID)) + return init_caps_from_video_cinepak(caps, format, format_size); + if (IsEqualGUID(subtype, &MFVideoFormat_H264)) + return init_caps_from_video_h264(caps, format, format_size); + if (IsEqualGUID(subtype, &MFVideoFormat_WMV1)) + return init_caps_from_video_wmv(caps, format, format_size, 1, "WMV1"); + if (IsEqualGUID(subtype, &MFVideoFormat_WMV2)) + return init_caps_from_video_wmv(caps, format, format_size, 2, "WMV2"); + if (IsEqualGUID(subtype, &MFVideoFormat_WMV3)) + return init_caps_from_video_wmv(caps, format, format_size, 3, "WMV3"); + if (IsEqualGUID(subtype, &MEDIASUBTYPE_WMVA)) + return init_caps_from_video_wmv(caps, format, format_size, 3, "WMVA"); + if (IsEqualGUID(subtype, &MFVideoFormat_WVC1)) + return init_caps_from_video_wmv(caps, format, format_size, 3, "WVC1"); + if (IsEqualGUID(subtype, &MFVideoFormat_IV50)) + return init_caps_from_video_indeo(caps, format, format_size); + if (IsEqualGUID(subtype, &MEDIASUBTYPE_MPEG1Payload)) + return init_caps_from_video_mpeg(caps, format, format_size); + + GST_FIXME("Unsupported subtype " WG_GUID_FORMAT, WG_GUID_ARGS(*subtype)); +} + +static GstVideoFormat subtype_to_gst_video_format(const GUID *subtype) +{ + GUID base = *subtype; + base.Data1 = 0; + + if (IsEqualGUID(&base, &MFVideoFormat_Base)) + { + switch (subtype->Data1) + { + case D3DFMT_A8R8G8B8: return GST_VIDEO_FORMAT_BGRA; + case D3DFMT_X8R8G8B8: return GST_VIDEO_FORMAT_BGRx; + case D3DFMT_R8G8B8: return GST_VIDEO_FORMAT_BGR; + case D3DFMT_A8B8G8R8: return GST_VIDEO_FORMAT_RGBA; + case D3DFMT_X1R5G5B5: return GST_VIDEO_FORMAT_RGB15; + case D3DFMT_R5G6B5: return GST_VIDEO_FORMAT_RGB16; + case MAKEFOURCC('A','Y','U','V'): return GST_VIDEO_FORMAT_AYUV; + case MAKEFOURCC('I','4','2','0'): return GST_VIDEO_FORMAT_I420; + case MAKEFOURCC('N','V','1','2'): return GST_VIDEO_FORMAT_NV12; + case MAKEFOURCC('U','Y','V','Y'): return GST_VIDEO_FORMAT_UYVY; + case MAKEFOURCC('Y','U','Y','2'): return GST_VIDEO_FORMAT_YUY2; + case MAKEFOURCC('Y','V','1','2'): return GST_VIDEO_FORMAT_YV12; + case MAKEFOURCC('Y','V','Y','U'): return GST_VIDEO_FORMAT_YVYU; + } + } + + return GST_VIDEO_FORMAT_ENCODED; +} + +static GstCaps *caps_from_video_format(const MFVIDEOFORMAT *format, UINT32 format_size) +{ + GstVideoFormat video_format = subtype_to_gst_video_format(&format->guidFormat); + GstCaps *caps; + + GST_TRACE("subtype " WG_GUID_FORMAT " %ux%u, FPS " WG_RATIO_FORMAT ", aperture " WG_APERTURE_FORMAT ", " + "PAR " WG_RATIO_FORMAT ", videoFlags %#x.", + WG_GUID_ARGS(format->guidFormat), (int)format->videoInfo.dwWidth, (int)format->videoInfo.dwHeight, + WG_RATIO_ARGS(format->videoInfo.FramesPerSecond), WG_APERTURE_ARGS(format->videoInfo.MinimumDisplayAperture), + WG_RATIO_ARGS(format->videoInfo.PixelAspectRatio), (int)format->videoInfo.VideoFlags ); + if (format->dwSize > sizeof(*format)) GST_MEMDUMP("extra bytes:", (guint8 *)(format + 1), format->dwSize - sizeof(*format)); + + if (!(caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, gst_video_format_to_string(video_format), NULL))) + return NULL; + + if (format->videoInfo.dwWidth) + gst_caps_set_simple(caps, "width", G_TYPE_INT, format->videoInfo.dwWidth, NULL); + if (format->videoInfo.dwHeight) + gst_caps_set_simple(caps, "height", G_TYPE_INT, format->videoInfo.dwHeight, NULL); + + if (format->videoInfo.PixelAspectRatio.Denominator) + gst_caps_set_simple(caps, "pixel-aspect-ratio", GST_TYPE_FRACTION, + format->videoInfo.PixelAspectRatio.Numerator, + format->videoInfo.PixelAspectRatio.Denominator, NULL); + if (format->videoInfo.FramesPerSecond.Denominator) + gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, + format->videoInfo.FramesPerSecond.Numerator, + format->videoInfo.FramesPerSecond.Denominator, NULL); + + if (video_format == GST_VIDEO_FORMAT_ENCODED) + init_caps_from_video_subtype(caps, &format->guidFormat, format, format_size); + + return caps; +} + +GstCaps *caps_from_media_type(const struct wg_media_type *media_type) +{ + GstCaps *caps = NULL; + + if (IsEqualGUID(&media_type->major, &MFMediaType_Video)) + caps = caps_from_video_format(media_type->u.video, media_type->format_size); + else if (IsEqualGUID(&media_type->major, &MFMediaType_Audio)) + caps = caps_from_wave_format(media_type->u.audio, media_type->format_size); + + GST_TRACE("caps %"GST_PTR_FORMAT, caps); + return caps; +} + static WORD wave_format_tag_from_gst_audio_format(GstAudioFormat audio_format) { switch (audio_format) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 06cd1aeeb0e..be49ec8b2aa 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1883,7 +1883,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_transform_create), X(wg_transform_destroy), X(wg_transform_get_output_type), - X(wg_transform_set_output_format), + X(wg_transform_set_output_type),
X(wg_transform_push_data), X(wg_transform_read_data), @@ -2100,19 +2100,24 @@ NTSTATUS wow64_wg_transform_get_output_type(void *args) return status; }
-NTSTATUS wow64_wg_transform_set_output_format(void *args) +NTSTATUS wow64_wg_transform_set_output_type(void *args) { struct { wg_transform_t transform; - PTR32 format; + struct wg_media_type32 media_type; } *params32 = args; - struct wg_transform_set_output_format_params params = + struct wg_transform_set_output_type_params params = { .transform = params32->transform, - .format = ULongToPtr(params32->format), + .media_type = + { + .major = params32->media_type.major, + .format_size = params32->media_type.format_size, + .u.format = ULongToPtr(params32->media_type.format), + }, }; - return wg_transform_set_output_format(¶ms); + return wg_transform_set_output_type(¶ms); }
NTSTATUS wow64_wg_transform_push_data(void *args) @@ -2265,7 +2270,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = X64(wg_transform_create), X(wg_transform_destroy), X64(wg_transform_get_output_type), - X64(wg_transform_set_output_format), + X64(wg_transform_set_output_type),
X64(wg_transform_push_data), X64(wg_transform_read_data), diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 4f678573e83..10345353e89 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -633,17 +633,20 @@ NTSTATUS wg_transform_get_output_type(void *args) return caps_to_media_type(output_caps, ¶ms->media_type, transform->attrs.output_plane_align); }
-NTSTATUS wg_transform_set_output_format(void *args) +NTSTATUS wg_transform_set_output_type(void *args) { - struct wg_transform_set_output_format_params *params = args; + struct wg_transform_set_output_type_params *params = args; struct wg_transform *transform = get_transform(params->transform); - const struct wg_format *format = params->format; + MFVideoInfo output_info = {0}; GstCaps *caps, *stripped; GstSample *sample;
- if (!(caps = wg_format_to_caps(format))) + if (IsEqualGUID(¶ms->media_type.major, &MFMediaType_Video)) + output_info = params->media_type.u.video->videoInfo; + + if (!(caps = caps_from_media_type(¶ms->media_type))) { - GST_ERROR("Failed to convert format %p to caps.", format); + GST_ERROR("Failed to convert media type to caps."); return STATUS_UNSUCCESSFUL; }
@@ -670,7 +673,7 @@ NTSTATUS wg_transform_set_output_format(void *args) if (transform->video_flip) { const char *value; - if (transform->input_is_flipped != wg_format_video_is_flipped(format)) + if (transform->input_is_flipped != !!(output_info.VideoFlags & MFVideoFlag_BottomUpLinearRep)) value = "vertical-flip"; else value = "none";