Я собираюсь с этим кодом больше недели 🙂
Я изменил пример кода, включенного в Windows SDK (CWavSink
), который является пользовательским приемником волн для записи данных PCM в файл wav.
Я внес некоторые изменения, чтобы использовать этот образец в качестве приемника видео для записи видеопотока с веб-камеры в Windows 8.
Мне удалось получить видеокадры с IMFSample
но проблемы у меня есть:
Когда вы записываете захваченные кадры в тестовый файл, попробуйте преобразовать его в avi или любой другой формат, используя ffmpeg, на выходе будут неправильные цвета, и видео не воспроизводится нормально.
Что бы я ни установил для ширины и высоты, я всегда получаю кадры как 320X240.
Буфер выборки всегда 600 КБ, который содержит 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
Задача ещё не решена.
Других решений пока нет …