winegstreamer: Implement IWMReaderAdvanced::GetMaxStreamSampleSize().

Signed-off-by: Zebediah Figura <zfigura@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2021-11-11 23:43:21 -06:00 committed by Alexandre Julliard
parent 3dbce69fd4
commit 639c04a5b4
5 changed files with 127 additions and 36 deletions

View File

@ -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, 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; 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 avi_splitter_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
HRESULT decodebin_parser_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; 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); void wm_reader_cleanup(struct wm_reader *reader);
HRESULT wm_reader_close(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, HRESULT wm_reader_get_output_format(struct wm_reader *reader, DWORD output,
DWORD index, IWMOutputMediaProps **props); DWORD index, IWMOutputMediaProps **props);
HRESULT wm_reader_get_output_format_count(struct wm_reader *reader, DWORD output, DWORD *count); HRESULT wm_reader_get_output_format_count(struct wm_reader *reader, DWORD output, DWORD *count);

View File

@ -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)) #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->major_type)
switch (format->u.video.format)
{ {
case WG_VIDEO_FORMAT_BGRA: case WG_MAJOR_TYPE_VIDEO:
case WG_VIDEO_FORMAT_BGRx: {
case WG_VIDEO_FORMAT_AYUV: unsigned int width = format->u.video.width, height = format->u.video.height;
return width * height * 4;
case WG_VIDEO_FORMAT_BGR: switch (format->u.video.format)
return ALIGN(width * 3, 4) * height; {
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_BGR:
case WG_VIDEO_FORMAT_RGB16: return ALIGN(width * 3, 4) * height;
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_I420: case WG_VIDEO_FORMAT_RGB15:
case WG_VIDEO_FORMAT_YV12: case WG_VIDEO_FORMAT_RGB16:
return ALIGN(width, 4) * ALIGN(height, 2) /* Y plane */ case WG_VIDEO_FORMAT_UYVY:
+ 2 * ALIGN((width + 1) / 2, 4) * ((height + 1) / 2); /* U and V planes */ case WG_VIDEO_FORMAT_YUY2:
case WG_VIDEO_FORMAT_YVYU:
return ALIGN(width * 2, 4) * height;
case WG_VIDEO_FORMAT_NV12: case WG_VIDEO_FORMAT_I420:
return ALIGN(width, 4) * ALIGN(height, 2) /* Y plane */ case WG_VIDEO_FORMAT_YV12:
+ ALIGN(width, 4) * ((height + 1) / 2); /* U/V plane */ 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: case WG_VIDEO_FORMAT_NV12:
/* Both ffmpeg's encoder and a Cinepak file seen in the wild report return ALIGN(width, 4) * ALIGN(height, 2) /* Y plane */
* 24 bpp. ffmpeg sets biSizeImage as below; others may be smaller, + ALIGN(width, 4) * ((height + 1) / 2); /* U/V plane */
* but as long as every sample fits into our allocator, we're fine. */
return width * height * 3;
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; 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); 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.biPlanes = 1;
video_format->bmiHeader.biBitCount = format_table[format->u.video.format].depth; 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.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) if (format->u.video.format == WG_VIDEO_FORMAT_RGB16)
{ {

View File

@ -566,11 +566,14 @@ static HRESULT WINAPI WMReaderAdvanced_GetMaxOutputSampleSize(IWMReaderAdvanced6
return E_NOTIMPL; 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); struct async_reader *reader = impl_from_IWMReaderAdvanced6(iface);
FIXME("(%p)->(%d %p)\n", This, stream, max);
return E_NOTIMPL; 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) static HRESULT WINAPI WMReaderAdvanced_NotifyLateDelivery(IWMReaderAdvanced6 *iface, QWORD lateness)

View File

@ -1994,6 +1994,24 @@ HRESULT wm_reader_set_read_compressed(struct wm_reader *reader, WORD stream_numb
return S_OK; 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) void wm_reader_init(struct wm_reader *reader, const struct wm_reader_ops *ops)
{ {
reader->IWMHeaderInfo3_iface.lpVtbl = &header_info_vtbl; reader->IWMHeaderInfo3_iface.lpVtbl = &header_info_vtbl;

View File

@ -1390,7 +1390,9 @@ struct callback
unsigned int got_closed, got_started, got_sample, got_end_of_streaming, got_eof; unsigned int got_closed, got_started, got_sample, got_end_of_streaming, got_eof;
bool all_streams_off; bool all_streams_off;
bool allocated_samples; bool allocated_samples;
bool read_compressed; bool read_compressed;
DWORD max_stream_sample_size[2];
}; };
static struct callback *impl_from_IWMReaderCallback(IWMReaderCallback *iface) 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) WORD stream_number, DWORD size, INSSBuffer **sample, void *context)
{ {
struct callback *callback = impl_from_IWMReaderCallbackAdvanced(iface); struct callback *callback = impl_from_IWMReaderCallbackAdvanced(iface);
DWORD max_size = callback->max_stream_sample_size[stream_number - 1];
struct buffer *object; struct buffer *object;
if (winetest_debug > 1) 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->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(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])))) if (!(object = malloc(offsetof(struct buffer, data[size]))))
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
@ -2016,12 +2021,21 @@ static void test_async_reader_compressed(IWMReader *reader,
{ {
HRESULT hr; 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); hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 0, TRUE);
ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 3, TRUE); hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 3, TRUE);
ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 1, TRUE); hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 1, TRUE);
ok(hr == S_OK, "Got hr %#x.\n", hr); ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 2, TRUE); hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 2, TRUE);