From: Ziqing Hui zhui@codeweavers.com
--- dlls/mf/tests/mf.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index fa538e8ad9f..8bcd0db4f70 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -166,6 +166,14 @@ static IMFSample *create_sample(const BYTE *data, ULONG size) return sample; }
+static void load_resource(const WCHAR *filename, const BYTE **data, DWORD *length) +{ + HRSRC resource = FindResourceW(NULL, filename, (const WCHAR *)RT_RCDATA); + ok(resource != 0, "FindResourceW failed, error %lu\n", GetLastError()); + *data = LockResource(LoadResource(GetModuleHandleW(NULL), resource)); + *length = SizeofResource(GetModuleHandleW(NULL), resource); +} + #define check_handler_required_attributes(a, b) check_handler_required_attributes_(__LINE__, a, b) static void check_handler_required_attributes_(int line, IMFMediaTypeHandler *handler, const struct attribute_desc *attributes) { @@ -2049,13 +2057,9 @@ static IMFMediaSource *create_media_source(const WCHAR *name, const WCHAR *mime) IMFMediaSource *source; IMFByteStream *stream; ULONG resource_len; - HRSRC resource; HRESULT hr;
- resource = FindResourceW(NULL, name, (const WCHAR *)RT_RCDATA); - ok(resource != 0, "FindResourceW %s failed, error %lu\n", debugstr_w(name), GetLastError()); - resource_data = LockResource(LoadResource(GetModuleHandleW(NULL), resource)); - resource_len = SizeofResource(GetModuleHandleW(NULL), resource); + load_resource(name, &resource_data, &resource_len);
hr = MFCreateTempFile(MF_ACCESSMODE_READWRITE, MF_OPENMODE_DELETE_IF_EXIST, MF_FILEFLAGS_NONE, &stream); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
From: Ziqing Hui zhui@codeweavers.com
--- dlls/mf/tests/mf.c | 302 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 302 insertions(+)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 8bcd0db4f70..469884edf58 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -41,6 +41,10 @@ #include "initguid.h" #include "evr9.h"
+#define H264_UNIT_TYPE_IDR 5 +#define H264_UNIT_TYPE_SPS 7 +#define H264_UNIT_TYPE_PPS 8 + #define DEFINE_EXPECT(func) \ static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
@@ -278,6 +282,80 @@ static void init_sink_node(IMFStreamSink *stream_sink, MF_CONNECT_METHOD method, } }
+static BOOL is_h264_unit_start(const BYTE *buffer) +{ + UINT32 value = *(UINT32 *)buffer; + return value == 0x01000000 || (value & 0xffffff) == 0x010000; +} + +static BOOL is_h264_unit_type(const BYTE *buffer, BYTE type) +{ + BYTE type_byte = (*(UINT32 *)buffer == 0x01000000) ? + *(buffer + 4): + *(buffer + 3); + return (type_byte & 0x1f) == type; +} + +static void next_h264_unit(const BYTE **data, DWORD *size) +{ + if (*size <= 4) + { + *data = NULL; + *size = 0; + return; + } + + ok(is_h264_unit_start(*data), "Invalid h264 buffer.\n"); + + *data += 4; + *size -= 4; + + while (*size >= 4) + { + if (is_h264_unit_start(*data)) + return; + + (*data)++; + (*size)--; + } + + *data = NULL; + *size = 0; +} + +static IMFSample *create_h264_sample(const BYTE *data, DWORD size) +{ + const BYTE *sample_data = data; + DWORD sample_size = size; + + next_h264_unit(&data, &size); + if (data) + sample_size -= size; + + return create_sample(sample_data, sample_size); +} + +static void get_h264_sequence_header(const BYTE *data, DWORD size, + const BYTE **sequence_header, DWORD *sequence_header_size) +{ + const BYTE *cur = data; + DWORD cur_size = size; + + while (cur && !is_h264_unit_type(cur, H264_UNIT_TYPE_SPS)) + next_h264_unit(&cur, &cur_size); + + ok(cur && is_h264_unit_type(cur, H264_UNIT_TYPE_SPS), "Unable to get SPS data.\n"); + *sequence_header = cur; + + next_h264_unit(&cur, &cur_size); + ok(cur && is_h264_unit_type(cur, H264_UNIT_TYPE_PPS), "Unable to get PPS data.\n"); + + next_h264_unit(&cur, &cur_size); + ok(!!cur, "No remaining data.\n"); + + *sequence_header_size = cur - *sequence_header; +} + DEFINE_EXPECT(test_source_BeginGetEvent); DEFINE_EXPECT(test_source_QueueEvent); DEFINE_EXPECT(test_source_Start); @@ -6755,6 +6833,117 @@ static void test_MFRequireProtectedEnvironment(void) ok(ref == 0, "Release returned %ld\n", ref); }
+struct test_media_sink_callback +{ + IMFAsyncCallback IMFAsyncCallback_iface; + HANDLE start_event; + HANDLE stop_event; + HANDLE finalize_event; + IMFMediaSink *media_sink; + IMFStreamSink *stream_sink; +}; + +static struct test_media_sink_callback *impl_from_media_sink_callback_IMFAsyncCallback(IMFAsyncCallback *iface) +{ + return CONTAINING_RECORD(iface, struct test_media_sink_callback, IMFAsyncCallback_iface); +} + +static HRESULT WINAPI test_media_sink_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IMFAsyncCallback) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFAsyncCallback_AddRef(iface); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_media_sink_callback_AddRef(IMFAsyncCallback *iface) +{ + return 2; +} + +static ULONG WINAPI test_media_sink_callback_Release(IMFAsyncCallback *iface) +{ + return 1; +} + +static HRESULT WINAPI test_media_sink_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_media_sink_callback_finalize_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + struct test_media_sink_callback *callback = impl_from_media_sink_callback_IMFAsyncCallback(iface); + HRESULT hr; + + ok(!!callback->media_sink, "NULL media sink.\n"); + hr = IMFFinalizableMediaSink_EndFinalize((IMFFinalizableMediaSink *)callback->media_sink, result); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + SetEvent(callback->finalize_event); + + return S_OK; +} + +static HRESULT WINAPI test_media_sink_callback_stream_event_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + struct test_media_sink_callback *callback = impl_from_media_sink_callback_IMFAsyncCallback(iface); + IMFMediaEvent *event; + MediaEventType type; + HRESULT hr; + + ok(!!callback->stream_sink, "NULL stream sink.\n"); + + hr = IMFStreamSink_EndGetEvent(callback->stream_sink, result, &event); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaEvent_GetType(event, &type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + switch (type) + { + case MEStreamSinkStarted: + SetEvent(callback->start_event); + break; + case MEStreamSinkStopped: + SetEvent(callback->stop_event); + break; + default: + break; + } + + IMFMediaEvent_Release(event); + + IMFStreamSink_BeginGetEvent(callback->stream_sink, iface, NULL); + + return S_OK; +} + +static const IMFAsyncCallbackVtbl test_media_sink_callback_finalize_vtbl = +{ + test_media_sink_callback_QueryInterface, + test_media_sink_callback_AddRef, + test_media_sink_callback_Release, + test_media_sink_callback_GetParameters, + test_media_sink_callback_finalize_Invoke, +}; + + +static const IMFAsyncCallbackVtbl test_media_sink_callback_event_vtbl = +{ + test_media_sink_callback_QueryInterface, + test_media_sink_callback_AddRef, + test_media_sink_callback_Release, + test_media_sink_callback_GetParameters, + test_media_sink_callback_stream_event_Invoke, +}; + static void test_mpeg4_media_sink(void) { IMFMediaSink *sink = NULL, *sink2 = NULL, *sink_audio = NULL, *sink_video = NULL, *sink_empty = NULL; @@ -7054,6 +7243,118 @@ static void test_mpeg4_media_sink(void) IMFMediaType_Release(audio_type); }
+static void test_mpeg4_media_sink_process(void) +{ + DWORD width = 96, height = 96, fps = 1, h264_data_size, ret, sequence_header_length = 0; + struct test_media_sink_callback finalize_callback, stream_event_callback; + const BYTE *h264_data, *sequence_header = NULL; + IMFPresentationTimeSource *time_source; + IMFPresentationClock *clock; + IMFStreamSink *stream_sink; + IMFByteStream *bytestream; + IMFMediaType *video_type; + IMFMediaSink *media_sink; + IMFSample *input_sample; + HRESULT hr; + + load_resource(L"h264data.bin", &h264_data, &h264_data_size); + get_h264_sequence_header(h264_data, h264_data_size, &sequence_header, &sequence_header_length); + + hr = MFCreateMediaType(&video_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetGUID(video_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetGUID(video_type, &MF_MT_SUBTYPE, &MFVideoFormat_H264); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT64(video_type, &MF_MT_FRAME_SIZE, ((UINT64)width << 32) | height); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetBlob(video_type, &MF_MT_MPEG_SEQUENCE_HEADER, sequence_header, sequence_header_length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT64(video_type, &MF_MT_FRAME_RATE, ((UINT64)fps << 32) | 1); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateTempFile(MF_ACCESSMODE_READWRITE, MF_OPENMODE_DELETE_IF_EXIST, MF_FILEFLAGS_NONE, &bytestream); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateMPEG4MediaSink(bytestream, video_type, NULL, &media_sink); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr != S_OK) + { + IMFByteStream_Release(bytestream); + IMFMediaType_Release(video_type); + return; + } + + /* Set presentation clock. */ + hr = MFCreateSystemTimeSource(&time_source); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFCreatePresentationClock(&clock); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFPresentationClock_SetTimeSource(clock, time_source); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSink_SetPresentationClock(media_sink, clock); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Stream event handler. */ + hr = IMFMediaSink_GetStreamSinkById(media_sink, 1, &stream_sink); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + stream_event_callback.IMFAsyncCallback_iface.lpVtbl = &test_media_sink_callback_event_vtbl; + stream_event_callback.start_event = CreateEventW(NULL, FALSE, FALSE, NULL); + stream_event_callback.stop_event = CreateEventW(NULL, FALSE, FALSE, NULL); + stream_event_callback.stream_sink = stream_sink; + hr = IMFStreamSink_BeginGetEvent(stream_sink, &stream_event_callback.IMFAsyncCallback_iface, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Start. */ + hr = IMFPresentationClock_Start(clock, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ret = WaitForSingleObject(stream_event_callback.start_event, 3000); + ok(!ret, "WaitForSingleObject returned %#lx.\n", ret); + + /* Find IDR frame. */ + while (!is_h264_unit_type(h264_data, H264_UNIT_TYPE_IDR)) + next_h264_unit(&h264_data, &h264_data_size); + + /* Process sample. */ + input_sample = create_h264_sample(h264_data, h264_data_size); + hr = IMFSample_SetSampleTime(input_sample, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFSample_SetSampleDuration(input_sample, 10000000); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFStreamSink_ProcessSample(stream_sink, input_sample); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Finalize media sink. */ + hr = IMFPresentationClock_Stop(clock); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + WaitForSingleObject(stream_event_callback.stop_event, 3000); + + finalize_callback.IMFAsyncCallback_iface.lpVtbl = &test_media_sink_callback_finalize_vtbl; + finalize_callback.finalize_event = CreateEventW(NULL, FALSE, FALSE, NULL); + finalize_callback.media_sink = media_sink; + hr = IMFFinalizableMediaSink_BeginFinalize((IMFFinalizableMediaSink *)media_sink, + &finalize_callback.IMFAsyncCallback_iface, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ret = WaitForSingleObject(finalize_callback.finalize_event, 3000); + ok(!ret, "WaitForSingleObject returned %#lx.\n", ret); + + hr = IMFMediaSink_Shutdown(media_sink); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ret = IMFMediaSink_Release(media_sink); + ok(ret == 0, "Release returned %lu.\n", ret); + + IMFSample_Release(input_sample); + CloseHandle(finalize_callback.finalize_event); + CloseHandle(stream_event_callback.stop_event); + CloseHandle(stream_event_callback.start_event); + IMFStreamSink_Release(stream_sink); + IMFPresentationClock_Release(clock); + IMFPresentationTimeSource_Release(time_source); + IMFByteStream_Release(bytestream); + IMFMediaType_Release(video_type); +} + START_TEST(mf) { init_functions(); @@ -7088,4 +7389,5 @@ START_TEST(mf) test_MFGetTopoNodeCurrentType(); test_MFRequireProtectedEnvironment(); test_mpeg4_media_sink(); + test_mpeg4_media_sink_process(); }
Nikolay Sivov (@nsivov) commented about dlls/mf/tests/mf.c:
- stream_event_callback.stream_sink = stream_sink;
- hr = IMFStreamSink_BeginGetEvent(stream_sink, &stream_event_callback.IMFAsyncCallback_iface, NULL);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- /* Start. */
- hr = IMFPresentationClock_Start(clock, 0);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- ret = WaitForSingleObject(stream_event_callback.start_event, 3000);
- ok(!ret, "WaitForSingleObject returned %#lx.\n", ret);
- /* Find IDR frame. */
- while (!is_h264_unit_type(h264_data, H264_UNIT_TYPE_IDR))
next_h264_unit(&h264_data, &h264_data_size);
- /* Process sample. */
- input_sample = create_h264_sample(h264_data, h264_data_size);
It might be easier to have a blob with some minimal frame data, of minimal dimensions.
Nikolay Sivov (@nsivov) commented about dlls/mf/tests/mf.c:
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- /* Start. */
- hr = IMFPresentationClock_Start(clock, 0);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- ret = WaitForSingleObject(stream_event_callback.start_event, 3000);
- ok(!ret, "WaitForSingleObject returned %#lx.\n", ret);
- /* Find IDR frame. */
- while (!is_h264_unit_type(h264_data, H264_UNIT_TYPE_IDR))
next_h264_unit(&h264_data, &h264_data_size);
- /* Process sample. */
- input_sample = create_h264_sample(h264_data, h264_data_size);
- hr = IMFSample_SetSampleTime(input_sample, 0);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
Isn't it zero by default?
Nikolay Sivov (@nsivov) commented about dlls/mf/tests/mf.c:
- input_sample = create_h264_sample(h264_data, h264_data_size);
- hr = IMFSample_SetSampleTime(input_sample, 0);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- hr = IMFSample_SetSampleDuration(input_sample, 10000000);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- hr = IMFStreamSink_ProcessSample(stream_sink, input_sample);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- /* Finalize media sink. */
- hr = IMFPresentationClock_Stop(clock);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- WaitForSingleObject(stream_event_callback.stop_event, 3000);
- finalize_callback.IMFAsyncCallback_iface.lpVtbl = &test_media_sink_callback_finalize_vtbl;
- finalize_callback.finalize_event = CreateEventW(NULL, FALSE, FALSE, NULL);
- finalize_callback.media_sink = media_sink;
This should be in some helper if we need this at all.
Nikolay Sivov (@nsivov) commented about dlls/mf/tests/mf.c:
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- hr = IMFSample_SetSampleDuration(input_sample, 10000000);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- hr = IMFStreamSink_ProcessSample(stream_sink, input_sample);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- /* Finalize media sink. */
- hr = IMFPresentationClock_Stop(clock);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- WaitForSingleObject(stream_event_callback.stop_event, 3000);
- finalize_callback.IMFAsyncCallback_iface.lpVtbl = &test_media_sink_callback_finalize_vtbl;
- finalize_callback.finalize_event = CreateEventW(NULL, FALSE, FALSE, NULL);
- finalize_callback.media_sink = media_sink;
- hr = IMFFinalizableMediaSink_BeginFinalize((IMFFinalizableMediaSink *)media_sink,
&finalize_callback.IMFAsyncCallback_iface, NULL);
This is not a good way to cast an interface pointer.
Nikolay Sivov (@nsivov) commented about dlls/mf/tests/mf.c:
return;
- }
- /* Set presentation clock. */
- hr = MFCreateSystemTimeSource(&time_source);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- hr = MFCreatePresentationClock(&clock);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- hr = IMFPresentationClock_SetTimeSource(clock, time_source);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- hr = IMFMediaSink_SetPresentationClock(media_sink, clock);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- /* Stream event handler. */
- hr = IMFMediaSink_GetStreamSinkById(media_sink, 1, &stream_sink);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
Why is that at index 1? What's at 0?
Nikolay Sivov (@nsivov) commented about dlls/mf/tests/mf.c:
- if (hr != S_OK)
- {
IMFByteStream_Release(bytestream);
IMFMediaType_Release(video_type);
return;
- }
- /* Set presentation clock. */
- hr = MFCreateSystemTimeSource(&time_source);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- hr = MFCreatePresentationClock(&clock);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- hr = IMFPresentationClock_SetTimeSource(clock, time_source);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- hr = IMFMediaSink_SetPresentationClock(media_sink, clock);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
Did you check if you can query for IMFClockStateSink and use that directly?
Nikolay Sivov (@nsivov) commented about dlls/mf/tests/mf.c:
- finalize_callback.media_sink = media_sink;
- hr = IMFFinalizableMediaSink_BeginFinalize((IMFFinalizableMediaSink *)media_sink,
&finalize_callback.IMFAsyncCallback_iface, NULL);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- ret = WaitForSingleObject(finalize_callback.finalize_event, 3000);
- ok(!ret, "WaitForSingleObject returned %#lx.\n", ret);
- hr = IMFMediaSink_Shutdown(media_sink);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- ret = IMFMediaSink_Release(media_sink);
- ok(ret == 0, "Release returned %lu.\n", ret);
- IMFSample_Release(input_sample);
- CloseHandle(finalize_callback.finalize_event);
- CloseHandle(stream_event_callback.stop_event);
- CloseHandle(stream_event_callback.start_event);
We have event waiting helpers somewhere in tests already. Might be a good idea to reuse that.
Nikolay Sivov (@nsivov) commented about dlls/mf/tests/mf.c:
test_MFGetTopoNodeCurrentType(); test_MFRequireProtectedEnvironment(); test_mpeg4_media_sink();
- test_mpeg4_media_sink_process();
This test does not really check anything regarding sample processing. Only that sample is accepted.
On Fri Jul 21 23:32:35 2023 +0000, Nikolay Sivov wrote:
Why is that at index 1? What's at 0?
The id of the stream is 1, the index of it is 0.
On Fri Jul 21 23:32:35 2023 +0000, Nikolay Sivov wrote:
Did you check if you can query for IMFClockStateSink and use that directly?
OK, I'll try that.
On Fri Jul 21 23:32:34 2023 +0000, Nikolay Sivov wrote:
Isn't it zero by default?
If I don't call SetSampleTime here, ProcessSample will return MF_E_NO_SAMPLE_TIMESTAMP.
On Fri Jul 21 23:32:33 2023 +0000, Nikolay Sivov wrote:
It might be easier to have a blob with some minimal frame data, of minimal dimensions.
OK, I'll try to generate a minimal h264 frame. I just thought of using the exsiting resource before.
On Fri Jul 21 23:32:34 2023 +0000, Nikolay Sivov wrote:
This is not a good way to cast an interface pointer.
IMFFinalizableMediaSink directly inherits from IMFMediaSink, so just cast it. Should I use QueryInterface to grab IMFFinalizableMediaSink from IMFMediaSink here?
On Fri Jul 21 23:32:36 2023 +0000, Nikolay Sivov wrote:
This test does not really check anything regarding sample processing. Only that sample is accepted.
BeginFinalize/EndFinalize will make sure that all samples in queue is processed and finally generate the mp4 file. If I change MFCreateTempFile to MFCreateFile("C:\Temp\1.mp4"), it do produce a mp4 file which contains the frame as we expected.
On Sat Jul 22 01:49:23 2023 +0000, Ziqing Hui wrote:
BeginFinalize/EndFinalize will make sure that all samples in queue is processed and finally generate the mp4 file. If I change MFCreateTempFile to MFCreateFile("C:\Temp\1.mp4"), it do produce a mp4 file which contains the frame as we expected.
I know I may should add more tests that decode the file which is generated by mediasink, and check the decoded frame with the original frame blob.