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; 
}