www.pudn.com > DS4050src.zip > divxfilter.cpp
/************************************************************************** * * * This code has been developed by Andrea Graziani. Those intending to * * use this software module in hardware or software products are advised * * that its use may infringe existing patents or copyrights, and any such * * use would be at such party's own risk. The original developer of this * * software module and his/her company, and subsequent editors and their * * companies (including Project Mayo), will have no liability for use of * * this software or modifications or derivatives thereof. * * * * Project Mayo gives users of the Codec and Filter a license to this * * software module or modifications thereof for use in hardware or * * software products claiming conformance to the MPEG-4 Video Standard * * as described in the Open DivX license. * * * * The complete Open DivX license can be found at * * http://www.projectmayo.com/opendivx/license.php * * * **************************************************************************/ /** * Copyright (C) 2001 - Project Mayo * * Andrea Graziani * * DivX Advanced Research Center* **/ // divxfilter.cpp // #include #include #include #include #include "decore.h" #include "divxuid.h" #include "divxfilter.h" #include "divxfilterproperties.h" /** * declaration of filter information **/ // setup data const AMOVIESETUP_MEDIATYPE sudPinInTypes[4] = { { // Type 0 &MEDIATYPE_Video, &CLSID_DivX }, { // Type 1 &MEDIATYPE_Video, &CLSID_DivX_U }, { // Type 2 &MEDIATYPE_Video, &CLSID_DivX_ }, { // Type 3 &MEDIATYPE_Video, &CLSID_DivX__U } }; const AMOVIESETUP_MEDIATYPE sudPinOutTypes[1] = { &MEDIATYPE_Video, &MEDIASUBTYPE_NULL }; const AMOVIESETUP_PIN psudPins[] = { { L"Input", // String pin name FALSE, // Is it rendered FALSE, // Is it an output FALSE, FALSE, &CLSID_NULL, // Connects to filter L"Output", // Connects to pin 4, // Number of types &sudPinInTypes[0] // The pin details }, { L"Output", // String pin name FALSE, // Is it rendered TRUE, // Is it an output FALSE, FALSE, &CLSID_NULL, // Connects to filter L"Input", // Connects to pin 1, // Number of types &sudPinOutTypes[0] // The pin details } }; const AMOVIESETUP_FILTER sudDivXReg = { &CLSID_DivX, // Filter CLSID L"OpenDivX Decoder Filter", // Filter name MERIT_PREFERRED, // Its merit 2, // Number of pins psudPins // Pin details }; /** * declaration of filter template **/ // List of class IDs and creator functions for the class factory. This // provides the link between the OLE entry point in the DLL and an object // being created. The class factory will call the static CreateInstance CFactoryTemplate g_Templates[2] = { { L"OpenDivX Decoder Filter", // Filter name &CLSID_DivX, // Filter CLSID DivXFilter::CreateInstance, // Creation function NULL, // &sudDivXReg // Self-registration information }, { L"OpenDivX Decoder Filter Properties Page", &CLSID_DivXPropertiesPage, DivXFilterProperties::CreateInstance } }; int g_cTemplates = sizeof(g_Templates)/(sizeof(g_Templates[0])); // // CreateInstance // CUnknown * WINAPI DivXFilter::CreateInstance(LPUNKNOWN lpunk, HRESULT * phr) { DivXFilter * pNewObject = new DivXFilter(NAME("OpenDivX Decoder Filter"), lpunk, phr); if (pNewObject == NULL) { *phr = E_OUTOFMEMORY; } return pNewObject; } // CreateInstance // // NonDelegatingQueryInterface // STDMETHODIMP DivXFilter::NonDelegatingQueryInterface(REFIID riid, void ** ppv) { if (riid == IID_IDivXFilterInterface) { return GetInterface((IDivXFilterInterface *) this, ppv); } else if (riid == IID_ISpecifyPropertyPages) { return GetInterface((ISpecifyPropertyPages *) this, ppv); } return CTransformFilter::NonDelegatingQueryInterface(riid, ppv); } // NonDelegatingQueryInterface /** * implementation of DllRegistrerServer **/ // the dll that export this component must contain this function // STDAPI DllRegisterServer(void) { HRESULT hr = AMovieDllRegisterServer2(TRUE); if ( FAILED(hr) ) return hr; IFilterMapper2 *pFM2 = 0; hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, IID_IFilterMapper2, (void **) &pFM2); if ( FAILED(hr) ) return hr; REGFILTER2 rf2; rf2.dwVersion = 1; rf2.dwMerit = MERIT_PREFERRED; rf2.cPins = NUMELMS(psudPins); rf2.rgPins = psudPins; hr = pFM2->RegisterFilter(CLSID_DivX, L"OpenDivX Decoder Filter", NULL, &CLSID_AVIDec, L"CLSID_DivXDeux", &rf2); pFM2->Release(); return hr; } // DllRegisterServer STDAPI DllUnregisterServer(void) { HRESULT hr = AMovieDllRegisterServer2(FALSE); if ( FAILED(hr) ) return hr; IFilterMapper2 * pFM2 = 0; hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, IID_IFilterMapper2, (void **) &pFM2); if ( FAILED(hr) ) return hr; if (pFM2 != 0) { hr = pFM2->UnregisterFilter(&CLSID_AVIDec, NULL, CLSID_DivX); pFM2->Release(); } return S_OK; } // DllUnregisterServer /** * override of functions **/ // determine if the proposed input is valid // HRESULT DivXFilter::CheckInputType(const CMediaType * pmtIn) { DbgLog((LOG_TRACE, 2, TEXT("DivXFilter::CheckInputType"))); if ( (*pmtIn->Type() != MEDIATYPE_Video) ) return E_INVALIDARG; VIDEOINFO * pvi = (VIDEOINFO *) pmtIn->Format(); m_DecParam.y_dim = (pvi->bmiHeader.biHeight > 0) ? pvi->bmiHeader.biHeight : -pvi->bmiHeader.biHeight; m_DecParam.x_dim = pvi->bmiHeader.biWidth; return S_OK; } // CheckInputType HRESULT DivXFilter::StartStreaming() { return S_OK; } // StartStreaming HRESULT DivXFilter::StopStreaming() { return S_OK; } // StopStreaming // performs my desired transformation on input media // HRESULT DivXFilter::Transform(IMediaSample *pIn, IMediaSample *pOut) { if (m_iInitialized == 0) { decore(1, DEC_OPT_MEMORY_REQS, &m_DecParam, &m_DecMemReqs); m_DecParam.buffers.mp4_edged_ref_buffers = malloc(m_DecMemReqs.mp4_edged_ref_buffers_size); m_DecParam.buffers.mp4_edged_for_buffers = malloc(m_DecMemReqs.mp4_edged_for_buffers_size); m_DecParam.buffers.mp4_display_buffers = malloc(m_DecMemReqs.mp4_display_buffers_size); m_DecParam.buffers.mp4_state = malloc(m_DecMemReqs.mp4_state_size); m_DecParam.buffers.mp4_tables = malloc(m_DecMemReqs.mp4_tables_size); m_DecParam.buffers.mp4_stream = malloc(m_DecMemReqs.mp4_stream_size); memset(m_DecParam.buffers.mp4_state, 0, m_DecMemReqs.mp4_state_size); memset(m_DecParam.buffers.mp4_tables, 0, m_DecMemReqs.mp4_tables_size); memset(m_DecParam.buffers.mp4_stream, 0, m_DecMemReqs.mp4_stream_size); decore((long) this, DEC_OPT_INIT, &m_DecParam, NULL); put_PPLevel(90); m_iInitialized = 1; } DEC_FRAME dec_frame; BYTE * input_buffer, * output_buffer; if (pIn->GetPointer(&input_buffer) != S_OK) return S_OK; // not valid pointer, forgot it! if (pOut->GetPointer(&output_buffer) != S_OK) return S_OK; dec_frame.length = pIn->GetSize(); dec_frame.render_flag = 1; dec_frame.bitstream = (char *) input_buffer; dec_frame.bmp = (char *) output_buffer; dec_frame.stride = m_DecParam.x_dim; decore((long) this, 0, &dec_frame, NULL); return S_OK; } // Transform HRESULT DivXFilter::SetMediaType(PIN_DIRECTION direction, const CMediaType *pmt) { if (pmt->subtype != m_CURRENTSubType) { if (pmt->subtype == MEDIASUBTYPE_RGB32) { m_DecParam.output_format = DEC_RGB32; } else if (pmt->subtype == MEDIASUBTYPE_RGB24) { m_DecParam.output_format = DEC_RGB24; } else if (pmt->subtype == MEDIASUBTYPE_RGB555) { m_DecParam.output_format = DEC_RGB555; } else if (pmt->subtype == MEDIASUBTYPE_RGB565) { m_DecParam.output_format = DEC_RGB565; } else if (pmt->subtype == MEDIASUBTYPE_YUY2) { m_DecParam.output_format = DEC_YUV2; } /*** [Ag] Thanks to Martin for this patch! else if (pmt->subtype == MEDIASUBTYPE_YV12) { m_DecParam.output_format = YUV12; } ***/ else { /*** MessageBox(NULL, "Output format not supported\nCheck your monitor settings\n", "Error", MB_ICONEXCLAMATION); ***/ m_iInitialized = 0; return E_INVALIDARG; } if (m_iInitialized == 1) decore((long) this, DEC_OPT_SETOUT, &m_DecParam, NULL); m_CURRENTSubType = pmt->subtype; } if (pmt->FormatType() == &FORMAT_VideoInfo2) { VIDEOINFOHEADER2 * videoinfo = (VIDEOINFOHEADER2 *) pmt->Format(); } else { VIDEOINFOHEADER2 * videoinfo = (VIDEOINFOHEADER2 *) pmt->Format(); } return S_OK; } // check if input and output media types are compatibles // HRESULT DivXFilter::CheckTransform(const CMediaType * pmtIn, const CMediaType * pmtOut) { VIDEOINFOHEADER2 * pvi = (VIDEOINFOHEADER2 *) pmtIn->Format(); VIDEOINFOHEADER2 * pvo = (VIDEOINFOHEADER2 *) pmtOut->Format(); if ( (*pmtIn->Type() != MEDIATYPE_Video) || (*pmtOut->Type() != MEDIATYPE_Video) ) return E_FAIL; if ( (pvo->rcSource.right != 0) || (pvo->rcSource.left != 0) || (pvo->rcSource.bottom != 0) || (pvo->rcSource.top != 0 ) ) return E_FAIL; return S_OK; } // CheckTransform // tell the output pin's allocator what buffer is required // HRESULT DivXFilter::DecideBufferSize(IMemAllocator *pAlloc,ALLOCATOR_PROPERTIES *pProperties) { HRESULT hr; ALLOCATOR_PROPERTIES Actual; // Is the input pin connected if (m_pInput->IsConnected() == FALSE) { return E_UNEXPECTED; } pProperties->cBuffers = 1; pProperties->cbBuffer = m_DecParam.x_dim * m_DecParam.y_dim * 4; hr = pAlloc->SetProperties(pProperties, &Actual); if (FAILED(hr)) { return hr; } // verify that the allocator is able to allocate what requested if (Actual.cbBuffer < pProperties->cbBuffer) { return E_FAIL; } return S_OK; } // DecideBufferSize // retrieve the preferred media type for the output pin // HRESULT DivXFilter::GetMediaType(int iPos, CMediaType * pmtOut) { VIDEOINFOHEADER * pvih = (VIDEOINFOHEADER *) pmtOut->ReallocFormatBuffer(sizeof(VIDEOINFOHEADER)); if (pvih == NULL) { return E_OUTOFMEMORY; } ZeroMemory(pvih, sizeof (VIDEOINFOHEADER)); // common bitmap info pvih->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pvih->bmiHeader.biWidth = m_DecParam.x_dim; pvih->bmiHeader.biHeight = m_DecParam.y_dim; pvih->bmiHeader.biPlanes = 1; pvih->bmiHeader.biClrImportant = 0; pvih->bmiHeader.biClrUsed = 0; pvih->rcSource.top = 0; pvih->rcSource.left = 0; pvih->rcSource.bottom = 0; pvih->rcSource.right = 0; pvih->rcTarget.top = 0; pvih->rcTarget.left = 0; pvih->rcTarget.bottom = 0; pvih->rcTarget.right = 0; // is the input pin connected if (m_pInput->IsConnected() == FALSE) { return E_UNEXPECTED; } // check position number limit if (iPos < 0) return E_INVALIDARG; if (iPos > 5) return VFW_S_NO_MORE_ITEMS; // common media type info pmtOut->SetType(&MEDIATYPE_Video); pmtOut->SetFormatType(&FORMAT_VideoInfo); pmtOut->SetTemporalCompression(TRUE); /*** [Ag] Thanks to Martin for this patch! if (iPos == 0) { FOURCCMap * pFourCC = new FOURCCMap(&MEDIASUBTYPE_YV12); pvih->bmiHeader.biCompression = pFourCC->GetFOURCC(); pvih->bmiHeader.biBitCount = 12; pmtOut->SetSubtype(&MEDIASUBTYPE_YV12); pvih->bmiHeader.biSizeImage = GetBitmapSize(&pvih->bmiHeader); delete pFourCC; } ***/ if (iPos == 0) { FOURCCMap *pFourCC = new FOURCCMap(&MEDIASUBTYPE_YUY2); pvih->bmiHeader.biCompression = pFourCC->GetFOURCC(); pvih->bmiHeader.biBitCount = 16; pmtOut->SetSubtype(&MEDIASUBTYPE_YUY2); pvih->bmiHeader.biSizeImage = GetBitmapSize(&pvih->bmiHeader); delete pFourCC; } else if (iPos == 1) { FOURCCMap *pFourCC = new FOURCCMap(&MEDIASUBTYPE_UYVY); pvih->bmiHeader.biCompression = pFourCC->GetFOURCC(); pvih->bmiHeader.biBitCount = 16; pmtOut->SetSubtype(&MEDIASUBTYPE_UYVY); pvih->bmiHeader.biSizeImage = GetBitmapSize(&pvih->bmiHeader); delete pFourCC; } else if (iPos == 2) { pvih->bmiHeader.biCompression = BI_RGB; pvih->bmiHeader.biBitCount = 32; pmtOut->SetSubtype(&MEDIASUBTYPE_RGB32); pmtOut->SetSampleSize(pvih->bmiHeader.biSizeImage); } else if (iPos == 3) { pvih->bmiHeader.biCompression = BI_RGB; pvih->bmiHeader.biBitCount = 24; pmtOut->SetSubtype(&MEDIASUBTYPE_RGB24); pmtOut->SetSampleSize(pvih->bmiHeader.biSizeImage); } else if (iPos == 4) { pvih->bmiHeader.biCompression = BI_RGB; pvih->bmiHeader.biBitCount = 16; pmtOut->SetSubtype(&MEDIASUBTYPE_RGB555); pmtOut->SetSampleSize(pvih->bmiHeader.biSizeImage); } else if (iPos == 5) { pvih->bmiHeader.biCompression = BI_RGB; pvih->bmiHeader.biBitCount = 16; pmtOut->SetSubtype(&MEDIASUBTYPE_RGB565); pmtOut->SetSampleSize(pvih->bmiHeader.biSizeImage); } ConvertVideoInfoToVideoInfo2(pmtOut); return NOERROR; } // GetMediaType /** * interface methods **/ // required for ISpecifyPropertyPages // STDMETHODIMP DivXFilter::GetPages(CAUUID * pPages) { pPages->cElems = 1; // allocate enough memory to hold thieir GUIDs pPages->pElems = (GUID *) CoTaskMemAlloc(sizeof(GUID)); if (pPages->pElems == NULL) { return E_OUTOFMEMORY; } pPages->pElems[0] = CLSID_DivXPropertiesPage; return S_OK; } STDMETHODIMP DivXFilter::FreePages(CAUUID * pPages) { CoTaskMemFree(pPages->pElems); return S_OK; } // return the current postprocessing level // STDMETHODIMP DivXFilter::get_PPLevel(int * PPLevel) { * PPLevel = m_iPPLevel; return S_OK; } // get_ContrastLevel // set the postprocessing level // STDMETHODIMP DivXFilter::put_PPLevel(int PPLevel) { m_iPPLevel = PPLevel; // call decore API to set postprocessing level DEC_SET dec_set; dec_set.postproc_level = m_iPPLevel; decore((long) this, DEC_OPT_SETPP, &dec_set, NULL); return S_OK; } // put_ContrastLevel // set the default postprocessing level // STDMETHODIMP DivXFilter::put_DefaultPPLevel() { m_iPPLevel = m_iDefaultPPLevel; return S_OK; } // put_DefaultContrastLevel /** * constructor/denstructor **/ DivXFilter::DivXFilter(TCHAR * pName, LPUNKNOWN lpUnk, HRESULT *pHr) : CVideoTransformFilter(pName, lpUnk, CLSID_DivX), m_iDefaultPPLevel(0), m_iPPLevel(m_iDefaultPPLevel), m_iPrevPPLevel(m_iPPLevel), m_iInitialized(0), m_CURRENTSubType(GUID_NULL) { ASSERT(pName); ASSERT(pHr); } // DivXFilter DivXFilter::~DivXFilter() { decore((long) this, DEC_OPT_RELEASE, NULL, NULL); } // ~DivXFilter