www.pudn.com > t264-src-0.14.rar > 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_wszEncName[] = L"T264 Encoder"; 
static const WCHAR g_wszEncPropName[] = L"T264 Properties"; 
static const WCHAR g_wszDecName[] = L"T264 Decoder"; 
static const WCHAR g_wszDecPropName[] = L"T264 decoder properties"; 
static const WCHAR g_wszSplitterName[] = L"T264 splitter"; 
 
// 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); 
// {EAB4831B-121B-4568-86A7-E8058BABA62E} 
DEFINE_GUID(CLSID_T264DEC,  
            0xeab4831b, 0x121b, 0x4568, 0x86, 0xa7, 0xe8, 0x5, 0x8b, 0xab, 0xa6, 0x2e); 
// {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); 
// {F3957FA3-98EE-4568-942D-953BBF79136F} 
DEFINE_GUID(CLSID_T264Splitter,  
            0xf3957fa3, 0x98ee, 0x4568, 0x94, 0x2d, 0x95, 0x3b, 0xbf, 0x79, 0x13, 0x6f); 
 
// 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_MEDIATYPE sudInPinTypes1[] =  
{ 
    { 
        &MEDIATYPE_Stream, 
        &MEDIASUBTYPE_NULL 
    } 
}; 
 
// encoder 
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 
    } 
}; 
 
// decoder 
const AMOVIESETUP_PIN psudPinsdec[] = 
{  
    {  
        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 
        sudInPinTypes,      // lpTypes 
    } 
}; 
 
// splitter 
const AMOVIESETUP_PIN psudPinssplitter[] = 
{ 
    {  
        L"Input",            // strName 
        FALSE,               // bRendered 
        FALSE,               // bOutput 
        FALSE,               // bZero 
        FALSE,               // bMany 
        &CLSID_NULL,         // clsConnectsToFilter 
        L"",                 // strConnectsToPin 
        1,                   // nTypes 
        sudInPinTypes1,       // lpTypes 
    }, 
    {  
        L"Output",           // strName 
        FALSE,               // bRendered 
        TRUE,                // bOutput 
        FALSE,               // bZero 
        FALSE,               // bMany 
        &CLSID_NULL,         // clsConnectsToFilter 
        L"",                 // strConnectsToPin 
        1,                   // nTypes 
        sudInPinTypes,      // lpTypes 
    } 
}; 
 
const AMOVIESETUP_FILTER sudDST264ENC = 
{  
    &CLSID_T264ENC,                  // clsID 
    g_wszEncName,                    // strName 
    MERIT_DO_NOT_USE,                // dwMerit 
    2,                               // nPins 
    psudPins,  
}; 
 
const AMOVIESETUP_FILTER sudDST264DEC = 
{  
    &CLSID_T264DEC,                  // clsID 
    g_wszDecName,                    // strName 
    MERIT_NORMAL,                    // dwMerit 
    2,                               // nPins 
    psudPinsdec,  
}; 
 
const AMOVIESETUP_FILTER subDST264Splitter =  
{ 
    &CLSID_T264Splitter,             // clsID 
    g_wszSplitterName,               // strName 
    MERIT_NORMAL + 3,                // dwMerit 
    2,                               // nPins 
    psudPinssplitter,  
}; 
 
CFactoryTemplate g_Templates[]= 
{    
    {  
        g_wszEncName,           
        &CLSID_T264ENC, 
        CT264Enc::CreateInstance,  // function called by class factory 
        NULL, 
        &sudDST264ENC  
    }, 
    {  
        g_wszEncPropName, 
        &CLSID_T264PropPage, 
        CT264EncProp::CreateInstance  
    }, 
    {  
        g_wszDecName,           
        &CLSID_T264DEC, 
        CT264Dec::CreateInstance,  // function called by class factory 
        NULL, 
        &sudDST264DEC  
    }, 
    { 
        g_wszSplitterName, 
        &CLSID_T264Splitter, 
        CT264Splitter::CreateInstance, 
        NULL, 
        &subDST264Splitter 
    } 
}; 
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; 
    memset(&m_param, 0, sizeof(m_param)); 
    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 ... 
    __asm emms 
    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 && lActualSize) 
    { 
        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 = '462T'; 
    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_FASTINTERPOLATE| 
        USE_SAD| 
        USE_EXTRASUBPELSEARCH| 
        USE_INTRAININTER| 
        USE_SCENEDETECT; 
 
    m_param.iframe = 300; 
    m_param.idrframe = 3000 * 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; 
        |SEARCH_16x16B 
        |SEARCH_16x8B 
        |SEARCH_8x16B; 
 
    m_param.disable_filter = 0; 
    m_param.aspect_ratio = 2; 
    m_param.video_format = 1; 
 
    m_param.ref_num  = 3; 
    m_param.luma_coeff_cost = 4;    // default 4, min qp please decrease this value 
    m_param.cpu      = 0; 
    m_param.cabac = 1; 
    m_param.b_num = 1; 
    if (m_param.bitrate != 0) 
        m_param.enable_rc = 1; 
    else 
        m_param.enable_rc = 0; 
 
    return S_OK; 
} 
 
