mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-19 11:09:04 +00:00
winegstreamer: Translate MFVIDEOFORMAT / WAVEFORMATEX directly to GstCaps in wg_transform.
This commit is contained in:
parent
fbceb9e60b
commit
0906f6957a
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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";
|
||||
|
|
Loading…
Reference in a new issue