mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-07 00:18:09 +00:00
winegstreamer: Support zero-copy in wg_transform_push_data.
Signed-off-by: Rémi Bernon <rbernon@codeweavers.com>
This commit is contained in:
parent
f17b801056
commit
c40ab0f9a6
|
@ -6423,7 +6423,6 @@ static void test_wma_decoder(void)
|
|||
hr = IMFTransform_ProcessInput(transform, 0, sample, 0);
|
||||
ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr);
|
||||
ret = IMFSample_Release(sample);
|
||||
todo_wine
|
||||
ok(ret == 1, "Release returned %lu\n", ret);
|
||||
|
||||
/* As output_info.dwFlags doesn't have MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES
|
||||
|
|
|
@ -64,6 +64,12 @@ static inline const char *debugstr_time(REFERENCE_TIME time)
|
|||
|
||||
#define MEDIATIME_FROM_BYTES(x) ((LONGLONG)(x) * 10000000)
|
||||
|
||||
struct wg_sample_queue;
|
||||
|
||||
HRESULT wg_sample_queue_create(struct wg_sample_queue **out);
|
||||
void wg_sample_queue_destroy(struct wg_sample_queue *queue);
|
||||
void wg_sample_queue_flush(struct wg_sample_queue *queue, bool all);
|
||||
|
||||
struct wg_parser *wg_parser_create(enum wg_parser_type type, bool unlimited_buffering);
|
||||
void wg_parser_destroy(struct wg_parser *parser);
|
||||
|
||||
|
@ -123,7 +129,8 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format);
|
|||
HRESULT wg_sample_create_mf(IMFSample *sample, struct wg_sample **out);
|
||||
void wg_sample_release(struct wg_sample *wg_sample);
|
||||
|
||||
HRESULT wg_transform_push_mf(struct wg_transform *transform, struct wg_sample *sample);
|
||||
HRESULT wg_transform_push_mf(struct wg_transform *transform, struct wg_sample *sample,
|
||||
struct wg_sample_queue *queue);
|
||||
HRESULT wg_transform_read_mf(struct wg_transform *transform, struct wg_sample *sample,
|
||||
struct wg_format *format);
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ struct h264_decoder
|
|||
|
||||
struct wg_format wg_format;
|
||||
struct wg_transform *wg_transform;
|
||||
struct wg_sample_queue *wg_sample_queue;
|
||||
};
|
||||
|
||||
static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface)
|
||||
|
@ -237,6 +238,8 @@ static ULONG WINAPI transform_Release(IMFTransform *iface)
|
|||
IMFMediaType_Release(decoder->input_type);
|
||||
if (decoder->output_type)
|
||||
IMFMediaType_Release(decoder->output_type);
|
||||
|
||||
wg_sample_queue_destroy(decoder->wg_sample_queue);
|
||||
free(decoder);
|
||||
}
|
||||
|
||||
|
@ -543,9 +546,7 @@ static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFS
|
|||
if (FAILED(hr = wg_sample_create_mf(sample, &wg_sample)))
|
||||
return hr;
|
||||
|
||||
hr = wg_transform_push_mf(decoder->wg_transform, wg_sample);
|
||||
wg_sample_release(wg_sample);
|
||||
return hr;
|
||||
return wg_transform_push_mf(decoder->wg_transform, wg_sample, decoder->wg_sample_queue);
|
||||
}
|
||||
|
||||
static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
|
||||
|
@ -582,7 +583,8 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags,
|
|||
return MF_E_BUFFERTOOSMALL;
|
||||
}
|
||||
|
||||
hr = wg_transform_read_mf(decoder->wg_transform, wg_sample, &wg_format);
|
||||
if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, wg_sample, &wg_format)))
|
||||
wg_sample_queue_flush(decoder->wg_sample_queue, false);
|
||||
wg_sample_release(wg_sample);
|
||||
|
||||
if (hr == MF_E_TRANSFORM_STREAM_CHANGE)
|
||||
|
@ -648,6 +650,7 @@ HRESULT h264_decoder_create(REFIID riid, void **ret)
|
|||
static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_H264};
|
||||
struct wg_transform *transform;
|
||||
struct h264_decoder *decoder;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret);
|
||||
|
||||
|
@ -669,6 +672,12 @@ HRESULT h264_decoder_create(REFIID riid, void **ret)
|
|||
decoder->wg_format.u.video.fps_n = 30000;
|
||||
decoder->wg_format.u.video.fps_d = 1001;
|
||||
|
||||
if (FAILED(hr = wg_sample_queue_create(&decoder->wg_sample_queue)))
|
||||
{
|
||||
free(decoder);
|
||||
return hr;
|
||||
}
|
||||
|
||||
*ret = &decoder->IMFTransform_iface;
|
||||
TRACE("Created decoder %p\n", *ret);
|
||||
return S_OK;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "mfapi.h"
|
||||
|
||||
#include "wine/debug.h"
|
||||
#include "wine/list.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
|
||||
|
||||
|
@ -958,11 +959,18 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format)
|
|||
FIXME("Unrecognized major type %s.\n", debugstr_guid(&major_type));
|
||||
}
|
||||
|
||||
struct wg_sample_queue
|
||||
{
|
||||
CRITICAL_SECTION cs;
|
||||
struct list samples;
|
||||
};
|
||||
|
||||
struct mf_sample
|
||||
{
|
||||
IMFSample *sample;
|
||||
IMFMediaBuffer *media_buffer;
|
||||
struct wg_sample wg_sample;
|
||||
struct list entry;
|
||||
};
|
||||
|
||||
HRESULT wg_sample_create_mf(IMFSample *sample, struct wg_sample **out)
|
||||
|
@ -1008,14 +1016,83 @@ void wg_sample_release(struct wg_sample *wg_sample)
|
|||
IMFMediaBuffer_Unlock(mf_sample->media_buffer);
|
||||
IMFMediaBuffer_Release(mf_sample->media_buffer);
|
||||
IMFSample_Release(mf_sample->sample);
|
||||
|
||||
free(mf_sample);
|
||||
}
|
||||
|
||||
HRESULT wg_transform_push_mf(struct wg_transform *transform, struct wg_sample *sample)
|
||||
static void wg_sample_queue_begin_append(struct wg_sample_queue *queue, struct wg_sample *wg_sample)
|
||||
{
|
||||
struct mf_sample *mf_sample = CONTAINING_RECORD(sample, struct mf_sample, wg_sample);
|
||||
struct mf_sample *mf_sample = CONTAINING_RECORD(wg_sample, struct mf_sample, wg_sample);
|
||||
|
||||
/* make sure a concurrent wg_sample_queue_flush call won't release the sample until we're done */
|
||||
InterlockedIncrement(&wg_sample->refcount);
|
||||
mf_sample->wg_sample.flags |= WG_SAMPLE_FLAG_HAS_REFCOUNT;
|
||||
|
||||
EnterCriticalSection(&queue->cs);
|
||||
list_add_tail(&queue->samples, &mf_sample->entry);
|
||||
LeaveCriticalSection(&queue->cs);
|
||||
}
|
||||
|
||||
static void wg_sample_queue_end_append(struct wg_sample_queue *queue, struct wg_sample *wg_sample)
|
||||
{
|
||||
/* release temporary ref taken in wg_sample_queue_begin_append */
|
||||
InterlockedDecrement(&wg_sample->refcount);
|
||||
|
||||
wg_sample_queue_flush(queue, false);
|
||||
}
|
||||
|
||||
void wg_sample_queue_flush(struct wg_sample_queue *queue, bool all)
|
||||
{
|
||||
struct mf_sample *mf_sample, *next;
|
||||
|
||||
EnterCriticalSection(&queue->cs);
|
||||
|
||||
LIST_FOR_EACH_ENTRY_SAFE(mf_sample, next, &queue->samples, struct mf_sample, entry)
|
||||
{
|
||||
if (!InterlockedOr(&mf_sample->wg_sample.refcount, 0) || all)
|
||||
{
|
||||
list_remove(&mf_sample->entry);
|
||||
wg_sample_release(&mf_sample->wg_sample);
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&queue->cs);
|
||||
}
|
||||
|
||||
HRESULT wg_sample_queue_create(struct wg_sample_queue **out)
|
||||
{
|
||||
struct wg_sample_queue *queue;
|
||||
|
||||
if (!(queue = calloc(1, sizeof(*queue))))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
InitializeCriticalSection(&queue->cs);
|
||||
queue->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs");
|
||||
list_init(&queue->samples);
|
||||
|
||||
TRACE("Created sample queue %p\n", queue);
|
||||
*out = queue;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void wg_sample_queue_destroy(struct wg_sample_queue *queue)
|
||||
{
|
||||
wg_sample_queue_flush(queue, true);
|
||||
|
||||
queue->cs.DebugInfo->Spare[0] = 0;
|
||||
InitializeCriticalSection(&queue->cs);
|
||||
|
||||
free(queue);
|
||||
}
|
||||
|
||||
HRESULT wg_transform_push_mf(struct wg_transform *transform, struct wg_sample *wg_sample,
|
||||
struct wg_sample_queue *queue)
|
||||
{
|
||||
struct mf_sample *mf_sample = CONTAINING_RECORD(wg_sample, struct mf_sample, wg_sample);
|
||||
LONGLONG time, duration;
|
||||
UINT32 value;
|
||||
HRESULT hr;
|
||||
|
||||
if (SUCCEEDED(IMFSample_GetSampleTime(mf_sample->sample, &time)))
|
||||
{
|
||||
|
@ -1030,7 +1107,11 @@ HRESULT wg_transform_push_mf(struct wg_transform *transform, struct wg_sample *s
|
|||
if (SUCCEEDED(IMFSample_GetUINT32(mf_sample->sample, &MFSampleExtension_CleanPoint, &value)) && value)
|
||||
mf_sample->wg_sample.flags |= WG_SAMPLE_FLAG_SYNC_POINT;
|
||||
|
||||
return wg_transform_push_data(transform, sample);
|
||||
wg_sample_queue_begin_append(queue, wg_sample);
|
||||
hr = wg_transform_push_data(transform, wg_sample);
|
||||
wg_sample_queue_end_append(queue, wg_sample);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT wg_transform_read_mf(struct wg_transform *transform, struct wg_sample *wg_sample,
|
||||
|
|
|
@ -40,6 +40,7 @@ struct transform
|
|||
IQualityControl *qc_sink;
|
||||
|
||||
struct wg_transform *transform;
|
||||
struct wg_sample_queue *sample_queue;
|
||||
|
||||
const struct transform_ops *ops;
|
||||
};
|
||||
|
@ -76,6 +77,7 @@ static void transform_destroy(struct strmbase_filter *iface)
|
|||
strmbase_sink_cleanup(&filter->sink);
|
||||
strmbase_filter_cleanup(&filter->filter);
|
||||
|
||||
wg_sample_queue_destroy(filter->sample_queue);
|
||||
free(filter);
|
||||
}
|
||||
|
||||
|
@ -572,11 +574,18 @@ static const IQualityControlVtbl source_quality_control_vtbl =
|
|||
static HRESULT transform_create(IUnknown *outer, const CLSID *clsid, const struct transform_ops *ops, struct transform **out)
|
||||
{
|
||||
struct transform *object;
|
||||
HRESULT hr;
|
||||
|
||||
object = calloc(1, sizeof(*object));
|
||||
if (!object)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
if (FAILED(hr = wg_sample_queue_create(&object->sample_queue)))
|
||||
{
|
||||
free(object);
|
||||
return hr;
|
||||
}
|
||||
|
||||
strmbase_filter_init(&object->filter, outer, clsid, &filter_ops);
|
||||
strmbase_sink_init(&object->sink, &object->filter, L"In", &sink_ops, NULL);
|
||||
strmbase_source_init(&object->source, &object->filter, L"Out", &source_ops);
|
||||
|
|
|
@ -121,6 +121,8 @@ enum wg_sample_flag
|
|||
WG_SAMPLE_FLAG_HAS_PTS = 2,
|
||||
WG_SAMPLE_FLAG_HAS_DURATION = 4,
|
||||
WG_SAMPLE_FLAG_SYNC_POINT = 8,
|
||||
|
||||
WG_SAMPLE_FLAG_HAS_REFCOUNT = 0x10000, /* sample is queued on the client side and may be wrapped */
|
||||
};
|
||||
|
||||
struct wg_sample
|
||||
|
|
|
@ -519,6 +519,13 @@ out:
|
|||
return status;
|
||||
}
|
||||
|
||||
static void wg_sample_free_notify(void *arg)
|
||||
{
|
||||
struct wg_sample *sample = arg;
|
||||
GST_DEBUG("Releasing wg_sample %p", sample);
|
||||
InterlockedDecrement(&sample->refcount);
|
||||
}
|
||||
|
||||
NTSTATUS wg_transform_push_data(void *args)
|
||||
{
|
||||
struct wg_transform_push_data_params *params = args;
|
||||
|
@ -535,12 +542,28 @@ NTSTATUS wg_transform_push_data(void *args)
|
|||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (!(buffer = gst_buffer_new_and_alloc(sample->size)))
|
||||
if (!(sample->flags & WG_SAMPLE_FLAG_HAS_REFCOUNT))
|
||||
{
|
||||
if (!(buffer = gst_buffer_new_and_alloc(sample->size)))
|
||||
{
|
||||
GST_ERROR("Failed to allocate input buffer");
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
gst_buffer_fill(buffer, 0, sample->data, sample->size);
|
||||
GST_INFO("Copied %u bytes from sample %p to buffer %p", sample->size, sample, buffer);
|
||||
}
|
||||
else if (!(buffer = gst_buffer_new_wrapped_full(GST_MEMORY_FLAG_READONLY, sample->data, sample->max_size,
|
||||
0, sample->size, sample, wg_sample_free_notify)))
|
||||
{
|
||||
GST_ERROR("Failed to allocate input buffer");
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
gst_buffer_fill(buffer, 0, sample->data, sample->size);
|
||||
else
|
||||
{
|
||||
InterlockedIncrement(&sample->refcount);
|
||||
GST_INFO("Wrapped %u/%u bytes from sample %p to buffer %p", sample->size, sample->max_size, sample, buffer);
|
||||
}
|
||||
|
||||
if (sample->flags & WG_SAMPLE_FLAG_HAS_PTS)
|
||||
GST_BUFFER_PTS(buffer) = sample->pts * 100;
|
||||
if (sample->flags & WG_SAMPLE_FLAG_HAS_DURATION)
|
||||
|
@ -549,7 +572,6 @@ NTSTATUS wg_transform_push_data(void *args)
|
|||
GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT);
|
||||
gst_buffer_list_insert(transform->input, -1, buffer);
|
||||
|
||||
GST_INFO("Copied %u bytes from sample %p to input buffer list", sample->size, sample);
|
||||
params->result = S_OK;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@ struct wma_decoder
|
|||
IMFMediaType *output_type;
|
||||
|
||||
struct wg_transform *wg_transform;
|
||||
struct wg_sample_queue *wg_sample_queue;
|
||||
};
|
||||
|
||||
static inline struct wma_decoder *impl_from_IUnknown(IUnknown *iface)
|
||||
|
@ -135,6 +136,8 @@ static ULONG WINAPI unknown_Release(IUnknown *iface)
|
|||
IMFMediaType_Release(decoder->input_type);
|
||||
if (decoder->output_type)
|
||||
IMFMediaType_Release(decoder->output_type);
|
||||
|
||||
wg_sample_queue_destroy(decoder->wg_sample_queue);
|
||||
free(decoder);
|
||||
}
|
||||
|
||||
|
@ -544,9 +547,7 @@ static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFS
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
hr = wg_transform_push_mf(decoder->wg_transform, wg_sample);
|
||||
wg_sample_release(wg_sample);
|
||||
return hr;
|
||||
return wg_transform_push_mf(decoder->wg_transform, wg_sample, decoder->wg_sample_queue);
|
||||
}
|
||||
|
||||
static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
|
||||
|
@ -590,6 +591,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags,
|
|||
{
|
||||
if (wg_sample->flags & WG_SAMPLE_FLAG_INCOMPLETE)
|
||||
samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_INCOMPLETE;
|
||||
wg_sample_queue_flush(decoder->wg_sample_queue, false);
|
||||
}
|
||||
|
||||
wg_sample_release(wg_sample);
|
||||
|
@ -882,6 +884,7 @@ HRESULT wma_decoder_create(IUnknown *outer, IUnknown **out)
|
|||
static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_WMA};
|
||||
struct wg_transform *transform;
|
||||
struct wma_decoder *decoder;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("outer %p, out %p.\n", outer, out);
|
||||
|
||||
|
@ -895,6 +898,12 @@ HRESULT wma_decoder_create(IUnknown *outer, IUnknown **out)
|
|||
if (!(decoder = calloc(1, sizeof(*decoder))))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
if (FAILED(hr = wg_sample_queue_create(&decoder->wg_sample_queue)))
|
||||
{
|
||||
free(decoder);
|
||||
return hr;
|
||||
}
|
||||
|
||||
decoder->IUnknown_inner.lpVtbl = &unknown_vtbl;
|
||||
decoder->IMFTransform_iface.lpVtbl = &transform_vtbl;
|
||||
decoder->IMediaObject_iface.lpVtbl = &media_object_vtbl;
|
||||
|
|
Loading…
Reference in a new issue