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:
parent
b90cd8b0a4
commit
1a20f9b06b
|
@ -27,6 +27,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(amstream);
|
|||
|
||||
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
|
||||
{
|
||||
IAMMediaStream IAMMediaStream_iface;
|
||||
|
@ -47,6 +56,7 @@ struct audio_stream
|
|||
WAVEFORMATEX format;
|
||||
FILTER_STATE state;
|
||||
BOOL eos;
|
||||
struct list receive_queue;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
@ -56,6 +66,24 @@ typedef struct {
|
|||
IAudioData *audio_data;
|
||||
} 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)
|
||||
{
|
||||
return CONTAINING_RECORD(iface, IAudioStreamSampleImpl, IAudioStreamSample_iface);
|
||||
|
@ -348,6 +376,8 @@ static HRESULT WINAPI audio_IAMMediaStream_SetState(IAMMediaStream *iface, FILTE
|
|||
|
||||
EnterCriticalSection(&stream->cs);
|
||||
|
||||
if (state == State_Stopped)
|
||||
flush_receive_queue(stream);
|
||||
if (stream->state == State_Stopped)
|
||||
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)
|
||||
{
|
||||
FIXME("iface %p, sample %p, stub!\n", iface, sample);
|
||||
return E_NOTIMPL;
|
||||
struct audio_stream *stream = impl_from_IMemInputPin(iface);
|
||||
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,
|
||||
|
@ -1102,6 +1168,7 @@ HRESULT audio_stream_create(IMultiMediaStream *parent, const MSPID *purpose_id,
|
|||
object->parent = parent;
|
||||
object->purpose_id = *purpose_id;
|
||||
object->stream_type = stream_type;
|
||||
list_init(&object->receive_queue);
|
||||
|
||||
*media_stream = &object->IAMMediaStream_iface;
|
||||
|
||||
|
|
|
@ -2904,6 +2904,137 @@ void test_audiostream_end_of_stream(void)
|
|||
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)
|
||||
{
|
||||
IAMMultiMediaStream *mmstream = create_ammultimediastream();
|
||||
|
@ -3077,6 +3208,7 @@ START_TEST(amstream)
|
|||
test_audiostream_receive_connection();
|
||||
test_audiostream_set_state();
|
||||
test_audiostream_end_of_stream();
|
||||
test_audiostream_receive();
|
||||
|
||||
test_mediastreamfilter_get_state();
|
||||
test_mediastreamfilter_stop_pause_run();
|
||||
|
|
Loading…
Reference in New Issue