From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mfsrcsnk/media_source.c | 2 +- dlls/winedmo/main.c | 12 ++++++------ dlls/winedmo/winedmo.spec | 2 +- include/wine/winedmo.h | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/dlls/mfsrcsnk/media_source.c b/dlls/mfsrcsnk/media_source.c index a4cc2a92c31..7f79c87b3db 100644 --- a/dlls/mfsrcsnk/media_source.c +++ b/dlls/mfsrcsnk/media_source.c @@ -588,7 +588,7 @@ static HRESULT media_source_async_create(struct media_source *source, IMFAsyncRe source->winedmo_stream.p_seek = media_source_seek_cb; source->winedmo_stream.p_read = media_source_read_cb;
- if ((status = winedmo_demuxer_create(source->url, &source->winedmo_stream, &source->file_size, &source->duration, + if ((status = winedmo_demuxer_create(source->url, &source->winedmo_stream, source->file_size, &source->duration, &source->stream_count, source->mime_type, &source->winedmo_demuxer))) { WARN("Failed to create demuxer, status %#lx\n", status); diff --git a/dlls/winedmo/main.c b/dlls/winedmo/main.c index 7d30c31d05d..0751337659a 100644 --- a/dlls/winedmo/main.c +++ b/dlls/winedmo/main.c @@ -24,13 +24,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmo);
-static struct stream_context *stream_context_create( struct winedmo_stream *stream, UINT64 *stream_size ) +static struct stream_context *stream_context_create( struct winedmo_stream *stream, UINT64 stream_size ) { struct stream_context *context;
if (!(context = malloc( 0x10000 ))) return NULL; context->stream = (UINT_PTR)stream; - context->length = *stream_size; + context->length = stream_size; context->position = 0; context->buffer_size = 0x10000 - offsetof(struct stream_context, buffer);
@@ -126,7 +126,7 @@ NTSTATUS CDECL winedmo_demuxer_check( const char *mime_type ) return status; }
-NTSTATUS CDECL winedmo_demuxer_create( const WCHAR *url, struct winedmo_stream *stream, UINT64 *stream_size, INT64 *duration, +NTSTATUS CDECL winedmo_demuxer_create( const WCHAR *url, struct winedmo_stream *stream, UINT64 stream_size, INT64 *duration, UINT *stream_count, WCHAR *mime_type, struct winedmo_demuxer *demuxer ) { struct demuxer_create_params params = {0}; @@ -135,7 +135,7 @@ NTSTATUS CDECL winedmo_demuxer_create( const WCHAR *url, struct winedmo_stream * UINT len;
TRACE( "url %s, stream %p, stream_size %#I64x, mime_type %p, demuxer %p\n", debugstr_w(url), - stream, *stream_size, mime_type, demuxer ); + stream, stream_size, mime_type, demuxer );
if (!(params.context = stream_context_create( stream, stream_size ))) return STATUS_NO_MEMORY;
@@ -158,8 +158,8 @@ NTSTATUS CDECL winedmo_demuxer_create( const WCHAR *url, struct winedmo_stream * *stream_count = params.stream_count; MultiByteToWideChar( CP_ACP, 0, params.mime_type, -1, mime_type, 256 ); *demuxer = params.demuxer; - TRACE( "created demuxer %#I64x, stream %p, stream_size %#I64x, duration %I64d, stream_count %u, mime_type %s\n", - demuxer->handle, stream, *stream_size, params.duration, params.stream_count, debugstr_a(params.mime_type) ); + TRACE( "created demuxer %#I64x, stream %p, duration %I64d, stream_count %u, mime_type %s\n", + demuxer->handle, stream, params.duration, params.stream_count, debugstr_a(params.mime_type) ); return STATUS_SUCCESS; }
diff --git a/dlls/winedmo/winedmo.spec b/dlls/winedmo/winedmo.spec index 8038312d942..3e9cc721f56 100644 --- a/dlls/winedmo/winedmo.spec +++ b/dlls/winedmo/winedmo.spec @@ -1,4 +1,4 @@ @ cdecl winedmo_demuxer_check(str) @ cdecl winedmo_demuxer_create(wstr ptr ptr ptr ptr ptr ptr) @ cdecl winedmo_demuxer_destroy(ptr) -@ cdecl winedmo_demuxer_stream_type(int64 ptr ptr) +@ cdecl winedmo_demuxer_stream_type(int64 long ptr ptr) diff --git a/include/wine/winedmo.h b/include/wine/winedmo.h index cdcd77f5dd0..7f9fb08bebd 100644 --- a/include/wine/winedmo.h +++ b/include/wine/winedmo.h @@ -43,7 +43,7 @@ struct winedmo_stream struct winedmo_demuxer { UINT64 handle; };
NTSTATUS CDECL winedmo_demuxer_check( const char *mime_type ); -NTSTATUS CDECL winedmo_demuxer_create( const WCHAR *url, struct winedmo_stream *stream, UINT64 *stream_size, INT64 *duration, +NTSTATUS CDECL winedmo_demuxer_create( const WCHAR *url, struct winedmo_stream *stream, UINT64 stream_size, INT64 *duration, UINT *stream_count, WCHAR *mime_type, struct winedmo_demuxer *demuxer ); NTSTATUS CDECL winedmo_demuxer_destroy( struct winedmo_demuxer *demuxer ); NTSTATUS CDECL winedmo_demuxer_stream_type( struct winedmo_demuxer demuxer, UINT stream,
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winedmo/unix_media_type.c | 108 ++++++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 1 deletion(-)
diff --git a/dlls/winedmo/unix_media_type.c b/dlls/winedmo/unix_media_type.c index fb0350d39b4..e233acf4ab2 100644 --- a/dlls/winedmo/unix_media_type.c +++ b/dlls/winedmo/unix_media_type.c @@ -35,6 +35,19 @@
WINE_DEFAULT_DEBUG_CHANNEL(dmo);
+DEFINE_MEDIATYPE_GUID( MFVideoFormat_ABGR32, D3DFMT_A8B8G8R8 ); + +static inline const char *debugstr_ratio( const MFRatio *ratio ) +{ + return wine_dbg_sprintf( "%d:%d", (int)ratio->Numerator, (int)ratio->Denominator ); +} + +static inline const char *debugstr_area( const MFVideoArea *area ) +{ + return wine_dbg_sprintf( "(%d,%d)-(%d,%d)", area->OffsetX.value, area->OffsetY.value, + (int)area->Area.cx, (int)area->Area.cy ); +} + #define TRACE_HEXDUMP( data, size ) \ if (__WINE_IS_DEBUG_ON(_TRACE, __wine_dbch___default)) \ do { \ @@ -54,6 +67,99 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmo); } \ } while (0)
+static GUID subtype_from_pixel_format( enum AVPixelFormat fmt ) +{ + switch (fmt) + { + case AV_PIX_FMT_NONE: return MFVideoFormat_Base; + case AV_PIX_FMT_YUV420P: return MFVideoFormat_I420; + case AV_PIX_FMT_YUVJ420P: return MFVideoFormat_I420; + case AV_PIX_FMT_YUYV422: return MFVideoFormat_YUY2; + case AV_PIX_FMT_UYVY422: return MFVideoFormat_UYVY; + case AV_PIX_FMT_BGR0: return MFVideoFormat_RGB32; + case AV_PIX_FMT_RGBA: return MFVideoFormat_ABGR32; + case AV_PIX_FMT_BGRA: return MFVideoFormat_ARGB32; + case AV_PIX_FMT_BGR24: return MFVideoFormat_RGB24; + case AV_PIX_FMT_NV12: return MFVideoFormat_NV12; + case AV_PIX_FMT_NV21: return MFVideoFormat_NV21; + case AV_PIX_FMT_RGB565: return MFVideoFormat_RGB565; + case AV_PIX_FMT_RGB555: return MFVideoFormat_RGB555; + case AV_PIX_FMT_RGB8: return MFVideoFormat_RGB8; + default: + FIXME( "Unsupported format %#x (%s)\n", fmt, av_get_pix_fmt_name( fmt ) ); + return MFVideoFormat_Base; + } +} + +static UINT video_format_tag_from_codec_id( enum AVCodecID id ) +{ + const struct AVCodecTag *table[] = {avformat_get_riff_video_tags(), avformat_get_mov_video_tags(), 0}; + return av_codec_get_tag( table, id ); +} + +static void mf_video_format_init( const AVCodecParameters *params, MFVIDEOFORMAT *format, UINT32 format_size, + const AVRational *sar, const AVRational *fps, UINT32 align ) +{ + memset( format, 0, format_size ); + format->dwSize = format_size; + + if (params->codec_id == AV_CODEC_ID_RAWVIDEO && params->format != AV_PIX_FMT_NONE) + format->guidFormat = subtype_from_pixel_format( params->format ); + else + { + format->guidFormat = MFVideoFormat_Base; + if (params->codec_tag) format->guidFormat.Data1 = params->codec_tag; + else format->guidFormat.Data1 = video_format_tag_from_codec_id( params->codec_id ); + } + + format->videoInfo.dwWidth = (params->width + align) & ~align; + format->videoInfo.dwHeight = (params->height + align) & ~align; + if (format->videoInfo.dwWidth != params->width || format->videoInfo.dwHeight != params->height) + { + format->videoInfo.MinimumDisplayAperture.Area.cx = params->width; + format->videoInfo.MinimumDisplayAperture.Area.cy = params->height; + } + format->videoInfo.GeometricAperture = format->videoInfo.MinimumDisplayAperture; + format->videoInfo.PanScanAperture = format->videoInfo.MinimumDisplayAperture; + + if (sar->num && sar->den) + { + format->videoInfo.PixelAspectRatio.Numerator = sar->num; + format->videoInfo.PixelAspectRatio.Denominator = sar->den; + } + else + { + format->videoInfo.PixelAspectRatio.Numerator = 1; + format->videoInfo.PixelAspectRatio.Denominator = 1; + } + + if (fps->num && fps->den) + { + format->videoInfo.FramesPerSecond.Numerator = fps->num; + format->videoInfo.FramesPerSecond.Denominator = fps->den; + } +} + +static NTSTATUS video_format_from_codec_params( const AVCodecParameters *params, MFVIDEOFORMAT *format, UINT32 *format_size, + const AVRational *sar, const AVRational *fps, UINT32 align ) +{ + UINT32 capacity = *format_size; + + *format_size = sizeof(*format) + params->extradata_size; + if (*format_size > capacity) return STATUS_BUFFER_TOO_SMALL; + + mf_video_format_init( params, format, *format_size, sar, fps, align ); + if (params->extradata_size && params->extradata) memcpy( format + 1, params->extradata, params->extradata_size ); + + TRACE( "subtype %s (%s) %ux%u, FPS %s, aperture %s, PAR %s, videoFlags %#x.\n", debugstr_guid(&format->guidFormat), + debugstr_fourcc(format->guidFormat.Data1), (int)format->videoInfo.dwWidth, (int)format->videoInfo.dwHeight, + debugstr_ratio(&format->videoInfo.FramesPerSecond), debugstr_area(&format->videoInfo.MinimumDisplayAperture), + debugstr_ratio(&format->videoInfo.PixelAspectRatio), (int)format->videoInfo.VideoFlags ); + if (format->dwSize > sizeof(*format)) TRACE_HEXDUMP( format + 1, format->dwSize - sizeof(*format) ); + + return STATUS_SUCCESS; +} + NTSTATUS media_type_from_codec_params( const AVCodecParameters *params, const AVRational *sar, const AVRational *fps, UINT32 align, struct media_type *media_type ) { @@ -70,7 +176,7 @@ NTSTATUS media_type_from_codec_params( const AVCodecParameters *params, const AV if (params->codec_type == AVMEDIA_TYPE_VIDEO) { media_type->major = MFMediaType_Video; - return STATUS_SUCCESS; + return video_format_from_codec_params( params, media_type->video, &media_type->format_size, sar, fps, align ); }
FIXME( "Unknown type %#x\n", params->codec_type );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winedmo/unix_media_type.c | 99 +++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 1 deletion(-)
diff --git a/dlls/winedmo/unix_media_type.c b/dlls/winedmo/unix_media_type.c index e233acf4ab2..67ea1f9baba 100644 --- a/dlls/winedmo/unix_media_type.c +++ b/dlls/winedmo/unix_media_type.c @@ -67,6 +67,103 @@ static inline const char *debugstr_area( const MFVideoArea *area ) } \ } while (0)
+static WORD wave_format_tag_from_codec_id( enum AVCodecID id ) +{ + const struct AVCodecTag *table[] = {avformat_get_riff_audio_tags(), avformat_get_mov_audio_tags(), 0}; + return av_codec_get_tag( table, id ); +} + +static void wave_format_ex_init( const AVCodecParameters *params, WAVEFORMATEX *format, UINT32 format_size, WORD format_tag ) +{ + memset( format, 0, format_size ); + format->cbSize = format_size - sizeof(*format); + format->wFormatTag = format_tag; +#if LIBAVUTIL_VERSION_MAJOR >= 58 + format->nChannels = params->ch_layout.nb_channels; +#else + format->nChannels = params->channels; +#endif + format->nSamplesPerSec = params->sample_rate; + format->wBitsPerSample = av_get_bits_per_sample( params->codec_id ); + if (!format->wBitsPerSample) format->wBitsPerSample = params->bits_per_coded_sample; + if (!(format->nBlockAlign = params->block_align)) format->nBlockAlign = format->wBitsPerSample * format->nChannels / 8; + if (!(format->nAvgBytesPerSec = params->bit_rate / 8)) format->nAvgBytesPerSec = format->nSamplesPerSec * format->nBlockAlign; +} + +static NTSTATUS wave_format_extensible_from_codec_params( const AVCodecParameters *params, WAVEFORMATEXTENSIBLE *format, UINT32 *format_size, + UINT wave_format_size, const GUID *subtype, UINT64 channel_mask ) +{ + UINT32 capacity = *format_size; + + *format_size = max( wave_format_size, sizeof(*format) + params->extradata_size ); + if (*format_size > capacity) return STATUS_BUFFER_TOO_SMALL; + + wave_format_ex_init( params, &format->Format, *format_size, WAVE_FORMAT_EXTENSIBLE ); + if (params->extradata_size && params->extradata) memcpy( format + 1, params->extradata, params->extradata_size ); + format->Samples.wValidBitsPerSample = 0; + format->dwChannelMask = channel_mask; + format->SubFormat = *subtype; + + TRACE( "tag %#x, %u channels, sample rate %u, %u bytes/sec, alignment %u, %u bits/sample, %u valid bps," + " channel mask %#x, subtype %s (%s).\n", 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, + debugstr_guid(&format->SubFormat), debugstr_fourcc(format->SubFormat.Data1) ); + if (format->Format.cbSize) + { + UINT extra_size = sizeof(WAVEFORMATEX) + format->Format.cbSize - sizeof(WAVEFORMATEXTENSIBLE); + TRACE_HEXDUMP( format + 1, extra_size ); + } + + return STATUS_SUCCESS; +} + +static NTSTATUS wave_format_ex_from_codec_params( const AVCodecParameters *params, WAVEFORMATEX *format, UINT32 *format_size, + UINT32 wave_format_size, WORD format_tag ) +{ + UINT32 capacity = *format_size; + + *format_size = max( wave_format_size, sizeof(*format) + params->extradata_size ); + if (*format_size > capacity) return STATUS_BUFFER_TOO_SMALL; + + wave_format_ex_init( params, format, *format_size, format_tag ); + if (params->extradata_size && params->extradata) memcpy( format + 1, params->extradata, params->extradata_size ); + + TRACE( "tag %#x, %u channels, sample rate %u, %u bytes/sec, alignment %u, %u bits/sample.\n", + format->wFormatTag, format->nChannels, (int)format->nSamplesPerSec, (int)format->nAvgBytesPerSec, + format->nBlockAlign, format->wBitsPerSample ); + if (format->cbSize) TRACE_HEXDUMP( format + 1, format->cbSize ); + + return STATUS_SUCCESS; +} + +static NTSTATUS audio_format_from_codec_params( const AVCodecParameters *params, void *format, UINT32 *format_size ) +{ + UINT64 channel_mask; + WORD format_tag; + int channels; + +#if LIBAVUTIL_VERSION_MAJOR >= 58 + if (!(channels = params->ch_layout.nb_channels)) channels = 1; + if (params->ch_layout.order != AV_CHANNEL_ORDER_NATIVE) channel_mask = 0; + else channel_mask = params->ch_layout.u.mask; +#else + if (!(channels = params->channels)) channels = 1; + channel_mask = params->channel_layout; +#endif + + format_tag = wave_format_tag_from_codec_id( params->codec_id ); + if (format_tag == WAVE_FORMAT_EXTENSIBLE || format_tag >> 16 || (channels > 2 && channel_mask != 0)) + { + GUID subtype = MFAudioFormat_Base; + subtype.Data1 = format_tag; + return wave_format_extensible_from_codec_params( params, format, format_size, sizeof(WAVEFORMATEXTENSIBLE), + &subtype, channel_mask ); + } + + return wave_format_ex_from_codec_params( params, format, format_size, sizeof(WAVEFORMATEX), format_tag ); +} + static GUID subtype_from_pixel_format( enum AVPixelFormat fmt ) { switch (fmt) @@ -170,7 +267,7 @@ NTSTATUS media_type_from_codec_params( const AVCodecParameters *params, const AV if (params->codec_type == AVMEDIA_TYPE_AUDIO) { media_type->major = MFMediaType_Audio; - return STATUS_SUCCESS; + return audio_format_from_codec_params( params, media_type->audio, &media_type->format_size ); }
if (params->codec_type == AVMEDIA_TYPE_VIDEO)
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mfsrcsnk/media_source.c | 188 ++++++++++++++++++++++++++++++++++- 1 file changed, 185 insertions(+), 3 deletions(-)
diff --git a/dlls/mfsrcsnk/media_source.c b/dlls/mfsrcsnk/media_source.c index 7f79c87b3db..31c9b82d52a 100644 --- a/dlls/mfsrcsnk/media_source.c +++ b/dlls/mfsrcsnk/media_source.c @@ -72,6 +72,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); #define DEFINE_MF_ASYNC_CALLBACK(type, name, base_iface) \ DEFINE_MF_ASYNC_CALLBACK_(type, name, type##_from_##name, type##_##name, name##_iface, &object->base_iface)
+struct media_stream +{ + IMFMediaStream IMFMediaStream_iface; + LONG refcount; + + IMFMediaSource *source; + IMFMediaEventQueue *queue; +}; + struct media_source { IMFMediaSource IMFMediaSource_iface; @@ -95,6 +104,7 @@ struct media_source WCHAR mime_type[256];
UINT *stream_map; + struct media_stream **streams;
enum { @@ -108,6 +118,162 @@ static struct media_source *media_source_from_IMFMediaSource(IMFMediaSource *ifa return CONTAINING_RECORD(iface, struct media_source, IMFMediaSource_iface); }
+static struct media_stream *media_stream_from_IMFMediaStream(IMFMediaStream *iface) +{ + return CONTAINING_RECORD(iface, struct media_stream, IMFMediaStream_iface); +} + +static HRESULT WINAPI media_stream_QueryInterface(IMFMediaStream *iface, REFIID riid, void **out) +{ + struct media_stream *stream = media_stream_from_IMFMediaStream(iface); + + TRACE("stream %p, riid %s, out %p\n", stream, debugstr_guid(riid), out); + + if (IsEqualIID(riid, &IID_IUnknown) + || IsEqualIID(riid, &IID_IMFMediaEventGenerator) + || IsEqualIID(riid, &IID_IMFMediaStream)) + { + IMFMediaStream_AddRef(&stream->IMFMediaStream_iface); + *out = &stream->IMFMediaStream_iface; + return S_OK; + } + + FIXME("Unsupported interface %s\n", debugstr_guid(riid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI media_stream_AddRef(IMFMediaStream *iface) +{ + struct media_stream *stream = media_stream_from_IMFMediaStream(iface); + ULONG refcount = InterlockedIncrement(&stream->refcount); + TRACE("stream %p, refcount %ld\n", stream, refcount); + return refcount; +} + +static ULONG WINAPI media_stream_Release(IMFMediaStream *iface) +{ + struct media_stream *stream = media_stream_from_IMFMediaStream(iface); + ULONG refcount = InterlockedDecrement(&stream->refcount); + + TRACE("stream %p, refcount %ld\n", stream, refcount); + + if (!refcount) + { + IMFMediaSource_Release(stream->source); + IMFMediaEventQueue_Release(stream->queue); + free(stream); + } + + return refcount; +} + +static HRESULT WINAPI media_stream_GetEvent(IMFMediaStream *iface, DWORD flags, IMFMediaEvent **event) +{ + struct media_stream *stream = media_stream_from_IMFMediaStream(iface); + TRACE("stream %p, flags %#lx, event %p\n", stream, flags, event); + return IMFMediaEventQueue_GetEvent(stream->queue, flags, event); +} + +static HRESULT WINAPI media_stream_BeginGetEvent(IMFMediaStream *iface, IMFAsyncCallback *callback, IUnknown *state) +{ + struct media_stream *stream = media_stream_from_IMFMediaStream(iface); + TRACE("stream %p, callback %p, state %p\n", stream, callback, state); + return IMFMediaEventQueue_BeginGetEvent(stream->queue, callback, state); +} + +static HRESULT WINAPI media_stream_EndGetEvent(IMFMediaStream *iface, IMFAsyncResult *result, IMFMediaEvent **event) +{ + struct media_stream *stream = media_stream_from_IMFMediaStream(iface); + TRACE("stream %p, result %p, event %p\n", stream, result, event); + return IMFMediaEventQueue_EndGetEvent(stream->queue, result, event); +} + +static HRESULT WINAPI media_stream_QueueEvent(IMFMediaStream *iface, MediaEventType event_type, REFGUID ext_type, + HRESULT hr, const PROPVARIANT *value) +{ + struct media_stream *stream = media_stream_from_IMFMediaStream(iface); + TRACE("stream %p, event_type %#lx, ext_type %s, hr %#lx, value %p\n", stream, event_type, debugstr_guid(ext_type), hr, value); + return IMFMediaEventQueue_QueueEventParamVar(stream->queue, event_type, ext_type, hr, value); +} + +static HRESULT WINAPI media_stream_GetMediaSource(IMFMediaStream *iface, IMFMediaSource **out) +{ + struct media_stream *stream = media_stream_from_IMFMediaStream(iface); + struct media_source *source = media_source_from_IMFMediaSource(stream->source); + HRESULT hr = S_OK; + + TRACE("stream %p, out %p\n", stream, out); + + EnterCriticalSection(&source->cs); + + if (source->state == SOURCE_SHUTDOWN) + hr = MF_E_SHUTDOWN; + else + { + IMFMediaSource_AddRef(&source->IMFMediaSource_iface); + *out = &source->IMFMediaSource_iface; + } + + LeaveCriticalSection(&source->cs); + + return hr; +} + +static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IMFStreamDescriptor **descriptor) +{ + struct media_stream *stream = media_stream_from_IMFMediaStream(iface); + FIXME("stream %p, descriptor %p, stub!\n", stream, descriptor); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token) +{ + struct media_stream *stream = media_stream_from_IMFMediaStream(iface); + FIXME("stream %p, token %p, stub!\n", stream, token); + return E_NOTIMPL; +} + +static const IMFMediaStreamVtbl media_stream_vtbl = +{ + media_stream_QueryInterface, + media_stream_AddRef, + media_stream_Release, + media_stream_GetEvent, + media_stream_BeginGetEvent, + media_stream_EndGetEvent, + media_stream_QueueEvent, + media_stream_GetMediaSource, + media_stream_GetStreamDescriptor, + media_stream_RequestSample, +}; + +static HRESULT media_stream_create(IMFMediaSource *source, struct media_stream **out) +{ + struct media_stream *object; + HRESULT hr; + + TRACE("source %p, out %p\n", source, out); + + if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; + + object->IMFMediaStream_iface.lpVtbl = &media_stream_vtbl; + object->refcount = 1; + + if (FAILED(hr = MFCreateEventQueue(&object->queue))) + { + free(object); + return hr; + } + + IMFMediaSource_AddRef((object->source = source)); + TRACE("Created stream object %p\n", object); + + *out = object; + return S_OK; +} + static struct media_source *media_source_from_IMFGetService(IMFGetService *iface) { return CONTAINING_RECORD(iface, struct media_source, IMFGetService_iface); @@ -345,6 +511,7 @@ static ULONG WINAPI media_source_Release(IMFMediaSource *iface)
winedmo_demuxer_destroy(&source->winedmo_demuxer); free(source->stream_map); + free(source->streams);
IMFMediaEventQueue_Release(source->queue); IMFByteStream_Release(source->stream); @@ -458,6 +625,13 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) IMFMediaEventQueue_Shutdown(source->queue); IMFByteStream_Close(source->stream);
+ while (source->stream_count--) + { + struct media_stream *stream = source->streams[source->stream_count]; + IMFMediaEventQueue_Shutdown(stream->queue); + IMFMediaStream_Release(&stream->IMFMediaStream_iface); + } + LeaveCriticalSection(&source->cs);
return S_OK; @@ -569,6 +743,7 @@ static NTSTATUS CDECL media_source_read_cb(struct winedmo_stream *stream, BYTE * static HRESULT media_source_async_create(struct media_source *source, IMFAsyncResult *result) { IUnknown *state = IMFAsyncResult_GetStateNoAddRef(result); + UINT i, stream_count; NTSTATUS status; HRESULT hr;
@@ -589,20 +764,27 @@ static HRESULT media_source_async_create(struct media_source *source, IMFAsyncRe source->winedmo_stream.p_read = media_source_read_cb;
if ((status = winedmo_demuxer_create(source->url, &source->winedmo_stream, source->file_size, &source->duration, - &source->stream_count, source->mime_type, &source->winedmo_demuxer))) + &stream_count, source->mime_type, &source->winedmo_demuxer))) { WARN("Failed to create demuxer, status %#lx\n", status); hr = HRESULT_FROM_NT(status); goto done; }
- if (!(source->stream_map = calloc(source->stream_count, sizeof(*source->stream_map)))) + if (!(source->stream_map = calloc(stream_count, sizeof(*source->stream_map))) + || !(source->streams = calloc(stream_count, sizeof(*source->streams)))) { hr = E_OUTOFMEMORY; goto done; }
- media_source_init_stream_map(source, source->stream_count); + media_source_init_stream_map(source, stream_count); + + for (i = 0; SUCCEEDED(hr) && i < stream_count; ++i) + { + if (SUCCEEDED(hr = media_stream_create(&source->IMFMediaSource_iface, &source->streams[i]))) + source->stream_count++; + }
done: IMFAsyncResult_SetStatus(result, hr);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mfsrcsnk/media_source.c | 158 +++++++++++++++++++++++++++++++---- 1 file changed, 144 insertions(+), 14 deletions(-)
diff --git a/dlls/mfsrcsnk/media_source.c b/dlls/mfsrcsnk/media_source.c index 31c9b82d52a..6c367111b49 100644 --- a/dlls/mfsrcsnk/media_source.c +++ b/dlls/mfsrcsnk/media_source.c @@ -79,6 +79,7 @@ struct media_stream
IMFMediaSource *source; IMFMediaEventQueue *queue; + IMFStreamDescriptor *descriptor; };
struct media_source @@ -161,6 +162,7 @@ static ULONG WINAPI media_stream_Release(IMFMediaStream *iface) if (!refcount) { IMFMediaSource_Release(stream->source); + IMFStreamDescriptor_Release(stream->descriptor); IMFMediaEventQueue_Release(stream->queue); free(stream); } @@ -223,8 +225,24 @@ static HRESULT WINAPI media_stream_GetMediaSource(IMFMediaStream *iface, IMFMedi static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IMFStreamDescriptor **descriptor) { struct media_stream *stream = media_stream_from_IMFMediaStream(iface); - FIXME("stream %p, descriptor %p, stub!\n", stream, descriptor); - return E_NOTIMPL; + struct media_source *source = media_source_from_IMFMediaSource(stream->source); + HRESULT hr = S_OK; + + TRACE("stream %p, descriptor %p\n", stream, descriptor); + + EnterCriticalSection(&source->cs); + + if (source->state == SOURCE_SHUTDOWN) + hr = MF_E_SHUTDOWN; + else + { + IMFStreamDescriptor_AddRef(stream->descriptor); + *descriptor = stream->descriptor; + } + + LeaveCriticalSection(&source->cs); + + return hr; }
static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token) @@ -248,12 +266,12 @@ static const IMFMediaStreamVtbl media_stream_vtbl = media_stream_RequestSample, };
-static HRESULT media_stream_create(IMFMediaSource *source, struct media_stream **out) +static HRESULT media_stream_create(IMFMediaSource *source, IMFStreamDescriptor *descriptor, struct media_stream **out) { struct media_stream *object; HRESULT hr;
- TRACE("source %p, out %p\n", source, out); + TRACE("source %p, descriptor %p, out %p\n", source, descriptor, out);
if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; @@ -268,6 +286,8 @@ static HRESULT media_stream_create(IMFMediaSource *source, struct media_stream * }
IMFMediaSource_AddRef((object->source = source)); + IMFStreamDescriptor_AddRef((object->descriptor = descriptor)); + TRACE("Created stream object %p\n", object);
*out = object; @@ -577,11 +597,55 @@ static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWO return hr; }
+static HRESULT media_source_create_presentation_descriptor(struct media_source *source, IMFPresentationDescriptor **descriptor) +{ + IMFStreamDescriptor **descriptors; + HRESULT hr; + UINT i; + + if (!(descriptors = malloc(source->stream_count * sizeof(*descriptors)))) + return E_OUTOFMEMORY; + for (i = 0; i < source->stream_count; ++i) + descriptors[i] = source->streams[i]->descriptor; + hr = MFCreatePresentationDescriptor(source->stream_count, descriptors, descriptor); + free(descriptors); + + return hr; +} + static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor) { struct media_source *source = media_source_from_IMFMediaSource(iface); - FIXME("source %p, descriptor %p, stub!\n", source, descriptor); - return E_NOTIMPL; + HRESULT hr; + UINT i; + + TRACE("source %p, descriptor %p\n", source, descriptor); + + EnterCriticalSection(&source->cs); + + if (source->state == SOURCE_SHUTDOWN) + hr = MF_E_SHUTDOWN; + else if (SUCCEEDED(hr = media_source_create_presentation_descriptor(source, descriptor))) + { + if (FAILED(hr = IMFPresentationDescriptor_SetString(*descriptor, &MF_PD_MIME_TYPE, source->mime_type))) + WARN("Failed to set presentation descriptor MF_PD_MIME_TYPE, hr %#lx\n", hr); + if (FAILED(hr = IMFPresentationDescriptor_SetUINT64(*descriptor, &MF_PD_TOTAL_FILE_SIZE, source->file_size))) + WARN("Failed to set presentation descriptor MF_PD_TOTAL_FILE_SIZE, hr %#lx\n", hr); + if (FAILED(hr = IMFPresentationDescriptor_SetUINT64(*descriptor, &MF_PD_DURATION, source->duration))) + WARN("Failed to set presentation descriptor MF_PD_DURATION, hr %#lx\n", hr); + + for (i = 0; i < source->stream_count; ++i) + { + if (FAILED(hr = IMFPresentationDescriptor_SelectStream(*descriptor, i))) + WARN("Failed to select stream %u, hr %#lx\n", i, hr); + } + + hr = S_OK; + } + + LeaveCriticalSection(&source->cs); + + return hr; }
static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *descriptor, const GUID *format, @@ -654,12 +718,42 @@ static const IMFMediaSourceVtbl media_source_vtbl = media_source_Shutdown, };
-static HRESULT get_stream_media_type(struct winedmo_demuxer demuxer, UINT index, GUID *major) +static HRESULT media_type_from_mf_video_format( const MFVIDEOFORMAT *format, IMFMediaType **media_type ) +{ + HRESULT hr; + + TRACE("format %p, media_type %p\n", format, media_type); + + if (FAILED(hr = MFCreateVideoMediaType( format, (IMFVideoMediaType **)media_type )) || + format->dwSize <= sizeof(*format)) + return hr; + + if (FAILED(IMFMediaType_GetItem(*media_type, &MF_MT_VIDEO_ROTATION, NULL))) + IMFMediaType_SetUINT32(*media_type, &MF_MT_VIDEO_ROTATION, MFVideoRotationFormat_0); + + return hr; +} + +static HRESULT media_type_from_winedmo_format( GUID major, union winedmo_format *format, IMFMediaType **media_type ) +{ + TRACE("major %p, format %p, media_type %p\n", &major, format, media_type); + + if (IsEqualGUID( &major, &MFMediaType_Video )) + return media_type_from_mf_video_format( &format->video, media_type ); + if (IsEqualGUID( &major, &MFMediaType_Audio )) + return MFCreateAudioMediaType( &format->audio, (IMFAudioMediaType **)media_type ); + + FIXME( "Unsupported major type %s\n", debugstr_guid( &major ) ); + return E_NOTIMPL; +} + +static HRESULT get_stream_media_type(struct winedmo_demuxer demuxer, UINT index, GUID *major, IMFMediaType **media_type) { union winedmo_format *format; NTSTATUS status; + HRESULT hr;
- TRACE("demuxer %p, index %u\n", &demuxer, index); + TRACE("demuxer %p, index %u, media_type %p\n", &demuxer, index, media_type);
if ((status = winedmo_demuxer_stream_type(demuxer, index, major, &format))) { @@ -667,8 +761,9 @@ static HRESULT get_stream_media_type(struct winedmo_demuxer demuxer, UINT index, return HRESULT_FROM_NT(status); }
+ hr = media_type ? media_type_from_winedmo_format(*major, format, media_type) : S_OK; free(format); - return S_OK; + return hr; }
static void media_source_init_stream_map(struct media_source *source, UINT stream_count) @@ -690,7 +785,7 @@ static void media_source_init_stream_map(struct media_source *source, UINT strea
for (i = stream_count - 1; i >= 0; i--) { - if (FAILED(get_stream_media_type(source->winedmo_demuxer, i, &major))) + if (FAILED(get_stream_media_type(source->winedmo_demuxer, i, &major, NULL))) continue; if (IsEqualGUID(&major, &MFMediaType_Audio)) { @@ -700,7 +795,7 @@ static void media_source_init_stream_map(struct media_source *source, UINT strea } for (i = stream_count - 1; i >= 0; i--) { - if (FAILED(get_stream_media_type(source->winedmo_demuxer, i, &major))) + if (FAILED(get_stream_media_type(source->winedmo_demuxer, i, &major, NULL))) continue; if (IsEqualGUID(&major, &MFMediaType_Video)) { @@ -710,7 +805,7 @@ static void media_source_init_stream_map(struct media_source *source, UINT strea } for (i = stream_count - 1; i >= 0; i--) { - if (FAILED(get_stream_media_type(source->winedmo_demuxer, i, &major))) + if (FAILED(get_stream_media_type(source->winedmo_demuxer, i, &major, NULL))) continue; if (!IsEqualGUID(&major, &MFMediaType_Audio) && !IsEqualGUID(&major, &MFMediaType_Video)) { @@ -720,6 +815,30 @@ static void media_source_init_stream_map(struct media_source *source, UINT strea } }
+static HRESULT stream_descriptor_create(UINT32 id, IMFMediaType *media_type, IMFStreamDescriptor **out) +{ + IMFStreamDescriptor *descriptor; + IMFMediaTypeHandler *handler; + HRESULT hr; + + TRACE("id %d, media_type %p, out %p\n", id, media_type, out); + + *out = NULL; + if (FAILED(hr = MFCreateStreamDescriptor(id, 1, &media_type, &descriptor))) + return hr; + + if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(descriptor, &handler))) + IMFStreamDescriptor_Release(descriptor); + else + { + if (SUCCEEDED(hr = IMFMediaTypeHandler_SetCurrentMediaType(handler, media_type))) + *out = descriptor; + IMFMediaTypeHandler_Release(handler); + } + + return hr; +} + static NTSTATUS CDECL media_source_seek_cb( struct winedmo_stream *stream, UINT64 *pos ) { struct media_source *source = CONTAINING_RECORD(stream, struct media_source, winedmo_stream); @@ -782,8 +901,19 @@ static HRESULT media_source_async_create(struct media_source *source, IMFAsyncRe
for (i = 0; SUCCEEDED(hr) && i < stream_count; ++i) { - if (SUCCEEDED(hr = media_stream_create(&source->IMFMediaSource_iface, &source->streams[i]))) - source->stream_count++; + IMFStreamDescriptor *descriptor; + IMFMediaType *media_type; + GUID major; + + if (FAILED(hr = get_stream_media_type(source->winedmo_demuxer, source->stream_map[i], &major, &media_type))) + goto done; + if (SUCCEEDED(hr = stream_descriptor_create(i + 1, media_type, &descriptor))) + { + if (SUCCEEDED(hr = media_stream_create(&source->IMFMediaSource_iface, descriptor, &source->streams[i]))) + source->stream_count++; + IMFStreamDescriptor_Release(descriptor); + } + IMFMediaType_Release(media_type); }
done:
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winedmo/unix_media_type.c | 41 +++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-)
diff --git a/dlls/winedmo/unix_media_type.c b/dlls/winedmo/unix_media_type.c index 67ea1f9baba..ff4625530aa 100644 --- a/dlls/winedmo/unix_media_type.c +++ b/dlls/winedmo/unix_media_type.c @@ -137,12 +137,44 @@ static NTSTATUS wave_format_ex_from_codec_params( const AVCodecParameters *param return STATUS_SUCCESS; }
+static NTSTATUS heaac_wave_format_from_codec_params( const AVCodecParameters *params, HEAACWAVEINFO *format, UINT32 *format_size ) +{ + UINT32 capacity = *format_size; + + *format_size = sizeof(*format) + params->extradata_size; + if (*format_size > capacity) return STATUS_BUFFER_TOO_SMALL; + + wave_format_ex_init( params, &format->wfx, *format_size, WAVE_FORMAT_MPEG_HEAAC ); + if (params->extradata_size && params->extradata) memcpy( format + 1, params->extradata, params->extradata_size ); + format->wPayloadType = 0; + format->wAudioProfileLevelIndication = 0; + format->wStructType = 0; + + TRACE( "tag %#x, %u channels, sample rate %u, %u bytes/sec, alignment %u, %u bits/sample, payload %#x, " + "level %#x, struct %#x.\n", format->wfx.wFormatTag, format->wfx.nChannels, (int)format->wfx.nSamplesPerSec, + (int)format->wfx.nAvgBytesPerSec, format->wfx.nBlockAlign, format->wfx.wBitsPerSample, format->wPayloadType, + format->wAudioProfileLevelIndication, format->wStructType ); + if (format->wfx.cbSize) TRACE_HEXDUMP( format + 1, sizeof(WAVEFORMATEX) + format->wfx.cbSize - sizeof(*format) ); + + return STATUS_SUCCESS; +} + static NTSTATUS audio_format_from_codec_params( const AVCodecParameters *params, void *format, UINT32 *format_size ) { + UINT wave_format_size = sizeof(WAVEFORMATEX); UINT64 channel_mask; WORD format_tag; int channels;
+ if (params->codec_id == AV_CODEC_ID_AAC) return heaac_wave_format_from_codec_params( params, format, format_size ); + if (params->codec_id == AV_CODEC_ID_MP1) wave_format_size = sizeof(MPEG1WAVEFORMAT); + if (params->codec_id == AV_CODEC_ID_MP3) wave_format_size = sizeof(MPEGLAYER3WAVEFORMAT); + if (params->codec_id == AV_CODEC_ID_WMAV1) wave_format_size = sizeof(MSAUDIO1WAVEFORMAT); + if (params->codec_id == AV_CODEC_ID_WMAV2) wave_format_size = sizeof(WMAUDIO2WAVEFORMAT); + if (params->codec_id == AV_CODEC_ID_WMAPRO) wave_format_size = sizeof(WMAUDIO3WAVEFORMAT); + if (params->codec_id == AV_CODEC_ID_WMAVOICE) wave_format_size = sizeof(WMAUDIO3WAVEFORMAT); + if (params->codec_id == AV_CODEC_ID_WMALOSSLESS) wave_format_size = sizeof(WMAUDIO3WAVEFORMAT); + #if LIBAVUTIL_VERSION_MAJOR >= 58 if (!(channels = params->ch_layout.nb_channels)) channels = 1; if (params->ch_layout.order != AV_CHANNEL_ORDER_NATIVE) channel_mask = 0; @@ -157,11 +189,12 @@ static NTSTATUS audio_format_from_codec_params( const AVCodecParameters *params, { GUID subtype = MFAudioFormat_Base; subtype.Data1 = format_tag; - return wave_format_extensible_from_codec_params( params, format, format_size, sizeof(WAVEFORMATEXTENSIBLE), + wave_format_size += sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); + return wave_format_extensible_from_codec_params( params, format, format_size, wave_format_size, &subtype, channel_mask ); }
- return wave_format_ex_from_codec_params( params, format, format_size, sizeof(WAVEFORMATEX), format_tag ); + return wave_format_ex_from_codec_params( params, format, format_size, wave_format_size, format_tag ); }
static GUID subtype_from_pixel_format( enum AVPixelFormat fmt ) @@ -205,7 +238,9 @@ static void mf_video_format_init( const AVCodecParameters *params, MFVIDEOFORMAT else { format->guidFormat = MFVideoFormat_Base; - if (params->codec_tag) format->guidFormat.Data1 = params->codec_tag; + if (params->codec_id == AV_CODEC_ID_MPEG1VIDEO) format->guidFormat = MEDIASUBTYPE_MPEG1Payload; + else if (params->codec_id == AV_CODEC_ID_H264) format->guidFormat.Data1 = MFVideoFormat_H264.Data1; + else if (params->codec_tag) format->guidFormat.Data1 = params->codec_tag; else format->guidFormat.Data1 = video_format_tag_from_codec_id( params->codec_id ); }
Emil Velikov (@xexaxo) commented about dlls/winedmo/winedmo.spec:
@ cdecl winedmo_demuxer_check(str) @ cdecl winedmo_demuxer_create(wstr ptr ptr ptr ptr ptr ptr)
We should be updating this instance right?
Emil Velikov (@xexaxo) commented about dlls/winedmo/winedmo.spec:
@ cdecl winedmo_demuxer_check(str) @ cdecl winedmo_demuxer_create(wstr ptr ptr ptr ptr ptr ptr) @ cdecl winedmo_demuxer_destroy(ptr) -@ cdecl winedmo_demuxer_stream_type(int64 ptr ptr) +@ cdecl winedmo_demuxer_stream_type(int64 long ptr ptr)
Technically this should be a separate commit - not sure how much it matters though.
Thanks for sorting it out :thumbsup: