📄 ff_wmv9.cpp
字号:
#include "stdafx.h"
#include "ff_wmv9.h"
#include "GenProfile_lib.h"
#include "writerSink.h"
#include "Twmv9dll.h"
#include <strmif.h>
#include <mediaobj.h>
#include "encode.h"
#include "encappErr.h"
#include "videoenc.h"
#include <uuids.h>
#include "baseclasses/amvideo.h"
#include "imgFilters/ffImgfmt.h"
#include <initguid.h>
#include "ffdshow_mediaguids.h"
#include "../../compiler.h"
#ifdef __GNUC__
#include "strmiids.cpp"
#else
DEFINE_GUID(IID_IMediaObject,0xd8ad0f58,0x5494,0x4102,0x97,0xc5,0xec,0x79,0x8e,0x59,0xbc,0xf4);
DEFINE_GUID(MEDIASUBTYPE_IYUV,0x56555949,0x0,0x10,0x80,0x0,0x0,0xAA,0x0,0x38,0x9B,0x71);
#endif
#if DEBUG
#define DEBUGS(s) OutputDebugString(s)
#else
#define DEBUGS(s)
#endif
using namespace std;
bool operator <(const Tff_wmv9codecInfo &c1,const Tff_wmv9codecInfo &c2)
{
return stricmp(c1.name,c2.name)<0;
}
struct Tff_wmv9 :public Iff_wmv9
{
private:
Tff_wmv9cfg cfg;
IWMProfile *pProfile;
IWMCodecInfo3 *m_pCodecInfo;
IWMWriter *pWMWriter;
IWMWriterAdvanced *pWMWriterA;
IWMWriterFileSink *filesink;
TmyWriterSink *mysink;
int wrinputnum;
bool ok,writing;
std::vector<Tff_wmv9codecInfo> codecs;
Twmv9dll *wmv9dll;
public:
Tff_wmv9(void)
{
ok=false;
pProfile=NULL;m_pCodecInfo=NULL;
pWMWriter=NULL;pWMWriterA=NULL;
mysink=NULL;filesink=NULL;
memset(&cfg,0,sizeof(cfg));
wmv9dll=new Twmv9dll;
if (!wmv9dll->ok) return;
#define JIF(x) if (FAILED(hr=(x))) {DEBUGS(_l("FAILED in ")_l(#x)_l("\n"));return;}
HRESULT hr;
JIF(EnsureIWMCodecInfo3(wmv9dll,&m_pCodecInfo));
DWORD codecCount;
m_pCodecInfo->GetCodecInfoCount(WMMEDIATYPE_Video,&codecCount);
for (DWORD i=0;i<codecCount;i++)
{
WCHAR codecName[1024];
DWORD codecNameLength=1024;
if (SUCCEEDED(m_pCodecInfo->GetCodecName(WMMEDIATYPE_Video,i,codecName,&codecNameLength)))
{
codecName[codecNameLength]=L'\0'; // terminate the codec name, just in case
Tff_wmv9codecInfo info;memset(&info,0,sizeof(info));
info.index=i;
//WideCharToMultiByte(CP_ACP,0,codecName,-1,info.name,256,NULL,NULL);
strcpy(info.name,text<char_t>(codecName));
WMT_ATTR_DATATYPE type;
BOOL isVBR;DWORD isVBRsize=sizeof(isVBR);
if (SUCCEEDED(m_pCodecInfo->GetCodecProp(WMMEDIATYPE_Video,i,g_wszIsVBRSupported,&type,(BYTE*)&isVBR,&isVBRsize)))
info.vbr=isVBR;
DWORD cmplxMax,cmplxMaxSize=sizeof(cmplxMax);
if (SUCCEEDED(m_pCodecInfo->GetCodecProp(WMMEDIATYPE_Video,i,g_wszComplexityMax,&type,(BYTE*)&cmplxMax,&cmplxMaxSize)))
info.cmplxMax=cmplxMax;
DWORD codecformatcount=0;
m_pCodecInfo->GetCodecFormatCount(WMMEDIATYPE_Video,i,&codecformatcount);
for (unsigned int j=0;j<min(DWORD(1),codecformatcount);j++)
{
IWMStreamConfig *wsc=NULL;
WCHAR desc[256];DWORD desclen=256;
if (SUCCEEDED(m_pCodecInfo->GetCodecFormatDesc(WMMEDIATYPE_Video,i,j,&wsc,desc,&desclen)))
{
IWMMediaProps *mp=NULL;
if (SUCCEEDED(wsc->QueryInterface(IID_IWMMediaProps,(void**)&mp)))
{
DWORD typelen=0;
if (SUCCEEDED(mp->GetMediaType(NULL,&typelen)) && typelen!=0)
{
WM_MEDIA_TYPE *type=(WM_MEDIA_TYPE*)malloc(typelen);
mp->GetMediaType(type,&typelen);
info.mediatype=type->subtype;
info.fcc=type->subtype.Data1;
codecs.push_back(info);
free(type);
}
mp->Release();
}
wsc->Release();
}
}
}
}
sort(codecs.begin(),codecs.end());
ok=true;
}
virtual ~Tff_wmv9()
{
end();
delete wmv9dll;
}
virtual bool __stdcall getOk(void) {return ok;}
virtual size_t __stdcall getCodecCount(void) {return codecs.size();}
virtual bool __stdcall getCodecInfo(size_t i,const Tff_wmv9codecInfo* *info)
{
if (i>=codecs.size() || !info) return false;
*info=&codecs[i];
return true;
}
virtual bool __stdcall start(const Tff_wmv9cfg &Icfg)
{
cfg=Icfg;
if (cfg.avioutput) return startAVI();
writing=false;
#undef JIF
#define JIF(x) if (FAILED(hr=(x))) {DEBUGS(_l("FAILED in ")_l(#x)_l("\n"));return false;}
HRESULT hr;
IWMProfileManager *pProfileManager=NULL;
JIF(wmv9dll->WMCreateProfileManager(&pProfileManager));
JIF(pProfileManager->CreateEmptyProfile(WMT_VER_9_0,&pProfile));
IWMProfile3 *pProfile3=NULL;
JIF(pProfile->QueryInterface(IID_IWMProfile3,(void**)&pProfile3));
JIF(pProfile->SetName(L"ff_wmv9 profile"));
JIF(pProfile->SetDescription(L"ff_wmv9 description"));
IWMStreamConfig *pNewStreamConfig=NULL;
JIF(CreateVideoStream(wmv9dll,
&pNewStreamConfig,
m_pCodecInfo,
pProfile,
cfg.codecIndex, // codec index
cfg.bitrate, // bitrate
3000, // buffer window
cfg.width, // width
cfg.height, // height
cfg.fps, // fps
cfg.quality, // video quality
cfg.seckf, // seconds per keyframes
cfg.bUseVBR, // video is VBR
cfg.vbr_mode, // VBR mode ( VIDEO_VBR_MODE )
cfg.vbrquality, // VBR Quality
cfg.maxbitrate, // Max Bitrate (VBR)
10000, // Max VBR Video Buffer
GetSystemDefaultLCID()));
JIF(pNewStreamConfig->SetStreamNumber(1));
JIF(pNewStreamConfig->SetStreamName(L"Video"));
#define CONN_NAME L"VideoConnect"
JIF(pNewStreamConfig->SetConnectionName(CONN_NAME));
JIF(pNewStreamConfig->SetBufferWindow(3000));
IWMPropertyVault *strprops=NULL;
if (SUCCEEDED(pNewStreamConfig->QueryInterface(IID_IWMPropertyVault,(void**)&strprops)))
{
WORD cplx=(WORD)cfg.cplx;if (cplx>codecs[cfg.codecIndex].cmplxMax) cplx=WORD(codecs[cfg.codecIndex].cmplxMax);
strprops->SetProperty(g_wszComplexity,WMT_TYPE_WORD,(BYTE*)&cplx,sizeof(cplx));
strprops->Release();
}
JIF(pProfile->AddStream(pNewStreamConfig));
pNewStreamConfig->Release();pNewStreamConfig=NULL;
pProfile3->Release();pProfile3=NULL;
pProfileManager->Release();pProfileManager=NULL;
JIF(wmv9dll->WMCreateWriter(NULL,&pWMWriter));
JIF(pWMWriter->QueryInterface(IID_IWMWriterAdvanced,(void**)&pWMWriterA));
JIF(pWMWriter->SetProfile(pProfile));
DWORD inpcnt=0;
pWMWriter->GetInputCount(&inpcnt);
wrinputnum=-1;
for (DWORD i=0;i<inpcnt && wrinputnum==-1;i++)
{
IWMInputMediaProps *props=NULL;
JIF(pWMWriter->GetInputProps(i,&props));
WCHAR connNameW[256];WORD connNameLen=256;
props->GetConnectionName(connNameW,&connNameLen);
if (wcscmp(connNameW,CONN_NAME)==0)
wrinputnum=i;
props->Release();
}
if (wrinputnum==-1) return false;
DWORD fmtcnt=0;
pWMWriter->GetInputFormatCount(wrinputnum,&fmtcnt);
WM_MEDIA_TYPE *mediatype=NULL;
IWMInputMediaProps *props=NULL;
for (DWORD fmti=0;fmti<fmtcnt && !mediatype;fmti++)
{
JIF(pWMWriter->GetInputFormat(wrinputnum,fmti,&props));
DWORD mtsize;
JIF(props->GetMediaType(NULL,&mtsize));
mediatype=(WM_MEDIA_TYPE*)malloc(mtsize);
JIF(props->GetMediaType(mediatype,&mtsize));
if (mediatype->subtype==WMMEDIASUBTYPE_YV12) break;
free(mediatype);mediatype=NULL;
props->Release();props=NULL;
}
if (!mediatype) return false;
//here we could modify input type settings, but they seem to be OK already
//WMVIDEOINFOHEADER *wvih=(WMVIDEOINFOHEADER*)mediatype->pbFormat;
// BITMAPINFOHEADER &bih=wvih->bmiHeader;
pWMWriter->SetInputProps(wrinputnum,props);
free(mediatype);
props->Release();
IWMWriterAdvanced2 *writerA2=NULL;
if (SUCCEEDED(pWMWriter->QueryInterface(IID_IWMWriterAdvanced2,(void**)&writerA2)))
{
if (cfg.ivtc)
{
DWORD a=WM_DM_DEINTERLACE_INVERSETELECINE;
hr=writerA2->SetInputSetting(wrinputnum,g_wszDeinterlaceMode,WMT_TYPE_DWORD,(const unsigned char *)&a,sizeof(DWORD));
}
if (cfg.deint)
{
DWORD a=WM_DM_DEINTERLACE_NORMAL;
hr=writerA2->SetInputSetting(wrinputnum,g_wszDeinterlaceMode,WMT_TYPE_DWORD,(const unsigned char *)&a,sizeof(DWORD));
}
writerA2->Release();
}
if (0)
{
mysink=new TmyWriterSink(NULL,&hr);
pWMWriterA->AddSink((IWMWriterSink*)mysink);
}
if (cfg.flnm)
{
wmv9dll->WMCreateWriterFileSink(&filesink);
//WCHAR flnmW[MAX_PATH];
//MultiByteToWideChar(CP_ACP,0,cfg.flnm,(int)strlen(cfg.flnm)+1,flnmW,MAX_PATH);
filesink->Open(text<wchar_t>(cfg.flnm));
pWMWriterA->AddSink(filesink);
}
JIF(pWMWriter->BeginWriting());
writing=true;
return true;
}
virtual int __stdcall write(unsigned int framenum,int csp,const unsigned char * const src[4],const stride_t srcStride[4],void *dst)
{
if (!writing) return 0;
if (cfg.avioutput) return writeAVI(framenum,csp,src,srcStride,dst);
INSSBuffer *buf=NULL;
if (SUCCEEDED(pWMWriter->AllocateSample(3*cfg.width*cfg.height/2,&buf)))
{
BYTE *bufptr=NULL;
buf->GetBuffer(&bufptr);
DWORD buflen=3*cfg.width*cfg.height/2;
memcpy(bufptr,src[0],buflen); //always XVID_CSP_YV12
buf->SetLength(buflen);
HRESULT res=pWMWriter->WriteSample(wrinputnum,QWORD(framenum*int64_t(10000000)/cfg.fps),0,buf);
buf->Release();
return 1;
}
else
return 0;
}
virtual void __stdcall end(void)
{
if (cfg.avioutput)
{
endAVI();
return;
}
if (pWMWriter)
{
if (writing) pWMWriter->EndWriting();writing=false;
if (filesink) filesink->Release();filesink=NULL;
if (mysink) mysink->Release();mysink=NULL;
if (pWMWriterA) pWMWriterA->Release();pWMWriterA=NULL;
if (pWMWriter) pWMWriter->Release();pWMWriter=NULL;
}
if (pProfile) pProfile->Release();pProfile=NULL;
if (m_pCodecInfo) m_pCodecInfo->Release();m_pCodecInfo=NULL;
}
private:
struct Tcontext
{
Tcontext(void)
{
memset(this,0,sizeof(*this));
}
IMediaObject *pDMO;
AM_MEDIA_TYPE mtIn;
AM_MEDIA_TYPE mtOut;
CHandlingMediaBuffer *pInputBuffer;
CHandlingMediaBuffer *pOutputBuffer;
REFERENCE_TIME rtDecimatorTimeStamp;
REFERENCE_TIME rtDecimatorDuration;
REFERENCE_TIME rtMaxJitter;
REFERENCE_TIME rtFrameDuration;
REFERENCE_TIME rtTimeStamp;
unsigned char *input;unsigned int inputSize;
unsigned char *output;unsigned int outputSize;
} pContext;
VideoEncParams pParams;
int nOutFrames;
DWORD cbVideoOut;
HRESULT InitializeEncoder(IMediaObject **ppDMO,
AM_MEDIA_TYPE *pmtIn,
AM_MEDIA_TYPE *pmtOut,
CHandlingMediaBuffer *pMediaBuffer)
{
HRESULT hr=S_OK;
if (!ppDMO ||!pmtIn || !pmtOut) return E_INVALIDARG;
hr=InitializeVideoEncoder(pmtIn,
&pParams,
ppDMO,
pmtOut,
pMediaBuffer);
return ( hr );
}
bool startAVI(void)
{
cbVideoOut = max(128 * 128 * 2,
(((cfg.width + 15) & ~15) *
((cfg.height + 15) & ~15) * 3));
HRESULT hr=S_OK;
DWORD dwFlags;
VIDEOINFOHEADER *vih=(VIDEOINFOHEADER*)CoTaskMemAlloc(sizeof(VIDEOINFOHEADER));
vih->rcSource.left=0;vih->rcSource.top=0;vih->rcSource.right=cfg.width;vih->rcSource.bottom=cfg.height;
vih->rcTarget=vih->rcSource;
vih->dwBitRate=DWORD(3*cfg.fps*cfg.width*cfg.height/2);
vih->dwBitErrorRate=0;
vih->AvgTimePerFrame=REFERENCE_TIME(10000000.0/cfg.fps);
vih->bmiHeader.biSize=sizeof(vih->bmiHeader);
vih->bmiHeader.biWidth=cfg.width;
vih->bmiHeader.biHeight=cfg.height;
vih->bmiHeader.biPlanes=1;
const TcspInfo *cspInfo=csp_getInfo(cfg.csp);
vih->bmiHeader.biBitCount=WORD(cspInfo->bpp);
vih->bmiHeader.biCompression=cspInfo->fcc;
vih->bmiHeader.biSizeImage=cspInfo->bpp*cfg.width*cfg.height/8;
pContext.mtIn.subtype=*cspInfo->subtype;
vih->bmiHeader.biXPelsPerMeter=0;
vih->bmiHeader.biYPelsPerMeter=0;
vih->bmiHeader.biClrUsed=0;
vih->bmiHeader.biClrImportant=0;
pContext.pDMO=NULL;
pContext.pInputBuffer=new CHandlingMediaBuffer;
pContext.mtIn.majortype=MEDIATYPE_Video;
pContext.mtIn.bFixedSizeSamples=TRUE;
pContext.mtIn.bTemporalCompression=FALSE;
pContext.mtIn.formattype=FORMAT_VideoInfo;
pContext.mtIn.lSampleSize=vih->bmiHeader.biSizeImage;
pContext.mtIn.pUnk=NULL;
pContext.mtIn.cbFormat=sizeof(VIDEOINFOHEADER);
pContext.mtIn.pbFormat=(unsigned char*)vih;
pContext.input=(unsigned char*)malloc(pContext.inputSize=pContext.mtIn.lSampleSize);
pContext.pOutputBuffer=new CHandlingMediaBuffer;
memset(&pContext.mtOut,0,sizeof(pContext.mtOut));
pParams.nBitrate=cfg.bitrate;
pParams.nWidth=cfg.width;
pParams.nHeight=cfg.height;
pParams.dFrameRate=cfg.fps;
pParams.nKeyDist=cfg.seckf*1000;
pParams.nBufferDelay=5000;
pParams.nCrisp=cfg.crisp;
pParams.nQuality=cfg.quality;
pParams.nPeakBuffer=5000;
pParams.nPeakBitrate=cfg.maxbitrate;
pParams.nComplexity=cfg.cplx;
pParams.nProfile=P_MAIN;
pParams.fIsVBR=cfg.bUseVBR;
pParams.fIsConstrained=FALSE;
pParams.fIsInterlaced=cfg.deint;
pParams.nPasses=1;
for (vector<Tff_wmv9codecInfo>::const_iterator c=codecs.begin();c!=codecs.end();c++)
if (c->index==cfg.codecIndex)
{
pParams.dwTag=c->fcc;
break;
}
hr=InitializeEncoder(&pContext.pDMO,
&pContext.mtIn,
&pContext.mtOut,
pContext.pInputBuffer);
if (FAILED(hr)) return false;
//
// The codecs used in this sample don't perform lookahead on the incoming data.
// If this changes the scheme used here may not work.
// FAIL is the encoder uses lookahead.
//
hr = pContext.pDMO->GetInputStreamInfo( 0, &dwFlags );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -