📄 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 <amvideo.h>#include "../imgFilters/ffImgfmt.h"#include <initguid.h>#include "ffdshow_mediaguids.h"#ifdef __GNUC__#include "strmiids.cpp"#elseDEFINE_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#if defined(_DEBUG)#include <stdio.h> /* vsprintf */#define DPRINTF_BUF_SZ 1024static __inline void DPRINTF(char *fmt, ...){ va_list args; char buf[DPRINTF_BUF_SZ]; va_start(args, fmt); vsprintf(buf, fmt, args); OutputDebugString(buf);}#elsestatic __inline void DPRINTF(char *fmt, ...) { }#endifusing 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; DWORD dwFcc = info.fcc; DPRINTF("mmioFOURCC('%c', '%c', '%c', '%c'); // %u %s\n", BYTE(dwFcc), BYTE(dwFcc >> 8), BYTE(dwFcc >> 16), BYTE(dwFcc >> 24), info.fcc, info.name); 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 int 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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -