winegstreamer: Translate MFVIDEOFORMAT / WAVEFORMATEX directly to GstCaps in wg_transform.

This commit is contained in:
Rémi Bernon 2024-05-07 18:28:07 +02:00 committed by Alexandre Julliard
parent fbceb9e60b
commit 0906f6957a
8 changed files with 476 additions and 37 deletions

View file

@ -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);

View file

@ -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, &params);
if (FAILED(hr = wg_media_type_from_mf(media_type, &params.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, &params)))
{
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)

View file

@ -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);

View file

@ -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,

View file

@ -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;
}

View file

@ -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)

View file

@ -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(&params);
return wg_transform_set_output_type(&params);
}
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),

View file

@ -633,17 +633,20 @@ NTSTATUS wg_transform_get_output_type(void *args)
return caps_to_media_type(output_caps, &params->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(&params->media_type.major, &MFMediaType_Video))
output_info = params->media_type.u.video->videoInfo;
if (!(caps = caps_from_media_type(&params->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";