Как я могу сохранить в avi файл захваченного потокового видео в C ++?

Это содержимое файла cpp:

// VideoCaptureFilterSampleDlg.cpp : implementation file
//

#include "stdafx.h"#include "VideoCaptureFilterSample.h"#include "VideoCaptureFilterSampleDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif// CVideoCaptureFilterSampleDlg dialogCVideoCaptureFilterSampleDlg::CVideoCaptureFilterSampleDlg(CWnd* pParent /*=NULL*/)
: CDialog(CVideoCaptureFilterSampleDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CVideoCaptureFilterSampleDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CVideoCaptureFilterSampleDlg, CDialog)
//{{AFX_MSG_MAP(CVideoCaptureFilterSampleDlg)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
ON_BN_CLICKED(IDC_PROPERTIES, &CVideoCaptureFilterSampleDlg::OnBnClickedProperties)
END_MESSAGE_MAP()// CVideoCaptureFilterSampleDlg message handlers

BOOL CVideoCaptureFilterSampleDlg::OnInitDialog()
{
CDialog::OnInitDialog();

// Set the icon for this dialog.  The framework does this automatically
//  when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE);         // Set big icon
SetIcon(m_hIcon, FALSE);        // Set small icon

// TODO: Add extra initialization here
InitGraph();

return TRUE;  // return TRUE  unless you set the focus to a control
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CVideoCaptureFilterSampleDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting

SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;

// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CVideoCaptureFilterSampleDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}

void CVideoCaptureFilterSampleDlg::OnBnClickedProperties()
{
ShowProperties();
}

void CVideoCaptureFilterSampleDlg::OnOK()
{
HRESULT hr = DestroyGraph();
_ASSERT(SUCCEEDED(hr));

CDialog::OnOK();
}

void CVideoCaptureFilterSampleDlg::OnCancel()
{
HRESULT hr = DestroyGraph();
_ASSERT(SUCCEEDED(hr));

CDialog::OnCancel();
}/*=============================================================================
// BUILD GRAPH
=============================================================================*/#include <initguid.h>
#include <streams.h>    // for DirectShow headers
#include <wmcodecdsp.h> // for MEDIASUBTYPE_MPEG_ADTS_AAC
#include <mmreg.h>      // for WAVE_FORMAT_MPEG_ADTS_AAC
#include <dvdmedia.h>   // for VIDEOINFOHEADER2
#include <bdaiface.h>   // for IMPEG2PIDMap

#pragma comment(lib, "strmbaseu.lib")       // for <streams.h>
#pragma comment(lib, "wmcodecdspuuid.lib")  // for UUIDs from <wmcodecdsp.h>

#if 1
#include "../VideoCaptureFilter/IVideoCaptureFilter.h"#else
#define ELGATO_VCF_VIDEO_PID    100 //!< video PID in MPEG-TS stream
#define ELGATO_VCF_AUDIO_PID    101 //!< audio PID in MPEG-TS stream

// Filter guid of Elgato Video Capture Filter
// {39F50F4C-99E1-464a-B6F9-D605B4FB5918}
DEFINE_GUID(CLSID_ElgatoVideoCaptureFilter,
0x39f50f4c, 0x99e1, 0x464a, 0xb6, 0xf9, 0xd6, 0x5, 0xb4, 0xfb, 0x59, 0x18);
#endif

// renderFromMpegTsPin: true  - use compressed data from the MPEG-TS pin (if present)
//                      false - use raw data from the video and audio pins
const bool renderFromMpegTsPin = false;#ifndef SAFE_RELEASE
#define SAFE_RELEASE(_pI_) { if(_pI_) { (_pI_)->Release(); (_pI_)=NULL;} }
#endifCComPtr<ICaptureGraphBuilder2>  pCapBuilder;
CComPtr<IFilterGraph2>          pFilterGraph;
CComPtr<IMediaControl>          pMediaControl;
CComPtr<IVideoWindow>           pVideoWindow;
CComPtr<IBasicAudio>            pBasicAudio;
CComPtr<IBaseFilter>            pCapFilter;

//! see https://msdn.microsoft.com/en-us/library/windows/desktop/dd757808(v=vs.85).aspx
AM_MEDIA_TYPE* GetVideoMediaType()
{
static VIDEOINFOHEADER2 vih;
ZeroMemory(&vih, sizeof(vih));

vih.bmiHeader.biSize            = sizeof(vih.bmiHeader);
vih.bmiHeader.biWidth           = 1920;
vih.bmiHeader.biHeight          = 1080;
vih.bmiHeader.biPlanes          = 1;
vih.bmiHeader.biBitCount        = 16;
vih.bmiHeader.biCompression     = MAKEFOURCC('H', '2', '6', '4');

vih.dwPictAspectRatioX          = 16;
vih.dwPictAspectRatioY          = 9;

static AM_MEDIA_TYPE  mt;
ZeroMemory(&mt, sizeof(mt));

mt.majortype                    = MEDIATYPE_Video;
mt.subtype                      = MEDIASUBTYPE_H264;

mt.bFixedSizeSamples            = FALSE;
mt.bTemporalCompression         = TRUE;
mt.lSampleSize                  = 1;

mt.formattype                   = FORMAT_VideoInfo2;
mt.cbFormat                     = sizeof(vih);
mt.pbFormat                     = (BYTE*)&vih;

return &mt;
}

//! @return audio media type that is accepted by "Microsoft DTV-DVD Audio Decoder"AM_MEDIA_TYPE* GetAudioMediaType()
{
static WAVEFORMATEX wfx;
ZeroMemory(&wfx, sizeof(wfx));

wfx.wFormatTag                  = WAVE_FORMAT_MPEG_ADTS_AAC;
wfx.nChannels                   = 2;
wfx.nSamplesPerSec              = 48000;
wfx.nAvgBytesPerSec             = 14000;
wfx.nBlockAlign                 = 24;
wfx.wBitsPerSample              = 16;
wfx.cbSize                      = 0;

static AM_MEDIA_TYPE  mt;
ZeroMemory(&mt, sizeof(mt));
mt.majortype                    = MEDIATYPE_Audio;
mt.subtype                      = MEDIASUBTYPE_MPEG_ADTS_AAC;

mt.bFixedSizeSamples            = TRUE;
mt.bTemporalCompression         = FALSE;
mt.lSampleSize                  = 1;

mt.formattype                   = FORMAT_WaveFormatEx;
mt.cbFormat                     = sizeof(wfx);
mt.pbFormat                     = (BYTE*)&wfx;

return &mt;
}

void _DumpGraph(IFilterGraph2* pIFilterGraph)
{
_ASSERTE(NULL != pIFilterGraph);
if (NULL != pIFilterGraph)
{
CComPtr<IEnumFilters> pEnumFilters;
HRESULT hrTmp = pFilterGraph->EnumFilters(&pEnumFilters);
if (SUCCEEDED(hrTmp))
{
IBaseFilter* pFilter = NULL;
while (S_OK == pEnumFilters->Next(1, &pFilter, NULL))
{
FILTER_INFO filterInfo;
memset(&filterInfo, 0, sizeof(filterInfo));
pFilter->QueryFilterInfo(&filterInfo);
SAFE_RELEASE(filterInfo.pGraph);

SAFE_RELEASE(pFilter);

OutputDebugStringA("  Filter: ");
OutputDebugStringW(filterInfo.achName);
OutputDebugStringA("\n");

}
}
}
}

HRESULT CVideoCaptureFilterSampleDlg::InitGraph()
{
CoInitialize(NULL);

HRESULT hr = S_OK;

/*----------------------------------------------------------------------------
// Create the graph builder & filter graph
-----------------------------------------------------------------------------*/
// FMB NOTE: This is pretty safe, so we can assume it will not fail
hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC, IID_ICaptureGraphBuilder2, (void **)&pCapBuilder);
_ASSERT(SUCCEEDED(hr));

hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IFilterGraph2, (void **)&pFilterGraph);
_ASSERT(SUCCEEDED(hr));

