X64 transport [Part 3.2](Update VD Fix: P010/P016/NV12/NV21.)
[xy_vsfilter.git] / src / filters / transform / basevideofilter / BaseVideoFilter.cpp
blob49d9258000f08ad9e40767e0cb60f896fc7cb225
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 #include <initguid.h>
29 #include "..\..\..\..\include\moreuuids.h"
30 #include <algorithm>
32 const GUID* InputFmts[] =
34 &MEDIASUBTYPE_P010,
35 &MEDIASUBTYPE_P016,
36 &MEDIASUBTYPE_NV12,
37 &MEDIASUBTYPE_NV21,
38 &MEDIASUBTYPE_YV12,
39 &MEDIASUBTYPE_I420,
40 &MEDIASUBTYPE_IYUV,
41 &MEDIASUBTYPE_YUY2,
42 &MEDIASUBTYPE_ARGB32,
43 &MEDIASUBTYPE_RGB32,
44 &MEDIASUBTYPE_RGB24,
45 &MEDIASUBTYPE_RGB565,
46 //&MEDIASUBTYPE_RGB555
49 const OutputFormatBase OutputFmts[] =
51 {&MEDIASUBTYPE_P010, 2, 24, '010P'},
52 {&MEDIASUBTYPE_P016, 2, 24, '610P'},
53 {&MEDIASUBTYPE_NV12, 2, 12, '21VN'},
54 {&MEDIASUBTYPE_NV21, 2, 12, '12VN'},
55 {&MEDIASUBTYPE_YV12, 3, 12, '21VY'},
56 {&MEDIASUBTYPE_I420, 3, 12, '024I'},
57 {&MEDIASUBTYPE_IYUV, 3, 12, 'VUYI'},
58 {&MEDIASUBTYPE_YUY2, 1, 16, '2YUY'},
59 {&MEDIASUBTYPE_ARGB32, 1, 32, BI_RGB},
60 {&MEDIASUBTYPE_RGB32, 1, 32, BI_RGB},
61 {&MEDIASUBTYPE_RGB24, 1, 24, BI_RGB},
62 {&MEDIASUBTYPE_RGB565, 1, 16, BI_RGB},
63 //{&MEDIASUBTYPE_RGB555, 1, 16, BI_RGB},
64 {&MEDIASUBTYPE_ARGB32, 1, 32, BI_BITFIELDS},
65 {&MEDIASUBTYPE_RGB32, 1, 32, BI_BITFIELDS},
66 {&MEDIASUBTYPE_RGB24, 1, 24, BI_BITFIELDS},
67 {&MEDIASUBTYPE_RGB565, 1, 16, BI_BITFIELDS},
68 //{&MEDIASUBTYPE_RGB555, 1, 16, BI_BITFIELDS},
71 //fixme: use the same function for by input and output
72 CString OutputFmt2String(const OutputFormatBase& fmt)
74 CString ret = CString(GuidNames[*fmt.subtype]);
75 if(!ret.Left(13).CompareNoCase(_T("MEDIASUBTYPE_"))) ret = ret.Mid(13);
76 if(fmt.biCompression == 3) ret += _T(" BITF");
77 if(*fmt.subtype == MEDIASUBTYPE_I420) ret = _T("I420"); // FIXME
78 else if(*fmt.subtype == MEDIASUBTYPE_NV21) ret = _T("NV21"); // FIXME
79 return(ret);
82 CString GetColorSpaceName(ColorSpaceId colorSpace, ColorSpaceDir inputOrOutput)
84 if(inputOrOutput==INPUT_COLOR_SPACE)
85 return Subtype2String(*InputFmts[colorSpace]);
86 else
87 return OutputFmt2String(OutputFmts[colorSpace]);
90 UINT GetOutputColorSpaceNumber()
92 return countof(OutputFmts);
95 UINT GetInputColorSpaceNumber()
97 return countof(InputFmts);
100 ColorSpaceId Subtype2OutputColorSpaceId( const GUID& subtype, ColorSpaceId startId /*=0 */ )
102 ColorSpaceId i=startId;
103 UINT num = GetOutputColorSpaceNumber();
104 for(i=startId;i<num;i++)
106 if (*(OutputFmts[i].subtype)==subtype)
108 break;
111 return i<num ? i:-1;
115 // CBaseVideoFilter
118 CBaseVideoFilter::CBaseVideoFilter(TCHAR* pName, LPUNKNOWN lpunk, HRESULT* phr, REFCLSID clsid, long cBuffers)
119 : CTransformFilter(pName, lpunk, clsid)
120 , m_cBuffers(cBuffers)
121 , m_inputFmtCount(-1),m_outputFmtCount(-1)
122 , m_donot_follow_upstream_preferred_order(false)
124 if(phr) *phr = S_OK;
125 if(!(m_pInput = new CBaseVideoInputPin(NAME("CBaseVideoInputPin"), this, phr, L"Video"))) *phr = E_OUTOFMEMORY;
126 if(FAILED(*phr)) return;
128 if(!(m_pOutput = new CBaseVideoOutputPin(NAME("CBaseVideoOutputPin"), this, phr, L"Output"))) *phr = E_OUTOFMEMORY;
129 if(FAILED(*phr)) {delete m_pInput, m_pInput = NULL; return;}
131 m_wout = m_win = m_w = 0;
132 m_hout = m_hin = m_h = 0;
133 m_arxout = m_arxin = m_arx = 0;
134 m_aryout = m_aryin = m_ary = 0;
137 CBaseVideoFilter::~CBaseVideoFilter()
141 int CBaseVideoFilter::GetPinCount()
143 return 2;
146 CBasePin* CBaseVideoFilter::GetPin(int n)
148 switch(n)
150 case 0: return m_pInput;
151 case 1: return m_pOutput;
153 return NULL;
156 HRESULT CBaseVideoFilter::Receive(IMediaSample* pIn)
158 #ifndef _WIN64
159 // TODOX64 : fixme!
160 _mm_empty(); // just for safety
161 #endif
163 CAutoLock cAutoLock(&m_csReceive);
165 HRESULT hr;
167 AM_SAMPLE2_PROPERTIES* const pProps = m_pInput->SampleProps();
168 if(pProps->dwStreamId != AM_STREAM_MEDIA)
169 return m_pOutput->Deliver(pIn);
171 AM_MEDIA_TYPE* pmt;
172 if(SUCCEEDED(pIn->GetMediaType(&pmt)) && pmt)
174 CMediaType mt(*pmt);
175 m_pInput->SetMediaType(&mt);
176 DeleteMediaType(pmt);
179 if(FAILED(hr = Transform(pIn)))
180 return hr;
182 return S_OK;
185 HRESULT CBaseVideoFilter::GetDeliveryBuffer(int w, int h, IMediaSample** ppOut)
187 CheckPointer(ppOut, E_POINTER);
189 HRESULT hr;
191 if(FAILED(hr = ReconnectOutput(w, h)))
192 return hr;
194 if(FAILED(hr = m_pOutput->GetDeliveryBuffer(ppOut, NULL, NULL, 0)))
195 return hr;
197 AM_MEDIA_TYPE* pmt;
198 if(SUCCEEDED((*ppOut)->GetMediaType(&pmt)) && pmt)
200 CMediaType mt = *pmt;
201 m_pOutput->SetMediaType(&mt);
202 DeleteMediaType(pmt);
205 (*ppOut)->SetDiscontinuity(FALSE);
206 (*ppOut)->SetSyncPoint(TRUE);
208 // FIXME: hell knows why but without this the overlay mixer starts very skippy
209 // (don't enable this for other renderers, the old for example will go crazy if you do)
210 if(GetCLSID(m_pOutput->GetConnected()) == CLSID_OverlayMixer)
211 (*ppOut)->SetDiscontinuity(TRUE);
213 return S_OK;
216 HRESULT CBaseVideoFilter::ReconnectOutput(int w, int h)
218 CMediaType& mt = m_pOutput->CurrentMediaType();
220 int w_org = m_w;
221 int h_org = m_h;
223 bool fForceReconnection = false;
224 if(w != m_w || h != m_h)
226 fForceReconnection = true;
227 m_w = w;
228 m_h = h;
231 HRESULT hr = S_OK;
233 if(fForceReconnection || m_w != m_wout || m_h != m_hout || m_arx != m_arxout || m_ary != m_aryout)
235 if(GetCLSID(m_pOutput->GetConnected()) == CLSID_VideoRenderer)
237 NotifyEvent(EC_ERRORABORT, 0, 0);
238 return E_FAIL;
241 BITMAPINFOHEADER* bmi = NULL;
243 if(mt.formattype == FORMAT_VideoInfo)
245 VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)mt.Format();
246 SetRect(&vih->rcSource, 0, 0, m_w, m_h);
247 SetRect(&vih->rcTarget, 0, 0, m_w, m_h);
248 bmi = &vih->bmiHeader;
249 bmi->biXPelsPerMeter = m_w * m_ary;
250 bmi->biYPelsPerMeter = m_h * m_arx;
252 else if(mt.formattype == FORMAT_VideoInfo2)
254 VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)mt.Format();
255 SetRect(&vih->rcSource, 0, 0, m_w, m_h);
256 SetRect(&vih->rcTarget, 0, 0, m_w, m_h);
257 bmi = &vih->bmiHeader;
258 vih->dwPictAspectRatioX = m_arx;
259 vih->dwPictAspectRatioY = m_ary;
262 bmi->biWidth = m_w;
263 bmi->biHeight = m_h;
264 bmi->biSizeImage = m_w*m_h*bmi->biBitCount>>3;
266 hr = m_pOutput->GetConnected()->QueryAccept(&mt);
267 ASSERT(SUCCEEDED(hr)); // should better not fail, after all "mt" is the current media type, just with a different resolution
268 HRESULT hr1 = 0, hr2 = 0;
269 CComPtr<IMediaSample> pOut;
270 if(SUCCEEDED(hr1 = m_pOutput->GetConnected()->ReceiveConnection(m_pOutput, &mt))
271 && SUCCEEDED(hr2 = m_pOutput->GetDeliveryBuffer(&pOut, NULL, NULL, 0)))
273 AM_MEDIA_TYPE* pmt;
274 if(SUCCEEDED(pOut->GetMediaType(&pmt)) && pmt)
276 CMediaType mt = *pmt;
277 m_pOutput->SetMediaType(&mt);
278 DeleteMediaType(pmt);
280 else // stupid overlay mixer won't let us know the new pitch...
282 long size = pOut->GetSize();
283 bmi->biWidth = size / bmi->biHeight * 8 / bmi->biBitCount;
286 else
288 m_w = w_org;
289 m_h = h_org;
290 return E_FAIL;
293 m_wout = m_w;
294 m_hout = m_h;
295 m_arxout = m_arx;
296 m_aryout = m_ary;
298 // some renderers don't send this
299 NotifyEvent(EC_VIDEO_SIZE_CHANGED, MAKELPARAM(m_w, m_h), 0);
301 return S_OK;
304 return S_FALSE;
307 HRESULT CBaseVideoFilter::CopyBuffer(BYTE* pOut, BYTE* pIn, int w, int h, int pitchIn, const GUID& subtype, bool fInterlaced)
309 int abs_h = abs(h);
310 BYTE* pInYUV[3] = {pIn, pIn + pitchIn*abs_h, pIn + pitchIn*abs_h + (pitchIn>>1)*(abs_h>>1)};
311 return CopyBuffer(pOut, pInYUV, w, h, pitchIn, subtype, fInterlaced);
314 HRESULT CBaseVideoFilter::CopyBuffer(BYTE* pOut, BYTE** ppIn, int w, int h, int pitchIn, const GUID& subtype, bool fInterlaced)
316 BITMAPINFOHEADER bihOut;
317 ExtractBIH(&m_pOutput->CurrentMediaType(), &bihOut);
319 int pitchOut = 0;
321 if(bihOut.biCompression == BI_RGB || bihOut.biCompression == BI_BITFIELDS)
323 pitchOut = bihOut.biWidth*bihOut.biBitCount>>3;
325 if(bihOut.biHeight > 0)
327 pOut += pitchOut*(h-1);
328 pitchOut = -pitchOut;
329 if(h < 0) h = -h;
333 if(h < 0)
335 h = -h;
336 ppIn[0] += pitchIn*(h-1);
338 if(subtype == MEDIASUBTYPE_I420 || subtype == MEDIASUBTYPE_IYUV || subtype == MEDIASUBTYPE_YV12)
340 ppIn[1] += (pitchIn>>1)*((h>>1)-1);
341 ppIn[2] += (pitchIn>>1)*((h>>1)-1);
343 else if(subtype == MEDIASUBTYPE_P010 || subtype == MEDIASUBTYPE_P016
344 || subtype == MEDIASUBTYPE_NV12 || subtype == MEDIASUBTYPE_NV21)
346 ppIn[1] += pitchIn*((h>>1)-1);
348 pitchIn = -pitchIn;
351 if(subtype == MEDIASUBTYPE_I420 || subtype == MEDIASUBTYPE_IYUV || subtype == MEDIASUBTYPE_YV12)
353 BYTE* pIn = ppIn[0];
354 BYTE* pInU = ppIn[1];
355 BYTE* pInV = ppIn[2];
357 if(subtype == MEDIASUBTYPE_YV12) {BYTE* tmp = pInU; pInU = pInV; pInV = tmp;}
359 BYTE* pOutU = pOut + bihOut.biWidth*h;
360 BYTE* pOutV = pOut + bihOut.biWidth*h*5/4;
362 if(bihOut.biCompression == '21VY') {BYTE* tmp = pOutU; pOutU = pOutV; pOutV = tmp;}
364 ASSERT(w <= abs(pitchIn));
366 if(bihOut.biCompression == '2YUY')
368 if (!fInterlaced) {
369 BitBltFromI420ToYUY2(w, h, pOut, bihOut.biWidth*2, pIn, pInU, pInV, pitchIn);
370 } else {
371 BitBltFromI420ToYUY2Interlaced(w, h, pOut, bihOut.biWidth*2, pIn, pInU, pInV, pitchIn);
374 else if(bihOut.biCompression == '024I' || bihOut.biCompression == 'VUYI' || bihOut.biCompression == '21VY')
376 BitBltFromI420ToI420(w, h, pOut, pOutU, pOutV, bihOut.biWidth, pIn, pInU, pInV, pitchIn);
378 else if(bihOut.biCompression == BI_RGB || bihOut.biCompression == BI_BITFIELDS)
380 if(!BitBltFromI420ToRGB(w, h, pOut, pitchOut, bihOut.biBitCount, pIn, pInU, pInV, pitchIn))
382 for(DWORD y = 0; y < h; y++, pOut += pitchOut)
383 memset(pOut, 0, pitchOut);
387 else if(subtype == MEDIASUBTYPE_P010 || subtype == MEDIASUBTYPE_P016)
389 if (bihOut.biCompression != subtype.Data1)
390 return VFW_E_TYPE_NOT_ACCEPTED;
391 BitBltFromP010ToP010(w, h, pOut, bihOut.biWidth*2, ppIn[0], pitchIn);
393 else if(subtype == MEDIASUBTYPE_NV12 || subtype == MEDIASUBTYPE_NV21)
395 if (bihOut.biCompression != subtype.Data1)
396 return VFW_E_TYPE_NOT_ACCEPTED;
397 BitBltFromNV12ToNV12(w, h, pOut, bihOut.biWidth, ppIn[0], pitchIn);
399 else if(subtype == MEDIASUBTYPE_YUY2)
401 if(bihOut.biCompression == '2YUY')
403 BitBltFromYUY2ToYUY2(w, h, pOut, bihOut.biWidth*2, ppIn[0], pitchIn);
405 else if(bihOut.biCompression == BI_RGB || bihOut.biCompression == BI_BITFIELDS)
407 if(!BitBltFromYUY2ToRGB(w, h, pOut, pitchOut, bihOut.biBitCount, ppIn[0], pitchIn))
409 for(DWORD y = 0; y < h; y++, pOut += pitchOut)
410 memset(pOut, 0, pitchOut);
414 else if(subtype == MEDIASUBTYPE_ARGB32 || subtype == MEDIASUBTYPE_RGB32 || subtype == MEDIASUBTYPE_RGB24 || subtype == MEDIASUBTYPE_RGB565)
416 int sbpp =
417 subtype == MEDIASUBTYPE_ARGB32 || subtype == MEDIASUBTYPE_RGB32 ? 32 :
418 subtype == MEDIASUBTYPE_RGB24 ? 24 :
419 subtype == MEDIASUBTYPE_RGB565 ? 16 : 0;
421 if(bihOut.biCompression == '2YUY')
423 // TODO
424 // BitBltFromRGBToYUY2();
426 else if(bihOut.biCompression == BI_RGB || bihOut.biCompression == BI_BITFIELDS)
428 if(!BitBltFromRGBToRGB(w, h, pOut, pitchOut, bihOut.biBitCount, ppIn[0], pitchIn, sbpp))
430 for(DWORD y = 0; y < h; y++, pOut += pitchOut)
431 memset(pOut, 0, pitchOut);
435 else
437 return VFW_E_TYPE_NOT_ACCEPTED;
440 return S_OK;
443 HRESULT CBaseVideoFilter::CheckInputType(const CMediaType* mtIn)
445 BITMAPINFOHEADER bih;
446 ExtractBIH(mtIn, &bih);
448 return mtIn->majortype == MEDIATYPE_Video
449 && GetInputSubtypePosition(mtIn->subtype)!=-1
450 && (mtIn->formattype == FORMAT_VideoInfo || mtIn->formattype == FORMAT_VideoInfo2)
451 && bih.biHeight > 0
452 ? S_OK
453 : VFW_E_TYPE_NOT_ACCEPTED;
456 HRESULT CBaseVideoFilter::DoCheckTransform( const CMediaType* mtIn, const CMediaType* mtOut, bool checkReconnection )
458 DbgLog((LOG_TRACE, 3, __FUNCTIONW__));
459 //DumpGraph(m_pGraph, 0);
460 if( FAILED(CheckInputType(mtIn)) || mtOut->majortype != MEDIATYPE_Video ||
461 GetOutputSubtypePosition(mtOut->subtype)==-1 )
462 return VFW_E_TYPE_NOT_ACCEPTED;
464 if( !checkReconnection &&
465 mtOut->subtype != mtIn->subtype )
467 bool can_reconnect = false;
468 CMediaType desiredMt;
469 int position = 0;
470 HRESULT hr;
472 position = GetOutputSubtypePosition(mtOut->subtype);
473 if(position>=0)
475 hr = GetMediaType(position, &desiredMt);
476 if (hr!=S_OK)
478 DbgLog((LOG_ERROR, 3, TEXT("Unexpected error when GetMediaType, position:%d"), position));
480 else
482 hr = DoCheckTransform(&desiredMt, mtOut, true);
483 if (hr!=S_OK)
485 DbgLog((LOG_TRACE, 3, TEXT("Transform not accept:")));
486 DisplayType(0,&desiredMt);
487 DisplayType(0,mtOut);
489 else
491 hr = m_pInput->GetConnected()->QueryAccept(&desiredMt);
492 if(hr!=S_OK)
494 DbgLog((LOG_TRACE, 3, TEXT("Upstream not accept:")));
495 DisplayType(0, &desiredMt);
497 else
499 can_reconnect = true;
505 if ( can_reconnect )
507 DbgLog((LOG_TRACE, 3, TEXT("agree input media type:")));
508 DisplayType(0, &desiredMt);
509 return S_OK;
513 bool can_transform = true;
514 if ( mtIn->subtype == MEDIASUBTYPE_P010
515 || mtIn->subtype == MEDIASUBTYPE_P016
516 || mtIn->subtype == MEDIASUBTYPE_NV12
517 || mtIn->subtype == MEDIASUBTYPE_NV21 )
519 if( mtOut->subtype!=mtIn->subtype )
520 can_transform = false;
522 else if( mtIn->subtype == MEDIASUBTYPE_YV12
523 || mtIn->subtype == MEDIASUBTYPE_I420
524 || mtIn->subtype == MEDIASUBTYPE_IYUV )
526 if( mtOut->subtype != MEDIASUBTYPE_YV12
527 && mtOut->subtype != MEDIASUBTYPE_I420
528 && mtOut->subtype != MEDIASUBTYPE_IYUV
529 && mtOut->subtype != MEDIASUBTYPE_YUY2
530 && mtOut->subtype != MEDIASUBTYPE_ARGB32
531 && mtOut->subtype != MEDIASUBTYPE_RGB32
532 && mtOut->subtype != MEDIASUBTYPE_RGB24
533 && mtOut->subtype != MEDIASUBTYPE_RGB565)
534 can_transform = false;
536 else if( mtIn->subtype == MEDIASUBTYPE_YUY2 )
538 if( mtOut->subtype != MEDIASUBTYPE_YUY2
539 && mtOut->subtype != MEDIASUBTYPE_ARGB32
540 && mtOut->subtype != MEDIASUBTYPE_RGB32
541 && mtOut->subtype != MEDIASUBTYPE_RGB24
542 && mtOut->subtype != MEDIASUBTYPE_RGB565)
543 can_transform = false;
545 else if( mtIn->subtype == MEDIASUBTYPE_ARGB32
546 || mtIn->subtype == MEDIASUBTYPE_RGB32
547 || mtIn->subtype == MEDIASUBTYPE_RGB24
548 || mtIn->subtype == MEDIASUBTYPE_RGB565 )
550 if(mtOut->subtype != MEDIASUBTYPE_ARGB32
551 && mtOut->subtype != MEDIASUBTYPE_RGB32
552 && mtOut->subtype != MEDIASUBTYPE_RGB24
553 && mtOut->subtype != MEDIASUBTYPE_RGB565)
554 can_transform = false;
557 if (!can_transform && !checkReconnection)
559 bool can_reconnect = false;
560 CMediaType desiredMt;
561 int position = 0;
562 HRESULT hr;
565 hr = GetMediaType(position, &desiredMt);
566 ++position;
567 if( hr!=S_OK )
568 break;
569 DbgLog((LOG_TRACE, 3, TEXT("Checking reconnect with media type:")));
570 DisplayType(0, &desiredMt);
571 if( DoCheckTransform(&desiredMt, mtOut, true)!=S_OK ||
572 m_pInput->GetConnected()->QueryAccept(&desiredMt)!=S_OK )
574 continue;
576 else
578 can_reconnect = true;
579 break;
581 } while ( true );
582 if ( can_reconnect )
584 DbgLog((LOG_TRACE, 3, TEXT("agree input media type:")));
585 DisplayType(0, &desiredMt);
586 return S_OK;
589 else if(can_transform)
591 return S_OK;
593 return VFW_E_TYPE_NOT_ACCEPTED;
596 HRESULT CBaseVideoFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut)
598 return DoCheckTransform(mtIn, mtOut, false);
601 HRESULT CBaseVideoFilter::CheckOutputType(const CMediaType& mtOut)
603 int wout = 0, hout = 0, arxout = 0, aryout = 0;
604 return ExtractDim(&mtOut, wout, hout, arxout, aryout)
605 && m_h == abs((int)hout)
606 && mtOut.subtype != MEDIASUBTYPE_ARGB32
607 && GetOutputSubtypePosition(mtOut.subtype)!=-1
608 ? S_OK
609 : VFW_E_TYPE_NOT_ACCEPTED;
612 HRESULT CBaseVideoFilter::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties)
614 if(m_pInput->IsConnected() == FALSE) return E_UNEXPECTED;
616 BITMAPINFOHEADER bih;
617 ExtractBIH(&m_pOutput->CurrentMediaType(), &bih);
619 long cBuffers = m_pOutput->CurrentMediaType().formattype == FORMAT_VideoInfo ? 1 : m_cBuffers;
621 pProperties->cBuffers = m_cBuffers;
622 pProperties->cbBuffer = bih.biSizeImage;
623 pProperties->cbAlign = 1;
624 pProperties->cbPrefix = 0;
626 HRESULT hr;
627 ALLOCATOR_PROPERTIES Actual;
628 if(FAILED(hr = pAllocator->SetProperties(pProperties, &Actual)))
629 return hr;
631 return pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer
632 ? E_FAIL
633 : NOERROR;
636 HRESULT CBaseVideoFilter::GetMediaType(int iPosition, CMediaType* pmt)
638 if(m_outputFmtCount <0)
640 InitOutputColorSpaces();
642 if(m_pInput->IsConnected() == FALSE) return E_UNEXPECTED;
644 // this will make sure we won't connect to the old renderer in dvd mode
645 // that renderer can't switch the format dynamically
647 bool fFoundDVDNavigator = false;
648 CComPtr<IBaseFilter> pBF = this;
649 CComPtr<IPin> pPin = m_pInput;
650 for(; !fFoundDVDNavigator && (pBF = GetUpStreamFilter(pBF, pPin)); pPin = GetFirstPin(pBF))
651 fFoundDVDNavigator = GetCLSID(pBF) == CLSID_DVDNavigator;
653 if(fFoundDVDNavigator || m_pInput->CurrentMediaType().formattype == FORMAT_VideoInfo2)
654 iPosition = iPosition*2;
658 if(iPosition < 0) return E_INVALIDARG;
659 if(iPosition >= 2*m_outputFmtCount) return VFW_S_NO_MORE_ITEMS;
661 pmt->majortype = MEDIATYPE_Video;
662 pmt->subtype = *m_outputFmt[iPosition/2]->subtype;
664 int w = m_win, h = m_hin, arx = m_arxin, ary = m_aryin;
665 GetOutputSize(w, h, arx, ary);
667 BITMAPINFOHEADER bihOut;
668 memset(&bihOut, 0, sizeof(bihOut));
669 bihOut.biSize = sizeof(bihOut);
670 bihOut.biWidth = w;
671 bihOut.biHeight = h;
672 bihOut.biPlanes = m_outputFmt[iPosition/2]->biPlanes;
673 bihOut.biBitCount = m_outputFmt[iPosition/2]->biBitCount;
674 bihOut.biCompression = m_outputFmt[iPosition/2]->biCompression;
675 bihOut.biSizeImage = w*h*bihOut.biBitCount>>3;
677 if(iPosition&1)
679 pmt->formattype = FORMAT_VideoInfo;
680 VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)pmt->AllocFormatBuffer(sizeof(VIDEOINFOHEADER));
681 memset(vih, 0, sizeof(VIDEOINFOHEADER));
682 vih->bmiHeader = bihOut;
683 vih->bmiHeader.biXPelsPerMeter = vih->bmiHeader.biWidth * ary;
684 vih->bmiHeader.biYPelsPerMeter = vih->bmiHeader.biHeight * arx;
686 else
688 pmt->formattype = FORMAT_VideoInfo2;
689 VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)pmt->AllocFormatBuffer(sizeof(VIDEOINFOHEADER2));
690 memset(vih, 0, sizeof(VIDEOINFOHEADER2));
691 vih->bmiHeader = bihOut;
692 vih->dwPictAspectRatioX = arx;
693 vih->dwPictAspectRatioY = ary;
694 if(IsVideoInterlaced()) vih->dwInterlaceFlags = AMINTERLACE_IsInterlaced;
697 CMediaType& mt = m_pInput->CurrentMediaType();
699 // these fields have the same field offset in all four structs
700 ((VIDEOINFOHEADER*)pmt->Format())->AvgTimePerFrame = ((VIDEOINFOHEADER*)mt.Format())->AvgTimePerFrame;
701 ((VIDEOINFOHEADER*)pmt->Format())->dwBitRate = ((VIDEOINFOHEADER*)mt.Format())->dwBitRate;
702 ((VIDEOINFOHEADER*)pmt->Format())->dwBitErrorRate = ((VIDEOINFOHEADER*)mt.Format())->dwBitErrorRate;
704 CorrectMediaType(pmt);
706 return S_OK;
709 int CBaseVideoFilter::GetInputSubtypePosition( const GUID& subtype )
711 if(m_inputFmtCount<0)
713 InitInputColorSpaces();
716 int i=0;
717 for (i=0;i<m_inputFmtCount;i++)
719 if (*m_inputFmt[i]==subtype)
721 break;
724 return i<m_inputFmtCount ? i : -1;
727 int CBaseVideoFilter::GetOutputSubtypePosition( const GUID& subtype, int startPos /*=0*/ )
729 if(m_outputFmtCount <0)
731 InitOutputColorSpaces();
733 int i=startPos;
734 for(i=startPos;i<m_outputFmtCount;i++)
736 if (*(m_outputFmt[i]->subtype)==subtype)
738 break;
741 return i<m_outputFmtCount ? i:-1;
744 HRESULT CBaseVideoFilter::SetMediaType(PIN_DIRECTION dir, const CMediaType* pmt)
746 if(dir == PINDIR_INPUT)
748 m_w = m_h = m_arx = m_ary = 0;
749 ExtractDim(pmt, m_w, m_h, m_arx, m_ary);
750 m_win = m_w;
751 m_hin = m_h;
752 m_arxin = m_arx;
753 m_aryin = m_ary;
754 GetOutputSize(m_w, m_h, m_arx, m_ary);
756 DWORD a = m_arx, b = m_ary;
757 while(a) {int tmp = a; a = b % tmp; b = tmp;}
758 if(b) m_arx /= b, m_ary /= b;
760 else if(dir == PINDIR_OUTPUT)
762 int wout = 0, hout = 0, arxout = 0, aryout = 0;
763 ExtractDim(pmt, wout, hout, arxout, aryout);
764 if(m_w == wout && m_h == hout && m_arx == arxout && m_ary == aryout)
766 m_wout = wout;
767 m_hout = hout;
768 m_arxout = arxout;
769 m_aryout = aryout;
773 return __super::SetMediaType(dir, pmt);
776 void CBaseVideoFilter::InitInputColorSpaces()
778 ColorSpaceId preferredOrder[MAX_COLOR_SPACE_NUM];
779 UINT count = 0;
780 GetInputColorspaces(preferredOrder, &count);
781 m_inputFmtCount = count;
782 for (int i=0;i<count;i++)
784 m_inputFmt[i] = InputFmts[preferredOrder[i]];
788 void CBaseVideoFilter::InitOutputColorSpaces()
790 ColorSpaceId preferredOrder[MAX_COLOR_SPACE_NUM];
791 UINT count = 0;
792 GetOutputColorspaces(preferredOrder, &count);
793 if( CombineOutputPriority(preferredOrder, &count)==S_OK )
795 m_outputFmtCount = count;
796 for (int i=0;i<count;i++)
798 m_outputFmt[i] = OutputFmts + preferredOrder[i];
801 else
803 m_outputFmtCount = -1;
807 void CBaseVideoFilter::GetInputColorspaces( ColorSpaceId *preferredOrder, UINT *count )
809 *count = GetInputColorSpaceNumber();
810 for (int i=0;i<*count;i++)
812 preferredOrder[i] = i;
816 void CBaseVideoFilter::GetOutputColorspaces( ColorSpaceId *preferredOrder, UINT *count )
818 *count = GetOutputColorSpaceNumber();
819 for (int i=0;i<*count;i++)
821 preferredOrder[i] = i;
825 HRESULT CBaseVideoFilter::GetUpstreamOutputPriority( int *priorities, UINT count )
827 memset(priorities, 0, count*sizeof(priorities[0]));
829 if( ! m_pInput->IsConnected() )
830 return VFW_E_ALREADY_CONNECTED;
832 int priority = count;
833 CComPtr<IEnumMediaTypes> pEnumMediaTypes = NULL;
834 HRESULT hr;
835 hr = m_pInput->GetConnected()->EnumMediaTypes( &pEnumMediaTypes );
836 if (FAILED(hr)) {
837 return hr;
839 ASSERT(pEnumMediaTypes);
841 hr = pEnumMediaTypes->Reset();
842 if (FAILED(hr)) {
843 return hr;
845 CMediaType *pMediaType = NULL;
846 ULONG ulMediaCount = 0;
848 // attempt to remember a specific error code if there is one
849 HRESULT hrFailure = S_OK;
851 for (;;) {
853 /* Retrieve the next media type NOTE each time round the loop the
854 enumerator interface will allocate another AM_MEDIA_TYPE structure
855 If we are successful then we copy it into our output object, if
856 not then we must delete the memory allocated before returning */
858 hr = pEnumMediaTypes->Next(1, (AM_MEDIA_TYPE**)&pMediaType,&ulMediaCount);
859 if (hr != S_OK) {
860 if (S_OK == hrFailure) {
861 hrFailure = VFW_E_NO_ACCEPTABLE_TYPES;
863 return hrFailure;
865 ASSERT(ulMediaCount == 1);
866 ASSERT(pMediaType);
868 ColorSpaceId pos = Subtype2OutputColorSpaceId(pMediaType->subtype, 0);
869 while(pos>=0 && pos<count)
871 priorities[pos] = priority;
872 priority--;
873 pos = Subtype2OutputColorSpaceId(pMediaType->subtype, pos+1);
876 DeleteMediaType(pMediaType);
878 return S_OK;
881 HRESULT CBaseVideoFilter::CombineOutputPriority( ColorSpaceId *preferredOrder, UINT *count )
883 if (!m_donot_follow_upstream_preferred_order)
885 int priorities1[MAX_COLOR_SPACE_NUM];
886 UINT total_count = GetOutputColorSpaceNumber();
888 if( GetUpstreamOutputPriority(priorities1, total_count) == VFW_E_ALREADY_CONNECTED )
890 *count = 0;
891 return VFW_E_ALREADY_CONNECTED;
894 for (int i=0;i<*count;i++)
896 int c = preferredOrder[i];
897 priorities1[c] = ((priorities1[c]+1)<<16) + c;
899 std::sort(priorities1, priorities1+total_count);
900 for (int i=total_count-1;i>=0;i--)
902 if( priorities1[i]>=(1<<16) )//enabled
904 preferredOrder[total_count-1-i] = (priorities1[i] & 0xffff);
906 else
908 break;
912 return S_OK;
916 // CBaseVideoInputAllocator
919 CBaseVideoInputAllocator::CBaseVideoInputAllocator(HRESULT* phr)
920 : CMemAllocator(NAME("CBaseVideoInputAllocator"), NULL, phr)
922 if(phr) *phr = S_OK;
925 void CBaseVideoInputAllocator::SetMediaType(const CMediaType& mt)
927 m_mt = mt;
930 STDMETHODIMP CBaseVideoInputAllocator::GetBuffer(IMediaSample** ppBuffer, REFERENCE_TIME* pStartTime, REFERENCE_TIME* pEndTime, DWORD dwFlags)
932 if(!m_bCommitted)
933 return VFW_E_NOT_COMMITTED;
935 HRESULT hr = __super::GetBuffer(ppBuffer, pStartTime, pEndTime, dwFlags);
937 if(SUCCEEDED(hr) && m_mt.majortype != GUID_NULL)
939 (*ppBuffer)->SetMediaType(&m_mt);
940 m_mt.majortype = GUID_NULL;
943 return hr;
947 // CBaseVideoInputPin
950 CBaseVideoInputPin::CBaseVideoInputPin(TCHAR* pObjectName, CBaseVideoFilter* pFilter, HRESULT* phr, LPCWSTR pName)
951 : CTransformInputPin(pObjectName, pFilter, phr, pName)
952 , m_pAllocator(NULL)
956 CBaseVideoInputPin::~CBaseVideoInputPin()
958 delete m_pAllocator;
961 STDMETHODIMP CBaseVideoInputPin::GetAllocator(IMemAllocator** ppAllocator)
963 CheckPointer(ppAllocator, E_POINTER);
965 if(m_pAllocator == NULL)
967 HRESULT hr = S_OK;
968 m_pAllocator = new CBaseVideoInputAllocator(&hr);
969 m_pAllocator->AddRef();
972 (*ppAllocator = m_pAllocator)->AddRef();
974 return S_OK;
977 STDMETHODIMP CBaseVideoInputPin::ReceiveConnection(IPin* pConnector, const AM_MEDIA_TYPE* pmt)
979 CAutoLock cObjectLock(m_pLock);
981 if(m_Connected)
983 CMediaType mt(*pmt);
985 if(FAILED(CheckMediaType(&mt)))
986 return VFW_E_TYPE_NOT_ACCEPTED;
988 ALLOCATOR_PROPERTIES props, actual;
990 CComPtr<IMemAllocator> pMemAllocator;
991 if(FAILED(GetAllocator(&pMemAllocator))
992 || FAILED(pMemAllocator->Decommit())
993 || FAILED(pMemAllocator->GetProperties(&props)))
994 return E_FAIL;
996 BITMAPINFOHEADER bih;
997 if(ExtractBIH(pmt, &bih) && bih.biSizeImage)
998 props.cbBuffer = bih.biSizeImage;
1000 if(FAILED(pMemAllocator->SetProperties(&props, &actual))
1001 || FAILED(pMemAllocator->Commit())
1002 || props.cbBuffer != actual.cbBuffer)
1003 return E_FAIL;
1005 if(m_pAllocator)
1006 m_pAllocator->SetMediaType(mt);
1008 return SetMediaType(&mt) == S_OK
1009 ? S_OK
1010 : VFW_E_TYPE_NOT_ACCEPTED;
1013 return __super::ReceiveConnection(pConnector, pmt);
1017 // CBaseVideoOutputPin
1020 CBaseVideoOutputPin::CBaseVideoOutputPin(TCHAR* pObjectName, CBaseVideoFilter* pFilter, HRESULT* phr, LPCWSTR pName)
1021 : CTransformOutputPin(pObjectName, pFilter, phr, pName)
1025 HRESULT CBaseVideoOutputPin::CheckMediaType(const CMediaType* mtOut)
1027 if(IsConnected())
1029 HRESULT hr = ((CBaseVideoFilter*)m_pFilter)->CheckOutputType(*mtOut);
1030 if(FAILED(hr)) return hr;
1033 return __super::CheckMediaType(mtOut);
1036 //// EnumMediaTypes
1037 //// - pass through to our upstream filter
1038 //STDMETHODIMP CBaseVideoOutputPin::EnumMediaTypes( IEnumMediaTypes **ppEnum )
1040 // // Can only pass through if connected.
1041 // if( ! reinterpret_cast<CBaseVideoFilter*>(m_pFilter)->m_pInput->IsConnected() )
1042 // return VFW_E_NOT_CONNECTED;
1044 // return reinterpret_cast<CBaseVideoFilter*>(m_pFilter)->m_pInput->GetConnected()->EnumMediaTypes( ppEnum );
1046 //} // EnumMediaTypes