问题
I have such an implementation
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();
}
So as you can see I have pointer to data and size this is actually my data I need to decode it. Problem is that here
hr = MFCreateMFByteStreamOnStreamEx((IUnknown*)pData, &spByteStream);
I got an error access violation
and as far as I see this is because I try to convert pData
to IUnknown*
. Question is - How to convert it right?
回答1:
You can't cut corners like this:
unsigned char const * pData;
...
hr = MFCreateMFByteStreamOnStreamEx((IUnknown*)pData, &spByteStream);
IUnknown
is not yet another fancy alias for a byte. You are supposed to literally supply interface pointer representing stream, as documented.
Media Foundation does offer you means to read from memory bytes. You need to create a create a real stream, IStream
or IRandomAccessStream
or IMFByteStream
per docuemntation. Also supply IMFAttributes
you created with proper attributes to specify data type (which otherwise in the case of a file are derived from extension or MIME type) and then Source Reader API would be able to process memory bytes as source of media file data, and suitable decoder would decode audio into PCM data (similar to this).
Something you can do real quick: CreateStreamOnHGlobal to create IStream
implementation and copy your bytes into underlying buffer (see docs). Then MFCreateMFByteStreamOnStream would create a IMFByteStream
wrappr over it, and you can use this wrapper as MFCreateSourceReaderFromByteStream
argument.
回答2:
I used to use a VectorStream class for such stuff. Some functions are not implemented, but you should get the basic idea.
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;
}
};
It encapsulates std::vector<> in a IStream.
来源:https://stackoverflow.com/questions/64971831/how-to-read-from-unsigned-char-const-when-use-media-foundation