使用媒体基金会时如何读取-“unsigned char const *”?
Posted
技术标签:
【中文标题】使用媒体基金会时如何读取-“unsigned char const *”?【英文标题】:How to read from - "unsigned char const *" when use Media Foundation? 【发布时间】:2020-11-23 15:58:24 【问题描述】:我有这样的实现
void coAudioPlayerSampleGrabber::test(SoundDataType dataType,
unsigned char const * pData,
int64_t dataLen)
HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
IMFSourceReader *pReader = NULL;
IMFByteStream * spByteStream = NULL;
HRESULT hr = S_OK;
// Initialize the COM library.
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
// Initialize the Media Foundation platform.
if (SUCCEEDED(hr))
hr = MFStartup(MF_VERSION);
hr = MFCreateMFByteStreamOnStreamEx((IUnknown*)pData, &spByteStream);
if (FAILED(hr))
printf("Error MFCreateMFByteStreamOnStreamEx");
IMFAttributes * Atrr = NULL;
hr = MFCreateAttributes(&Atrr, 10);
if (FAILED(hr))
printf("Error MFCreateAttributes");
hr = Atrr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, true);
if (FAILED(hr))
printf("Error Atrr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, true)");
hr = MFCreateSourceReaderFromByteStream(spByteStream, Atrr, &pReader);
if (FAILED(hr))
printf("Error MFCreateSourceReaderFromByteStream");
if (FAILED(hr))
printf("Error opening input file");
IMFMediaType *pAudioType = NULL; // Represents the PCM audio format.
hr = ConfigureAudiostream(dataType, pReader, &pAudioType);
if (FAILED(hr))
printf("Error ConfigureAudioStream");
IMFSample *pSample = NULL;
IMFMediaBuffer *pBuffer = NULL;
BYTE *pAudioData = NULL;
DWORD cbBuffer = 0;
std::vector<SampleData> samples_vec;
while (true)
DWORD dwFlags = 0;
hr = pReader->ReadSample((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, NULL, &dwFlags, NULL, &pSample);
if (FAILED(hr)) break;
if (dwFlags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)
printf("Type change - not supported by WAVE file format.\n");
break;
if (dwFlags & MF_SOURCE_READERF_ENDOFSTREAM)
printf("End of input file.\n");
break;
hr = pSample->ConvertToContiguousBuffer(&pBuffer);
if (FAILED(hr)) break;
hr = pBuffer->Lock(&pAudioData, NULL, &cbBuffer);
if (FAILED(hr)) break;
//Do something with the pAudioData which is an array of unsigned chars of lenth cbBuffer
SampleData tmp;
tmp.pAudioData = new byte[cbBuffer];
memcpy(tmp.pAudioData, pAudioData, cbBuffer);
tmp.cbBuffer = cbBuffer;
samples_vec.push_back(tmp);
// Unlock the buffer.
hr = pBuffer->Unlock();
pAudioData = NULL;
if (FAILED(hr)) break;
SafeRelease(&pReader);
SafeRelease(&pSample);
SafeRelease(&pBuffer);
SafeRelease(&spByteStream);
SafeRelease(&Atrr);
// Shut down Media Foundation.
MFShutdown();
CoUninitialize();
如您所见,我有指向数据和大小的指针,这实际上是我需要解码的数据。问题是这里
hr = MFCreateMFByteStreamOnStreamEx((IUnknown*)pData, &spByteStream);
我收到一个错误access violation
,据我所知,这是因为我尝试将pData
转换为IUnknown*
。问题是 - 如何正确转换它?
【问题讨论】:
【参考方案1】:你不能这样偷工减料:
unsigned char const * pData;
...
hr = MFCreateMFByteStreamOnStreamEx((IUnknown*)pData, &spByteStream);
IUnknown
不是字节的另一个花哨的别名。如文档所述,您应该按字面意思提供表示流的接口指针。
Media Foundation 确实为您提供了从内存字节中读取的方法。您需要为每个文档创建一个真实的流,IStream
或 IRandomAccessStream
或 IMFByteStream
。还提供 IMFAttributes
您创建的具有适当属性以指定数据类型(否则在文件的情况下是从扩展名或 MIME 类型派生的),然后 Source Reader API 将能够处理内存字节作为媒体文件数据的源,合适的解码器会将音频解码为 PCM 数据(类似于this)。
您可以快速做的事情:CreateStreamOnHGlobal
创建IStream
实现并将您的字节复制到底层缓冲区(请参阅文档)。然后MFCreateMFByteStreamOnStream
将在其上创建一个IMFByteStream
wrappr,您可以将此包装器用作MFCreateSourceReaderFromByteStream
参数。
【讨论】:
【参考方案2】:我曾经使用 VectorStream 类来处理这些东西。有的功能没有实现,但基本思路你应该明白了。
class VectorStream : public IStream
public:
bool ReadOnly = false;
ULONG r = 1;
std::vector<char> d;
size_t p = 0;
VectorStream()
void Clear()
d.clear();
p = 0;
// IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(
/* [in] */ REFIID riid,
/* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject)
if (riid == __uuidof(IUnknown) || riid == __uuidof(IStream))
*ppvObject = (IStream*)this;
r++;
return S_OK;
return E_NOINTERFACE;
virtual ULONG STDMETHODCALLTYPE AddRef(void)
return ++r;
virtual ULONG STDMETHODCALLTYPE Release(void)
return --r;
HRESULT __stdcall Clone(
IStream** ppstm
)
return E_NOTIMPL;
HRESULT __stdcall Commit(
DWORD grfCommitFlags
)
return S_OK;
HRESULT __stdcall CopyTo(
IStream* pstm,
ULARGE_INTEGER cb,
ULARGE_INTEGER* pcbRead,
ULARGE_INTEGER* pcbWritten
)
return E_NOINTERFACE;
HRESULT __stdcall LockRegion(
ULARGE_INTEGER libOffset,
ULARGE_INTEGER cb,
DWORD dwLockType
)
return S_OK;
HRESULT __stdcall UnlockRegion(
ULARGE_INTEGER libOffset,
ULARGE_INTEGER cb,
DWORD dwLockType
)
return S_OK;
HRESULT __stdcall Revert()
return E_NOTIMPL;
HRESULT __stdcall Seek(
LARGE_INTEGER dlibMove,
DWORD dwOrigin,
ULARGE_INTEGER* plibNewPosition
)
LARGE_INTEGER lo = 0 ;
if (dwOrigin == STREAM_SEEK_SET)
p = dlibMove.QuadPart;
if (dwOrigin == STREAM_SEEK_CUR)
p += dlibMove.QuadPart;
if (dwOrigin == STREAM_SEEK_END)
p = d.size() - dlibMove.QuadPart;
if (p >= d.size())
p = d.size();
if (plibNewPosition)
plibNewPosition->QuadPart = p;
return S_OK;
HRESULT __stdcall SetSize(
ULARGE_INTEGER libNewSize
)
d.resize(libNewSize.QuadPart);
return S_OK;
int eb = 0;
HRESULT __stdcall Stat(
STATSTG* pstatstg,
DWORD grfStatFlag
)
pstatstg->type = STGTY_STREAM;
pstatstg->cbSize.QuadPart = d.size();
pstatstg->grfLocksSupported = true;
return S_OK;
unsigned long long readbytes = 0;
HRESULT __stdcall Read(
void* pv,
ULONG cb,
ULONG* pcbRead
)
auto av = d.size() - p;
if (cb < av)
av = cb;
memcpy(pv, d.data() + p, av);
p += av;
if (pcbRead)
*pcbRead = (ULONG)av;
// if (av < cb)
// return S_FALSE;
return S_OK;
HRESULT __stdcall Write(
const void* pv,
ULONG cb,
ULONG* pcbWritten
)
if (ReadOnly)
return STG_E_ACCESSDENIED;
if (d.size() < (p + cb))
auto exc = (p + cb) - d.size();
d.resize(d.size() + exc);
memcpy(d.data() + p, pv, cb);
p += cb;
if (pcbWritten)
*pcbWritten = cb;
return S_OK;
;
它将 std::vector 封装在 IStream 中。
【讨论】:
以上是关于使用媒体基金会时如何读取-“unsigned char const *”?的主要内容,如果未能解决你的问题,请参考以下文章