hr = pCapBuilder->SetFiltergraph(pFilterGraph);
_ASSERT(SUCCEEDED(hr));

hr = pFilterGraph->QueryInterface(IID_IMediaControl, (void**)&pMediaControl);
_ASSERT(SUCCEEDED(hr));/*-----------------------------------------------------------------------------
// Build graph
-----------------------------------------------------------------------------*/

// Add "Elgato Game Capture HD" filter
hr = CoCreateInstance(CLSID_ElgatoVideoCaptureFilter, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void **)&pCapFilter);
_ASSERT(SUCCEEDED(hr));

hr = pFilterGraph->AddFilter(pCapFilter, L"Elgato Game Capture HD");
_ASSERT(SUCCEEDED(hr));

// Add "Video Mixing Renderer 9" filter (VMR-9)
CComPtr<IBaseFilter> pVideoRendererFilter;
hr = CoCreateInstance(CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void **)&pVideoRendererFilter);
_ASSERT(SUCCEEDED(hr));

hr = pFilterGraph->AddFilter(pVideoRendererFilter, L"VMR-9");
_ASSERT(SUCCEEDED(hr));

// Add Audio Renderer filter (must be in the graph as reference clock even if it is not connected)
CComPtr<IBaseFilter> pAudioRendererFilter;
hr = CoCreateInstance(CLSID_DSoundRender, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void **)&pAudioRendererFilter);
_ASSERT(SUCCEEDED(hr));