HRESULT CT264Enc::put_InfoWnd(INT hWnd) 
{ 
    m_hWnd = (HWND)hWnd; 
 
    return S_OK; 
} 
 
////////////////////////////////////////////////////////////////////////// 
// CT264Dec 
CT264Dec::CT264Dec(TCHAR *tszName,LPUNKNOWN punk,HRESULT *phr) : 
CTransformFilter(tszName, punk, CLSID_T264ENC) 
{ 
    m_t264 = 0; 
    m_hWnd = 0; 
} 
 
CT264Dec::~CT264Dec() 
{ 
    if (m_t264 != 0) 
    { 
        T264dec_close(m_t264); 
    } 
} 
 
// 
// CreateInstance 
// 
// Provide the way for COM to create a CT264Dec object 
// 
CUnknown * WINAPI CT264Dec::CreateInstance(LPUNKNOWN punk, HRESULT *phr)  
{ 
    ASSERT(phr); 
 
    CT264Dec *pNewObject = new CT264Dec(NAME("T264Dec"), punk, phr); 
    if (pNewObject == NULL) { 
        if (phr) 
            *phr = E_OUTOFMEMORY; 
    } 
 
    return pNewObject; 
 
} // CreateInstance 
 
// 
// NonDelegatingQueryInterface 
// 
// Reveals IContrast and ISpecifyPropertyPages 
// 
STDMETHODIMP CT264Dec::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 CT264Dec::Transform(IMediaSample *pIn, IMediaSample *pOut) 
{ 
    return S_OK; 
} // Transform 
 
HRESULT CT264Dec::SendSample(T264_t* t, T264_frame_t *frame, IMediaSample* pSample) 
{ 
    INT	i; 
    BYTE* p, *pDst; 
    HRESULT hr; 
    IMediaSample* pOutSample; 
 
    // Set up the output sample 
    hr = InitializeOutputSample(pSample, &pOutSample); 
 
    if (FAILED(hr))  
    { 
        return hr; 
    } 
    hr = pOutSample->GetPointer(&pDst); 
    ASSERT(hr == S_OK); 
 
    p = frame->Y[0]; 
    for(i = 0 ; i < t->height ; i ++) 
    { 
        memcpy(pDst, p, t->width); 
        pDst += m_nStride; 
        p += t->edged_stride; 
    } 
    p = frame->V; 
    for(i = 0 ; i < t->height >> 1 ; i ++) 
    { 
        memcpy(pDst, p, t->width); 
        pDst += m_nStride >> 1; 
        p += t->edged_stride_uv; 
    } 
    p = frame->U; 
    for(i = 0 ; i < t->height >> 1 ; i ++) 
    { 
        memcpy(pDst, p, t->width); 
        pDst += m_nStride >> 1; 
        p += t->edged_stride_uv; 
    } 
 
    pOutSample->SetActualDataLength(t->width * t->height + (t->width * t->height >> 1)); 
    pOutSample->SetSyncPoint(TRUE); 
    CRefTime rtEnd = m_time + m_avgFrameTime; 
    pOutSample->SetTime(&m_time.m_time, &rtEnd.m_time); 
    m_time = rtEnd; 
 
    hr = m_pNextFilterInputpin->Receive(pOutSample); 
    m_bSampleSkipped = FALSE;	// last thing no longer dropped 
 
    // release the output buffer. If the connected pin still needs it, 
    // it will have addrefed it itself. 
    pOutSample->Release(); 
 
    return hr; 
} 
 
HRESULT CT264Dec::CompleteConnect(PIN_DIRECTION direction, IPin *pReceivePin) 
{ 
    HRESULT hr = CTransformFilter::CompleteConnect(direction, pReceivePin); 
    if (direction == PINDIR_OUTPUT) 
    { 
        hr = pReceivePin->QueryInterface(__uuidof(m_pNextFilterInputpin), (VOID**)&m_pNextFilterInputpin); 
        ASSERT(hr == S_OK); 
        // we do not want to hold the reference of the input pin 
        m_pNextFilterInputpin->Release(); 
    } 
    return hr; 
} 
 
