From: Torge Matthies tmatthies@codeweavers.com
--- dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/media_sink.c | 28 +++++++++-- dlls/winegstreamer/mfplat.c | 81 ++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 4 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 2374fb6fddd..07a02e42cc3 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -126,6 +126,7 @@ extern HRESULT mfplat_DllRegisterServer(void);
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 mf_media_type_add_aac_user_data(IMFMediaType *type);
HRESULT wg_sample_create_mf(IMFSample *sample, struct wg_sample **out); HRESULT wg_sample_create_quartz(IMediaSample *sample, struct wg_sample **out); diff --git a/dlls/winegstreamer/media_sink.c b/dlls/winegstreamer/media_sink.c index ebabf4c1eae..128f103f7bb 100644 --- a/dlls/winegstreamer/media_sink.c +++ b/dlls/winegstreamer/media_sink.c @@ -757,26 +757,44 @@ static HRESULT WINAPI media_sink_AddStreamSink(IMFFinalizableMediaSink *iface, D IMFMediaType *media_type, IMFStreamSink **stream_sink) { struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(iface); + IMFMediaType *type_copy = NULL; struct stream_sink *object; + GUID major_type, subtype; struct wg_format format; HRESULT hr;
TRACE("iface %p, stream_sink_id %#lx, media_type %p, stream_sink %p.\n", iface, stream_sink_id, media_type, stream_sink);
+ if (!FAILED(IMFMediaType_GetMajorType(media_type, &major_type)) && + IsEqualGUID(&major_type, &MFMediaType_Audio) && + !FAILED(IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype)) && + (IsEqualGUID(&subtype, &MFAudioFormat_AAC) || IsEqualGUID(&subtype, &MFAudioFormat_RAW_AAC)) && + FAILED(IMFMediaType_GetItem(media_type, &MF_MT_USER_DATA, NULL))) + { + if (FAILED(hr = MFCreateMediaType(&type_copy)) || + FAILED(hr = IMFMediaType_CopyAllItems(media_type, (IMFAttributes*)type_copy))) + goto done; + hr = mf_media_type_add_aac_user_data(type_copy); + if (FAILED(hr)) + goto done; + media_type = type_copy; + } + EnterCriticalSection(&media_sink->cs);
if (media_sink_get_stream_sink_by_id(media_sink, stream_sink_id)) { LeaveCriticalSection(&media_sink->cs); - return MF_E_STREAMSINK_EXISTS; + hr = MF_E_STREAMSINK_EXISTS; + goto done; }
if (FAILED(hr = stream_sink_create(stream_sink_id, media_type, media_sink, &object))) { WARN("Failed to create stream sink, hr %#lx.\n", hr); LeaveCriticalSection(&media_sink->cs); - return hr; + goto done; }
mf_media_type_to_wg_format(media_type, &format); @@ -784,7 +802,7 @@ static HRESULT WINAPI media_sink_AddStreamSink(IMFFinalizableMediaSink *iface, D { LeaveCriticalSection(&media_sink->cs); IMFStreamSink_Release(&object->IMFStreamSink_iface); - return hr; + goto done; }
list_add_tail(&media_sink->stream_sinks, &object->entry); @@ -794,7 +812,9 @@ static HRESULT WINAPI media_sink_AddStreamSink(IMFFinalizableMediaSink *iface, D if (stream_sink) IMFStreamSink_AddRef((*stream_sink = &object->IMFStreamSink_iface));
- return S_OK; +done: + if (type_copy) IMFMediaType_Release(type_copy); + return hr; }
static HRESULT WINAPI media_sink_RemoveStreamSink(IMFFinalizableMediaSink *iface, DWORD stream_sink_id) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index e6d9fb9fd2c..0572b3bfd64 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -25,6 +25,7 @@ #include "initguid.h" #include "d3d9types.h" #include "mfapi.h" +#include "mferror.h" #include "mmreg.h"
#include "wine/debug.h" @@ -904,3 +905,83 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) else FIXME("Unrecognized major type %s.\n", debugstr_guid(&major_type)); } + +static inline int min_int(int a, int b) +{ + return a < b ? a : b; +} + +static inline void write_bits(BYTE *dst, int *bit_pos, UINT32 val, int bits) +{ + BYTE *start_ptr = dst + *bit_pos / 8; + int used = *bit_pos % 8; + *bit_pos += bits; + + do + { + int c = min_int(8 - used, bits); + BYTE m = ((1U << c) - 1); + BYTE v = val >> (bits - c); + *start_ptr = (*start_ptr & ~(m << (8 - c - used))) | ((v & m) << (8 - c - used)); + bits -= c; + start_ptr++; + used = 0; + } while (bits); +} + +HRESULT mf_media_type_add_aac_user_data(IMFMediaType *type) +{ + BYTE buffer[64]; + HEAACWAVEFORMAT *user_data = (HEAACWAVEFORMAT *)buffer; + UINT32 frequency, channels, payload_type, profile_level, size; + BYTE *ptr = user_data->pbAudioSpecificConfig; + int bits = 0; + + if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &frequency)) || + frequency > 0xFFFFFF) + return MF_E_INVALIDMEDIATYPE; + if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &channels)) || + channels < 1 || channels > 8 || channels == 7) + return MF_E_INVALIDMEDIATYPE; + + if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AAC_PAYLOAD_TYPE, &payload_type))) + payload_type = 0; + else if (payload_type > 3) + return MF_E_INVALIDMEDIATYPE; + if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, &profile_level))) + profile_level = 0x29; + else if (profile_level > 0xFFFF) + return MF_E_INVALIDMEDIATYPE; + + if (channels == 8) + channels = 7; + + memset( user_data, 0, sizeof(buffer) ); + user_data->wfInfo.wPayloadType = payload_type; + user_data->wfInfo.wAudioProfileLevelIndication = profile_level; + write_bits(ptr, &bits, 2, 5); + switch (frequency) + { + case 96000: write_bits(ptr, &bits, 0, 4); break; + case 88200: write_bits(ptr, &bits, 1, 4); break; + case 64000: write_bits(ptr, &bits, 2, 4); break; + case 48000: write_bits(ptr, &bits, 3, 4); break; + case 44100: write_bits(ptr, &bits, 4, 4); break; + case 32000: write_bits(ptr, &bits, 5, 4); break; + case 24000: write_bits(ptr, &bits, 6, 4); break; + case 22050: write_bits(ptr, &bits, 7, 4); break; + case 16000: write_bits(ptr, &bits, 8, 4); break; + case 12000: write_bits(ptr, &bits, 9, 4); break; + case 11025: write_bits(ptr, &bits, 10, 4); break; + case 8000: write_bits(ptr, &bits, 11, 4); break; + case 7350: write_bits(ptr, &bits, 12, 4); break; + default: + write_bits(ptr, &bits, 15, 4); + write_bits(ptr, &bits, frequency, 24); + break; + } + write_bits(ptr, &bits, channels, 4); + + size = FIELD_OFFSET(HEAACWAVEFORMAT, pbAudioSpecificConfig[(bits + 7) / 8]) - sizeof(user_data->wfInfo.wfx); + return IMFMediaType_SetBlob(type, &MF_MT_USER_DATA, (void*)(&user_data->wfInfo.wfx + 1), size); +}