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 #pragma warning(disable:4995)
32 #include "..\..\..\..\include\moreuuids.h"
37 const GUID
* InputFmts
[] =
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
89 CString
GetColorSpaceName(ColorSpaceId colorSpace
, ColorSpaceDir inputOrOutput
)
91 if(inputOrOutput
==INPUT_COLOR_SPACE
)
92 return Subtype2String(*InputFmts
[colorSpace
]);
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
)
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)
134 m_pInput
= new CBaseVideoInputPin(NAME("CBaseVideoInputPin"), this, &hr
, L
"Video");
137 if (phr
) *phr
= E_OUTOFMEMORY
;
145 m_pOutput
= new CBaseVideoOutputPin(NAME("CBaseVideoOutputPin"), this, &hr
, L
"Output");
148 delete m_pInput
, m_pInput
= NULL
;
149 if (phr
) *phr
= E_OUTOFMEMORY
;
154 delete m_pInput
, m_pInput
= NULL
;
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()
174 CBasePin
* CBaseVideoFilter::GetPin(int n
)
178 case 0: return m_pInput
;
179 case 1: return m_pOutput
;
184 HRESULT
CBaseVideoFilter::Receive(IMediaSample
* pIn
)
188 _mm_empty(); // just for safety
191 CAutoLock
cAutoLock(&m_csReceive
);
195 AM_SAMPLE2_PROPERTIES
* const pProps
= m_pInput
->SampleProps();
196 if(pProps
->dwStreamId
!= AM_STREAM_MEDIA
)
197 return m_pOutput
->Deliver(pIn
);
200 if(SUCCEEDED(pIn
->GetMediaType(&pmt
)) && pmt
)
203 m_pInput
->SetMediaType(&mt
);
204 DeleteMediaType(pmt
);
207 if(FAILED(hr
= Transform(pIn
)))
213 HRESULT
CBaseVideoFilter::GetDeliveryBuffer(int w
, int h
, IMediaSample
** ppOut
)
215 CheckPointer(ppOut
, E_POINTER
);
219 if(FAILED(hr
= ReconnectOutput(w
, h
)))
222 if(FAILED(hr
= m_pOutput
->GetDeliveryBuffer(ppOut
, NULL
, NULL
, 0)))
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
);
244 HRESULT
CBaseVideoFilter::ReconnectOutput(int w
, int h
)
246 CMediaType
& mt
= m_pOutput
->CurrentMediaType();
251 bool fForceReconnection
= false;
252 if(w
!= m_w
|| h
!= m_h
)
254 fForceReconnection
= true;
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);
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
;
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)))
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
;
326 // some renderers don't send this
327 NotifyEvent(EC_VIDEO_SIZE_CHANGED
, MAKELPARAM(m_w
, m_h
), 0);
335 HRESULT
CBaseVideoFilter::CopyBuffer(BYTE
* pOut
, BYTE
* pIn
, int w
, int h
, int pitchIn
, const GUID
& subtype
, bool fInterlaced
)
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
);
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
;
360 if (bihOut
.biCompression
== 'VUYA')
362 pitchOut
= bihOut
.biWidth
*bihOut
.biBitCount
>>3;
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);
382 if(subtype
== MEDIASUBTYPE_I420
|| subtype
== MEDIASUBTYPE_IYUV
|| subtype
== MEDIASUBTYPE_YV12
)
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')
400 BitBltFromI420ToYUY2(w
, h
, pOut
, bihOut
.biWidth
*2, pIn
, pInU
, pInV
, pitchIn
);
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
)
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')
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
);
470 return VFW_E_TYPE_NOT_ACCEPTED
;
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
)
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
;
505 position
= GetOutputSubtypePosition(mtOut
->subtype
);
508 hr
= GetMediaType(position
, &desiredMt
);
511 DbgLog((LOG_ERROR
, 3, TEXT("Unexpected error when GetMediaType, position:%d"), position
));
515 hr
= DoCheckTransform(&desiredMt
, mtOut
, true);
518 DbgLog((LOG_TRACE
, 3, TEXT("Transform not accept:")));
519 DisplayType(0,&desiredMt
);
520 DisplayType(0,mtOut
);
524 hr
= m_pInput
->GetConnected()->QueryAccept(&desiredMt
);
527 DbgLog((LOG_TRACE
, 3, TEXT("Upstream not accept:")));
528 DisplayType(0, &desiredMt
);
532 can_reconnect
= true;
540 DbgLog((LOG_TRACE
, 3, TEXT("agree input media type:")));
541 DisplayType(0, &desiredMt
);
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
;
599 hr
= GetMediaType(position
, &desiredMt
);
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
)
612 can_reconnect
= true;
618 DbgLog((LOG_TRACE
, 3, TEXT("agree input media type:")));
619 DisplayType(0, &desiredMt
);
623 else if(can_transform
)
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
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;
661 ALLOCATOR_PROPERTIES Actual
;
662 if(FAILED(hr
= pAllocator
->SetProperties(pProperties
, &Actual
)))
665 return pProperties
->cBuffers
> Actual
.cBuffers
|| pProperties
->cbBuffer
> Actual
.cbBuffer
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
);
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;
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
;
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
);
743 int CBaseVideoFilter::GetInputSubtypePosition( const GUID
& subtype
)
745 if(m_inputFmtCount
<0)
747 InitInputColorSpaces();
751 for (i
=0;i
<m_inputFmtCount
;i
++)
753 if (*m_inputFmt
[i
]==subtype
)
758 return i
<m_inputFmtCount
? i
: -1;
761 int CBaseVideoFilter::GetOutputSubtypePosition( const GUID
& subtype
, int startPos
/*=0*/ )
763 if(m_outputFmtCount
<0)
765 InitOutputColorSpaces();
768 for(i
=startPos
;i
<m_outputFmtCount
;i
++)
770 if (*(m_outputFmt
[i
]->subtype
)==subtype
)
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
);
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
)
807 return __super::SetMediaType(dir
, pmt
);
810 void CBaseVideoFilter::InitInputColorSpaces()
812 ColorSpaceId preferredOrder
[MAX_COLOR_SPACE_NUM
];
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
];
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
];
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
;
869 hr
= m_pInput
->GetConnected()->EnumMediaTypes( &pEnumMediaTypes
);
873 ASSERT(pEnumMediaTypes
);
875 hr
= pEnumMediaTypes
->Reset();
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
;
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
);
894 if (S_OK
== hrFailure
) {
895 hrFailure
= VFW_E_NO_ACCEPTABLE_TYPES
;
899 ASSERT(ulMediaCount
== 1);
902 ColorSpaceId pos
= Subtype2OutputColorSpaceId(pMediaType
->subtype
, 0);
903 while(pos
>=0 && pos
<count
)
905 priorities
[pos
] = priority
;
907 pos
= Subtype2OutputColorSpaceId(pMediaType
->subtype
, pos
+1);
910 DeleteMediaType(pMediaType
);
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
)
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);
950 // CBaseVideoInputAllocator
953 CBaseVideoInputAllocator::CBaseVideoInputAllocator(HRESULT
* phr
)
954 : CMemAllocator(NAME("CBaseVideoInputAllocator"), NULL
, phr
)
959 void CBaseVideoInputAllocator::SetMediaType(const CMediaType
& mt
)
964 STDMETHODIMP
CBaseVideoInputAllocator::GetBuffer(IMediaSample
** ppBuffer
, REFERENCE_TIME
* pStartTime
, REFERENCE_TIME
* pEndTime
, DWORD dwFlags
)
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
;
981 // CBaseVideoInputPin
984 CBaseVideoInputPin::CBaseVideoInputPin(TCHAR
* pObjectName
, CBaseVideoFilter
* pFilter
, HRESULT
* phr
, LPCWSTR pName
)
985 : CTransformInputPin(pObjectName
, pFilter
, phr
, pName
)
990 CBaseVideoInputPin::~CBaseVideoInputPin()
995 STDMETHODIMP
CBaseVideoInputPin::GetAllocator(IMemAllocator
** ppAllocator
)
997 CheckPointer(ppAllocator
, E_POINTER
);
999 if(m_pAllocator
== NULL
)
1002 m_pAllocator
= new CBaseVideoInputAllocator(&hr
);
1003 m_pAllocator
->AddRef();
1006 (*ppAllocator
= m_pAllocator
)->AddRef();
1011 STDMETHODIMP
CBaseVideoInputPin::ReceiveConnection(IPin
* pConnector
, const AM_MEDIA_TYPE
* pmt
)
1013 CAutoLock
cObjectLock(m_pLock
);
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
)))
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
)
1040 m_pAllocator
->SetMediaType(mt
);
1042 return SetMediaType(&mt
) == 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
)
1063 HRESULT hr
= ((CBaseVideoFilter
*)m_pFilter
)->CheckOutputType(*mtOut
);
1064 if(FAILED(hr
)) return hr
;
1067 return __super::CheckMediaType(mtOut
);
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