hr = pFilterGraph->AddFilter(pAudioRendererFilter, L"DirectSound Renderer");
_ASSERT(SUCCEEDED(hr));

/*-----------------------------------------------------------------------------
// a) Render from MPEG-TS pin (if available)
-----------------------------------------------------------------------------*/
CComPtr<IPin> pMpegTsOutput;
HRESULT hrTmp = pCapBuilder->FindPin(pCapFilter, PINDIR_OUTPUT, NULL, &MEDIATYPE_Stream, TRUE, 0, &pMpegTsOutput);
bool hasMpegTsPin = SUCCEEDED(hrTmp); // Elgato note: older versions of the capture filter don't have an MPEG-TS pin

if (hasMpegTsPin && renderFromMpegTsPin)
{
// Add Microsoft Demultiplexer filter
CComPtr<IBaseFilter> pDemultiplexerFilter;
hr = CoCreateInstance(CLSID_MPEG2Demultiplexer, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void **)&pDemultiplexerFilter);
_ASSERT(SUCCEEDED(hr));

hr = pFilterGraph->AddFilter(pDemultiplexerFilter, L"MS Demux");
_ASSERT(SUCCEEDED(hr));

// Configure Microsoft Demultiplexer filter
CComPtr<IPin> pVideoPin;
CComPtr<IPin> pAudioPin;
{
CComPtr<IMpeg2Demultiplexer> pIDemultiplexer;
hr = pDemultiplexerFilter->QueryInterface(IID_IMpeg2Demultiplexer, (void**)&pIDemultiplexer);
_ASSERT(SUCCEEDED(hr));

// Add video pin
{
hr = pIDemultiplexer->CreateOutputPin(GetVideoMediaType(), L"H.264", &pVideoPin);
_ASSERT(SUCCEEDED(hr));

CComPtr<IMPEG2PIDMap> pIPidMap;
hr = pVideoPin->QueryInterface(__uuidof(IMPEG2PIDMap), (void**)&pIPidMap);
_ASSERT(SUCCEEDED(hr));

ULONG pid = ELGATO_VCF_VIDEO_PID;
hr = pIPidMap->MapPID(1, &pid, MEDIA_ELEMENTARY_STREAM);
_ASSERT(SUCCEEDED(hr));
}

// Add audio pin
{
hr = pIDemultiplexer->CreateOutputPin(GetAudioMediaType(), L"AAC", &pAudioPin);
_ASSERT(SUCCEEDED(hr));

CComPtr<IMPEG2PIDMap> pIPidMap;
hr = pAudioPin->QueryInterface(__uuidof(IMPEG2PIDMap), (void**)&pIPidMap);
_ASSERT(SUCCEEDED(hr));

ULONG pid = ELGATO_VCF_AUDIO_PID;
hr = pIPidMap->MapPID(1, &pid, MEDIA_ELEMENTARY_STREAM);
_ASSERT(SUCCEEDED(hr));
}
}

// Connect filters
CComPtr<IPin> pDemultiplexerInput;
hr = pCapBuilder->FindPin(pDemultiplexerFilter, PINDIR_INPUT, NULL, NULL, TRUE, 0, &pDemultiplexerInput);
_ASSERT(SUCCEEDED(hr));

hr = pFilterGraph->Connect(pMpegTsOutput, pDemultiplexerInput);
_ASSERT(SUCCEEDED(hr));

hr = pCapBuilder->RenderStream(NULL, &MEDIATYPE_Video, pVideoPin, NULL, pVideoRendererFilter);
_ASSERT(SUCCEEDED(hr));

