我正在使用此代码堆叠一周以上:)
我已经更改了Windows SDK(CWavSink
)附带的示例代码,这是一个自定义波形接收器,用于将PCM数据记录到wav文件中。
我做了一些更改,将该示例用作视频接收器,以便在Windows 8上记录来自网络摄像头的视频流。
我设法从IMFSample
获取视频帧,但我遇到的问题是:
当将捕获的帧记录到测试文件中时,尝试使用ffmpeg将其转换为avi或任何其他格式,输出颜色错误,视频播放不正常。
我为宽度和高度设置的内容我总是将帧设置为320X240。
样本缓冲区总是600kb,包含2帧(我将其设置为一帧作为样本大小)
我尝试将格式从RGB32更改为H263,但似乎忽略了设置,我总是得到RGB32。
我很感激你的任何帮助
这是我的代码
#include "pch.h"
#include "VideoSink.h"
#pragma warning( push )
#pragma warning( disable : 4355 ) // 'this' used in base member initializer list
using namespace VideoRecorder;
const DWORD VIDEO_SINK_STREAM_ID = 1;
HRESULT ValidateVideoFormat(const WAVEFORMATEX *pWav, DWORD cbSize);
HRESULT CreateRawVideoType(
UINT32 frameRate, // Samples per second
UINT32 width, // Bits per sample
UINT32 hieght, // Number of channels
IMFMediaType **ppType // Receives a pointer to the media type.
);
IFACEMETHODIMP CVideoSink::Initialize()
{
IMFByteStream *pStream = nullptr;
HRESULT hr = S_OK;
if (SUCCEEDED(hr))
{
hr = this->Initialize(pStream);
}
return hr;
}
CVideoSink::CVideoSink() :
m_nRefCount(1), m_IsShutdown(FALSE), m_pStream(NULL), m_pClock(NULL)
{
}
CVideoSink::~CVideoSink()
{
TRACE((L"~CVideoSink\n"));
assert(m_IsShutdown);
}
IFACEMETHODIMP CVideoSink::GetCharacteristics(DWORD *pdwCharacteristics)
{
AutoLock lock(m_critSec);
if (pdwCharacteristics == NULL)
{
return E_INVALIDARG;
}
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
*pdwCharacteristics = MEDIASINK_FIXED_STREAMS | MEDIASINK_RATELESS;
}
return hr;
}
IFACEMETHODIMP CVideoSink::AddStreamSink(
DWORD dwStreamSinkIdentifier,
IMFMediaType *pMediaType,
IMFStreamSink **ppStreamSink)
{
return MF_E_STREAMSINKS_FIXED;
}
IFACEMETHODIMP CVideoSink::RemoveStreamSink(DWORD dwStreamSinkIdentifier)
{
return MF_E_STREAMSINKS_FIXED;
}
IFACEMETHODIMP CVideoSink::GetStreamSinkCount(DWORD *pcStreamSinkCount)
{
AutoLock lock(m_critSec);
if (pcStreamSinkCount == NULL)
{
return E_INVALIDARG;
}
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
*pcStreamSinkCount = 1; // Fixed number of streams.
}
return hr;
}
IFACEMETHODIMP CVideoSink::GetStreamSinkByIndex(
DWORD dwIndex,
IMFStreamSink **ppStreamSink)
{
AutoLock lock(m_critSec);
if (ppStreamSink == NULL)
{
return E_INVALIDARG;
}
// Fixed stream: Index 0.
if (dwIndex > 0)
{
return MF_E_INVALIDINDEX;
}
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
*ppStreamSink = m_pStream;
(*ppStreamSink)->AddRef();
}
return hr;
}
IFACEMETHODIMP CVideoSink::GetStreamSinkById(
DWORD dwStreamSinkIdentifier,
IMFStreamSink **ppStreamSink)
{
AutoLock lock(m_critSec);
if (ppStreamSink == NULL)
{
return E_INVALIDARG;
}
// Fixed stream ID.
if (dwStreamSinkIdentifier != VIDEO_SINK_STREAM_ID)
{
return MF_E_INVALIDSTREAMNUMBER;
}
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
*ppStreamSink = m_pStream;
(*ppStreamSink)->AddRef();
}
return hr;
}
IFACEMETHODIMP CVideoSink::SetPresentationClock(IMFPresentationClock *pPresentationClock)
{
AutoLock lock(m_critSec);
HRESULT hr = CheckShutdown();
// If we already have a clock, remove ourselves from that clock's
// state notifications.
if (SUCCEEDED(hr))
{
if (m_pClock)
{
hr = m_pClock->RemoveClockStateSink(this);
}
}
// Register ourselves to get state notifications from the new clock.
if (SUCCEEDED(hr))
{
if (pPresentationClock)
{
hr = pPresentationClock->AddClockStateSink(this);
}
}
if (SUCCEEDED(hr))
{
// Release the pointer to the old clock.
// Store the pointer to the new clock.
SAFE_RELEASE(m_pClock);
m_pClock = pPresentationClock;
if (m_pClock)
{
m_pClock->AddRef();
}
}
return hr;
}
IFACEMETHODIMP CVideoSink::GetPresentationClock(IMFPresentationClock **ppPresentationClock)
{
AutoLock lock(m_critSec);
if (ppPresentationClock == NULL)
{
return E_INVALIDARG;
}
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
if (m_pClock == NULL)
{
hr = MF_E_NO_CLOCK; // There is no presentation clock.
}
else
{
// Return the pointer to the caller.
*ppPresentationClock = m_pClock;
(*ppPresentationClock)->AddRef();
}
}
return hr;
}
IFACEMETHODIMP CVideoSink::Shutdown()
{
TRACE((L"CVideoSink::Shutdown\n"));
AutoLock lock(m_critSec);
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
hr = m_pStream->Shutdown();
SAFE_RELEASE(m_pClock);
SAFE_RELEASE(m_pStream);
m_IsShutdown = true;
}
return hr;
}
IFACEMETHODIMP CVideoSink::BeginFinalize(
IMFAsyncCallback *pCallback,
IUnknown *punkState)
{
TRACE((L"CVideoSink::BeginFinalize\n"));
AutoLock lock(m_critSec);
HRESULT hr = CheckShutdown();
// Tell the stream to finalize.
if (SUCCEEDED(hr))
{
hr = m_pStream->Finalize(pCallback, punkState);
}
return hr;
}
IFACEMETHODIMP CVideoSink::EndFinalize(IMFAsyncResult *pResult)
{
TRACE((L"CVideoSink::EndFinalize\n"));
HRESULT hr = S_OK;
// Return the status code from the async result.
if (pResult == NULL)
{
hr = E_INVALIDARG;
}
else
{
hr = pResult->GetStatus();
}
return hr;
}
HRESULT CVideoSink::OnClockStart(
/* [in] */ MFTIME hnsSystemTime,
/* [in] */ LONGLONG llClockStartOffset)
{
AutoLock lock(m_critSec);
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
hr = m_pStream->Start(llClockStartOffset);
}
return hr;
}
HRESULT CVideoSink::OnClockStop(
/* [in] */ MFTIME hnsSystemTime)
{
TRACE((L"CVideoSink::OnClockStop\n"));
AutoLock lock(m_critSec);
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
hr = m_pStream->Stop();
}
return hr;
}
HRESULT CVideoSink::OnClockPause(
/* [in] */ MFTIME hnsSystemTime)
{
AutoLock lock(m_critSec);
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
hr = m_pStream->Pause();
}
return hr;
}
HRESULT CVideoSink::OnClockRestart(
/* [in] */ MFTIME hnsSystemTime)
{
AutoLock lock(m_critSec);
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
hr = m_pStream->Restart();
}
return hr;
}
HRESULT CVideoSink::OnClockSetRate(
/* [in] */ MFTIME hnsSystemTime,
/* [in] */ float flRate)
{
return S_OK;
}
HRESULT CVideoSink::Initialize(IMFByteStream *pByteStream)
{
HRESULT hr = S_OK;
m_pStream = new CVideoStream();
if (m_pStream == NULL)
{
hr = E_OUTOFMEMORY;
}
IMFMediaTypeHandler* typeHandler;
IMFMediaType* type;
// Initialize the stream.
if (SUCCEEDED(hr))
{
hr = m_pStream->Initialize(this, pByteStream);
}
return hr;
}
我将第二部分添加为另一篇文章(对不起,这是长代码:))
#不允许:)从这里获取https://github.com/Felixsoft/VideoSink