winegstreamer: Request the new transform output format explicitly.

This commit is contained in:
Rémi Bernon 2024-03-11 12:47:06 +01:00 committed by Alexandre Julliard
parent 3dd3535a2c
commit 1e8e0d41b4
13 changed files with 107 additions and 57 deletions

View file

@ -521,7 +521,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags,
return hr;
if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, samples->pSample,
info.cbSize, NULL, &samples->dwStatus)))
info.cbSize, &samples->dwStatus)))
wg_sample_queue_flush(decoder->wg_sample_queue, false);
else
samples->dwStatus = MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE;

View file

@ -582,7 +582,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags,
return hr;
if (SUCCEEDED(hr = wg_transform_read_mf(impl->wg_transform, samples->pSample,
info.cbSize, NULL, &samples->dwStatus)))
info.cbSize, &samples->dwStatus)))
wg_sample_queue_flush(impl->wg_sample_queue, false);
return hr;

View file

@ -88,6 +88,7 @@ HRESULT wg_transform_create_mf(IMFMediaType *input_type, IMFMediaType *output_ty
HRESULT wg_transform_create_quartz(const AM_MEDIA_TYPE *input_format, const AM_MEDIA_TYPE *output_format,
const struct wg_transform_attrs *attrs, wg_transform_t *transform);
void wg_transform_destroy(wg_transform_t transform);
bool wg_transform_get_output_format(wg_transform_t transform, struct wg_format *format);
bool wg_transform_set_output_format(wg_transform_t transform, struct wg_format *format);
bool wg_transform_get_status(wg_transform_t transform, bool *accepts_input);
HRESULT wg_transform_drain(wg_transform_t transform);
@ -146,10 +147,16 @@ HRESULT wg_transform_push_quartz(wg_transform_t transform, struct wg_sample *sam
HRESULT wg_transform_push_dmo(wg_transform_t transform, IMediaBuffer *media_buffer,
DWORD flags, REFERENCE_TIME time_stamp, REFERENCE_TIME time_length, struct wg_sample_queue *queue);
HRESULT wg_transform_read_mf(wg_transform_t transform, IMFSample *sample,
DWORD sample_size, struct wg_format *format, DWORD *flags);
DWORD sample_size, DWORD *flags);
HRESULT wg_transform_read_quartz(wg_transform_t transform, struct wg_sample *sample);
HRESULT wg_transform_read_dmo(wg_transform_t transform, DMO_OUTPUT_DATA_BUFFER *buffer);
/* These unixlib entry points should not be used directly, they assume samples
* to be queued and zero-copy support, use the helpers below instead.
*/
HRESULT wg_transform_push_data(wg_transform_t transform, struct wg_sample *sample);
HRESULT wg_transform_read_data(wg_transform_t transform, struct wg_sample *sample);
HRESULT gstreamer_byte_stream_handler_create(REFIID riid, void **obj);
unsigned int wg_format_get_stride(const struct wg_format *format);

View file

@ -415,18 +415,16 @@ HRESULT wg_transform_push_data(wg_transform_t transform, struct wg_sample *sampl
return params.result;
}
HRESULT wg_transform_read_data(wg_transform_t transform, struct wg_sample *sample,
struct wg_format *format)
HRESULT wg_transform_read_data(wg_transform_t transform, struct wg_sample *sample)
{
struct wg_transform_read_data_params params =
{
.transform = transform,
.sample = sample,
.format = format,
};
NTSTATUS status;
TRACE("transform %#I64x, sample %p, format %p.\n", transform, sample, format);
TRACE("transform %#I64x, sample %p.\n", transform, sample);
if ((status = WINE_UNIX_CALL(unix_wg_transform_read_data, &params)))
return HRESULT_FROM_NT(status);
@ -450,6 +448,19 @@ bool wg_transform_get_status(wg_transform_t transform, bool *accepts_input)
return true;
}
bool wg_transform_get_output_format(wg_transform_t transform, struct wg_format *format)
{
struct wg_transform_get_output_format_params params =
{
.transform = transform,
.format = format,
};
TRACE("transform %#I64x, format %p.\n", transform, format);
return !WINE_UNIX_CALL(unix_wg_transform_get_output_format, &params);
}
bool wg_transform_set_output_format(wg_transform_t transform, struct wg_format *format)
{
struct wg_transform_set_output_format_params params =

View file

@ -541,7 +541,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags,
return hr;
if (SUCCEEDED(hr = wg_transform_read_mf(impl->wg_transform, samples->pSample,
info.cbSize, NULL, &samples->dwStatus)))
info.cbSize, &samples->dwStatus)))
wg_sample_queue_flush(impl->wg_sample_queue, false);
return hr;

