媒体基础:从 SinkWriter 获取 MediaSink
Media Foundation: Getting a MediaSink from a SinkWriter
我正在尝试将 MP4 文件接收器添加到拓扑。当我的 MediaSource
已经是 MP4 时,我使用 MFCreateMPEG4MediaSink
和 MF_MPEG4SINK_SPSPPS_PASSTHROUGH
。当我的 MediaSource
不是 MP4(来自网络摄像头的原始 YUV)时,我想使用 MFCreateSinkWriterFromURL
这样我就不必弄清楚 MP4 headers 和其他复杂的东西。
根据 the MSDN Docs,我应该可以使用 GetServiceForStream
得到 MediaSink
,因为输入类型与输出类型不同。但是它总是 returns MF_E_UNSUPPORTED_SERVICE
.
如何从 MediaSinkWriter
中获取基础 MediaSink
?
或者,我如何轻松地为任意拓扑创建 MP4 媒体接收器?
HRESULT CreateVideoFileSink(
IMFStreamDescriptor *pSourceSD, // Pointer to the stream descriptor.
LPCWSTR pFilename, // Name of file to save to.
IMFStreamSink **ppStream) // Receives a pointer to the stream sink.
HRESULT hr = S_OK;
CComPtr<IMFAttributes> pAttr;
CComPtr<IMFMediaTypeHandler> pHandler;
CComPtr<IMFMediaType> pType;
CComPtr<IMFMediaSink> pSink;
CComPtr<IMFStreamSink> pStream;
CComPtr<IMFSinkWriter> pSinkWriter;
CComPtr<IMFByteStream> pByteStream;
*ppStream = nullptr;
// Get the media type handler for the stream.
IFR(pSourceSD->GetMediaTypeHandler(&pHandler));
// Get the major media type.
GUID guidMajorType;
IFR(pHandler->GetMajorType(&guidMajorType));
IFR(MFCreateAttributes(&pAttr, 1));
IFR(pAttr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, TRUE));
// Create an output file
if (MFMediaType_Video == guidMajorType)
{
GUID guidSubType;
IFR(pHandler->GetCurrentMediaType(&pType));
IFR(pType->GetGUID(MF_MT_SUBTYPE, &guidSubType));
if (MFVideoFormat_H264 == guidSubType)
{
// ... use MFCreateMPEG4MediaSink
}
else
{
IFR(MFCreateSinkWriterFromURL(pFilename, nullptr, pAttr, &pSinkWriter));
DWORD streamIdx;
IFR(pSinkWriter->AddStream(pType, &streamIdx));
IFR(pSinkWriter->GetServiceForStream(MF_SINK_WRITER_MEDIASINK, GUID_NULL, IID_PPV_ARGS(&pSink)));
IFR(pSink->GetStreamSinkByIndex(streamIdx, &pStream));
}
}
else
{
// Don't use this stream
IFR(E_FAIL)
}
// Return IMFStreamSink pointer to caller.
*ppStream = pStream.Detach();
return S_OK;
}
写完问题就想通了——当然。在您调用 BeginWriting
.
之前,SinkWriter
没有 一个 MediaSink
IFR(MFCreateSinkWriterFromURL(pFilename, nullptr, pAttr, &pSinkWriter));
DWORD streamIdx;
IFR(pSinkWriter->AddStream(pType, &streamIdx));
IFR(pSinkWriter->BeginWriting()); // <<----
IFR(pSinkWriter->GetServiceForStream(MF_SINK_WRITER_MEDIASINK, GUID_NULL, IID_PPV_ARGS(&pSink)));
IFR(pSink->GetStreamSinkByIndex(streamIdx, &pStream));
(确保在使用 StreamSink
时不要让 SinkWriter
被释放)
我正在尝试将 MP4 文件接收器添加到拓扑。当我的 MediaSource
已经是 MP4 时,我使用 MFCreateMPEG4MediaSink
和 MF_MPEG4SINK_SPSPPS_PASSTHROUGH
。当我的 MediaSource
不是 MP4(来自网络摄像头的原始 YUV)时,我想使用 MFCreateSinkWriterFromURL
这样我就不必弄清楚 MP4 headers 和其他复杂的东西。
根据 the MSDN Docs,我应该可以使用 GetServiceForStream
得到 MediaSink
,因为输入类型与输出类型不同。但是它总是 returns MF_E_UNSUPPORTED_SERVICE
.
如何从 MediaSinkWriter
中获取基础 MediaSink
?
或者,我如何轻松地为任意拓扑创建 MP4 媒体接收器?
HRESULT CreateVideoFileSink(
IMFStreamDescriptor *pSourceSD, // Pointer to the stream descriptor.
LPCWSTR pFilename, // Name of file to save to.
IMFStreamSink **ppStream) // Receives a pointer to the stream sink.
HRESULT hr = S_OK;
CComPtr<IMFAttributes> pAttr;
CComPtr<IMFMediaTypeHandler> pHandler;
CComPtr<IMFMediaType> pType;
CComPtr<IMFMediaSink> pSink;
CComPtr<IMFStreamSink> pStream;
CComPtr<IMFSinkWriter> pSinkWriter;
CComPtr<IMFByteStream> pByteStream;
*ppStream = nullptr;
// Get the media type handler for the stream.
IFR(pSourceSD->GetMediaTypeHandler(&pHandler));
// Get the major media type.
GUID guidMajorType;
IFR(pHandler->GetMajorType(&guidMajorType));
IFR(MFCreateAttributes(&pAttr, 1));
IFR(pAttr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, TRUE));
// Create an output file
if (MFMediaType_Video == guidMajorType)
{
GUID guidSubType;
IFR(pHandler->GetCurrentMediaType(&pType));
IFR(pType->GetGUID(MF_MT_SUBTYPE, &guidSubType));
if (MFVideoFormat_H264 == guidSubType)
{
// ... use MFCreateMPEG4MediaSink
}
else
{
IFR(MFCreateSinkWriterFromURL(pFilename, nullptr, pAttr, &pSinkWriter));
DWORD streamIdx;
IFR(pSinkWriter->AddStream(pType, &streamIdx));
IFR(pSinkWriter->GetServiceForStream(MF_SINK_WRITER_MEDIASINK, GUID_NULL, IID_PPV_ARGS(&pSink)));
IFR(pSink->GetStreamSinkByIndex(streamIdx, &pStream));
}
}
else
{
// Don't use this stream
IFR(E_FAIL)
}
// Return IMFStreamSink pointer to caller.
*ppStream = pStream.Detach();
return S_OK;
}
写完问题就想通了——当然。在您调用 BeginWriting
.
SinkWriter
没有 一个 MediaSink
IFR(MFCreateSinkWriterFromURL(pFilename, nullptr, pAttr, &pSinkWriter));
DWORD streamIdx;
IFR(pSinkWriter->AddStream(pType, &streamIdx));
IFR(pSinkWriter->BeginWriting()); // <<----
IFR(pSinkWriter->GetServiceForStream(MF_SINK_WRITER_MEDIASINK, GUID_NULL, IID_PPV_ARGS(&pSink)));
IFR(pSink->GetStreamSinkByIndex(streamIdx, &pStream));
(确保在使用 StreamSink
时不要让 SinkWriter
被释放)