HRESULT CT264Dec::Receive(IMediaSample* pSample) 
{ 
    /*  Check for other streams and pass them on */ 
    AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); 
    if (pProps->dwStreamId != AM_STREAM_MEDIA) { 
        return m_pNextFilterInputpin->Receive(pSample); 
    } 
    HRESULT hr; 
    ASSERT(pSample); 
 
    ASSERT (m_pOutput != NULL) ; 
    { 
        // some decoder does not reset emms(such as mainconcept mpeg2 decoder), and we need compute floating ... 
        BYTE* pSrc; 
        LONG lSrcSize; 
        INT run = 1; 
        hr = pSample->GetPointer(&pSrc); 
        ASSERT(hr == S_OK); 
        lSrcSize = pSample->GetSize(); 
 
        T264dec_buffer(m_t264, pSrc, lSrcSize); 
        while (run) 
        { 
            decoder_state_t state = T264dec_parse(m_t264); 
            switch(state)  
            { 
            case DEC_STATE_SLICE: 
                { 
                    if (m_t264->output.poc >= 0) 
                    { 
                        SendSample(m_t264, &m_t264->output, pSample); 
                    } 
                } 
                break; 
            case DEC_STATE_BUFFER: 
                /* read more data */ 
                return S_OK; 
            case DEC_STATE_SEQ: 
                if (m_t264->frame_id > 0) 
                { 
                    SendSample(m_t264, T264dec_flush_frame(m_t264), pSample); 
                } 
                break; 
            /*case DEC_STATE_PIC:*/ 
            default: 
                /* do not care */ 
                break; 
            } 
        } 
    } 
 
    return hr; 
} 
 
HRESULT CT264Dec::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 CT264Dec::CheckInputType(const CMediaType *mtIn) 
{ 
    CheckPointer(mtIn,E_POINTER); 
 
    if(*mtIn->FormatType() == FORMAT_VideoInfo) 
    { 
//        if (*mtIn->Subtype() == CLSID_T264SUBTYPE) 
        { 
            if(mtIn->FormatLength() < sizeof(VIDEOINFOHEADER)) 
                return E_INVALIDARG; 
 
            VIDEOINFO *pInput  = (VIDEOINFO *) mtIn->Format(); 
            if (pInput->bmiHeader.biCompression == 'HSSV' || pInput->bmiHeader.biCompression == '462T') 
            { 
                m_nWidth = pInput->bmiHeader.biWidth; 
                m_nHeight = pInput->bmiHeader.biHeight; 
                m_framerate = (float)(INT)((float)10000000 / pInput->AvgTimePerFrame + 0.5); 
                m_avgFrameTime = pInput->AvgTimePerFrame; 
                return NOERROR; 
            } 
        } 
    } 
    else if (*mtIn->FormatType() == FORMAT_VideoInfo2) 
    { 
//        if (*mtIn->Subtype() == CLSID_T264SUBTYPE) 
        { 
            if(mtIn->FormatLength() < sizeof(VIDEOINFOHEADER2)) 
                return E_INVALIDARG; 
 
            VIDEOINFOHEADER2 *pInput  = (VIDEOINFOHEADER2*) mtIn->Format(); 
            if (pInput->bmiHeader.biCompression == 'HSSV' || pInput->bmiHeader.biCompression == '462T') 
            { 
                m_nWidth = pInput->bmiHeader.biWidth; 
                m_nHeight = pInput->bmiHeader.biHeight; 
                m_avgFrameTime = pInput->AvgTimePerFrame; 
                m_framerate = (float)(INT)((float)10000000 / pInput->AvgTimePerFrame + 0.5); 
                return NOERROR; 
            } 
        } 
    } 
 
    return E_INVALIDARG; 
 
} // CheckInputType 
 
HRESULT CT264Dec::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; 
 
    VIDEOINFO* pInfo = (VIDEOINFO*)mtOut->Format(); 
    m_nStride = pInfo->bmiHeader.biWidth; 
    return NOERROR; 
 
} // CheckTransform 
 
