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)
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
24 #include "BaseVideoFilter.h"
25 #include "..\..\..\DSUtil\DSUtil.h"
26 #include "..\..\..\DSUtil\MediaTypes.h"
29 #include "..\..\..\..\include\moreuuids.h"
32 const GUID
* InputFmts
[] =
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
82 CString
GetColorSpaceName(ColorSpaceId colorSpace
, ColorSpaceDir inputOrOutput
)
84 if(inputOrOutput
==INPUT_COLOR_SPACE
)
85 return Subtype2String(*InputFmts
[colorSpace
]);
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
)
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)
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()
146 CBasePin
* CBaseVideoFilter::GetPin(int n
)
150 case 0: return m_pInput
;
151 case 1: return m_pOutput
;
156 HRESULT
CBaseVideoFilter::Receive(IMediaSample
* pIn
)
160 _mm_empty(); // just for safety
163 CAutoLock
cAutoLock(&m_csReceive
);
167 AM_SAMPLE2_PROPERTIES
* const pProps
= m_pInput
->SampleProps();
168 if(pProps
->dwStreamId
!= AM_STREAM_MEDIA
)
169 return m_pOutput
->Deliver(pIn
);
172 if(SUCCEEDED(pIn
->GetMediaType(&pmt
)) && pmt
)
175 m_pInput
->SetMediaType(&mt
);
176 DeleteMediaType(pmt
);
179 if(FAILED(hr
= Transform(pIn
)))
185 HRESULT
CBaseVideoFilter::GetDeliveryBuffer(int w
, int h
, IMediaSample
** ppOut
)
187 CheckPointer(ppOut
, E_POINTER
);
191 if(FAILED(hr
= ReconnectOutput(w
, h
)))
194 if(FAILED(hr
= m_pOutput
->GetDeliveryBuffer(ppOut
, NULL
, NULL
, 0)))
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
);
216 HRESULT
CBaseVideoFilter::ReconnectOutput(int w
, int h
)
218 CMediaType
& mt
= m_pOutput
->CurrentMediaType();
223 bool fForceReconnection
= false;
224 if(w
!= m_w
|| h
!= m_h
)
226 fForceReconnection
= true;
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);
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
;
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)))
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
;
298 // some renderers don't send this
299 NotifyEvent(EC_VIDEO_SIZE_CHANGED
, MAKELPARAM(m_w
, m_h
), 0);
307 HRESULT
CBaseVideoFilter::CopyBuffer(BYTE
* pOut
, BYTE
* pIn
, int w
, int h
, int pitchIn
, const GUID
& subtype
, bool fInterlaced
)
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
);
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
;
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);
351 if(subtype
== MEDIASUBTYPE_I420
|| subtype
== MEDIASUBTYPE_IYUV
|| subtype
== MEDIASUBTYPE_YV12
)
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')
369 BitBltFromI420ToYUY2(w
, h
, pOut
, bihOut
.biWidth
*2, pIn
, pInU
, pInV
, pitchIn
);
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
)
417 subtype
== MEDIASUBTYPE_ARGB32
|| subtype
== MEDIASUBTYPE_RGB32
? 32 :
418 subtype
== MEDIASUBTYPE_RGB24
? 24 :
419 subtype
== MEDIASUBTYPE_RGB565
? 16 : 0;
421 if(bihOut
.biCompression
== '2YUY')
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
);
437 return VFW_E_TYPE_NOT_ACCEPTED
;
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
)
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
;
472 position
= GetOutputSubtypePosition(mtOut
->subtype
);
475 hr
= GetMediaType(position
, &desiredMt
);
478 DbgLog((LOG_ERROR
, 3, TEXT("Unexpected error when GetMediaType, position:%d"), position
));
482 hr
= DoCheckTransform(&desiredMt
, mtOut
, true);
485 DbgLog((LOG_TRACE
, 3, TEXT("Transform not accept:")));
486 DisplayType(0,&desiredMt
);
487 DisplayType(0,mtOut
);
491 hr
= m_pInput
->GetConnected()->QueryAccept(&desiredMt
);
494 DbgLog((LOG_TRACE
, 3, TEXT("Upstream not accept:")));
495 DisplayType(0, &desiredMt
);
499 can_reconnect
= true;
507 DbgLog((LOG_TRACE
, 3, TEXT("agree input media type:")));
508 DisplayType(0, &desiredMt
);
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
;
565 hr
= GetMediaType(position
, &desiredMt
);
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
)
578 can_reconnect
= true;
584 DbgLog((LOG_TRACE
, 3, TEXT("agree input media type:")));
585 DisplayType(0, &desiredMt
);
589 else if(can_transform
)
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
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;
627 ALLOCATOR_PROPERTIES Actual
;
628 if(FAILED(hr
= pAllocator
->SetProperties(pProperties
, &Actual
)))
631 return pProperties
->cBuffers
> Actual
.cBuffers
|| pProperties
->cbBuffer
> Actual
.cbBuffer
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
);
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;
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
;
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
);
709 int CBaseVideoFilter::GetInputSubtypePosition( const GUID
& subtype
)
711 if(m_inputFmtCount
<0)
713 InitInputColorSpaces();
717 for (i
=0;i
<m_inputFmtCount
;i
++)
719 if (*m_inputFmt
[i
]==subtype
)
724 return i
<m_inputFmtCount
? i
: -1;
727 int CBaseVideoFilter::GetOutputSubtypePosition( const GUID
& subtype
, int startPos
/*=0*/ )
729 if(m_outputFmtCount
<0)
731 InitOutputColorSpaces();
734 for(i
=startPos
;i
<m_outputFmtCount
;i
++)
736 if (*(m_outputFmt
[i
]->subtype
)==subtype
)
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
);
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
)
773 return __super::SetMediaType(dir
, pmt
);
776 void CBaseVideoFilter::InitInputColorSpaces()
778 ColorSpaceId preferredOrder
[MAX_COLOR_SPACE_NUM
];
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
];
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
];
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
;
835 hr
= m_pInput
->GetConnected()->EnumMediaTypes( &pEnumMediaTypes
);
839 ASSERT(pEnumMediaTypes
);
841 hr
= pEnumMediaTypes
->Reset();
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
;
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
);
860 if (S_OK
== hrFailure
) {
861 hrFailure
= VFW_E_NO_ACCEPTABLE_TYPES
;
865 ASSERT(ulMediaCount
== 1);
868 ColorSpaceId pos
= Subtype2OutputColorSpaceId(pMediaType
->subtype
, 0);
869 while(pos
>=0 && pos
<count
)
871 priorities
[pos
] = priority
;
873 pos
= Subtype2OutputColorSpaceId(pMediaType
->subtype
, pos
+1);
876 DeleteMediaType(pMediaType
);
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
)
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);
916 // CBaseVideoInputAllocator
919 CBaseVideoInputAllocator::CBaseVideoInputAllocator(HRESULT
* phr
)
920 : CMemAllocator(NAME("CBaseVideoInputAllocator"), NULL
, phr
)
925 void CBaseVideoInputAllocator::SetMediaType(const CMediaType
& mt
)
930 STDMETHODIMP
CBaseVideoInputAllocator::GetBuffer(IMediaSample
** ppBuffer
, REFERENCE_TIME
* pStartTime
, REFERENCE_TIME
* pEndTime
, DWORD dwFlags
)
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
;
947 // CBaseVideoInputPin
950 CBaseVideoInputPin::CBaseVideoInputPin(TCHAR
* pObjectName
, CBaseVideoFilter
* pFilter
, HRESULT
* phr
, LPCWSTR pName
)
951 : CTransformInputPin(pObjectName
, pFilter
, phr
, pName
)
956 CBaseVideoInputPin::~CBaseVideoInputPin()
961 STDMETHODIMP
CBaseVideoInputPin::GetAllocator(IMemAllocator
** ppAllocator
)
963 CheckPointer(ppAllocator
, E_POINTER
);
965 if(m_pAllocator
== NULL
)
968 m_pAllocator
= new CBaseVideoInputAllocator(&hr
);
969 m_pAllocator
->AddRef();
972 (*ppAllocator
= m_pAllocator
)->AddRef();
977 STDMETHODIMP
CBaseVideoInputPin::ReceiveConnection(IPin
* pConnector
, const AM_MEDIA_TYPE
* pmt
)
979 CAutoLock
cObjectLock(m_pLock
);
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
)))
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
)
1006 m_pAllocator
->SetMediaType(mt
);
1008 return SetMediaType(&mt
) == 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
)
1029 HRESULT hr
= ((CBaseVideoFilter
*)m_pFilter
)->CheckOutputType(*mtOut
);
1030 if(FAILED(hr
)) return hr
;
1033 return __super::CheckMediaType(mtOut
);
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