hr = pCapBuilder->RenderStream(NULL, &MEDIATYPE_Audio, pAudioPin, NULL, pAudioRendererFilter);
_ASSERT(SUCCEEDED(hr));

}
/*-----------------------------------------------------------------------------
// b) Render from audio and video pins
-----------------------------------------------------------------------------*/
else
{
hr = pCapBuilder->RenderStream(NULL, &MEDIATYPE_Video, pCapFilter, NULL, pVideoRendererFilter);
_ASSERT(SUCCEEDED(hr));

hr = pCapBuilder->RenderStream(NULL, &MEDIATYPE_Audio, pCapFilter, NULL, pAudioRendererFilter);
_ASSERT(SUCCEEDED(hr));
}

/*-----------------------------------------------------------------------------
// Set audio renderer as reference clock for the graph
-----------------------------------------------------------------------------*/
if (SUCCEEDED(hr))
{
CComPtr<IReferenceClock> pRefClock;
hr = pAudioRendererFilter->QueryInterface(IID_IReferenceClock, (void**)&pRefClock);
_ASSERT(SUCCEEDED(hr));
CComPtr<IMediaFilter> pMediaFilter;
hr = pFilterGraph->QueryInterface(IID_IMediaFilter, (void**)&pMediaFilter);
_ASSERT(SUCCEEDED(hr));
hr = pMediaFilter->SetSyncSource(pRefClock);
_ASSERT(SUCCEEDED(hr));

#if 1
// TS WORKAROUND 15-Aug-11: Avoid cracking noise after graph is started
// by increasing the error tolerance of the Audio Renderer from 20ms to 200ms
CComPtr<IAMClockSlave> pIAMClockSlave;
HRESULT hrTmp = pAudioRendererFilter->QueryInterface(IID_IAMClockSlave, (void**)&pIAMClockSlave);
if (SUCCEEDED(hrTmp))
hrTmp = pIAMClockSlave->SetErrorTolerance(200);
_ASSERT(SUCCEEDED(hrTmp));
#endif
}

/*-----------------------------------------------------------------------------
// Playback
-----------------------------------------------------------------------------*/
// set video window
if (SUCCEEDED(hr))
{
hr = pFilterGraph->QueryInterface(IID_IVideoWindow, (void**)&pVideoWindow);
_ASSERT(SUCCEEDED(hr));CWnd* pWnd = GetDlgItem(IDC_VIDEOWINDOW);
CRect rcClient;
pWnd->GetClientRect(&rcClient);

hr = pVideoWindow->put_Owner((OAHWND)pWnd->m_hWnd);
_ASSERT(SUCCEEDED(hr));

pVideoWindow->put_WindowStyleEx(0);
pVideoWindow->put_WindowStyle(WS_CHILD);
pVideoWindow->SetWindowPosition(0, 0, rcClient.Width(), rcClient.Height());

void SaveVideoToFile(int hr);
SaveVideoToFile(hr);
}

// play
hr = pMediaControl->Run();
_ASSERT(SUCCEEDED(hr));

// set volume to maximum
hr = pFilterGraph->QueryInterface(IID_IBasicAudio, (void**)&pBasicAudio);
_ASSERT(SUCCEEDED(hr));
hr = pBasicAudio->put_Volume(0);
_ASSERT(SUCCEEDED(hr));

#ifdef _DEBUG   // Dump graph
_DumpGraph(pFilterGraph);
#endif

return hr;
}

HRESULT CVideoCaptureFilterSampleDlg::DestroyGraph()
{
HRESULT hr = S_FALSE;

_ASSERTE(NULL != pMediaControl);
hr = pMediaControl->Stop();
_ASSERT(SUCCEEDED(hr));// Elgato note: This may take a few seconds
_ASSERTE(NULL != pFilterGraph);
hr = pFilterGraph->RemoveFilter(pCapFilter);
_ASSERT(SUCCEEDED(hr));

return S_OK;
}

HRESULT CVideoCaptureFilterSampleDlg::ShowProperties()
{
HRESULT hr = E_FAIL;
if(NULL != pCapFilter)
{
CComPtr<ISpecifyPropertyPages> pSpec;
hr = pCapFilter->QueryInterface(IID_ISpecifyPropertyPages, (void **) &pSpec);
if (hr == S_OK)
{
CAUUID  cauuid;
hr = pSpec->GetPages(&cauuid);
if (hr == S_OK && cauuid.cElems > 0)
{
IBaseFilter* pFilter = pCapFilter;
hr = OleCreatePropertyFrame(NULL,40, 40, NULL, 1,(IUnknown **)&pFilter,
cauuid.cElems,(GUID *)cauuid.pElems, 0, 0, NULL);
CoTaskMemFree(cauuid.pElems);
}
}
}
return hr;
}