HRESULT CT264Dec::InitOutMediaType(CMediaType* pmt) 
{ 
    pmt->InitMediaType(); 
 
    pmt->SetType(&MEDIATYPE_Video); 
    pmt->SetSubtype(&MEDIASUBTYPE_YV12); 
 
    VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER*)pmt->AllocFormatBuffer(sizeof(VIDEOINFOHEADER)); 
    ZeroMemory(pvi, sizeof(VIDEOINFOHEADER)); 
    pvi->AvgTimePerFrame = m_avgFrameTime; 
    pvi->bmiHeader.biCompression = '21VY'; 
    pvi->bmiHeader.biBitCount    = 12; 
    pvi->bmiHeader.biPlanes = 1; 
    pvi->bmiHeader.biSize       = sizeof(BITMAPINFOHEADER); 
    pvi->bmiHeader.biWidth      = m_nWidth; 
    pvi->bmiHeader.biHeight     = m_nHeight; 
    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 CT264Dec::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_nWidth * m_nHeight >> 1) + m_nWidth * m_nHeight; 
 
    ASSERT(pProperties->cbBuffer); 
 
    // If we don't have fixed sized samples we must guess some size 
 
    if(!m_pOutput->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 CT264Dec::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 CT264Dec::StartStreaming() 
{ 
    _asm emms 
    if (m_t264 == NULL) 
    { 
        m_t264 = T264dec_open(); 
        ASSERT(m_t264); 
    } 
    m_time = 0; 
    return CTransformFilter::StartStreaming(); 
} 
 
HRESULT CT264Dec::StopStreaming() 
{ 
    if (m_t264 != NULL) 
    { 
        T264dec_close(m_t264); 
        m_t264 = 0; 
    } 
    return CTransformFilter::StopStreaming(); 
} 
 
////////////////////////////////////////////////////////////////////////// 
// CT264Splitter 
CT264Splitter::CT264Splitter( 
    LPUNKNOWN pUnk, 
    HRESULT *phr) : 
    CBaseSplitterFilter( 
                    TEXT("CT264Splitter"), 
                    pUnk, 
                    CLSID_T264Splitter, 
                    phr) 
{ 
    //  Create our input pin 
    m_pInput = new CSplitterInputPin(this, phr); 
} 
 
CUnknown *CT264Splitter::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr) 
{ 
    CUnknown *pUnkRet = new CT264Splitter(pUnk, phr); 
    return pUnkRet; 
} 
 
//  Override type checking 
HRESULT CT264Splitter::CheckInputType(const CMediaType *pmt) 
{ 
    /*  We'll accept our preferred type or a wild card for the subtype */ 
 
    /*if (pmt->majortype != MEDIATYPE_Stream || 
        pmt->subtype != MEDIASUBTYPE_NULL) { 
            return S_FALSE; 
        } else { 
            return S_OK; 
        }*/ 
    // Async. source filter just send majortype equal null 
    return S_OK; 
} 
 
LPAMOVIESETUP_FILTER CT264Splitter::GetSetupData() 
{ 
    return (LPAMOVIESETUP_FILTER)&subDST264Splitter; 
} 
 
/*  Complete connection and instantiate parser 
This involves: 
 
Instatiate the parser with for the type and have it check the format 
*/ 
 
CBaseParser *CT264Splitter::CreateParser( 
    CParserNotify *pNotify, 
    CMediaType *pType 
    ) 
{ 
    HRESULT hr = S_OK; 
    return new CT264Parser(pNotify, &hr); 
} 
 
