1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/capture/video/win/sink_input_pin_win.h"
9 // Avoid including strsafe.h via dshow as it will cause build warnings.
10 #define NO_DSHOW_STRSAFE
13 #include "base/logging.h"
17 const REFERENCE_TIME kSecondsToReferenceTime
= 10000000;
19 static DWORD
GetArea(const BITMAPINFOHEADER
& info_header
) {
20 return info_header
.biWidth
* info_header
.biHeight
;
23 SinkInputPin::SinkInputPin(IBaseFilter
* filter
, SinkFilterObserver
* observer
)
24 : PinBase(filter
), requested_frame_rate_(0), observer_(observer
) {
27 void SinkInputPin::SetRequestedMediaFormat(
28 VideoCapturePixelFormat pixel_format
,
30 const BITMAPINFOHEADER
& info_header
) {
31 requested_pixel_format_
= pixel_format
;
32 requested_frame_rate_
= frame_rate
;
33 requested_info_header_
= info_header
;
34 resulting_format_
.frame_size
.SetSize(0, 0);
35 resulting_format_
.frame_rate
= 0;
36 resulting_format_
.pixel_format
= VIDEO_CAPTURE_PIXEL_FORMAT_UNKNOWN
;
39 const VideoCaptureFormat
& SinkInputPin::ResultingFormat() {
40 return resulting_format_
;
43 bool SinkInputPin::IsMediaTypeValid(const AM_MEDIA_TYPE
* media_type
) {
44 GUID type
= media_type
->majortype
;
45 if (type
!= MEDIATYPE_Video
)
48 GUID format_type
= media_type
->formattype
;
49 if (format_type
!= FORMAT_VideoInfo
)
52 // Check for the sub types we support.
53 GUID sub_type
= media_type
->subtype
;
54 VIDEOINFOHEADER
* pvi
=
55 reinterpret_cast<VIDEOINFOHEADER
*>(media_type
->pbFormat
);
59 // Store the incoming width and height.
60 resulting_format_
.frame_size
.SetSize(pvi
->bmiHeader
.biWidth
,
61 abs(pvi
->bmiHeader
.biHeight
));
62 if (pvi
->AvgTimePerFrame
> 0) {
63 resulting_format_
.frame_rate
=
64 static_cast<int>(kSecondsToReferenceTime
/ pvi
->AvgTimePerFrame
);
66 resulting_format_
.frame_rate
= requested_frame_rate_
;
68 if (sub_type
== kMediaSubTypeI420
&&
69 pvi
->bmiHeader
.biCompression
== MAKEFOURCC('I', '4', '2', '0')) {
70 resulting_format_
.pixel_format
= VIDEO_CAPTURE_PIXEL_FORMAT_I420
;
73 if (sub_type
== MEDIASUBTYPE_YUY2
&&
74 pvi
->bmiHeader
.biCompression
== MAKEFOURCC('Y', 'U', 'Y', '2')) {
75 resulting_format_
.pixel_format
= VIDEO_CAPTURE_PIXEL_FORMAT_YUY2
;
78 if (sub_type
== MEDIASUBTYPE_MJPG
&&
79 pvi
->bmiHeader
.biCompression
== MAKEFOURCC('M', 'J', 'P', 'G')) {
80 resulting_format_
.pixel_format
= VIDEO_CAPTURE_PIXEL_FORMAT_MJPEG
;
83 if (sub_type
== MEDIASUBTYPE_RGB24
&&
84 pvi
->bmiHeader
.biCompression
== BI_RGB
) {
85 resulting_format_
.pixel_format
= VIDEO_CAPTURE_PIXEL_FORMAT_RGB24
;
88 if (sub_type
== MEDIASUBTYPE_RGB32
&&
89 pvi
->bmiHeader
.biCompression
== BI_RGB
) {
90 resulting_format_
.pixel_format
= VIDEO_CAPTURE_PIXEL_FORMAT_RGB32
;
96 bool SinkInputPin::GetValidMediaType(int index
, AM_MEDIA_TYPE
* media_type
) {
97 if (media_type
->cbFormat
< sizeof(VIDEOINFOHEADER
))
100 VIDEOINFOHEADER
* pvi
=
101 reinterpret_cast<VIDEOINFOHEADER
*>(media_type
->pbFormat
);
103 ZeroMemory(pvi
, sizeof(VIDEOINFOHEADER
));
104 pvi
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
105 pvi
->bmiHeader
.biPlanes
= 1;
106 pvi
->bmiHeader
.biClrImportant
= 0;
107 pvi
->bmiHeader
.biClrUsed
= 0;
108 if (requested_frame_rate_
> 0) {
109 pvi
->AvgTimePerFrame
= kSecondsToReferenceTime
/ requested_frame_rate_
;
112 media_type
->majortype
= MEDIATYPE_Video
;
113 media_type
->formattype
= FORMAT_VideoInfo
;
114 media_type
->bTemporalCompression
= FALSE
;
116 if (requested_pixel_format_
== VIDEO_CAPTURE_PIXEL_FORMAT_MJPEG
) {
117 // If the requested pixel format is MJPEG, accept only MJPEG.
118 // This is ok since the capabilities of the capturer have been
119 // enumerated and we know that it is supported.
123 pvi
->bmiHeader
= requested_info_header_
;
129 pvi
->bmiHeader
.biCompression
= MAKEFOURCC('I', '4', '2', '0');
130 pvi
->bmiHeader
.biBitCount
= 12; // bit per pixel
131 pvi
->bmiHeader
.biWidth
= requested_info_header_
.biWidth
;
132 pvi
->bmiHeader
.biHeight
= requested_info_header_
.biHeight
;
133 pvi
->bmiHeader
.biSizeImage
= GetArea(requested_info_header_
) * 3 / 2;
134 media_type
->subtype
= kMediaSubTypeI420
;
138 pvi
->bmiHeader
.biCompression
= MAKEFOURCC('Y', 'U', 'Y', '2');
139 pvi
->bmiHeader
.biBitCount
= 16;
140 pvi
->bmiHeader
.biWidth
= requested_info_header_
.biWidth
;
141 pvi
->bmiHeader
.biHeight
= requested_info_header_
.biHeight
;
142 pvi
->bmiHeader
.biSizeImage
= GetArea(requested_info_header_
) * 2;
143 media_type
->subtype
= MEDIASUBTYPE_YUY2
;
147 pvi
->bmiHeader
.biCompression
= BI_RGB
;
148 pvi
->bmiHeader
.biBitCount
= 24;
149 pvi
->bmiHeader
.biWidth
= requested_info_header_
.biWidth
;
150 pvi
->bmiHeader
.biHeight
= requested_info_header_
.biHeight
;
151 pvi
->bmiHeader
.biSizeImage
= GetArea(requested_info_header_
) * 3;
152 media_type
->subtype
= MEDIASUBTYPE_RGB24
;
156 pvi
->bmiHeader
.biCompression
= BI_RGB
;
157 pvi
->bmiHeader
.biBitCount
= 32;
158 pvi
->bmiHeader
.biWidth
= requested_info_header_
.biWidth
;
159 pvi
->bmiHeader
.biHeight
= requested_info_header_
.biHeight
;
160 pvi
->bmiHeader
.biSizeImage
= GetArea(requested_info_header_
) * 4;
161 media_type
->subtype
= MEDIASUBTYPE_RGB32
;
168 media_type
->bFixedSizeSamples
= TRUE
;
169 media_type
->lSampleSize
= pvi
->bmiHeader
.biSizeImage
;
173 HRESULT
SinkInputPin::Receive(IMediaSample
* sample
) {
174 const int length
= sample
->GetActualDataLength();
175 uint8
* buffer
= NULL
;
178 DLOG(WARNING
) << "Media sample length is 0 or less.";
182 if (FAILED(sample
->GetPointer(&buffer
)))
185 observer_
->FrameReceived(buffer
, length
);
189 SinkInputPin::~SinkInputPin() {