void SaveVideoToFile(int hr)
{

IBaseFilter *pMux;
hr = pCapBuilder->SetOutputFileName(
&MEDIASUBTYPE_Avi,  // Specifies AVI for the target file.
L"E:\\Example.avi", // File name.
&pMux,              // Receives a pointer to the mux.
NULL);

hr = pCapBuilder->RenderStream(
&PIN_CATEGORY_CAPTURE, // Pin category.
&MEDIATYPE_Video,      // Media type.
pCapFilter,                  // Capture filter.
NULL,                  // Intermediate filter (optional).
pMux);                 // Mux or file sink filter.

// Release the mux filter.
pMux->Release();

IConfigAviMux *pConfigMux = NULL;
hr = pMux->QueryInterface(IID_IConfigAviMux, (void**)&pConfigMux);
if (SUCCEEDED(hr))
{
pConfigMux->SetMasterStream(1);
pConfigMux->Release();
}

IConfigInterleaving *pInterleave = NULL;
hr = pMux->QueryInterface(IID_IConfigInterleaving, (void**)&pInterleave);
if (SUCCEEDED(hr))
{
pInterleave->put_Mode(INTERLEAVE_CAPTURE);
pInterleave->Release();
}

IBaseFilter *pEncoder;
//Create the encoder filter (not shown).
// Add it to the filter graph.
pFilterGraph->AddFilter(pEncoder, L"Encoder");

//Call SetOutputFileName as shown previously.

// Render the stream.
hr = pCapBuilder->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,
pCapFilter,
pEncoder, pMux);
pEncoder->Release();
}

Это метод, который я пытаюсь сохранить видео в файл AVI. Пример из MSDN документ сайта:

void SaveVideoToFile(int hr)
{

IBaseFilter *pMux;
hr = pCapBuilder->SetOutputFileName(
&MEDIASUBTYPE_Avi,  // Specifies AVI for the target file.
L"E:\\Example.avi", // File name.
&pMux,              // Receives a pointer to the mux.
NULL);

hr = pCapBuilder->RenderStream(
&PIN_CATEGORY_CAPTURE, // Pin category.
&MEDIATYPE_Video,      // Media type.
pCapFilter,                  // Capture filter.
NULL,                  // Intermediate filter (optional).
pMux);                 // Mux or file sink filter.

// Release the mux filter.
pMux->Release();

IConfigAviMux *pConfigMux = NULL;
hr = pMux->QueryInterface(IID_IConfigAviMux, (void**)&pConfigMux);
if (SUCCEEDED(hr))
{
pConfigMux->SetMasterStream(1);
pConfigMux->Release();
}

IConfigInterleaving *pInterleave = NULL;
hr = pMux->QueryInterface(IID_IConfigInterleaving, (void**)&pInterleave);
if (SUCCEEDED(hr))
{
pInterleave->put_Mode(INTERLEAVE_CAPTURE);
pInterleave->Release();
}

IBaseFilter *pEncoder;
//Create the encoder filter (not shown).
// Add it to the filter graph.
pFilterGraph->AddFilter(pEncoder, L"Encoder");

//Call SetOutputFileName as shown previously.

// Render the stream.
hr = pCapBuilder->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,
pCapFilter,
pEncoder, pMux);
pEncoder->Release();
}

И я называю это так в нижней части части окна видео:

void SaveVideoToFile(int hr);
SaveVideoToFile(hr);

Теперь я получаю ошибку, так как в SaveVideoToFile Я не инициализировал
pEncoder,

Ошибка:

Переменная ‘pEncoder’ используется без инициализации

Если pEncoder не используется, он ничего не делает без ошибок, но сохраняет что-либо в файл avi.

Вот пример, который я использую с сайта Microsoft MSDN:

Захват видео в файл AVI

0

Решение

Пример кода ясно о pEncoder переменная «не показано»:

IBaseFilter *pEncoder;
//Create the encoder filter (not shown). <<--------
// Add it to the filter graph.
pFilterGraph->AddFilter(pEncoder, L"Encoder");

Не показано означает, что эта инициализация опущена для краткости кода. Статья MSDN для Выбор фильтра сжатия является несколько устаревшим, наряду с форматом AVI, но в конечном итоге именно вы несете ответственность за организацию сжатия вашего видеопотока и, следовательно, за выбор фильтра кодировщика, добавление его в график фильтра. Вы можете попробовать для начала Фильтр компрессора MJPEG, который является фондовым фильтром.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]