/*  Cheap'n nasty parser - DON'T do yours like this! */ 
/*  Initialize a parser 
 
pmt     - type of stream if known - can be NULL 
pRdr    - way to read the source medium - can be NULL 
*/ 
HRESULT CT264Parser::Init(CParseReader *pRdr) 
{ 
    const DWORD dwLen = 128; 
    /*  Just read 32K and look for interesting stuff */ 
    PBYTE pbData = new BYTE[dwLen]; 
    if (pbData == NULL) { 
        return E_OUTOFMEMORY; 
    } 
    HRESULT hr = pRdr->Read(pbData, dwLen); 
    if (S_OK != hr) { 
        delete [] pbData; 
        return hr; 
    } 
 
    /*  Now just loop looking for start codes */ 
    DWORD dwLeft = dwLen; 
    int is_t264 = 0; 
    PBYTE pbCurrent = pbData; 
    { 
        DWORD dwCode = *(UNALIGNED DWORD *)pbCurrent; 
 
        /*  Check if it's a valid start code */ 
        if (dwCode == 0x01000000)  
        { 
            int run = 1; 
            /*  Create the media type from the stream 
            only support Payload streams for now 
            */ 
            VIDEOINFO* pInfo; 
            CMediaType cmt; 
            cmt.InitMediaType(); 
 
            T264_t* t = T264dec_open(); 
            T264dec_buffer(t, pbData, dwLen); 
 
            while (run) 
            { 
                decoder_state_t state = T264dec_parse(t); 
                switch(state)  
                { 
                case DEC_STATE_CUSTOM_SET: 
                    is_t264 = true; 
                    break; 
                case DEC_STATE_SEQ: 
                    run = 0; 
                    cmt.SetType(&MEDIATYPE_Video); 
                    cmt.SetSubtype(&CLSID_T264SUBTYPE); 
                    cmt.SetFormatType(&FORMAT_VideoInfo); 
                    cmt.AllocFormatBuffer(sizeof(VIDEOINFO)); 
                    ZeroMemory(cmt.pbFormat, sizeof(VIDEOINFO)); 
                    pInfo = (VIDEOINFO*)cmt.Format(); 
                    pInfo->bmiHeader.biWidth = t->width; 
                    pInfo->bmiHeader.biHeight = t->height; 
                    pInfo->bmiHeader.biBitCount = 12; 
                    pInfo->bmiHeader.biCompression = '462T'; 
                    pInfo->bmiHeader.biPlanes = 1; 
                    pInfo->bmiHeader.biSizeImage  = GetBitmapSize(&pInfo->bmiHeader); 
                    SetRectEmpty(&(pInfo->rcSource)); 
                    SetRectEmpty(&(pInfo->rcTarget)); 
                    cmt.SetVariableSize(); 
                    cmt.SetTemporalCompression(true); 
                    if (t->aspect_ratio == 2) 
                        pInfo->AvgTimePerFrame = 400000; 
                    else 
                        pInfo->AvgTimePerFrame = 333333; 
                    break; 
                case DEC_STATE_SLICE: 
                case DEC_STATE_BUFFER: 
                    ASSERT(false); 
                    break; 
                case DEC_STATE_PIC: 
                    break; 
                default: 
                    /* do not care */ 
                    break; 
                } 
            }; 
            T264dec_close(t); 
 
            /*  Create our video stream */ 
            m_pNotify->CreateStream(L"Video", &m_Video.m_pNotify); 
            m_Video.m_pNotify->AddMediaType(&cmt); 
        } 
    } 
    delete [] pbData; 
    if (!is_t264 || !m_Video.Initialized())  
    { 
        return VFW_E_TYPE_NOT_ACCEPTED; 
    }  
    else  
    { 
        return S_OK; 
    } 
} 
 
 
/*  Get the size and count of buffers preferred based on the 
actual content 
*/ 
void CT264Parser::GetSizeAndCount(LONG *plSize, LONG *plCount) 
{ 
    *plSize = 32768; 
    *plCount = 4; 
} 
 
/*  Call this to reinitialize for a new stream */ 
void CT264Parser::StreamReset() 
{ 
} 
 
/*  Call this to pass new stream data : 
 
pbData        - pointer to data 
lData         - length of data 
plProcessed   - Amount of data consumed 
*/ 
HRESULT CT264Parser::Process( 
                              const BYTE * pbData, 
                              LONG lData, 
                              LONG *plProcessed 
                              ) 
{ 
    /*  Just loop processing packets until we run out of data 
    We should do a lot more to sync up than just eat a start 
    code ! 
    */ 
    // we do not to parse anything, the decoder do itself! 
    m_Video.m_pNotify->SendSample( 
        pbData, 
        lData, 
        0, 
        false); 
    *plProcessed = lData; 
/* 
    DWORD dwLeft = lData; 
    const BYTE * pbCurrent = pbData; 
 
    pbCurrent += 4; 
    DWORD dwCode = 0xffffff00; 
    BOOL bSend = false; 
    DWORD dwSend = 0; 
    while (dwLeft > 4)  
    { 
        //  Find a start code  
        dwCode = (dwCode << 8) | (*pbCurrent ++); 
        if (dwCode == 0x00000001) 
        { 
            m_Video.m_pNotify->SendSample( 
                pbData, 
                pbCurrent - pbData - 4, 
                0, 
                false); 
            bSend = true; 
            dwSend += pbCurrent - pbData - 4; 
            pbData = pbCurrent - 4; 
        } 
        dwLeft --; 
    } 
    if (bSend) 
    { 
        *plProcessed = dwSend; 
    } 
    else 
    { 
        m_Video.m_pNotify->SendSample( 
            pbData, 
            lData, 
            0, 
            false); 
        *plProcessed = lData; 
    } 
    */ 
    return S_OK; 
}