Support unrar64.dll
[xy_vsfilter.git] / src / filters / transform / basevideofilter / BaseVideoFilter.cpp
blob2eebab37d79707a42598c47e1b042b7abd72469b
1 /*
2 * Copyright (C) 2003-2006 Gabest
3 * http://www.gabest.org
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GNU Make; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
22 #include "StdAfx.h"
23 #include <mmintrin.h>
24 #include "BaseVideoFilter.h"
25 #include "..\..\..\DSUtil\DSUtil.h"
26 #include "..\..\..\DSUtil\MediaTypes.h"
28 #pragma warning(push)
29 #pragma warning(disable:4995)
31 #include <initguid.h>
32 #include "..\..\..\..\include\moreuuids.h"
33 #include <algorithm>
35 #pragma warning(pop)
37 const GUID* InputFmts[] =
39 &MEDIASUBTYPE_P010,
40 &MEDIASUBTYPE_P016,
41 &MEDIASUBTYPE_NV12,
42 &MEDIASUBTYPE_NV21,
43 &MEDIASUBTYPE_YV12,
44 &MEDIASUBTYPE_I420,
45 &MEDIASUBTYPE_IYUV,
46 &MEDIASUBTYPE_YUY2,
47 &MEDIASUBTYPE_AYUV,
48 &MEDIASUBTYPE_ARGB32,
49 &MEDIASUBTYPE_RGB32,
50 &MEDIASUBTYPE_RGB24,
51 &MEDIASUBTYPE_RGB565,
52 //&MEDIASUBTYPE_RGB555
55 const OutputFormatBase OutputFmts[] =
57 {&MEDIASUBTYPE_P010, 2, 24, '010P'},
58 {&MEDIASUBTYPE_P016, 2, 24, '610P'},
59 {&MEDIASUBTYPE_NV12, 2, 12, '21VN'},
60 {&MEDIASUBTYPE_NV21, 2, 12, '12VN'},
61 {&MEDIASUBTYPE_YV12, 3, 12, '21VY'},
62 {&MEDIASUBTYPE_I420, 3, 12, '024I'},
63 {&MEDIASUBTYPE_IYUV, 3, 12, 'VUYI'},
64 {&MEDIASUBTYPE_YUY2, 1, 16, '2YUY'},
65 {&MEDIASUBTYPE_AYUV, 1, 32, 'VUYA'},
66 {&MEDIASUBTYPE_ARGB32, 1, 32, BI_RGB},
67 {&MEDIASUBTYPE_RGB32, 1, 32, BI_RGB},
68 {&MEDIASUBTYPE_RGB24, 1, 24, BI_RGB},
69 {&MEDIASUBTYPE_RGB565, 1, 16, BI_RGB},
70 //{&MEDIASUBTYPE_RGB555, 1, 16, BI_RGB},
71 {&MEDIASUBTYPE_ARGB32, 1, 32, BI_BITFIELDS},
72 {&MEDIASUBTYPE_RGB32, 1, 32, BI_BITFIELDS},
73 {&MEDIASUBTYPE_RGB24, 1, 24, BI_BITFIELDS},
74 {&MEDIASUBTYPE_RGB565, 1, 16, BI_BITFIELDS},
75 //{&MEDIASUBTYPE_RGB555, 1, 16, BI_BITFIELDS},
78 //fixme: use the same function for by input and output
79 CString OutputFmt2String(const OutputFormatBase& fmt)
81 CString ret = CString(GuidNames[*fmt.subtype]);
82 if(!ret.Left(13).CompareNoCase(_T("MEDIASUBTYPE_"))) ret = ret.Mid(13);
83 if(fmt.biCompression == 3) ret += _T(" BITF");
84 if(*fmt.subtype == MEDIASUBTYPE_I420) ret = _T("I420"); // FIXME
85 else if(*fmt.subtype == MEDIASUBTYPE_NV21) ret = _T("NV21"); // FIXME
86 return(ret);
89 CString GetColorSpaceName(ColorSpaceId colorSpace, ColorSpaceDir inputOrOutput)
91 if(inputOrOutput==INPUT_COLOR_SPACE)
92 return Subtype2String(*InputFmts[colorSpace]);
93 else
94 return OutputFmt2String(OutputFmts[colorSpace]);
97 UINT GetOutputColorSpaceNumber()
99 return countof(OutputFmts);
102 UINT GetInputColorSpaceNumber()
104 return countof(InputFmts);
107 ColorSpaceId Subtype2OutputColorSpaceId( const GUID& subtype, ColorSpaceId startId /*=0 */ )
109 ColorSpaceId i=startId;
110 int num = GetOutputColorSpaceNumber();
111 for(i=startId;i<num;i++)
113 if (*(OutputFmts[i].subtype)==subtype)
115 break;
118 return i<num ? i:-1;
122 // CBaseVideoFilter
125 CBaseVideoFilter::CBaseVideoFilter(TCHAR* pName, LPUNKNOWN lpunk, HRESULT* phr, REFCLSID clsid, long cBuffers)
126 : CTransformFilter(pName, lpunk, clsid)
127 , m_cBuffers(cBuffers)
128 , m_inputFmtCount(-1),m_outputFmtCount(-1)
129 , m_donot_follow_upstream_preferred_order(false)
131 if(phr)
132 *phr = S_OK;
133 HRESULT hr = S_OK;
134 m_pInput = new CBaseVideoInputPin(NAME("CBaseVideoInputPin"), this, &hr, L"Video");
135 if(!m_pInput)
137 if (phr) *phr = E_OUTOFMEMORY;
138 return;
140 if(FAILED(hr))
142 if (phr) *phr = hr;
143 return;
145 m_pOutput = new CBaseVideoOutputPin(NAME("CBaseVideoOutputPin"), this, &hr, L"Output");
146 if(!m_pOutput)
148 delete m_pInput, m_pInput = NULL;
149 if (phr) *phr = E_OUTOFMEMORY;
150 return;
152 if(FAILED(hr))
154 delete m_pInput, m_pInput = NULL;
155 if (phr) *phr = hr;
156 return;
159 m_wout = m_win = m_w = 0;
160 m_hout = m_hin = m_h = 0;
161 m_arxout = m_arxin = m_arx = 0;
162 m_aryout = m_aryin = m_ary = 0;
165 CBaseVideoFilter::~CBaseVideoFilter()
169 int CBaseVideoFilter::GetPinCount()
171 return 2;
174 CBasePin* CBaseVideoFilter::GetPin(int n)
176 switch(n)
178 case 0: return m_pInput;
179 case 1: return m_pOutput;
181 return NULL;
184 HRESULT CBaseVideoFilter::Receive(IMediaSample* pIn)
186 #ifndef _WIN64
187 // TODOX64 : fixme!
188 _mm_empty(); // just for safety
189 #endif
191 CAutoLock cAutoLock(&m_csReceive);
193 HRESULT hr;
195 AM_SAMPLE2_PROPERTIES* const pProps = m_pInput->SampleProps();
196 if(pProps->dwStreamId != AM_STREAM_MEDIA)
197 return m_pOutput->Deliver(pIn);
199 AM_MEDIA_TYPE* pmt;
200 if(SUCCEEDED(pIn->GetMediaType(&pmt)) && pmt)
202 CMediaType mt(*pmt);
203 m_pInput->SetMediaType(&mt);
204 DeleteMediaType(pmt);
207 if(FAILED(hr = Transform(pIn)))
208 return hr;
210 return S_OK;
213 HRESULT CBaseVideoFilter::GetDeliveryBuffer(int w, int h, IMediaSample** ppOut)
215 CheckPointer(ppOut, E_POINTER);
217 HRESULT hr;
219 if(FAILED(hr = ReconnectOutput(w, h)))
220 return hr;
222 if(FAILED(hr = m_pOutput->GetDeliveryBuffer(ppOut, NULL, NULL, 0)))
223 return hr;
225 AM_MEDIA_TYPE* pmt;
226 if(SUCCEEDED((*ppOut)->GetMediaType(&pmt)) && pmt)
228 CMediaType mt = *pmt;
229 m_pOutput->SetMediaType(&mt);
230 DeleteMediaType(pmt);
233 (*ppOut)->SetDiscontinuity(FALSE);
234 (*ppOut)->SetSyncPoint(TRUE);
236 // FIXME: hell knows why but without this the overlay mixer starts very skippy
237 // (don't enable this for other renderers, the old for example will go crazy if you do)
238 if(GetCLSID(m_pOutput->GetConnected()) == CLSID_OverlayMixer)
239 (*ppOut)->SetDiscontinuity(TRUE);
241 return S_OK;
244 HRESULT CBaseVideoFilter::ReconnectOutput(int w, int h)
246 CMediaType& mt = m_pOutput->CurrentMediaType();
248 int w_org = m_w;
249 int h_org = m_h;
251 bool fForceReconnection = false;
252 if(w != m_w || h != m_h)
254 fForceReconnection = true;
255 m_w = w;
256 m_h = h;
259 HRESULT hr = S_OK;
261 if(fForceReconnection || m_w != m_wout || m_h != m_hout || m_arx != m_arxout || m_ary != m_aryout)
263 if(GetCLSID(m_pOutput->GetConnected()) == CLSID_VideoRenderer)
265 NotifyEvent(EC_ERRORABORT, 0, 0);
266 return E_FAIL;
269 BITMAPINFOHEADER* bmi = NULL;
271 if(mt.formattype == FORMAT_VideoInfo)
273 VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)mt.Format();
274 SetRect(&vih->rcSource, 0, 0, m_w, m_h);
275 SetRect(&vih->rcTarget, 0, 0, m_w, m_h);
276 bmi = &vih->bmiHeader;
277 bmi->biXPelsPerMeter = m_w * m_ary;
278 bmi->biYPelsPerMeter = m_h * m_arx;
280 else if(mt.formattype == FORMAT_VideoInfo2)
282 VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)mt.Format();
283 SetRect(&vih->rcSource, 0, 0, m_w, m_h);
284 SetRect(&vih->rcTarget, 0, 0, m_w, m_h);
285 bmi = &vih->bmiHeader;
286 vih->dwPictAspectRatioX = m_arx;
287 vih->dwPictAspectRatioY = m_ary;
290 bmi->biWidth = m_w;
291 bmi->biHeight = m_h;
292 bmi->biSizeImage = m_w*m_h*bmi->biBitCount>>3;
294 hr = m_pOutput->GetConnected()->QueryAccept(&mt);
295 ASSERT(SUCCEEDED(hr)); // should better not fail, after all "mt" is the current media type, just with a different resolution
296 HRESULT hr1 = 0, hr2 = 0;
297 CComPtr<IMediaSample> pOut;
298 if(SUCCEEDED(hr1 = m_pOutput->GetConnected()->ReceiveConnection(m_pOutput, &mt))
299 && SUCCEEDED(hr2 = m_pOutput->GetDeliveryBuffer(&pOut, NULL, NULL, 0)))
301 AM_MEDIA_TYPE* pmt;
302 if(SUCCEEDED(pOut->GetMediaType(&pmt)) && pmt)
304 CMediaType mt = *pmt;
305 m_pOutput->SetMediaType(&mt);
306 DeleteMediaType(pmt);
308 else // stupid overlay mixer won't let us know the new pitch...
310 long size = pOut->GetSize();
311 bmi->biWidth = size / bmi->biHeight * 8 / bmi->biBitCount;
314 else
316 m_w = w_org;
317 m_h = h_org;
318 return E_FAIL;
321 m_wout = m_w;
322 m_hout = m_h;
323 m_arxout = m_arx;
324 m_aryout = m_ary;
326 // some renderers don't send this
327 NotifyEvent(EC_VIDEO_SIZE_CHANGED, MAKELPARAM(m_w, m_h), 0);
329 return S_OK;
332 return S_FALSE;
335 HRESULT CBaseVideoFilter::CopyBuffer(BYTE* pOut, BYTE* pIn, int w, int h, int pitchIn, const GUID& subtype, bool fInterlaced)
337 int abs_h = abs(h);
338 BYTE* pInYUV[3] = {pIn, pIn + pitchIn*abs_h, pIn + pitchIn*abs_h + (pitchIn>>1)*(abs_h>>1)};
339 return CopyBuffer(pOut, pInYUV, w, h, pitchIn, subtype, fInterlaced);
342 HRESULT CBaseVideoFilter::CopyBuffer(BYTE* pOut, BYTE** ppIn, int w, int h, int pitchIn, const GUID& subtype, bool fInterlaced)
344 BITMAPINFOHEADER bihOut;
345 ExtractBIH(&m_pOutput->CurrentMediaType(), &bihOut);
347 int pitchOut = 0;
349 if (bihOut.biCompression == BI_RGB || bihOut.biCompression == BI_BITFIELDS)
351 pitchOut = bihOut.biWidth*bihOut.biBitCount>>3;
353 if(bihOut.biHeight > 0)
355 pOut += pitchOut*(h-1);
356 pitchOut = -pitchOut;
357 if(h < 0) h = -h;
360 if (bihOut.biCompression == 'VUYA')
362 pitchOut = bihOut.biWidth*bihOut.biBitCount>>3;
364 if(h < 0)
366 h = -h;
367 ppIn[0] += pitchIn*(h-1);
369 if(subtype == MEDIASUBTYPE_I420 || subtype == MEDIASUBTYPE_IYUV || subtype == MEDIASUBTYPE_YV12)
371 ppIn[1] += (pitchIn>>1)*((h>>1)-1);
372 ppIn[2] += (pitchIn>>1)*((h>>1)-1);
374 else if(subtype == MEDIASUBTYPE_P010 || subtype == MEDIASUBTYPE_P016
375 || subtype == MEDIASUBTYPE_NV12 || subtype == MEDIASUBTYPE_NV21)
377 ppIn[1] += pitchIn*((h>>1)-1);
379 pitchIn = -pitchIn;
382 if(subtype == MEDIASUBTYPE_I420 || subtype == MEDIASUBTYPE_IYUV || subtype == MEDIASUBTYPE_YV12)
384 BYTE* pIn = ppIn[0];
385 BYTE* pInU = ppIn[1];
386 BYTE* pInV = ppIn[2];
388 if(subtype == MEDIASUBTYPE_YV12) {BYTE* tmp = pInU; pInU = pInV; pInV = tmp;}
390 BYTE* pOutU = pOut + bihOut.biWidth*h;
391 BYTE* pOutV = pOut + bihOut.biWidth*h*5/4;
393 if(bihOut.biCompression == '21VY') {BYTE* tmp = pOutU; pOutU = pOutV; pOutV = tmp;}
395 ASSERT(w <= abs(pitchIn));
397 if(bihOut.biCompression == '2YUY')
399 if (!fInterlaced) {
400 BitBltFromI420ToYUY2(w, h, pOut, bihOut.biWidth*2, pIn, pInU, pInV, pitchIn);
401 } else {
402 BitBltFromI420ToYUY2Interlaced(w, h, pOut, bihOut.biWidth*2, pIn, pInU, pInV, pitchIn);
405 else if(bihOut.biCompression == '024I' || bihOut.biCompression == 'VUYI' || bihOut.biCompression == '21VY')
407 BitBltFromI420ToI420(w, h, pOut, pOutU, pOutV, bihOut.biWidth, pIn, pInU, pInV, pitchIn);
409 else if(bihOut.biCompression == BI_RGB || bihOut.biCompression == BI_BITFIELDS)
411 if(!BitBltFromI420ToRGB(w, h, pOut, pitchOut, bihOut.biBitCount, pIn, pInU, pInV, pitchIn))
413 for(int y = 0; y < h; y++, pOut += pitchOut)
414 memset(pOut, 0, pitchOut);
418 else if(subtype == MEDIASUBTYPE_P010 || subtype == MEDIASUBTYPE_P016)
420 if (bihOut.biCompression != subtype.Data1)
421 return VFW_E_TYPE_NOT_ACCEPTED;
422 BitBltFromP010ToP010(w, h, pOut, bihOut.biWidth*2, ppIn[0], pitchIn);
424 else if(subtype == MEDIASUBTYPE_NV12 || subtype == MEDIASUBTYPE_NV21)
426 if (bihOut.biCompression != subtype.Data1)
427 return VFW_E_TYPE_NOT_ACCEPTED;
428 BitBltFromNV12ToNV12(w, h, pOut, bihOut.biWidth, ppIn[0], pitchIn);
430 else if(subtype == MEDIASUBTYPE_YUY2)
432 if(bihOut.biCompression == '2YUY')
434 BitBltFromYUY2ToYUY2(w, h, pOut, bihOut.biWidth*2, ppIn[0], pitchIn);
436 else if(bihOut.biCompression == BI_RGB || bihOut.biCompression == BI_BITFIELDS)
438 if(!BitBltFromYUY2ToRGB(w, h, pOut, pitchOut, bihOut.biBitCount, ppIn[0], pitchIn))
440 for(int y = 0; y < h; y++, pOut += pitchOut)
441 memset(pOut, 0, pitchOut);
445 else if(subtype == MEDIASUBTYPE_ARGB32 || subtype == MEDIASUBTYPE_RGB32 || subtype == MEDIASUBTYPE_RGB24 || subtype == MEDIASUBTYPE_RGB565
446 || subtype == MEDIASUBTYPE_AYUV)
448 int sbpp =
449 subtype == MEDIASUBTYPE_ARGB32 || subtype == MEDIASUBTYPE_RGB32 || subtype == MEDIASUBTYPE_AYUV ? 32 :
450 subtype == MEDIASUBTYPE_RGB24 ? 24 :
451 subtype == MEDIASUBTYPE_RGB565 ? 16 : 0;
453 if(bihOut.biCompression == '2YUY')
455 // TODO
456 // BitBltFromRGBToYUY2();
458 else if(bihOut.biCompression == BI_RGB || bihOut.biCompression == BI_BITFIELDS ||
459 bihOut.biCompression == 'VUYA' )
461 if(!BitBltFromRGBToRGB(w, h, pOut, pitchOut, bihOut.biBitCount, ppIn[0], pitchIn, sbpp))
463 for(int y = 0; y < h; y++, pOut += pitchOut)
464 memset(pOut, 0, pitchOut);
468 else
470 return VFW_E_TYPE_NOT_ACCEPTED;
473 return S_OK;
476 HRESULT CBaseVideoFilter::CheckInputType(const CMediaType* mtIn)
478 BITMAPINFOHEADER bih;
479 ExtractBIH(mtIn, &bih);
481 return mtIn->majortype == MEDIATYPE_Video
482 && GetInputSubtypePosition(mtIn->subtype)!=-1
483 && (mtIn->formattype == FORMAT_VideoInfo || mtIn->formattype == FORMAT_VideoInfo2)
484 && bih.biHeight > 0
485 ? S_OK
486 : VFW_E_TYPE_NOT_ACCEPTED;
489 HRESULT CBaseVideoFilter::DoCheckTransform( const CMediaType* mtIn, const CMediaType* mtOut, bool checkReconnection )
491 DbgLog((LOG_TRACE, 3, __FUNCTIONW__));
492 //DumpGraph(m_pGraph, 0);
493 if( FAILED(CheckInputType(mtIn)) || mtOut->majortype != MEDIATYPE_Video ||
494 GetOutputSubtypePosition(mtOut->subtype)==-1 )
495 return VFW_E_TYPE_NOT_ACCEPTED;
497 if( !checkReconnection &&
498 mtOut->subtype != mtIn->subtype )
500 bool can_reconnect = false;
501 CMediaType desiredMt;
502 int position = 0;
503 HRESULT hr;
505 position = GetOutputSubtypePosition(mtOut->subtype);
506 if(position>=0)
508 hr = GetMediaType(position, &desiredMt);
509 if (hr!=S_OK)
511 DbgLog((LOG_ERROR, 3, TEXT("Unexpected error when GetMediaType, position:%d"), position));
513 else
515 hr = DoCheckTransform(&desiredMt, mtOut, true);
516 if (hr!=S_OK)
518 DbgLog((LOG_TRACE, 3, TEXT("Transform not accept:")));
519 DisplayType(0,&desiredMt);
520 DisplayType(0,mtOut);
522 else
524 hr = m_pInput->GetConnected()->QueryAccept(&desiredMt);
525 if(hr!=S_OK)
527 DbgLog((LOG_TRACE, 3, TEXT("Upstream not accept:")));
528 DisplayType(0, &desiredMt);
530 else
532 can_reconnect = true;
538 if ( can_reconnect )
540 DbgLog((LOG_TRACE, 3, TEXT("agree input media type:")));
541 DisplayType(0, &desiredMt);
542 return S_OK;
546 bool can_transform = true;
547 if ( mtIn->subtype == MEDIASUBTYPE_P010
548 || mtIn->subtype == MEDIASUBTYPE_P016
549 || mtIn->subtype == MEDIASUBTYPE_NV12
550 || mtIn->subtype == MEDIASUBTYPE_NV21
551 || mtIn->subtype == MEDIASUBTYPE_AYUV )
553 if( mtOut->subtype!=mtIn->subtype )
554 can_transform = false;
556 else if( mtIn->subtype == MEDIASUBTYPE_YV12
557 || mtIn->subtype == MEDIASUBTYPE_I420
558 || mtIn->subtype == MEDIASUBTYPE_IYUV )
560 if( mtOut->subtype != MEDIASUBTYPE_YV12
561 && mtOut->subtype != MEDIASUBTYPE_I420
562 && mtOut->subtype != MEDIASUBTYPE_IYUV
563 && mtOut->subtype != MEDIASUBTYPE_YUY2
564 && mtOut->subtype != MEDIASUBTYPE_ARGB32
565 && mtOut->subtype != MEDIASUBTYPE_RGB32
566 && mtOut->subtype != MEDIASUBTYPE_RGB24
567 && mtOut->subtype != MEDIASUBTYPE_RGB565)
568 can_transform = false;
570 else if( mtIn->subtype == MEDIASUBTYPE_YUY2 )
572 if( mtOut->subtype != MEDIASUBTYPE_YUY2
573 && mtOut->subtype != MEDIASUBTYPE_ARGB32
574 && mtOut->subtype != MEDIASUBTYPE_RGB32
575 && mtOut->subtype != MEDIASUBTYPE_RGB24
576 && mtOut->subtype != MEDIASUBTYPE_RGB565)
577 can_transform = false;
579 else if( mtIn->subtype == MEDIASUBTYPE_ARGB32
580 || mtIn->subtype == MEDIASUBTYPE_RGB32
581 || mtIn->subtype == MEDIASUBTYPE_RGB24
582 || mtIn->subtype == MEDIASUBTYPE_RGB565 )
584 if(mtOut->subtype != MEDIASUBTYPE_ARGB32
585 && mtOut->subtype != MEDIASUBTYPE_RGB32
586 && mtOut->subtype != MEDIASUBTYPE_RGB24
587 && mtOut->subtype != MEDIASUBTYPE_RGB565)
588 can_transform = false;
591 if (!can_transform && !checkReconnection)
593 bool can_reconnect = false;
594 CMediaType desiredMt;
595 int position = 0;
596 HRESULT hr;
599 hr = GetMediaType(position, &desiredMt);
600 ++position;
601 if( hr!=S_OK )
602 break;
603 DbgLog((LOG_TRACE, 3, TEXT("Checking reconnect with media type:")));
604 DisplayType(0, &desiredMt);
605 if( DoCheckTransform(&desiredMt, mtOut, true)!=S_OK ||
606 m_pInput->GetConnected()->QueryAccept(&desiredMt)!=S_OK )
608 continue;
610 else
612 can_reconnect = true;
613 break;
615 } while ( true );
616 if ( can_reconnect )
618 DbgLog((LOG_TRACE, 3, TEXT("agree input media type:")));
619 DisplayType(0, &desiredMt);
620 return S_OK;
623 else if(can_transform)
625 return S_OK;
627 return VFW_E_TYPE_NOT_ACCEPTED;
630 HRESULT CBaseVideoFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut)
632 return DoCheckTransform(mtIn, mtOut, false);
635 HRESULT CBaseVideoFilter::CheckOutputType(const CMediaType& mtOut)
637 int wout = 0, hout = 0, arxout = 0, aryout = 0;
638 return ExtractDim(&mtOut, wout, hout, arxout, aryout)
639 && m_h == abs((int)hout)
640 && mtOut.subtype != MEDIASUBTYPE_ARGB32
641 && GetOutputSubtypePosition(mtOut.subtype)!=-1
642 ? S_OK
643 : VFW_E_TYPE_NOT_ACCEPTED;
646 HRESULT CBaseVideoFilter::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties)
648 if(m_pInput->IsConnected() == FALSE) return E_UNEXPECTED;
650 BITMAPINFOHEADER bih;
651 ExtractBIH(&m_pOutput->CurrentMediaType(), &bih);
653 long cBuffers = m_pOutput->CurrentMediaType().formattype == FORMAT_VideoInfo ? 1 : m_cBuffers;
655 pProperties->cBuffers = m_cBuffers;
656 pProperties->cbBuffer = bih.biSizeImage;
657 pProperties->cbAlign = 1;
658 pProperties->cbPrefix = 0;
660 HRESULT hr;
661 ALLOCATOR_PROPERTIES Actual;
662 if(FAILED(hr = pAllocator->SetProperties(pProperties, &Actual)))
663 return hr;
665 return pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer
666 ? E_FAIL
667 : NOERROR;
670 HRESULT CBaseVideoFilter::GetMediaType(int iPosition, CMediaType* pmt)
672 if(m_outputFmtCount <0)
674 InitOutputColorSpaces();
676 if(m_pInput->IsConnected() == FALSE) return E_UNEXPECTED;
678 // this will make sure we won't connect to the old renderer in dvd mode
679 // that renderer can't switch the format dynamically
681 bool fFoundDVDNavigator = false;
682 CComPtr<IBaseFilter> pBF = this;
683 CComPtr<IPin> pPin = m_pInput;
684 for(; !fFoundDVDNavigator && (pBF = GetUpStreamFilter(pBF, pPin)); pPin = GetFirstPin(pBF))
685 fFoundDVDNavigator = ((GetCLSID(pBF) == CLSID_DVDNavigator)==TRUE);
687 if(fFoundDVDNavigator || m_pInput->CurrentMediaType().formattype == FORMAT_VideoInfo2)
688 iPosition = iPosition*2;
692 if(iPosition < 0) return E_INVALIDARG;
693 if(iPosition >= 2*m_outputFmtCount) return VFW_S_NO_MORE_ITEMS;
695 pmt->majortype = MEDIATYPE_Video;
696 pmt->subtype = *m_outputFmt[iPosition/2]->subtype;
698 int w = m_win, h = m_hin, arx = m_arxin, ary = m_aryin;
699 GetOutputSize(w, h, arx, ary);
701 BITMAPINFOHEADER bihOut;
702 memset(&bihOut, 0, sizeof(bihOut));
703 bihOut.biSize = sizeof(bihOut);
704 bihOut.biWidth = w;
705 bihOut.biHeight = h;
706 bihOut.biPlanes = m_outputFmt[iPosition/2]->biPlanes;
707 bihOut.biBitCount = m_outputFmt[iPosition/2]->biBitCount;
708 bihOut.biCompression = m_outputFmt[iPosition/2]->biCompression;
709 bihOut.biSizeImage = w*h*bihOut.biBitCount>>3;
711 if(iPosition&1)
713 pmt->formattype = FORMAT_VideoInfo;
714 VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)pmt->AllocFormatBuffer(sizeof(VIDEOINFOHEADER));
715 memset(vih, 0, sizeof(VIDEOINFOHEADER));
716 vih->bmiHeader = bihOut;
717 vih->bmiHeader.biXPelsPerMeter = vih->bmiHeader.biWidth * ary;
718 vih->bmiHeader.biYPelsPerMeter = vih->bmiHeader.biHeight * arx;
720 else
722 pmt->formattype = FORMAT_VideoInfo2;
723 VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)pmt->AllocFormatBuffer(sizeof(VIDEOINFOHEADER2));
724 memset(vih, 0, sizeof(VIDEOINFOHEADER2));
725 vih->bmiHeader = bihOut;
726 vih->dwPictAspectRatioX = arx;
727 vih->dwPictAspectRatioY = ary;
728 if(IsVideoInterlaced()) vih->dwInterlaceFlags = AMINTERLACE_IsInterlaced;
731 CMediaType& mt = m_pInput->CurrentMediaType();
733 // these fields have the same field offset in all four structs
734 ((VIDEOINFOHEADER*)pmt->Format())->AvgTimePerFrame = ((VIDEOINFOHEADER*)mt.Format())->AvgTimePerFrame;
735 ((VIDEOINFOHEADER*)pmt->Format())->dwBitRate = ((VIDEOINFOHEADER*)mt.Format())->dwBitRate;
736 ((VIDEOINFOHEADER*)pmt->Format())->dwBitErrorRate = ((VIDEOINFOHEADER*)mt.Format())->dwBitErrorRate;
738 CorrectMediaType(pmt);
740 return S_OK;
743 int CBaseVideoFilter::GetInputSubtypePosition( const GUID& subtype )
745 if(m_inputFmtCount<0)
747 InitInputColorSpaces();
750 int i=0;
751 for (i=0;i<m_inputFmtCount;i++)
753 if (*m_inputFmt[i]==subtype)
755 break;
758 return i<m_inputFmtCount ? i : -1;
761 int CBaseVideoFilter::GetOutputSubtypePosition( const GUID& subtype, int startPos /*=0*/ )
763 if(m_outputFmtCount <0)
765 InitOutputColorSpaces();
767 int i=startPos;
768 for(i=startPos;i<m_outputFmtCount;i++)
770 if (*(m_outputFmt[i]->subtype)==subtype)
772 break;
775 return i<m_outputFmtCount ? i:-1;
778 HRESULT CBaseVideoFilter::SetMediaType(PIN_DIRECTION dir, const CMediaType* pmt)
780 if(dir == PINDIR_INPUT)
782 m_w = m_h = m_arx = m_ary = 0;
783 ExtractDim(pmt, m_w, m_h, m_arx, m_ary);
784 m_win = m_w;
785 m_hin = m_h;
786 m_arxin = m_arx;
787 m_aryin = m_ary;
788 GetOutputSize(m_w, m_h, m_arx, m_ary);
790 DWORD a = m_arx, b = m_ary;
791 while(a) {int tmp = a; a = b % tmp; b = tmp;}
792 if(b) m_arx /= b, m_ary /= b;
794 else if(dir == PINDIR_OUTPUT)
796 int wout = 0, hout = 0, arxout = 0, aryout = 0;
797 ExtractDim(pmt, wout, hout, arxout, aryout);
798 if(m_w == wout && m_h == hout && m_arx == arxout && m_ary == aryout)
800 m_wout = wout;
801 m_hout = hout;
802 m_arxout = arxout;
803 m_aryout = aryout;
807 return __super::SetMediaType(dir, pmt);
810 void CBaseVideoFilter::InitInputColorSpaces()
812 ColorSpaceId preferredOrder[MAX_COLOR_SPACE_NUM];
813 UINT count = 0;
814 GetInputColorspaces(preferredOrder, &count);
815 m_inputFmtCount = count;
816 for (UINT i=0;i<count;i++)
818 m_inputFmt[i] = InputFmts[preferredOrder[i]];
822 void CBaseVideoFilter::InitOutputColorSpaces()
824 ColorSpaceId preferredOrder[MAX_COLOR_SPACE_NUM];
825 UINT count = 0;
826 GetOutputColorspaces(preferredOrder, &count);
827 if( CombineOutputPriority(preferredOrder, &count)==S_OK )
829 m_outputFmtCount = count;
830 for (UINT i=0;i<count;i++)
832 m_outputFmt[i] = OutputFmts + preferredOrder[i];
835 else
837 m_outputFmtCount = -1;
841 void CBaseVideoFilter::GetInputColorspaces( ColorSpaceId *preferredOrder, UINT *count )
843 *count = GetInputColorSpaceNumber();
844 for (UINT i=0;i<*count;i++)
846 preferredOrder[i] = i;
850 void CBaseVideoFilter::GetOutputColorspaces( ColorSpaceId *preferredOrder, UINT *count )
852 *count = GetOutputColorSpaceNumber();
853 for (UINT i=0;i<*count;i++)
855 preferredOrder[i] = i;
859 HRESULT CBaseVideoFilter::GetUpstreamOutputPriority( int *priorities, UINT count )
861 memset(priorities, 0, count*sizeof(priorities[0]));
863 if( ! m_pInput->IsConnected() )
864 return VFW_E_ALREADY_CONNECTED;
866 int priority = count;
867 CComPtr<IEnumMediaTypes> pEnumMediaTypes = NULL;
868 HRESULT hr;
869 hr = m_pInput->GetConnected()->EnumMediaTypes( &pEnumMediaTypes );
870 if (FAILED(hr)) {
871 return hr;
873 ASSERT(pEnumMediaTypes);
875 hr = pEnumMediaTypes->Reset();
876 if (FAILED(hr)) {
877 return hr;
879 CMediaType *pMediaType = NULL;
880 ULONG ulMediaCount = 0;
882 // attempt to remember a specific error code if there is one
883 HRESULT hrFailure = S_OK;
885 for (;;) {
887 /* Retrieve the next media type NOTE each time round the loop the
888 enumerator interface will allocate another AM_MEDIA_TYPE structure
889 If we are successful then we copy it into our output object, if
890 not then we must delete the memory allocated before returning */
892 hr = pEnumMediaTypes->Next(1, (AM_MEDIA_TYPE**)&pMediaType,&ulMediaCount);
893 if (hr != S_OK) {
894 if (S_OK == hrFailure) {
895 hrFailure = VFW_E_NO_ACCEPTABLE_TYPES;
897 return hrFailure;
899 ASSERT(ulMediaCount == 1);
900 ASSERT(pMediaType);
902 ColorSpaceId pos = Subtype2OutputColorSpaceId(pMediaType->subtype, 0);
903 while(pos>=0 && pos<count)
905 priorities[pos] = priority;
906 priority--;
907 pos = Subtype2OutputColorSpaceId(pMediaType->subtype, pos+1);
910 DeleteMediaType(pMediaType);
912 return S_OK;
915 HRESULT CBaseVideoFilter::CombineOutputPriority( ColorSpaceId *preferredOrder, UINT *count )
917 if (!m_donot_follow_upstream_preferred_order)
919 int priorities1[MAX_COLOR_SPACE_NUM];
920 UINT total_count = GetOutputColorSpaceNumber();
922 if( GetUpstreamOutputPriority(priorities1, total_count) == VFW_E_ALREADY_CONNECTED )
924 *count = 0;
925 return VFW_E_ALREADY_CONNECTED;
928 for (UINT i=0;i<*count;i++)
930 int c = preferredOrder[i];
931 priorities1[c] = ((priorities1[c]+1)<<16) + c;
933 std::sort(priorities1, priorities1+total_count);
934 for (int i=total_count-1;i>=0;i--)
936 if( priorities1[i]>=(1<<16) )//enabled
938 preferredOrder[total_count-1-i] = (priorities1[i] & 0xffff);
940 else
942 break;
946 return S_OK;
950 // CBaseVideoInputAllocator
953 CBaseVideoInputAllocator::CBaseVideoInputAllocator(HRESULT* phr)
954 : CMemAllocator(NAME("CBaseVideoInputAllocator"), NULL, phr)
956 if(phr) *phr = S_OK;
959 void CBaseVideoInputAllocator::SetMediaType(const CMediaType& mt)
961 m_mt = mt;
964 STDMETHODIMP CBaseVideoInputAllocator::GetBuffer(IMediaSample** ppBuffer, REFERENCE_TIME* pStartTime, REFERENCE_TIME* pEndTime, DWORD dwFlags)
966 if(!m_bCommitted)
967 return VFW_E_NOT_COMMITTED;
969 HRESULT hr = __super::GetBuffer(ppBuffer, pStartTime, pEndTime, dwFlags);
971 if(SUCCEEDED(hr) && m_mt.majortype != GUID_NULL)
973 (*ppBuffer)->SetMediaType(&m_mt);
974 m_mt.majortype = GUID_NULL;
977 return hr;
981 // CBaseVideoInputPin
984 CBaseVideoInputPin::CBaseVideoInputPin(TCHAR* pObjectName, CBaseVideoFilter* pFilter, HRESULT* phr, LPCWSTR pName)
985 : CTransformInputPin(pObjectName, pFilter, phr, pName)
986 , m_pAllocator(NULL)
990 CBaseVideoInputPin::~CBaseVideoInputPin()
992 delete m_pAllocator;
995 STDMETHODIMP CBaseVideoInputPin::GetAllocator(IMemAllocator** ppAllocator)
997 CheckPointer(ppAllocator, E_POINTER);
999 if(m_pAllocator == NULL)
1001 HRESULT hr = S_OK;
1002 m_pAllocator = new CBaseVideoInputAllocator(&hr);
1003 m_pAllocator->AddRef();
1006 (*ppAllocator = m_pAllocator)->AddRef();
1008 return S_OK;
1011 STDMETHODIMP CBaseVideoInputPin::ReceiveConnection(IPin* pConnector, const AM_MEDIA_TYPE* pmt)
1013 CAutoLock cObjectLock(m_pLock);
1015 if(m_Connected)
1017 CMediaType mt(*pmt);
1019 if(FAILED(CheckMediaType(&mt)))
1020 return VFW_E_TYPE_NOT_ACCEPTED;
1022 ALLOCATOR_PROPERTIES props, actual;
1024 CComPtr<IMemAllocator> pMemAllocator;
1025 if(FAILED(GetAllocator(&pMemAllocator))
1026 || FAILED(pMemAllocator->Decommit())
1027 || FAILED(pMemAllocator->GetProperties(&props)))
1028 return E_FAIL;
1030 BITMAPINFOHEADER bih;
1031 if(ExtractBIH(pmt, &bih) && bih.biSizeImage)
1032 props.cbBuffer = bih.biSizeImage;
1034 if(FAILED(pMemAllocator->SetProperties(&props, &actual))
1035 || FAILED(pMemAllocator->Commit())
1036 || props.cbBuffer != actual.cbBuffer)
1037 return E_FAIL;
1039 if(m_pAllocator)
1040 m_pAllocator->SetMediaType(mt);
1042 return SetMediaType(&mt) == S_OK
1043 ? S_OK
1044 : VFW_E_TYPE_NOT_ACCEPTED;
1047 return __super::ReceiveConnection(pConnector, pmt);
1051 // CBaseVideoOutputPin
1054 CBaseVideoOutputPin::CBaseVideoOutputPin(TCHAR* pObjectName, CBaseVideoFilter* pFilter, HRESULT* phr, LPCWSTR pName)
1055 : CTransformOutputPin(pObjectName, pFilter, phr, pName)
1059 HRESULT CBaseVideoOutputPin::CheckMediaType(const CMediaType* mtOut)
1061 if(IsConnected())
1063 HRESULT hr = ((CBaseVideoFilter*)m_pFilter)->CheckOutputType(*mtOut);
1064 if(FAILED(hr)) return hr;
1067 return __super::CheckMediaType(mtOut);
1070 //// EnumMediaTypes
1071 //// - pass through to our upstream filter
1072 //STDMETHODIMP CBaseVideoOutputPin::EnumMediaTypes( IEnumMediaTypes **ppEnum )
1074 // // Can only pass through if connected.
1075 // if( ! reinterpret_cast<CBaseVideoFilter*>(m_pFilter)->m_pInput->IsConnected() )
1076 // return VFW_E_NOT_CONNECTED;
1078 // return reinterpret_cast<CBaseVideoFilter*>(m_pFilter)->m_pInput->GetConnected()->EnumMediaTypes( ppEnum );
1080 //} // EnumMediaTypes