/******************************************************** DirectShow Video decoder implementation Copyright 2000 Eugene Kuznetsov (divx@euro.ru) *********************************************************/ #include #include "DS_VideoDecoder.h" #include #include #include #define __MODULE__ "DirectShow_VideoDecoder" #include #ifdef HAVE_MALLOC_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include "guids.h" #include "allocator.h" #include "interfaces.h" #include "inputpin.h" #include "outputpin.h" #include using namespace std; typedef long STDCALL (*GETCLASS) (GUID*, GUID*, void**); extern "C" char* def_path; DS_VideoDecoder::DS_VideoDecoder(const CodecInfo& info, const BITMAPINFOHEADER& format, int flip) :m_iState(0), record(info), m_iHandle(0), m_pFilter(0), m_pInputPin(0), m_pOutputPin(0), m_pSrcFilter(0), m_pOurInput(0), m_pOurOutput(0), m_pImp(0), m_pAll(0), m_sVhdr2(0), m_pParentFilter(0) { m_outFrame=0; try { m_bh=format; memset(&m_obh, 0, sizeof(m_obh)); m_obh.biSize=sizeof(m_obh); switch(m_bh.biCompression) { case mmioFOURCC('M', 'P', '4', '1'): case mmioFOURCC('M', 'P', '4', '3'): m_bh.biCompression=mmioFOURCC('d', 'i', 'v', '3'); break; } GETCLASS func; string _fullname=def_path; _fullname+="/"; _fullname+=info.dll; m_iHandle= LoadLibraryA(_fullname.c_str()); if(!m_iHandle)throw FATAL("Could not open DLL"); func=(GETCLASS)GetProcAddress(m_iHandle, "DllGetClassObject"); if(!func)throw FATAL("Illegal or corrupt DLL"); HRESULT result; IClassFactory* factory=0; result=func(info.guid, &IID_IClassFactory, (void**)&factory); if(result || (!factory)) throw FATAL("No such class object");; IUnknown* object=0; result=factory->vt->CreateInstance(factory, 0, &IID_IUnknown, (void**)&object); factory->vt->Release((IUnknown*)factory); if(result || (!object)) throw FATAL("Class factory failure"); result=object->vt->QueryInterface(object, &IID_IBaseFilter, (void**)&m_pFilter); object->vt->Release((IUnknown*)object); if(result || (!m_pFilter)) throw FATAL("Object does not have IBaseFilter interface"); IEnumPins* enum_pins=0; // enumerate pins result=m_pFilter->vt->EnumPins(m_pFilter, &enum_pins); if(result || (!enum_pins)) throw FATAL("Could not enumerate pins"); IPin* array[256]; ULONG fetched; enum_pins->vt->Reset(enum_pins); result=enum_pins->vt->Next(enum_pins, (ULONG)256, (IPin**)array, &fetched); Debug printf("Pins enumeration returned %d pins, error is %x\n", fetched, result); for(int i=0; ivt->QueryDirection(array[i], (PIN_DIRECTION*)&direction); if((!m_pInputPin)&&(direction==0)) { m_pInputPin=array[i]; m_pInputPin->vt->AddRef((IUnknown*)m_pInputPin); } if((!m_pOutputPin)&&(direction==1)) { m_pOutputPin=array[i]; m_pOutputPin->vt->AddRef((IUnknown*)m_pOutputPin); } array[i]->vt->Release((IUnknown*)(array[i])); } if(!m_pInputPin)throw FATAL("Input pin not found"); if(!m_pOutputPin)throw FATAL("Output pin not found"); result=m_pInputPin->vt->QueryInterface((IUnknown*)m_pInputPin, &IID_IMemInputPin, (void**)&m_pImp); if(result) throw FATAL("Error getting IMemInputPin interface"); memset(&m_sVhdr, 0, sizeof m_sVhdr); m_sVhdr.bmiHeader=m_bh; m_sVhdr.rcSource.left=m_sVhdr.rcSource.top=0; m_sVhdr.rcSource.right=m_sVhdr.bmiHeader.biWidth; m_sVhdr.rcSource.bottom=m_sVhdr.bmiHeader.biHeight; m_sVhdr.rcTarget=m_sVhdr.rcSource; m_sOurType.majortype=MEDIATYPE_Video; m_sOurType.subtype=MEDIATYPE_Video; m_sOurType.subtype.f1=m_sVhdr.bmiHeader.biCompression; m_sOurType.formattype=FORMAT_VideoInfo; m_sOurType.bFixedSizeSamples=false; m_sOurType.bTemporalCompression=true; m_sOurType.pUnk=0; m_sOurType.cbFormat=sizeof m_sVhdr; m_sOurType.pbFormat=(char*)&m_sVhdr; result=m_pInputPin->vt->QueryAccept(m_pInputPin, &m_sOurType); if(result) { cout<<"QueryAccept Faild "<GetPin(); m_pOurInput->vt->AddRef((IUnknown*)m_pOurInput); result=m_pInputPin->vt->ReceiveConnection(m_pInputPin, m_pOurInput, &m_sOurType); if(result) throw FATAL("Error connecting to input pin"); memset(&m_sDestType, 0, sizeof m_sDestType); m_sVhdr2=(VIDEOINFOHEADER*)(new char[sizeof(VIDEOINFOHEADER)+12]); *m_sVhdr2=m_sVhdr; m_sVhdr2->bmiHeader.biCompression=0; m_sVhdr2->bmiHeader.biBitCount=24; m_sDestType.majortype=MEDIATYPE_Video; m_sDestType.subtype=MEDIASUBTYPE_RGB24; m_sDestType.formattype=FORMAT_VideoInfo; m_sDestType.bFixedSizeSamples=true; m_sDestType.bTemporalCompression=false; m_sDestType.lSampleSize=abs(m_sVhdr2->bmiHeader.biWidth*m_sVhdr2->bmiHeader.biHeight* ((m_sVhdr2->bmiHeader.biBitCount+7)/8)); m_sVhdr2->bmiHeader.biSizeImage=m_sDestType.lSampleSize; m_sDestType.pUnk=0; m_sDestType.cbFormat=sizeof(VIDEOINFOHEADER); m_sDestType.pbFormat=(char*)m_sVhdr2; m_obh=m_bh; m_obh.setBits(24); m_pOurOutput=new COutputPin(m_sDestType); if(!flip) { m_sVhdr2->bmiHeader.biHeight*=-1; m_obh.biHeight*=-1; result=m_pOutputPin->vt->QueryAccept(m_pOutputPin, &m_sDestType); if(result) throw FATAL("Decoder does not support upside-down frames"); } result=m_pOutputPin->vt->ReceiveConnection(m_pOutputPin, m_pOurOutput, &m_sDestType); if(result)throw FATAL("Error connecting to output pin"); caps=(CAPS)0; m_sVhdr2->bmiHeader.biBitCount=16; m_sVhdr2->bmiHeader.biCompression=fccYUY2; m_sDestType.subtype=MEDIASUBTYPE_YUY2; result=m_pOutputPin->vt->QueryAccept(m_pOutputPin, &m_sDestType); if(!result) caps=(CAPS)(caps | CAP_YUY2); m_sVhdr2->bmiHeader.biBitCount=12; m_sVhdr2->bmiHeader.biCompression=fccIYUV; m_sDestType.subtype=MEDIASUBTYPE_IYUV; result=m_pOutputPin->vt->QueryAccept(m_pOutputPin, &m_sDestType); if(!result) caps=(CAPS)(caps | CAP_IYUV); m_sVhdr2->bmiHeader.biBitCount=16; m_sVhdr2->bmiHeader.biCompression=fccUYVY; m_sDestType.subtype=MEDIASUBTYPE_UYVY; result=m_pOutputPin->vt->QueryAccept(m_pOutputPin, &m_sDestType); if(!result) caps=(CAPS)(caps | CAP_UYVY); m_sVhdr2->bmiHeader.biBitCount=12; m_sVhdr2->bmiHeader.biCompression=fccYV12; m_sDestType.subtype=MEDIASUBTYPE_YV12; result=m_pOutputPin->vt->QueryAccept(m_pOutputPin, &m_sDestType); if(!result) caps=(CAPS)(caps | CAP_YV12); m_sVhdr2->bmiHeader.biBitCount=16; m_sVhdr2->bmiHeader.biCompression=fccYVYU; m_sDestType.subtype=MEDIASUBTYPE_YVYU; result=m_pOutputPin->vt->QueryAccept(m_pOutputPin, &m_sDestType); if(!result) caps=(CAPS)(caps | CAP_YVYU); if(caps) { cerr<<"Decoder is capable of YUV output ( flags 0x"<bmiHeader.biBitCount=24; m_sVhdr2->bmiHeader.biCompression=0; m_sDestType.subtype=MEDIASUBTYPE_RGB24; m_iState=1; return; } catch(FatalError& error) { if(m_pFilter)m_pFilter->vt->Release((IUnknown*)m_pFilter); if(m_pOutputPin)m_pOutputPin->vt->Release((IUnknown*)m_pOutputPin); if(m_pInputPin)m_pInputPin->vt->Release((IUnknown*)m_pInputPin); if(m_pImp)m_pImp->vt->Release((IUnknown*)m_pImp); delete m_pSrcFilter; delete m_pParentFilter; delete m_pOurOutput; delete m_sVhdr2; if(m_iHandle)FreeLibrary(m_iHandle); throw; } } void DS_VideoDecoder::Start() { if(m_iState!=1) return; HRESULT hr=m_pFilter->vt->Run(m_pFilter, 0); if(hr!=0) { Debug cerr<<"WARNING: m_Filter->Run() failed, error code "<vt->GetAllocator(m_pImp, &m_pAll); if(hr) { Debug cerr<<"Error getting IMemAllocator interface "<vt->Release((IUnknown*)m_pImp); return; } m_pImp->vt->NotifyAllocator(m_pImp, m_pAll, 0); ALLOCATOR_PROPERTIES props, props1; props.cBuffers=1; props.cbBuffer=m_sDestType.lSampleSize;//don't know how to do this correctly props.cbAlign=props.cbPrefix=0; m_pAll->vt->SetProperties(m_pAll, &props, &props1); m_pAll->vt->Commit(m_pAll); m_outFrame=new CImage(&m_obh,(unsigned char *)malloc(m_sDestType.lSampleSize),false); printf("Datap %x\n",m_outFrame->getaddr()); m_pOurOutput->SetFramePointer((char **)m_outFrame->getaddr()); m_iState=2; return; } void DS_VideoDecoder::Stop() { if(m_iState!=2) return; m_pAll->vt->Release((IUnknown*)m_pAll); m_pAll=0; m_pFilter->vt->Stop(m_pFilter); m_pOurOutput->SetFramePointer(0); m_outFrame->release();//just in case m_outFrame=0; m_iState=1; return; } void DS_VideoDecoder::Restart() { if(m_iState!=2) return; m_pAll->vt->Release((IUnknown*)m_pAll); m_pAll=0; m_pFilter->vt->Stop(m_pFilter); HRESULT hr=m_pFilter->vt->Run(m_pFilter, 0); if(hr!=0) { Debug cerr<<"WARNING: m_Filter->Run() failed, error code "<vt->GetAllocator(m_pImp, &m_pAll); if(hr) { printf("Error getting IMemAllocator interface %x\n", hr); m_pImp->vt->Release((IUnknown*)m_pImp); return; } ALLOCATOR_PROPERTIES props, props1; props.cBuffers=1; props.cbBuffer=m_sDestType.lSampleSize;//don't know how to do this correctly props.cbAlign=props.cbPrefix=0; m_pAll->vt->SetProperties(m_pAll, &props, &props1); m_pAll->vt->Commit(m_pAll); } void DS_VideoDecoder::Close() { if(m_iState==0) return; if(m_iState==2)Stop(); if(m_pFilter)m_pFilter->vt->Release((IUnknown*)m_pFilter); if(m_pOutputPin)m_pOutputPin->vt->Release((IUnknown*)m_pOutputPin); if(m_pInputPin)m_pInputPin->vt->Release((IUnknown*)m_pInputPin); if(m_pImp)m_pImp->vt->Release((IUnknown*)m_pImp); delete m_pSrcFilter; delete m_pParentFilter; delete m_pOurOutput; if(m_iHandle)FreeLibrary(m_iHandle); delete m_outFrame; m_pSrcFilter=0; m_pParentFilter=0; m_pOurOutput=0; m_iHandle=0; m_pFilter=0; m_pOutputPin=0; m_pInputPin=0; m_pImp=0; m_outFrame=0; m_iState=0; } int DS_VideoDecoder::DecodeFrame(char* src, int size, int is_keyframe) { if(!size)return 0; m_bh.biSizeImage=size; IMediaSample* sample=0; m_pAll->vt->GetBuffer(m_pAll, &sample, 0, 0, 0); if(!sample) { Debug cerr<<"ERROR: null sample"<vt->GetPointer(sample, (BYTE **)&ptr); memcpy(ptr, src, size); sample->vt->SetActualDataLength(sample, size); sample->vt->SetSyncPoint(sample, is_keyframe); sample->vt->SetPreroll(sample, 0); // sample->vt->SetMediaType(sample, &m_sOurType); int result=m_pImp->vt->Receive(m_pImp, sample); if(result) Debug printf("Error putting data into input pin %x\n", result); sample->vt->Release((IUnknown*)sample); return 0; } int DS_VideoDecoder::SetDestFmt(int bits, int csp) { if(m_iState==0) return -1; if(CImage::UnknownColorSpace(csp)) return -1; HRESULT result; BitmapInfo temp=m_obh; if(csp==0) { switch(bits) { case 15: m_sDestType.subtype=MEDIASUBTYPE_RGB555; break; case 16: m_sDestType.subtype=MEDIASUBTYPE_RGB565; break; case 24: m_sDestType.subtype=MEDIASUBTYPE_RGB24; break; case 32: m_sDestType.subtype=MEDIASUBTYPE_RGB32; break; default: break; } temp.setBits(bits); temp.biSizeImage=abs(temp.biWidth*temp.biHeight*((temp.biBitCount+7)/8)); } else { temp.setRGB(); temp.biBitCount=CImage::BitCount(csp); temp.biCompression=csp; temp.biSizeImage=abs(temp.biWidth*temp.biHeight*CImage::BitCount(csp)/8); switch(csp) { case fccYUY2: m_sDestType.subtype=MEDIASUBTYPE_YUY2; break; case fccYV12: m_sDestType.subtype=MEDIASUBTYPE_YV12; break; case fccIYUV: m_sDestType.subtype=MEDIASUBTYPE_IYUV; break; case fccUYVY: m_sDestType.subtype=MEDIASUBTYPE_UYVY; break; case fccYVYU: m_sDestType.subtype=MEDIASUBTYPE_YVYU; break; } } m_sDestType.lSampleSize=temp.biSizeImage; memcpy(&(m_sVhdr2->bmiHeader), &temp, sizeof(temp)); m_sVhdr2->bmiHeader.biSize=sizeof(BITMAPINFOHEADER); if(m_sVhdr2->bmiHeader.biCompression==3) m_sDestType.cbFormat=sizeof(VIDEOINFOHEADER)+12; else m_sDestType.cbFormat=sizeof(VIDEOINFOHEADER); result=m_pOutputPin->vt->QueryAccept(m_pOutputPin, &m_sDestType); if(result!=0) { if(csp) cerr<<"Unsupported color space"<0) { int old_state=m_iState; if(m_iState==2)Stop(); m_pInputPin->vt->Disconnect(m_pInputPin); m_pOutputPin->vt->Disconnect(m_pOutputPin); m_pOurOutput->SetNewFormat(m_sDestType); result=m_pInputPin->vt->ReceiveConnection(m_pInputPin, m_pOurInput, &m_sOurType); if(result) { cerr<<"Error reconnecting input pin "<vt->ReceiveConnection(m_pOutputPin, m_pOurOutput, &m_sDestType); if(result) { cerr<<"Error reconnecting output pin "<