最近在做个录制WMV格式的音视频的问题,录制完回放的时候,画面不连续,下面是我的源码,肯定有经验的朋友帮帮忙看看哪里出了问题?WMVRecorderDlg.cpp:implement
最近在做个录制WMV格式的音视频的问题,录制完回放的时候,画面不连续,下面是我的源码,肯定有经验的朋友帮帮忙看看哪里出了问题?
// WMVRecorderDlg.cpp : implementation file
BOOL CWMVRecorderDlg::Run()
{
HRESULT hr;
CString s;
IBaseFilter *pWriter = NULL;
IFileSinkFilter2 *pSink = NULL;
IBaseFilter *pAviDest = NULL;
IConfigAviMux *pAviCfg = NULL;
IBaseFilter *pReader = NULL;
IFileSourceFilter *pSink2 = NULL;
// create the graph
hr = CoCreateInstance( CLSID_FilterGraph,
NULL,
CLSCTX_INPROC_SERVER,
IID_IGraphBuilder,
(void**)&(pGraph) );
if( FAILED( hr ) )
{
s.Format( "不能生成FilterGraph,错误码:%X,说明:%s\n", hr, ErrMsgLib( hr ) );
ERRMSG0( s );
AfxMessageBox( s );
return FALSE;
}
// add file writer
hr = AddFilterByClsid(pGraph, L"File Writer", CLSID_FileWriter, &pWriter);
if( FAILED( hr ) )
{
s.Format( "不能生成FileWriter,错误码:%X,说明:%s\n", hr, ErrMsgLib( hr ) );
ERRMSG0( s );
// AfxMessageBox( s );
return FALSE;
}
pWriter->QueryInterface(IID_IFileSinkFilter2, (void**)&pSink);
if( pSink != NULL )
{
// pSink->SetFileName( MultiByte2WideChar( m_fname ), NULL );
pSink->SetFileName( MultiByte2WideChar(_T("E:\\dest.wmv"))/*录制后的文件*/, NULL );
// pSink->SetFileName( L"mms://192.168.1.2:9000", NULL );
pSink->SetMode( AM_FILE_OVERWRITE );
SAFE_RELEASE( pSink );
}
// add avi mux
hr = AddFilterByClsid(pGraph, L"Avi Mux", CLSID_AviDest, &pAviDest);
if( FAILED( hr ) )
{
s.Format( "不能生成AviDest,错误码:%X,说明:%s\n", hr, ErrMsgLib( hr ) );
ERRMSG0( s );
// AfxMessageBox( s );
return FALSE;
}
pAviDest->QueryInterface(IID_IConfigAviMux, (void**)&pAviCfg);
if( pAviCfg != NULL )
{
SAFE_RELEASE( pAviCfg );
}
// connect avi mux to file writer
hr = ConnectTwoFilters( pGraph, pAviDest, pWriter );
if( FAILED( hr ) )
{
s.Format( "连接avi mux到file writer,错误码:%X,说明:%s\n", hr, ErrMsgLib( hr ) );
ERRMSG0( s );
// AfxMessageBox( s );
return FALSE;
}
hr = AddFilterByClsid(pGraph, L"Asf Reader1", CLSID_WMAsfReader, &pReader);
if( FAILED( hr ) )
{
s.Format( "不能生成流读取filter,错误码:%X,说明:%s\n", hr, ErrMsgLib( hr ) );
ERRMSG0( s );
// AfxMessageBox( s );
return FALSE;
}
hr = pReader->QueryInterface(IID_IFileSourceFilter, (void**)&(pSink2) );
if( FAILED( hr ) )
{
s.Format( "无法设定流,错误码:%X,说明:%s\n", hr, ErrMsgLib( hr ) );
ERRMSG0( s );
// AfxMessageBox( s );
return FALSE;
}
//hr = pSink2->Load( MultiByte2WideChar( m_address1 ), NULL );
hr = pSink2->Load(MultiByte2WideChar(_T("E:\\source.wmv"))/*需要录制的源媒体文件*/, NULL );
// hr = pSink2->Load( L"mms://192.168.1.2:9000", NULL );
SAFE_RELEASE( pSink2 );
if( FAILED( hr ) )
{
s.Format( "无法设定流参数,错误码:%X,说明:%s\n", hr, ErrMsgLib( hr ) );
ERRMSG0( s );
// AfxMessageBox( s );
return FALSE;
}
hr = RenderOutputPins( pGraph, pReader );
if( FAILED( hr ) )
{
s.Format( "无法连接流,错误码:%X,说明:%s\n", hr, ErrMsgLib( hr ) );
ERRMSG0( s );
// AfxMessageBox( s );
return FALSE;
}
//第二个码流
int bUse2 = GetConfigInt("双码流", "是否采用", 0);
if(bUse2)
{
hr = AddFilterByClsid(pGraph, L"Asf Reader2", CLSID_WMAsfReader, &pReader);
if( FAILED( hr ) )
{
s.Format( "不能生成流读取filter,错误码:%X,说明:%s\n", hr, ErrMsgLib( hr ) );
ERRMSG0( s );
// AfxMessageBox( s );
return FALSE;
}
hr = pReader->QueryInterface(IID_IFileSourceFilter, (void**)&(pSink2) );
if( FAILED( hr ) )
{
s.Format( "无法设定流,错误码:%X,说明:%s\n", hr, ErrMsgLib( hr ) );
ERRMSG0( s );
// AfxMessageBox( s );
return FALSE;
}
hr = pSink2->Load( MultiByte2WideChar( m_address2 ), NULL );
SAFE_RELEASE( pSink2 );
if( FAILED( hr ) )
{
s.Format( "无法设定流参数,错误码:%X,说明:%s\n", hr, ErrMsgLib( hr ) );
ERRMSG0( s );
// AfxMessageBox( s );
return FALSE;
}
hr = RenderOutputPins( pGraph, pReader );
if( FAILED( hr ) )
{
s.Format( "无法连接流,错误码:%X,说明:%s\n", hr, ErrMsgLib( hr ) );
ERRMSG0( s );
// AfxMessageBox( s );
return FALSE;
}
}
hr = pGraph->QueryInterface(IID_IMediaControl, (void**)&(pControl) );
if( FAILED( hr ) )
{
s.Format( "不能获得视频控制,错误码:%X,说明:%s\n", hr, ErrMsgLib( hr ) );
ERRMSG0( s );
// AfxMessageBox( s );
return FALSE;
}
pControl->Run();
AfxMessageBox(_T("run return"));
return TRUE;
}
4 个解决方案
// Filename: WmvRec.h
// Version: 0.0
#ifndef __WMVREC_H
#define __WMVREC_H
char* WideChar2MultiByte( WCHAR* p );
WCHAR* MultiByte2WideChar( const char* p );
IPin* GetPin(IBaseFilter* pFilter, PIN_DIRECTION dirRequest);
ULONG EnumAllPins( IBaseFilter* pFilter, IPin* Pins[], ULONG nMaxNumber );
HRESULT ConnectTwoFilters(IGraphBuilder *pGraph, IBaseFilter *pSrc, IBaseFilter *pDest);
HRESULT AddFilterByClsid(IGraphBuilder *pGraph, LPCWSTR wszName, const GUID& clsid, IBaseFilter **ppF);
ULONG EnumCaptureDeviceName( REFCLSID clsidDeviceClass, CString* pStrArray, ULONG nMaxNumber );
void FindAudioCapture( IBaseFilter** pSrc, const char* name );
ULONG EnumAudioInputName( IBaseFilter* pSrc, CString* pStrArray, ULONG nMaxNumber );
void EnableAudioInput( IBaseFilter* pSrc, const char* strName, bool bEnable );
HRESULT RenderOutputPins(IGraphBuilder *pGB, IBaseFilter *pFilter);
#endif // __WMVREC_H
// Filename:WmvRec.cpp
// Version: 0.0
//
#include "stdafx.h"
#include "Report.h"
#include "Config.h"
#include
#include "Wmsysprf.h"
#include
#include
#include "WmvRec.h"
// 将宽字符转换成多字节串,返回静态对象,无需删除,必须立刻使用
char* WideChar2MultiByte( WCHAR* p )
{
static char buffer[ 1024 ];
WideCharToMultiByte( CP_ACP, 0, p, -1, buffer, 1024, NULL, NULL );
return buffer;
}
// 将多字节串转换成宽字符,返回静态对象,无需删除,必须立刻使用
WCHAR* MultiByte2WideChar( const char* p )
{
static WCHAR buffer[ 1024 ];
MultiByteToWideChar( CP_ACP, 0, p, -1, buffer, 1024 );
return buffer;
}
// 取得filter指定方向的第一个pin
IPin* GetPin(IBaseFilter* pFilter, PIN_DIRECTION dirRequest)
{
IPin * foundPin = NULL;
if( pFilter != NULL )
{
IEnumPins* pEnum = NULL;
HRESULT hr = pFilter->EnumPins(&pEnum);
if (SUCCEEDED(hr))
{
IPin* pPin = NULL;
while (!foundPin && pEnum->Next(1, &pPin, 0) == S_OK)
{
PIN_DIRECTION dir;
pPin->QueryDirection(&dir);
if (dir == dirRequest)
{
foundPin = pPin;
}
else
{
pPin->Release();
}
}
pEnum->Release();
}
}
return foundPin;
}
// 找出filter全部的pin
ULONG EnumAllPins( IBaseFilter* pFilter, IPin* Pins[], ULONG nMaxNumber )
{
ULONG nCount = 0;
if( pFilter != NULL )
{
IEnumPins* pEnum = NULL;
HRESULT hr = pFilter->EnumPins( &pEnum );
if( SUCCEEDED(hr) )
{
pEnum->Next( nMaxNumber, Pins, &nCount );
pEnum->Release();
}
}
return nCount;
}
// ConnectTwoFilters: Connects two filters using the first pin on each.
HRESULT ConnectTwoFilters(IGraphBuilder *pGraph, IBaseFilter *pSrc, IBaseFilter *pDest)
{
IPin *pOut = GetPin( pSrc, PINDIR_OUTPUT );
if( !pOut ) return E_FAIL;
IPin *pIn = GetPin( pDest, PINDIR_INPUT );
if( !pOut )
{
pIn->Release();
return E_FAIL;
}
HRESULT hr = pGraph->ConnectDirect( pOut, pIn, NULL );
pIn->Release();
pOut->Release();
return hr;
}
// 根据指定的CLSID, 把filter加入到graph中并返回filter
HRESULT AddFilterByClsid(IGraphBuilder *pGraph, LPCWSTR wszName,
const GUID& clsid, IBaseFilter **ppF)
{
*ppF = NULL;
HRESULT hr = CoCreateInstance( clsid,
NULL,
CLSCTX_INPROC_SERVER,
IID_IBaseFilter,
(void**)ppF );
if( SUCCEEDED( hr ) )
{
hr = pGraph->AddFilter( (*ppF), wszName );
}
return hr;
}
ULONG EnumCaptureDeviceName( REFCLSID clsidDeviceClass, CString* pStrArray, ULONG nMaxNumber )
{
HRESULT hr;
ULONG nCount = 0;
// Create the system device enumerator.
ICreateDevEnum *pDevEnum = NULL;
CoCreateInstance(CLSID_SystemDeviceEnum,
NULL,
CLSCTX_INPROC,
IID_ICreateDevEnum,
(void **)&pDevEnum);
// Create an enumerator for video capture devices.
IEnumMoniker *pClassEnum = NULL;
pDevEnum->CreateClassEnumerator( clsidDeviceClass, &pClassEnum, 0 );
ULONG cFetched;
IMoniker *pMoniker = NULL;
while( pClassEnum->Next( 1, &pMoniker, &cFetched ) == S_OK )
{
IPropertyBag *pPropBag;
pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag);
// To retrieve the friendly name of the filter, do the following:
VARIANT varName;
VariantInit(&varName);
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
if (SUCCEEDED(hr))
{
if( varName.vt == VT_BSTR )
{
pStrArray[ nCount ++ ] = WideChar2MultiByte( varName.bstrVal );
}
}
VariantClear(&varName);
pMoniker->Release();
if( nCount >= nMaxNumber ) break;
}
pClassEnum->Release();
pDevEnum->Release();
return nCount;
}
void FindAudioCapture( IBaseFilter** pSrc, const char* name )
{
HRESULT hr;
*pSrc = NULL;
// Create the system device enumerator.
ICreateDevEnum *pDevEnum = NULL;
CoCreateInstance(CLSID_SystemDeviceEnum,
NULL,
CLSCTX_INPROC,
IID_ICreateDevEnum,
(void **)&pDevEnum);
// Create an enumerator for video capture devices.
IEnumMoniker *pClassEnum = NULL;
pDevEnum->CreateClassEnumerator(CLSID_AudioInputDeviceCategory, &pClassEnum, 0);
ULONG cFetched;
IMoniker *pMoniker = NULL;
while( pClassEnum->Next( 1, &pMoniker, &cFetched ) == S_OK )
{
IPropertyBag *pPropBag;
pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag);
// To retrieve the friendly name of the filter, do the following:
VARIANT varName;
VariantInit(&varName);
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
if (SUCCEEDED(hr))
{
// Display the name in your UI somehow.
if( varName.vt == VT_BSTR )
{
if( strcmp( WideChar2MultiByte( varName.bstrVal ), name ) == 0 )
{
pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)pSrc);
VariantClear(&varName);
break;
}
}
}
VariantClear(&varName);
// Bind the first moniker to a filter object.
pMoniker->Release();
}
pClassEnum->Release();
pDevEnum->Release();
}
ULONG EnumAudioInputName( IBaseFilter* pSrc, CString* pStrArray, ULONG nMaxNumber )
{
HRESULT hr;
ULONG nCount = 0;
if( pSrc != NULL )
{
IEnumPins* pEnum = NULL;
IBaseFilter* pFilter = pSrc;
hr = pFilter->EnumPins(&pEnum);
if (SUCCEEDED(hr))
{
IPin* pPin = NULL;
while(pEnum->Next(1, &pPin, 0) == S_OK)
{
PIN_DIRECTION dir;
pPin->QueryDirection(&dir);
if (dir == PINDIR_INPUT )
{
PIN_INFO info;
pPin->QueryPinInfo( &info );
pStrArray[ nCount ++ ] = WideChar2MultiByte( info.achName );
}
pPin->Release();
}
pEnum->Release();
}
}
return nCount;
}
void EnableAudioInput( IBaseFilter* pSrc, const char* strName, bool bEnable )
{
HRESULT hr;
ULONG nCount = 0;
if( pSrc != NULL )
{
IEnumPins* pEnum = NULL;
IBaseFilter* pFilter = pSrc;
hr = pFilter->EnumPins(&pEnum);
if (SUCCEEDED(hr))
{
IPin* pPin = NULL;
while(pEnum->Next(1, &pPin, 0) == S_OK)
{
PIN_DIRECTION dir;
pPin->QueryDirection(&dir);
if (dir == PINDIR_INPUT )
{
PIN_INFO info;
pPin->QueryPinInfo( &info );
IAMAudioInputMixer* pPinCfg;
pPin->QueryInterface( IID_IAMAudioInputMixer, (void**)&pPinCfg );
if( strcmp( WideChar2MultiByte( info.achName ), strName ) == 0 )
{
if( pPinCfg )
{
pPinCfg->put_Enable( bEnable );
pPinCfg->Release();
}
}
}
pPin->Release();
}
pEnum->Release();
}
}
}
//------------------------------------------------------------------------------
// Name: RenderOutputPins()
// Desc: Renders every output pin on a specified filter.
//
// pGB: Pointer to the Filter Graph Manager.
// pFilter: Pointer to the filter.
//------------------------------------------------------------------------------
HRESULT RenderOutputPins(IGraphBuilder *pGB, IBaseFilter *pFilter)
{
HRESULT hr = S_OK;
IEnumPins * pEnumPin = NULL;
IPin * pConnectedPin = NULL, * pPin;
PIN_DIRECTION PinDirection;
ULONG ulFetched;
// Enumerate all the pins on the filter.
hr = pFilter->EnumPins( &pEnumPin );
if(SUCCEEDED(hr))
{
// Step through every pin, looking for the output pins.
while (S_OK == (hr = pEnumPin->Next( 1L, &pPin, &ulFetched)))
{
// Check whether this pin is already connected. If so, ignore it.
hr = pPin->ConnectedTo(&pConnectedPin);
if (pConnectedPin)
{
// Release the IPin interface on the connected pin.
pConnectedPin->Release();
pConnectedPin = NULL;
}
if (VFW_E_NOT_CONNECTED == hr)
{
// This pin is not connected to another filter yet. Check
// whether it is an output pin. If so, use the Filter Graph
// Manager's Render() method to render the pin.
hr = pPin->QueryDirection( &PinDirection );
if ( ( S_OK == hr ) && ( PinDirection == PINDIR_OUTPUT ) )
{
hr = pGB->Render(pPin);
}
}
pPin->Release();
// If there was an error, stop enumerating.
if (FAILED(hr))
break;
}
}
// Release the pin enumerator object.
pEnumPin->Release();
return hr;
}