On 3/17/20 7:48 PM, Derek Lesho wrote:
@@ -587,6 +594,8 @@ static ULONG WINAPI src_reader_Release(IMFSourceReader *iface) list_remove(&ptr->entry); heap_free(ptr); } + + MFUnlockWorkQueue(stream->read_samples_queue); } heap_free(reader->streams); DeleteCriticalSection(&reader->cs); Is additional queue necessary for synchronous case?
+ if (FAILED(hr = media_stream_get_id(state, &id))) + { + WARN("Bad stream %p, hr %#x.\n", state, hr); + } + + for (unsigned int i = 0; i < reader->stream_count; ++i) + { + if (id == reader->streams[i].id) + { + struct media_stream *stream = &reader->streams[i]; + IMFSample *sample = NULL; + DWORD stream_flags; + LONGLONG timestamp = 0; + + hr = next_sample(stream, &sample, &stream_flags, FALSE); + if (sample) + { + IMFSample_GetSampleTime(sample, ×tamp); + } + + TRACE("Invoking read sample callback %p with (hr = %#x, stream_idx = %u, flags = %#x, timestamp %lu, sample %p)\n", reader->async_callback, hr, i, stream_flags, timestamp, sample); + hr = IMFSourceReaderCallback_OnReadSample(reader->async_callback, hr, i, stream_flags, timestamp, sample); + IMFSample_Release(sample); + return hr; + } + } + + return S_OK; We already talked about this part - blocking in next_sample(), even on dedicated thread, is unnecessary.
What will happen is MENewSample from stream queue -> wake thread in dedicated per-stream queue -> process -> call OnReadSample. Without blocking you'll have MENewSample -> process on same event handling thread -> call OnReadSample. I don't see a need for additional complexity.
+ switch (index) + { + case MF_SOURCE_READER_FIRST_VIDEO_STREAM: + stream_index = reader->first_video_stream_index; + break; + case MF_SOURCE_READER_FIRST_AUDIO_STREAM: + stream_index = reader->first_audio_stream_index; + break; + case MF_SOURCE_READER_ANY_STREAM: + FIXME("Non-specific requests are not supported.\n"); + return E_NOTIMPL; + default: + stream_index = index; + } + + /* Can't read from deselected streams. */ + if (FAILED(hr = source_reader_get_stream_selection(reader, stream_index, &selected)) && !selected) + return hr; If that's how it works, this part applies to both sync and async cases.
+ EnterCriticalSection(&stream->cs); + while(!stream->stream) + { + SleepConditionVariableCS(&stream->sample_event, &stream->cs, INFINITE); + } + LeaveCriticalSection(&stream->cs); + + TRACE("Dispatching read sample callback for stream %p\n", stream->stream); + if (FAILED(hr = MFPutWorkItem(stream->read_samples_queue, &reader->read_samples_callback, (IUnknown*)stream->stream))) + { + WARN("Failed to submit item hr = %#x\n", hr); + return E_FAIL; + } This blocks for indefinite amount of time, for ReadSample method that's supposed to be non-blocking. It's correct of course to start the source here, which also could be potentially shared with sync case, but waiting for new samples, using 'sample_event' that's not meant for it, is wrong.
It should start source, and keep a note of number of times each stream was requested, later on MENewStream/MEUpdatedStream you can issue that many requests at once.