[PATCH 1/4] winegstreamer: Implement IWMReaderAdvanced::GetMaxStreamSampleSize().

Zebediah Figura zfigura at codeweavers.com
Thu Nov 11 23:43:21 CST 2021


Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
 dlls/winegstreamer/gst_private.h    |   3 +
 dlls/winegstreamer/quartz_parser.c  | 113 ++++++++++++++++++++--------
 dlls/winegstreamer/wm_asyncreader.c |  11 ++-
 dlls/winegstreamer/wm_reader.c      |  18 +++++
 dlls/wmvcore/tests/wmvcore.c        |  18 ++++-
 5 files changed, 127 insertions(+), 36 deletions(-)

diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index e0f8bdae4a6..9e1d67417d4 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -96,6 +96,8 @@ uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream) DECLSPEC
 void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate,
         uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags) DECLSPEC_HIDDEN;
 
+unsigned int wg_format_get_max_size(const struct wg_format *format);
+
 HRESULT avi_splitter_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
 HRESULT decodebin_parser_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
 HRESULT mpeg_splitter_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
@@ -168,6 +170,7 @@ struct wm_reader_ops
 
 void wm_reader_cleanup(struct wm_reader *reader);
 HRESULT wm_reader_close(struct wm_reader *reader);
+HRESULT wm_reader_get_max_stream_size(struct wm_reader *reader, WORD stream_number, DWORD *size);
 HRESULT wm_reader_get_output_format(struct wm_reader *reader, DWORD output,
         DWORD index, IWMOutputMediaProps **props);
 HRESULT wm_reader_get_output_format_count(struct wm_reader *reader, DWORD output, DWORD *count);
diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c
index 89df41feb66..d91a93532c4 100644
--- a/dlls/winegstreamer/quartz_parser.c
+++ b/dlls/winegstreamer/quartz_parser.c
@@ -231,44 +231,97 @@ static bool amt_from_wg_format_audio(AM_MEDIA_TYPE *mt, const struct wg_format *
 
 #define ALIGN(n, alignment) (((n) + (alignment) - 1) & ~((alignment) - 1))
 
-static unsigned int get_image_size(const struct wg_format *format)
+unsigned int wg_format_get_max_size(const struct wg_format *format)
 {
-    unsigned int width = format->u.video.width, height = format->u.video.height;
-
-    switch (format->u.video.format)
+    switch (format->major_type)
     {
-        case WG_VIDEO_FORMAT_BGRA:
-        case WG_VIDEO_FORMAT_BGRx:
-        case WG_VIDEO_FORMAT_AYUV:
-            return width * height * 4;
+        case WG_MAJOR_TYPE_VIDEO:
+        {
+            unsigned int width = format->u.video.width, height = format->u.video.height;
 
-        case WG_VIDEO_FORMAT_BGR:
-            return ALIGN(width * 3, 4) * height;
+            switch (format->u.video.format)
+            {
+                case WG_VIDEO_FORMAT_BGRA:
+                case WG_VIDEO_FORMAT_BGRx:
+                case WG_VIDEO_FORMAT_AYUV:
+                    return width * height * 4;
 
-        case WG_VIDEO_FORMAT_RGB15:
-        case WG_VIDEO_FORMAT_RGB16:
-        case WG_VIDEO_FORMAT_UYVY:
-        case WG_VIDEO_FORMAT_YUY2:
-        case WG_VIDEO_FORMAT_YVYU:
-            return ALIGN(width * 2, 4) * height;
+                case WG_VIDEO_FORMAT_BGR:
+                    return ALIGN(width * 3, 4) * height;
 
-        case WG_VIDEO_FORMAT_I420:
-        case WG_VIDEO_FORMAT_YV12:
-            return ALIGN(width, 4) * ALIGN(height, 2) /* Y plane */
-                    + 2 * ALIGN((width + 1) / 2, 4) * ((height + 1) / 2); /* U and V planes */
+                case WG_VIDEO_FORMAT_RGB15:
+                case WG_VIDEO_FORMAT_RGB16:
+                case WG_VIDEO_FORMAT_UYVY:
+                case WG_VIDEO_FORMAT_YUY2:
+                case WG_VIDEO_FORMAT_YVYU:
+                    return ALIGN(width * 2, 4) * height;
 
-        case WG_VIDEO_FORMAT_NV12:
-            return ALIGN(width, 4) * ALIGN(height, 2) /* Y plane */
-                    + ALIGN(width, 4) * ((height + 1) / 2); /* U/V plane */
+                case WG_VIDEO_FORMAT_I420:
+                case WG_VIDEO_FORMAT_YV12:
+                    return ALIGN(width, 4) * ALIGN(height, 2) /* Y plane */
+                            + 2 * ALIGN((width + 1) / 2, 4) * ((height + 1) / 2); /* U and V planes */
 
-        case WG_VIDEO_FORMAT_CINEPAK:
-            /* Both ffmpeg's encoder and a Cinepak file seen in the wild report
-             * 24 bpp. ffmpeg sets biSizeImage as below; others may be smaller,
-             * but as long as every sample fits into our allocator, we're fine. */
-            return width * height * 3;
+                case WG_VIDEO_FORMAT_NV12:
+                    return ALIGN(width, 4) * ALIGN(height, 2) /* Y plane */
+                            + ALIGN(width, 4) * ((height + 1) / 2); /* U/V plane */
 
-        case WG_VIDEO_FORMAT_UNKNOWN:
+                case WG_VIDEO_FORMAT_CINEPAK:
+                    /* Both ffmpeg's encoder and a Cinepak file seen in the wild report
+                     * 24 bpp. ffmpeg sets biSizeImage as below; others may be smaller,
+                     * but as long as every sample fits into our allocator, we're fine. */
+                    return width * height * 3;
+
+                case WG_VIDEO_FORMAT_UNKNOWN:
+                    FIXME("Cannot guess maximum sample size for unknown video format.\n");
+                    return 0;
+            }
             break;
+        }
+
+        case WG_MAJOR_TYPE_AUDIO:
+        {
+            unsigned int rate = format->u.audio.rate, channels = format->u.audio.channels;
+
+            /* Actually we don't know how large of a sample GStreamer will give
+             * us. Hopefully 1 second is enough... */
+
+            switch (format->u.audio.format)
+            {
+                case WG_AUDIO_FORMAT_U8:
+                    return rate * channels;
+
+                case WG_AUDIO_FORMAT_S16LE:
+                    return rate * channels * 2;
+
+                case WG_AUDIO_FORMAT_S24LE:
+                    return rate * channels * 3;
+
+                case WG_AUDIO_FORMAT_S32LE:
+                case WG_AUDIO_FORMAT_F32LE:
+                    return rate * channels * 4;
+
+                case WG_AUDIO_FORMAT_F64LE:
+                    return rate * channels * 8;
+
+                case WG_AUDIO_FORMAT_MPEG1_LAYER1:
+                    return 56000;
+
+                case WG_AUDIO_FORMAT_MPEG1_LAYER2:
+                    return 48000;
+
+                case WG_AUDIO_FORMAT_MPEG1_LAYER3:
+                    return 40000;
+
+                case WG_AUDIO_FORMAT_UNKNOWN:
+                    FIXME("Cannot guess maximum sample size for unknown audio format.\n");
+                    return 0;
+            }
+            break;
+        }
+
+        case WG_MAJOR_TYPE_UNKNOWN:
+            FIXME("Cannot guess maximum sample size for unknown format.\n");
+            return 0;
     }
 
     assert(0);
@@ -338,7 +391,7 @@ static bool amt_from_wg_format_video(AM_MEDIA_TYPE *mt, const struct wg_format *
     video_format->bmiHeader.biPlanes = 1;
     video_format->bmiHeader.biBitCount = format_table[format->u.video.format].depth;
     video_format->bmiHeader.biCompression = format_table[format->u.video.format].compression;
-    video_format->bmiHeader.biSizeImage = get_image_size(format);
+    video_format->bmiHeader.biSizeImage = wg_format_get_max_size(format);
 
     if (format->u.video.format == WG_VIDEO_FORMAT_RGB16)
     {
diff --git a/dlls/winegstreamer/wm_asyncreader.c b/dlls/winegstreamer/wm_asyncreader.c
index b3dd7d41873..6549c9052e1 100644
--- a/dlls/winegstreamer/wm_asyncreader.c
+++ b/dlls/winegstreamer/wm_asyncreader.c
@@ -566,11 +566,14 @@ static HRESULT WINAPI WMReaderAdvanced_GetMaxOutputSampleSize(IWMReaderAdvanced6
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI WMReaderAdvanced_GetMaxStreamSampleSize(IWMReaderAdvanced6 *iface, WORD stream, DWORD *max)
+static HRESULT WINAPI WMReaderAdvanced_GetMaxStreamSampleSize(IWMReaderAdvanced6 *iface,
+        WORD stream_number, DWORD *size)
 {
-    struct async_reader *This = impl_from_IWMReaderAdvanced6(iface);
-    FIXME("(%p)->(%d %p)\n", This, stream, max);
-    return E_NOTIMPL;
+    struct async_reader *reader = impl_from_IWMReaderAdvanced6(iface);
+
+    TRACE("reader %p, stream_number %u, size %p.\n", reader, stream_number, size);
+
+    return wm_reader_get_max_stream_size(&reader->reader, stream_number, size);
 }
 
 static HRESULT WINAPI WMReaderAdvanced_NotifyLateDelivery(IWMReaderAdvanced6 *iface, QWORD lateness)
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c
index a6e73c2857e..deef2031c96 100644
--- a/dlls/winegstreamer/wm_reader.c
+++ b/dlls/winegstreamer/wm_reader.c
@@ -2016,6 +2016,24 @@ HRESULT wm_reader_set_read_compressed(struct wm_reader *reader, WORD stream_numb
     return S_OK;
 }
 
+HRESULT wm_reader_get_max_stream_size(struct wm_reader *reader, WORD stream_number, DWORD *size)
+{
+    struct wm_stream *stream;
+
+    EnterCriticalSection(&reader->cs);
+
+    if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
+    {
+        LeaveCriticalSection(&reader->cs);
+        return E_INVALIDARG;
+    }
+
+    *size = wg_format_get_max_size(&stream->format);
+
+    LeaveCriticalSection(&reader->cs);
+    return S_OK;
+}
+
 void wm_reader_init(struct wm_reader *reader, const struct wm_reader_ops *ops)
 {
     reader->IWMHeaderInfo3_iface.lpVtbl = &header_info_vtbl;
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c
index 9ddd53ab9e7..c979a06fdb0 100644
--- a/dlls/wmvcore/tests/wmvcore.c
+++ b/dlls/wmvcore/tests/wmvcore.c
@@ -1390,7 +1390,9 @@ struct callback
     unsigned int got_closed, got_started, got_sample, got_end_of_streaming, got_eof;
     bool all_streams_off;
     bool allocated_samples;
+
     bool read_compressed;
+    DWORD max_stream_sample_size[2];
 };
 
 static struct callback *impl_from_IWMReaderCallback(IWMReaderCallback *iface)
@@ -1661,6 +1663,7 @@ static HRESULT WINAPI callback_advanced_AllocateForStream(IWMReaderCallbackAdvan
         WORD stream_number, DWORD size, INSSBuffer **sample, void *context)
 {
     struct callback *callback = impl_from_IWMReaderCallbackAdvanced(iface);
+    DWORD max_size = callback->max_stream_sample_size[stream_number - 1];
     struct buffer *object;
 
     if (winetest_debug > 1)
@@ -1670,6 +1673,8 @@ static HRESULT WINAPI callback_advanced_AllocateForStream(IWMReaderCallbackAdvan
     ok(callback->read_compressed, "AllocateForStream() should only be called when reading compressed samples.\n");
     ok(callback->allocated_samples, "AllocateForStream() should only be called when using a custom allocator.\n");
 
+    ok(size <= max_size, "Got size %u, max stream sample size %u.\n", size, max_size);
+
     if (!(object = malloc(offsetof(struct buffer, data[size]))))
         return E_OUTOFMEMORY;
 
@@ -2016,12 +2021,21 @@ static void test_async_reader_compressed(IWMReader *reader,
 {
     HRESULT hr;
 
+    hr = IWMReaderAdvanced2_GetMaxStreamSampleSize(advanced, 0, &callback->max_stream_sample_size[0]);
+    ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+    hr = IWMReaderAdvanced2_GetMaxStreamSampleSize(advanced, 3, &callback->max_stream_sample_size[0]);
+    ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+    hr = IWMReaderAdvanced2_GetMaxStreamSampleSize(advanced, 1, &callback->max_stream_sample_size[0]);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(callback->max_stream_sample_size[0] > 0, "Expected nonzero size.\n");
+    hr = IWMReaderAdvanced2_GetMaxStreamSampleSize(advanced, 2, &callback->max_stream_sample_size[1]);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(callback->max_stream_sample_size[1] > 0, "Expected nonzero size.\n");
+
     hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 0, TRUE);
     ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
-
     hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 3, TRUE);
     ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
-
     hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 1, TRUE);
     ok(hr == S_OK, "Got hr %#x.\n", hr);
     hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 2, TRUE);
-- 
2.33.0




More information about the wine-devel mailing list