www.pudn.com > T264-src-0.02.zip > T264Enc.cpp
#include "stdafx.h" #include// declares DEFINE_GUID to declare an EXTERN_C const. #if (_MSC_VER < 1100) #include #else #include #endif #include "T264Enc.h" #include "malloc.h" #include "T264EncProp.h" #include "dvdmedia.h" static const WCHAR g_wszName[] = L"T264 Encoder"; static const WCHAR g_wszPropName[] = L"T264 Properties"; // dshow needs this STDAPI DllRegisterServer() { return AMovieDllRegisterServer2( TRUE ); } STDAPI DllUnregisterServer() { return AMovieDllRegisterServer2( FALSE ); } // // DllEntryPoint // extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID); BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) { return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved); } // {6D2616AA-3C89-4703-9CEB-693C051C9E5F} DEFINE_GUID(CLSID_T264ENC, 0x6d2616aa, 0x3c89, 0x4703, 0x9c, 0xeb, 0x69, 0x3c, 0x5, 0x1c, 0x9e, 0x5f); // {0CA6ED63-793D-4a4e-BF64-6E37F6F4D44E} DEFINE_GUID(CLSID_T264SUBTYPE, 0xca6ed63, 0x793d, 0x4a4e, 0xbf, 0x64, 0x6e, 0x37, 0xf6, 0xf4, 0xd4, 0x4e); // {E795D14A-879D-4ea9-95EE-B6884276AEEF} DEFINE_GUID(CLSID_T264PropPage, 0xe795d14a, 0x879d, 0x4ea9, 0x95, 0xee, 0xb6, 0x88, 0x42, 0x76, 0xae, 0xef); // setup data - allows the self-registration to work. const AMOVIESETUP_MEDIATYPE sudInPinTypes[] = { { &MEDIATYPE_Video, &MEDIASUBTYPE_NULL } }; const AMOVIESETUP_MEDIATYPE sudOutPinTypes[] = { { &MEDIATYPE_Stream, &MEDIASUBTYPE_NULL } }; const AMOVIESETUP_PIN psudPins[] = { { L"Input", // strName FALSE, // bRendered FALSE, // bOutput FALSE, // bZero FALSE, // bMany &CLSID_NULL, // clsConnectsToFilter L"", // strConnectsToPin 1, // nTypes sudInPinTypes, // lpTypes }, { L"Output", // strName FALSE, // bRendered TRUE, // bOutput FALSE, // bZero FALSE, // bMany &CLSID_NULL, // clsConnectsToFilter L"", // strConnectsToPin 1, // nTypes sudOutPinTypes, // lpTypes } }; const AMOVIESETUP_FILTER sudDST264ENC = { &CLSID_T264ENC, // clsID g_wszName, // strName MERIT_DO_NOT_USE, // dwMerit 2, // nPins psudPins, }; CFactoryTemplate g_Templates[]= { { g_wszName, &CLSID_T264ENC, CT264Enc::CreateInstance, // function called by class factory NULL, &sudDST264ENC }, { g_wszPropName, &CLSID_T264PropPage, CT264EncProp::CreateInstance } }; int g_cTemplates = sizeof(g_Templates)/sizeof(g_Templates[0]); ////////////////////////////////////////////////////////////////////////// // CT264Enc CT264Enc::CT264Enc(TCHAR *tszName,LPUNKNOWN punk,HRESULT *phr) : CTransformFilter(tszName, punk, CLSID_T264ENC) { m_t264 = 0; put_Default(); m_hWnd = 0; } CT264Enc::~CT264Enc() { if (m_t264 != 0) { T264_close(m_t264); _aligned_free(m_pBuffer); } } // // CreateInstance // // Provide the way for COM to create a CT264Enc object // CUnknown * WINAPI CT264Enc::CreateInstance(LPUNKNOWN punk, HRESULT *phr) { ASSERT(phr); CT264Enc *pNewObject = new CT264Enc(NAME("T264Enc"), punk, phr); if (pNewObject == NULL) { if (phr) *phr = E_OUTOFMEMORY; } return pNewObject; } // CreateInstance // // NonDelegatingQueryInterface // // Reveals IContrast and ISpecifyPropertyPages // STDMETHODIMP CT264Enc::NonDelegatingQueryInterface(REFIID riid, void **ppv) { CheckPointer(ppv, E_POINTER); if (riid == IID_IProp) { return GetInterface((IProp*) this, ppv); } else if (riid == IID_ISpecifyPropertyPages) { return GetInterface((ISpecifyPropertyPages*) this, ppv); } else { return CTransformFilter::NonDelegatingQueryInterface(riid, ppv); } } // NonDelegatingQueryInterface HRESULT CT264Enc::Transform(IMediaSample *pIn, IMediaSample *pOut) { INT plane = m_param.width * m_param.height; HRESULT hr; // some decoder does not reset emms(such as mainconcept mpeg2 decoder), and we need compute floating ... BYTE* pSrc, *pDst; LONG lDstSize, lActualSize; hr = pIn->GetPointer(&pSrc); ASSERT(hr == S_OK); hr = pOut->GetPointer(&pDst); ASSERT(hr == S_OK); lDstSize = pOut->GetSize(); // convert yv12 ==> iyuv CopyMemory(m_pBuffer, pSrc, plane); CopyMemory(m_pBuffer + plane, pSrc + plane + (plane >> 2), plane >> 2); CopyMemory(m_pBuffer + plane + (plane >> 2), pSrc + plane, plane >> 2); lActualSize = T264_encode(m_t264, m_pBuffer, pDst, lDstSize); ASSERT(lActualSize <= lDstSize); pOut->SetActualDataLength(lActualSize); if (m_hWnd) { wsprintf(m_szInfo, "Frame = %d, Qp = %d, Length = %d.", m_t264->frame_id, m_t264->qp_y, lActualSize); SendMessage(m_hWnd, WM_SETTEXT, 0, (LPARAM)m_szInfo); } return hr; } // Transform HRESULT CT264Enc::Copy(IMediaSample *pSource, IMediaSample *pDest) const { CheckPointer(pSource,E_POINTER); CheckPointer(pDest,E_POINTER); // Copy the sample data BYTE *pSourceBuffer, *pDestBuffer; long lSourceSize = pSource->GetActualDataLength(); #ifdef DEBUG long lDestSize = pDest->GetSize(); ASSERT(lDestSize >= lSourceSize); #endif pSource->GetPointer(&pSourceBuffer); pDest->GetPointer(&pDestBuffer); CopyMemory((PVOID) pDestBuffer,(PVOID) pSourceBuffer,lSourceSize); // Copy the sample times REFERENCE_TIME TimeStart, TimeEnd; if(NOERROR == pSource->GetTime(&TimeStart, &TimeEnd)) { pDest->SetTime(&TimeStart, &TimeEnd); } LONGLONG MediaStart, MediaEnd; if(pSource->GetMediaTime(&MediaStart,&MediaEnd) == NOERROR) { pDest->SetMediaTime(&MediaStart,&MediaEnd); } // Copy the Sync point property HRESULT hr = pSource->IsSyncPoint(); if(hr == S_OK) { pDest->SetSyncPoint(TRUE); } else if(hr == S_FALSE) { pDest->SetSyncPoint(FALSE); } else { // an unexpected error has occured... return E_UNEXPECTED; } // Copy the media type AM_MEDIA_TYPE *pMediaType; pSource->GetMediaType(&pMediaType); pDest->SetMediaType(pMediaType); DeleteMediaType(pMediaType); // Copy the preroll property hr = pSource->IsPreroll(); if(hr == S_OK) { pDest->SetPreroll(TRUE); } else if(hr == S_FALSE) { pDest->SetPreroll(FALSE); } else { // an unexpected error has occured... return E_UNEXPECTED; } // Copy the discontinuity property hr = pSource->IsDiscontinuity(); if(hr == S_OK) { pDest->SetDiscontinuity(TRUE); } else if(hr == S_FALSE) { pDest->SetDiscontinuity(FALSE); } else { // an unexpected error has occured... return E_UNEXPECTED; } // Copy the actual data length long lDataLength = pSource->GetActualDataLength(); pDest->SetActualDataLength(lDataLength); return NOERROR; } // Copy HRESULT CT264Enc::CheckInputType(const CMediaType *mtIn) { CheckPointer(mtIn,E_POINTER); if(*mtIn->FormatType() == FORMAT_VideoInfo) { if(IsEqualGUID(*mtIn->Subtype(), MEDIASUBTYPE_YV12)) { if(mtIn->FormatLength() < sizeof(VIDEOINFOHEADER)) return E_INVALIDARG; VIDEOINFO *pInput = (VIDEOINFO *) mtIn->Format(); m_param.width = pInput->bmiHeader.biWidth; m_param.height = pInput->bmiHeader.biHeight; m_param.framerate = (float)(INT)((float)10000000 / pInput->AvgTimePerFrame + 0.5); m_avgFrameTime = pInput->AvgTimePerFrame; return NOERROR; } } else if (*mtIn->FormatType() == FORMAT_VideoInfo2) { if(IsEqualGUID(*mtIn->Subtype(), MEDIASUBTYPE_YV12)) { if(mtIn->FormatLength() < sizeof(VIDEOINFOHEADER2)) return E_INVALIDARG; VIDEOINFOHEADER2 *pInput = (VIDEOINFOHEADER2*) mtIn->Format(); m_param.width = pInput->bmiHeader.biWidth; m_param.height = pInput->bmiHeader.biHeight; m_avgFrameTime = (LONGLONG)((float)10000000 / m_param.framerate);//pInput->AvgTimePerFrame; m_param.framerate = (float)(INT)(m_param.framerate + 0.5f); return NOERROR; } } return E_INVALIDARG; } // CheckInputType HRESULT CT264Enc::CheckTransform(const CMediaType *mtIn,const CMediaType *mtOut) { CheckPointer(mtIn,E_POINTER); CheckPointer(mtOut,E_POINTER); HRESULT hr; if(FAILED(hr = CheckInputType(mtIn))) { return hr; } if(*mtOut->FormatType() != FORMAT_VideoInfo) { return E_INVALIDARG; } // formats must be big enough if(mtIn->FormatLength() < sizeof(VIDEOINFOHEADER) || mtOut->FormatLength() < sizeof(VIDEOINFOHEADER)) return E_INVALIDARG; return NOERROR; } // CheckTransform HRESULT CT264Enc::InitOutMediaType(CMediaType* pmt) { pmt->InitMediaType(); pmt->SetType(&MEDIATYPE_Video); pmt->SetSubtype(&CLSID_T264SUBTYPE); VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER*)pmt->AllocFormatBuffer(sizeof(VIDEOINFOHEADER)); ZeroMemory(pvi, sizeof(VIDEOINFOHEADER)); DWORD fcc = 'HSSV'; pvi->dwBitRate = m_param.bitrate; pvi->AvgTimePerFrame = m_avgFrameTime; pvi->bmiHeader.biCompression = fcc; pvi->bmiHeader.biBitCount = 12; pvi->bmiHeader.biPlanes = 1; pvi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pvi->bmiHeader.biWidth = m_param.width; pvi->bmiHeader.biHeight = m_param.height; pvi->bmiHeader.biSizeImage = GetBitmapSize(&pvi->bmiHeader); SetRectEmpty(&(pvi->rcSource)); SetRectEmpty(&(pvi->rcTarget)); pmt->SetFormatType(&FORMAT_VideoInfo); pmt->SetVariableSize(); pmt->SetTemporalCompression(true); return S_OK; } // // DecideBufferSize // // Tell the output pin's allocator what size buffers we // require. Can only do this when the input is connected // HRESULT CT264Enc::DecideBufferSize(IMemAllocator *pAlloc,ALLOCATOR_PROPERTIES *pProperties) { CheckPointer(pAlloc,E_POINTER); CheckPointer(pProperties,E_POINTER); // Is the input pin connected if(m_pInput->IsConnected() == FALSE) { return E_UNEXPECTED; } HRESULT hr = NOERROR; pProperties->cBuffers = 1; pProperties->cbBuffer = m_pInput->CurrentMediaType().GetSampleSize(); ASSERT(pProperties->cbBuffer); // If we don't have fixed sized samples we must guess some size if(!m_pInput->CurrentMediaType().bFixedSizeSamples) { if(pProperties->cbBuffer < OUTPIN_BUFFER_SIZE) { // nothing more than a guess!! pProperties->cbBuffer = OUTPIN_BUFFER_SIZE; } } // Ask the allocator to reserve us some sample memory, NOTE the function // can succeed (that is return NOERROR) but still not have allocated the // memory that we requested, so we must check we got whatever we wanted ALLOCATOR_PROPERTIES Actual; hr = pAlloc->SetProperties(pProperties,&Actual); if(FAILED(hr)) { return hr; } ASSERT(Actual.cBuffers == 1); if(pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer) { return E_FAIL; } return NOERROR; } // DecideBufferSize // // GetMediaType // // I support one type, namely the type of the input pin // We must be connected to support the single output type // HRESULT CT264Enc::GetMediaType(int iPosition, CMediaType *pMediaType) { // Is the input pin connected if(m_pInput->IsConnected() == FALSE) { return E_UNEXPECTED; } // This should never happen if(iPosition < 0) { return E_INVALIDARG; } // Do we have more items to offer if(iPosition > 0) { return VFW_S_NO_MORE_ITEMS; } CheckPointer(pMediaType,E_POINTER); InitOutMediaType(pMediaType); return NOERROR; } // GetMediaType HRESULT CT264Enc::StartStreaming() { _asm emms if (m_t264 == NULL) { INT plane = m_param.width * m_param.height; m_t264 = T264_open(&m_param); m_pBuffer = (BYTE*)_aligned_malloc(plane + (plane >> 1), 16); ASSERT(m_t264); } return CTransformFilter::StartStreaming(); } HRESULT CT264Enc::StopStreaming() { if (m_t264 != NULL) { T264_close(m_t264); m_t264 = 0; _aligned_free(m_pBuffer); m_pBuffer = 0; } return CTransformFilter::StopStreaming(); } // // GetPages // // This is the sole member of ISpecifyPropertyPages // Returns the clsid's of the property pages we support // STDMETHODIMP CT264Enc::GetPages(CAUUID *pPages) { CheckPointer(pPages,E_POINTER); pPages->cElems = 1; pPages->pElems = (GUID *) CoTaskMemAlloc(sizeof(GUID)); if(pPages->pElems == NULL) { return E_OUTOFMEMORY; } *(pPages->pElems) = CLSID_T264PropPage; return NOERROR; } // GetPages HRESULT CT264Enc::get_Para(INT** pPara) { *pPara = (INT*)&m_param; return S_OK; } HRESULT CT264Enc::put_Default() { m_param.flags = //USE_INTRA16x16| USE_INTRA4x4| USE_HALFPEL| USE_QUARTPEL| USE_SUBBLOCK| // USE_FULLSEARCH| USE_DIAMONDSEACH| USE_FORCEBLOCKSIZE| USE_EXTPSKIPDETECT| USE_SAD; m_param.iframe = 300; m_param.idrframe = 300 * 300; m_param.qp = 28; m_param.min_qp = 8; m_param.max_qp = 34; m_param.bitrate = 600 * 1024; m_param.framerate= 30; m_param.search_x = 16; m_param.search_y = 16; m_param.block_size = SEARCH_16x16P |SEARCH_16x8P |SEARCH_8x16P; // |SEARCH_8x8P // |SEARCH_8x4P // |SEARCH_4x8P // |SEARCH_4x4P; m_param.disable_filter = 0; m_param.aspect_ratio = 2; m_param.video_format = 1; m_param.ref_num = 1; m_param.luma_coeff_cost = 4; // default 4, min qp please decrease this value m_param.cpu = 0; return S_OK; } HRESULT CT264Enc::put_InfoWnd(INT hWnd) { m_hWnd = (HWND)hWnd; return S_OK; }