View file

@ -56,6 +56,7 @@ extern GstCaps *wg_format_to_caps(const struct wg_format *format);
extern NTSTATUS wg_transform_create(void *args);
extern NTSTATUS wg_transform_destroy(void *args);
extern NTSTATUS wg_transform_get_output_format(void *args);
extern NTSTATUS wg_transform_set_output_format(void *args);
extern NTSTATUS wg_transform_push_data(void *args);
extern NTSTATUS wg_transform_read_data(void *args);

View file

@ -325,10 +325,15 @@ struct wg_transform_read_data_params
{
wg_transform_t transform;
struct wg_sample *sample;
struct wg_format *format;
HRESULT result;
};
struct wg_transform_get_output_format_params
{
wg_transform_t transform;
struct wg_format *format;
};
struct wg_transform_set_output_format_params
{
wg_transform_t transform;
@ -410,6 +415,7 @@ enum unix_funcs
unix_wg_transform_create,
unix_wg_transform_destroy,
unix_wg_transform_get_output_format,
unix_wg_transform_set_output_format,
unix_wg_transform_push_data,

View file

@ -852,14 +852,17 @@ static HRESULT output_sample(struct video_decoder *decoder, IMFSample **out, IMF
return S_OK;
}
static HRESULT handle_stream_type_change(struct video_decoder *decoder, const struct wg_format *format)
static HRESULT handle_stream_type_change(struct video_decoder *decoder)
{
UINT64 frame_size, frame_rate;
struct wg_format format;
HRESULT hr;
if (decoder->stream_type)
IMFMediaType_Release(decoder->stream_type);
if (!(decoder->stream_type = mf_media_type_from_wg_format(format)))
if (!(wg_transform_get_output_format(decoder->wg_transform, &format)))
return E_FAIL;
if (!(decoder->stream_type = mf_media_type_from_wg_format(&format)))
return E_OUTOFMEMORY;
if (SUCCEEDED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_RATE, &frame_rate))
@ -879,7 +882,6 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags,
MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status)
{
struct video_decoder *decoder = impl_from_IMFTransform(iface);
struct wg_format wg_format;
UINT32 sample_size;
LONGLONG duration;
IMFSample *sample;
@ -929,7 +931,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags,
}
if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, sample,
sample_size, &wg_format, &samples->dwStatus)))
sample_size, &samples->dwStatus)))
{
wg_sample_queue_flush(decoder->wg_sample_queue, false);
@ -948,7 +950,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags,
{
samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE;
*status |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE;
hr = handle_stream_type_change(decoder, &wg_format);
hr = handle_stream_type_change(decoder);
}
if (decoder->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES)

View file

@ -693,8 +693,7 @@ static HRESULT WINAPI video_processor_ProcessOutput(IMFTransform *iface, DWORD f
IMFSample_AddRef(output_sample);
}
if (FAILED(hr = wg_transform_read_mf(impl->wg_transform, output_sample, info.cbSize,
NULL, &samples->dwStatus)))
if (FAILED(hr = wg_transform_read_mf(impl->wg_transform, output_sample, info.cbSize, &samples->dwStatus)))
goto done;
wg_sample_queue_flush(impl->wg_sample_queue, false);

View file

@ -1889,6 +1889,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
X(wg_transform_create),
X(wg_transform_destroy),
X(wg_transform_get_output_format),
X(wg_transform_set_output_format),
X(wg_transform_push_data),
@ -2074,6 +2075,21 @@ NTSTATUS wow64_wg_transform_create(void *args)
return ret;
}
NTSTATUS wow64_wg_transform_get_output_format(void *args)
{
struct
{
wg_transform_t transform;
PTR32 format;
} *params32 = args;
struct wg_transform_get_output_format_params params =
{
.transform = params32->transform,
.format = ULongToPtr(params32->format),
};
return wg_transform_get_output_format(&params);
}
NTSTATUS wow64_wg_transform_set_output_format(void *args)
{
struct
@ -2115,14 +2131,12 @@ NTSTATUS wow64_wg_transform_read_data(void *args)
{
wg_transform_t transform;
PTR32 sample;
PTR32 format;
HRESULT result;
} *params32 = args;
struct wg_transform_read_data_params params =
{
.transform = params32->transform,
.sample = ULongToPtr(params32->sample),
.format = ULongToPtr(params32->format),
};
NTSTATUS ret;
@ -2240,6 +2254,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
X64(wg_transform_create),
X(wg_transform_destroy),
X64(wg_transform_get_output_format),
X64(wg_transform_set_output_format),
X64(wg_transform_push_data),

View file

@ -303,13 +303,6 @@ void wg_sample_queue_destroy(struct wg_sample_queue *queue)
free(queue);
}
/* These unixlib entry points should not be used directly, they assume samples
* to be queued and zero-copy support, use the helpers below instead.
*/
HRESULT wg_transform_push_data(wg_transform_t transform, struct wg_sample *sample);
HRESULT wg_transform_read_data(wg_transform_t transform, struct wg_sample *sample,
struct wg_format *format);
HRESULT wg_transform_push_mf(wg_transform_t transform, IMFSample *sample,
struct wg_sample_queue *queue)
{
@ -346,23 +339,21 @@ HRESULT wg_transform_push_mf(wg_transform_t transform, IMFSample *sample,
}
HRESULT wg_transform_read_mf(wg_transform_t transform, IMFSample *sample,
DWORD sample_size, struct wg_format *format, DWORD *flags)
DWORD sample_size, DWORD *flags)
{
struct wg_sample *wg_sample;
IMFMediaBuffer *buffer;
HRESULT hr;
TRACE_(mfplat)("transform %#I64x, sample %p, format %p, flags %p.\n", transform, sample, format, flags);
TRACE_(mfplat)("transform %#I64x, sample %p, flags %p.\n", transform, sample, flags);
if (FAILED(hr = wg_sample_create_mf(sample, &wg_sample)))
return hr;
wg_sample->size = 0;
if (FAILED(hr = wg_transform_read_data(transform, wg_sample, format)))
if (FAILED(hr = wg_transform_read_data(transform, wg_sample)))
{
if (hr == MF_E_TRANSFORM_STREAM_CHANGE && !format)
FIXME("Unexpected stream format change!\n");
wg_sample_release(wg_sample);
return hr;
}
@ -430,7 +421,7 @@ HRESULT wg_transform_read_quartz(wg_transform_t transform, struct wg_sample *wg_
TRACE_(mfplat)("transform %#I64x, wg_sample %p.\n", transform, wg_sample);
if (FAILED(hr = wg_transform_read_data(transform, wg_sample, NULL)))
if (FAILED(hr = wg_transform_read_data(transform, wg_sample)))
{
if (hr == MF_E_TRANSFORM_STREAM_CHANGE)
FIXME("Unexpected stream format change!\n");
@ -505,7 +496,7 @@ HRESULT wg_transform_read_dmo(wg_transform_t transform, DMO_OUTPUT_DATA_BUFFER *
return hr;
wg_sample->size = 0;
if (FAILED(hr = wg_transform_read_data(transform, wg_sample, NULL)))
if (FAILED(hr = wg_transform_read_data(transform, wg_sample)))
{
if (hr == MF_E_TRANSFORM_STREAM_CHANGE)
TRACE_(mfplat)("Stream format changed.\n");

View file

@ -616,6 +616,48 @@ out:
return status;
}
NTSTATUS wg_transform_get_output_format(void *args)
{
struct wg_transform_get_output_format_params *params = args;
struct wg_transform *transform = get_transform(params->transform);
struct wg_format *format = params->format;
GstVideoInfo video_info;
GstCaps *output_caps;
if (transform->output_sample)
output_caps = gst_sample_get_caps(transform->output_sample);
else
output_caps = transform->output_caps;
GST_INFO("transform %p output caps %"GST_PTR_FORMAT, transform, output_caps);
wg_format_from_caps(format, output_caps);
if (stream_type_from_caps(output_caps) == GST_STREAM_TYPE_VIDEO
&& gst_video_info_from_caps(&video_info, output_caps))
{
gsize plane_align = transform->attrs.output_plane_align;
GstVideoAlignment align = {0};
/* set the desired output buffer alignment on the dest video info */
align_video_info_planes(plane_align, &video_info, &align);
GST_INFO("Returning video alignment left %u, top %u, right %u, bottom %u.", align.padding_left,
align.padding_top, align.padding_right, align.padding_bottom);
format->u.video.padding.left = align.padding_left;
format->u.video.width += format->u.video.padding.left;
format->u.video.padding.right = align.padding_right;
format->u.video.width += format->u.video.padding.right;
format->u.video.padding.top = align.padding_top;
format->u.video.height += format->u.video.padding.top;
format->u.video.padding.bottom = align.padding_bottom;
format->u.video.height += format->u.video.padding.bottom;
}
return STATUS_SUCCESS;
}
NTSTATUS wg_transform_set_output_format(void *args)
{
struct wg_transform_set_output_format_params *params = args;
@ -927,7 +969,6 @@ NTSTATUS wg_transform_read_data(void *args)
struct wg_transform *transform = get_transform(params->transform);
GstVideoInfo src_video_info, dst_video_info;
struct wg_sample *sample = params->sample;
struct wg_format *format = params->format;
GstVideoAlignment align = {0};
GstBuffer *output_buffer;
GstCaps *output_caps;
@ -961,29 +1002,6 @@ NTSTATUS wg_transform_read_data(void *args)
if (GST_MINI_OBJECT_FLAG_IS_SET(transform->output_sample, GST_SAMPLE_FLAG_WG_CAPS_CHANGED))
{
GST_MINI_OBJECT_FLAG_UNSET(transform->output_sample, GST_SAMPLE_FLAG_WG_CAPS_CHANGED);
GST_INFO("transform %p output caps %"GST_PTR_FORMAT, transform, output_caps);
if (format)
{
wg_format_from_caps(format, output_caps);
if (format->major_type == WG_MAJOR_TYPE_VIDEO)
{
GST_INFO("Returning video alignment left %u, top %u, right %u, bottom %u.", align.padding_left,
align.padding_top, align.padding_right, align.padding_bottom);
format->u.video.padding.left = align.padding_left;
format->u.video.width += format->u.video.padding.left;
format->u.video.padding.right = align.padding_right;
format->u.video.width += format->u.video.padding.right;
format->u.video.padding.top = align.padding_top;
format->u.video.height += format->u.video.padding.top;
format->u.video.padding.bottom = align.padding_bottom;
format->u.video.height += format->u.video.padding.bottom;
}
}
params->result = MF_E_TRANSFORM_STREAM_CHANGE;
GST_INFO("Format changed detected, returning no output");
wg_allocator_release_sample(transform->allocator, sample, false);

View file

@ -557,7 +557,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags,
return hr;
if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, samples->pSample,
info.cbSize, NULL, &samples->dwStatus)))
info.cbSize, &samples->dwStatus)))
wg_sample_queue_flush(decoder->wg_sample_queue, false);
return hr;