[PATCH v3 0/2] MR10298: mfreadwrite: Implement sample encoding.
-- v3: mfreadwrite: Process samples through converter and encoder. mfreadwrite: Set encoder types correctly. https://gitlab.winehq.org/wine/wine/-/merge_requests/10298
From: Ziqing Hui <zhui@codeweavers.com> --- dlls/mfreadwrite/writer.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/dlls/mfreadwrite/writer.c b/dlls/mfreadwrite/writer.c index b697c41cb4a..5dc85725d3d 100644 --- a/dlls/mfreadwrite/writer.c +++ b/dlls/mfreadwrite/writer.c @@ -298,14 +298,20 @@ static HRESULT stream_create_transforms(struct stream *stream, { /* Create the converter with a recursive call. */ hr = stream_create_transforms(stream, input_type, encoder_input_type, FALSE, attributes); - IMFMediaType_Release(encoder_input_type); if (SUCCEEDED(hr)) { /* Converter is already set in the recursive call, set encoder here. */ - stream->encoder = transform; - TRACE("Created encoder %p.", transform); - break; + if (SUCCEEDED(hr = stream_set_transform(stream, transform, encoder_input_type, output_type, TRUE))) + { + IMFMediaType_Release(encoder_input_type); + break; + } + else + { + stream_release_transforms(stream); + } } + IMFMediaType_Release(encoder_input_type); } IMFTransform_Release(transform); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10298
From: Ziqing Hui <zhui@codeweavers.com> --- dlls/mfreadwrite/writer.c | 135 +++++++++++++++++++++++++++++++++----- 1 file changed, 118 insertions(+), 17 deletions(-) diff --git a/dlls/mfreadwrite/writer.c b/dlls/mfreadwrite/writer.c index 5dc85725d3d..d831af7ab20 100644 --- a/dlls/mfreadwrite/writer.c +++ b/dlls/mfreadwrite/writer.c @@ -324,6 +324,122 @@ static HRESULT stream_create_transforms(struct stream *stream, return hr; } +static HRESULT stream_queue_sample(struct stream *stream, IMFSample *sample) +{ + struct pending_item *item; + + if (!(item = calloc(1, sizeof(*item)))) + return E_OUTOFMEMORY; + + item->sample = sample; + IMFSample_AddRef(item->sample); + list_add_tail(&stream->queue, &item->entry); + + return S_OK; +} + +static HRESULT allocate_transform_output(IMFTransform *transform, IMFSample **sample) +{ + MFT_OUTPUT_STREAM_INFO output_info; + IMFMediaBuffer *buffer; + HRESULT hr; + + *sample = NULL; + + if (FAILED(hr = IMFTransform_GetOutputStreamInfo(transform, 0, &output_info))) + return hr; + if (output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) + return S_OK; + if (!output_info.cbSize) + { + if (output_info.dwFlags & MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES) + return S_OK; + WARN("Transform %p returned zero output cbSize.\n", transform); + return E_FAIL; + } + + if (FAILED(hr = MFCreateSample(sample))) + return hr; + if (FAILED(hr = MFCreateMemoryBuffer(output_info.cbSize, &buffer))) + { + IMFSample_Release(*sample); + *sample = NULL; + return hr; + } + hr = IMFSample_AddBuffer(*sample, buffer); + IMFMediaBuffer_Release(buffer); + if (FAILED(hr)) + { + IMFSample_Release(*sample); + *sample = NULL; + } + + return hr; +} + +static HRESULT stream_process_sample(struct stream *stream, + IMFSample *sample, IMFTransform *transform, IMFTransform *next_transform); + +static HRESULT stream_drain_transform_output(struct stream *stream, + IMFTransform *transform, IMFTransform *next_transform) +{ + MFT_OUTPUT_DATA_BUFFER output_buffer; + HRESULT hr = S_OK; + DWORD status; + + while (SUCCEEDED(hr)) + { + memset(&output_buffer, 0, sizeof(output_buffer)); + if (FAILED(hr = allocate_transform_output(transform, &output_buffer.pSample))) + break; + + if (SUCCEEDED(hr = IMFTransform_ProcessOutput(transform, 0, 1, &output_buffer, &status))) + { + if (next_transform) + hr = stream_process_sample(stream, output_buffer.pSample, next_transform, NULL); + else + hr = stream_queue_sample(stream, output_buffer.pSample); + } + + if (output_buffer.pSample) + IMFSample_Release(output_buffer.pSample); + if (output_buffer.pEvents) + IMFCollection_Release(output_buffer.pEvents); + } + + if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) + hr = S_OK; + + return hr; +} + +static HRESULT stream_process_sample(struct stream *stream, + IMFSample *sample, IMFTransform *transform, IMFTransform *next_transform) +{ + HRESULT hr; + + if (!transform) + { + if (!next_transform) + return stream_queue_sample(stream, sample); + + transform = next_transform; + next_transform = NULL; + } + + hr = IMFTransform_ProcessInput(transform, 0, sample, 0); + if (hr == MF_E_NOTACCEPTING) + { + if (FAILED(hr = stream_drain_transform_output(stream, transform, next_transform))) + return hr; + hr = IMFTransform_ProcessInput(transform, 0, sample, 0); + } + if (FAILED(hr)) + return hr; + + return stream_drain_transform_output(stream, transform, next_transform); +} + static struct stream *sink_writer_get_stream(const struct sink_writer *writer, DWORD index) { if (index >= writer->streams.count) @@ -718,22 +834,6 @@ static HRESULT sink_writer_process_sample(struct sink_writer *writer, struct str return hr; } -static HRESULT sink_writer_encode_sample(struct sink_writer *writer, struct stream *stream, IMFSample *sample) -{ - struct pending_item *item; - - /* FIXME: call the encoder, queue its output */ - - if (!(item = calloc(1, sizeof(*item)))) - return E_OUTOFMEMORY; - - item->sample = sample; - IMFSample_AddRef(item->sample); - list_add_tail(&stream->queue, &item->entry); - - return S_OK; -} - static HRESULT sink_writer_write_sample(struct sink_writer *writer, struct stream *stream, IMFSample *sample) { LONGLONG timestamp; @@ -750,7 +850,8 @@ static HRESULT sink_writer_write_sample(struct sink_writer *writer, struct strea writer->stats.qwNumSamplesReceived++; writer->stats.dwByteCountQueued += length; - if (FAILED(hr = sink_writer_encode_sample(writer, stream, sample))) return hr; + if (FAILED(hr = stream_process_sample(stream, sample, stream->converter, stream->encoder))) + return hr; if (stream->stats.dwNumOutstandingSinkSampleRequests) hr = sink_writer_process_sample(writer, stream); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10298
On Sun Apr 12 02:05:23 2026 +0000, Ziqing Hui wrote: > > This one is confusing. Why would be do encode_sample() more than once? > Is it possible to have multiple encoders one after another? Or is the > helper name simply misleading and it means "process" in general, instead > of "encode"? > Sorry for the misleading name. Yes, it means "process" instead of > "encode". It is used for transform processing in general, not only for encoding. > > What is the idea behind next_transform? It looks like this code allows > two transforms at maximum, is there a limit to this chain on Windows? > next_transform is for the converter -> encoder case. We support at most > two transforms: one converter and one encoder. As far as I now, there is > no longer transform chain on Windows. > We have 2 cases for the next_transform: > 1. next_transform is NULL, in this case, there is only one transform for > the stream, or we have already handled converter and we are passing > converter output to encoder. > 2. next_transform is a encoder, in this case we have converter -> encoder. > Having the next_transform parameter makes us be able to handle each case > in one single helper function. If it's two transform at most, can we have a single helper that does processinput->processoutput, and then use it twice in a row? Also in case of stream_drain_transform_output(), both transforms are a property of a stream that you already pass in as a parameter. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10298#note_136671
participants (3)
-
Nikolay Sivov (@nsivov) -
Ziqing Hui -
Ziqing Hui (@zhui)