amstream: Implement AMAudioStream::Receive().

Signed-off-by: Anton Baskanov <baskanov@gmail.com>
Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Anton Baskanov 2020-04-22 15:16:14 -05:00 committed by Alexandre Julliard
parent b90cd8b0a4
commit 1a20f9b06b
2 changed files with 201 additions and 2 deletions

View File

@ -27,6 +27,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(amstream);
static const WCHAR sink_id[] = L"I{A35FF56B-9FDA-11D0-8FDF-00C04FD9189D}"; static const WCHAR sink_id[] = L"I{A35FF56B-9FDA-11D0-8FDF-00C04FD9189D}";
struct queued_receive
{
struct list entry;
IMediaSample *sample;
DWORD length;
BYTE *pointer;
DWORD position;
};
struct audio_stream struct audio_stream
{ {
IAMMediaStream IAMMediaStream_iface; IAMMediaStream IAMMediaStream_iface;
@ -47,6 +56,7 @@ struct audio_stream
WAVEFORMATEX format; WAVEFORMATEX format;
FILTER_STATE state; FILTER_STATE state;
BOOL eos; BOOL eos;
struct list receive_queue;
}; };
typedef struct { typedef struct {
@ -56,6 +66,24 @@ typedef struct {
IAudioData *audio_data; IAudioData *audio_data;
} IAudioStreamSampleImpl; } IAudioStreamSampleImpl;
static void remove_queued_receive(struct queued_receive *receive)
{
list_remove(&receive->entry);
IMediaSample_Release(receive->sample);
free(receive);
}
static void flush_receive_queue(struct audio_stream *stream)
{
while (!list_empty(&stream->receive_queue))
{
struct queued_receive *receive =
LIST_ENTRY(list_head(&stream->receive_queue), struct queued_receive, entry);
remove_queued_receive(receive);
}
}
static inline IAudioStreamSampleImpl *impl_from_IAudioStreamSample(IAudioStreamSample *iface) static inline IAudioStreamSampleImpl *impl_from_IAudioStreamSample(IAudioStreamSample *iface)
{ {
return CONTAINING_RECORD(iface, IAudioStreamSampleImpl, IAudioStreamSample_iface); return CONTAINING_RECORD(iface, IAudioStreamSampleImpl, IAudioStreamSample_iface);
@ -348,6 +376,8 @@ static HRESULT WINAPI audio_IAMMediaStream_SetState(IAMMediaStream *iface, FILTE
EnterCriticalSection(&stream->cs); EnterCriticalSection(&stream->cs);
if (state == State_Stopped)
flush_receive_queue(stream);
if (stream->state == State_Stopped) if (stream->state == State_Stopped)
stream->eos = FALSE; stream->eos = FALSE;
@ -1048,8 +1078,44 @@ static HRESULT WINAPI audio_meminput_GetAllocatorRequirements(IMemInputPin *ifac
static HRESULT WINAPI audio_meminput_Receive(IMemInputPin *iface, IMediaSample *sample) static HRESULT WINAPI audio_meminput_Receive(IMemInputPin *iface, IMediaSample *sample)
{ {
FIXME("iface %p, sample %p, stub!\n", iface, sample); struct audio_stream *stream = impl_from_IMemInputPin(iface);
return E_NOTIMPL; struct queued_receive *receive;
BYTE *pointer;
HRESULT hr;
TRACE("stream %p, sample %p.\n", stream, sample);
EnterCriticalSection(&stream->cs);
if (stream->state == State_Stopped)
{
LeaveCriticalSection(&stream->cs);
return VFW_E_WRONG_STATE;
}
hr = IMediaSample_GetPointer(sample, &pointer);
if (FAILED(hr))
{
LeaveCriticalSection(&stream->cs);
return hr;
}
receive = calloc(1, sizeof(*receive));
if (!receive)
{
LeaveCriticalSection(&stream->cs);
return E_OUTOFMEMORY;
}
receive->length = IMediaSample_GetActualDataLength(sample);
receive->pointer = pointer;
receive->sample = sample;
IMediaSample_AddRef(receive->sample);
list_add_tail(&stream->receive_queue, &receive->entry);
LeaveCriticalSection(&stream->cs);
return S_OK;
} }
static HRESULT WINAPI audio_meminput_ReceiveMultiple(IMemInputPin *iface, static HRESULT WINAPI audio_meminput_ReceiveMultiple(IMemInputPin *iface,
@ -1102,6 +1168,7 @@ HRESULT audio_stream_create(IMultiMediaStream *parent, const MSPID *purpose_id,
object->parent = parent; object->parent = parent;
object->purpose_id = *purpose_id; object->purpose_id = *purpose_id;
object->stream_type = stream_type; object->stream_type = stream_type;
list_init(&object->receive_queue);
*media_stream = &object->IAMMediaStream_iface; *media_stream = &object->IAMMediaStream_iface;

View File

@ -2904,6 +2904,137 @@ void test_audiostream_end_of_stream(void)
ok(!ref, "Got outstanding refcount %d.\n", ref); ok(!ref, "Got outstanding refcount %d.\n", ref);
} }
static void test_audiostream_receive(void)
{
static const WAVEFORMATEX format =
{
.wFormatTag = WAVE_FORMAT_PCM,
.nChannels = 1,
.nSamplesPerSec = 11025,
.wBitsPerSample = 16,
.nBlockAlign = 2,
.nAvgBytesPerSec = 2 * 11025,
};
const AM_MEDIA_TYPE mt =
{
.majortype = MEDIATYPE_Audio,
.subtype = MEDIASUBTYPE_PCM,
.formattype = FORMAT_WaveFormatEx,
.cbFormat = sizeof(WAVEFORMATEX),
.pbFormat = (BYTE *)&format,
};
ALLOCATOR_PROPERTIES properties =
{
.cBuffers = 3,
.cbBuffer = 16,
.cbAlign = 1,
};
IAMMultiMediaStream *mmstream = create_ammultimediastream();
ALLOCATOR_PROPERTIES actual;
struct testfilter source;
IMemAllocator *allocator;
IGraphBuilder *graph;
IMediaStream *stream;
IMediaSample *sample1;
IMediaSample *sample2;
IMediaSample *sample3;
HRESULT hr;
ULONG ref;
IPin *pin;
hr = IAMMultiMediaStream_Initialize(mmstream, STREAMTYPE_READ, 0, NULL);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IAMMultiMediaStream_AddMediaStream(mmstream, NULL, &MSPID_PrimaryAudio, 0, &stream);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IMediaStream_QueryInterface(stream, &IID_IPin, (void **)&pin);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IAMMultiMediaStream_GetFilterGraph(mmstream, &graph);
ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(graph != NULL, "Expected non-NULL graph.\n");
testfilter_init(&source);
hr = IGraphBuilder_AddFilter(graph, &source.filter.IBaseFilter_iface, NULL);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, &IID_IMemAllocator, (void **)&allocator);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IMemAllocator_SetProperties(allocator, &properties, &actual);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IMemAllocator_Commit(allocator);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IGraphBuilder_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &mt);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IMemAllocator_GetBuffer(allocator, &sample1, NULL, NULL, 0);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IMemInputPin_Receive(source.source.pMemInputPin, sample1);
ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
ref = IMediaSample_Release(sample1);
ok(!ref, "Got outstanding refcount %d.\n", ref);
hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IMemAllocator_GetBuffer(allocator, &sample1, NULL, NULL, 0);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IMemInputPin_Receive(source.source.pMemInputPin, sample1);
ok(hr == S_OK, "Got hr %#x.\n", hr);
ref = get_refcount(sample1);
ok(ref == 2, "Got unexpected refcount %d.\n", ref);
hr = IMemAllocator_GetBuffer(allocator, &sample2, NULL, NULL, 0);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IMemInputPin_Receive(source.source.pMemInputPin, sample2);
ok(hr == S_OK, "Got hr %#x.\n", hr);
ref = get_refcount(sample2);
ok(ref == 2, "Got unexpected refcount %d.\n", ref);
hr = IPin_EndOfStream(pin);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IMemAllocator_GetBuffer(allocator, &sample3, NULL, NULL, 0);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IMemInputPin_Receive(source.source.pMemInputPin, sample3);
ok(hr == S_OK, "Got hr %#x.\n", hr);
ref = get_refcount(sample3);
ok(ref == 2, "Got unexpected refcount %d.\n", ref);
hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP);
ok(hr == S_OK, "Got hr %#x.\n", hr);
ref = IMediaSample_Release(sample1);
ok(!ref, "Got outstanding refcount %d.\n", ref);
ref = IMediaSample_Release(sample2);
ok(!ref, "Got outstanding refcount %d.\n", ref);
ref = IMediaSample_Release(sample3);
ok(!ref, "Got outstanding refcount %d.\n", ref);
hr = IMemAllocator_GetBuffer(allocator, &sample1, NULL, NULL, 0);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IMemInputPin_Receive(source.source.pMemInputPin, sample1);
ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
ref = IMediaSample_Release(sample1);
ok(!ref, "Got outstanding refcount %d.\n", ref);
IGraphBuilder_Disconnect(graph, pin);
IGraphBuilder_Disconnect(graph, &source.source.pin.IPin_iface);
hr = IMemAllocator_Decommit(allocator);
ok(hr == S_OK, "Got hr %#x.\n", hr);
ref = IAMMultiMediaStream_Release(mmstream);
ok(!ref, "Got outstanding refcount %d.\n", ref);
ref = IGraphBuilder_Release(graph);
ok(!ref, "Got outstanding refcount %d.\n", ref);
IPin_Release(pin);
ref = IMediaStream_Release(stream);
ok(!ref, "Got outstanding refcount %d.\n", ref);
ref = IMemAllocator_Release(allocator);
ok(!ref, "Got outstanding refcount %d.\n", ref);
}
void test_mediastreamfilter_get_state(void) void test_mediastreamfilter_get_state(void)
{ {
IAMMultiMediaStream *mmstream = create_ammultimediastream(); IAMMultiMediaStream *mmstream = create_ammultimediastream();
@ -3077,6 +3208,7 @@ START_TEST(amstream)
test_audiostream_receive_connection(); test_audiostream_receive_connection();
test_audiostream_set_state(); test_audiostream_set_state();
test_audiostream_end_of_stream(); test_audiostream_end_of_stream();
test_audiostream_receive();
test_mediastreamfilter_get_state(); test_mediastreamfilter_get_state();
test_mediastreamfilter_stop_pause_run(); test_mediastreamfilter_stop_pause_run();