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 VideoPixelFormat 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
= PIXEL_FORMAT_UNKNOWN
;
39 bool SinkInputPin::IsMediaTypeValid(const AM_MEDIA_TYPE
* media_type
) {
40 const GUID type
= media_type
->majortype
;
41 if (type
!= MEDIATYPE_Video
)
44 const GUID format_type
= media_type
->formattype
;
45 if (format_type
!= FORMAT_VideoInfo
)
48 // Check for the sub types we support.
49 const GUID sub_type
= media_type
->subtype
;
50 VIDEOINFOHEADER
* pvi
=
51 reinterpret_cast<VIDEOINFOHEADER
*>(media_type
->pbFormat
);
55 // Store the incoming width and height.
56 resulting_format_
.frame_size
.SetSize(pvi
->bmiHeader
.biWidth
,
57 abs(pvi
->bmiHeader
.biHeight
));
58 if (pvi
->AvgTimePerFrame
> 0) {
59 resulting_format_
.frame_rate
=
60 static_cast<int>(kSecondsToReferenceTime
/ pvi
->AvgTimePerFrame
);
62 resulting_format_
.frame_rate
= requested_frame_rate_
;
64 if (sub_type
== kMediaSubTypeI420
&&
65 pvi
->bmiHeader
.biCompression
== MAKEFOURCC('I', '4', '2', '0')) {
66 resulting_format_
.pixel_format
= PIXEL_FORMAT_I420
;
69 if (sub_type
== MEDIASUBTYPE_YUY2
&&
70 pvi
->bmiHeader
.biCompression
== MAKEFOURCC('Y', 'U', 'Y', '2')) {
71 resulting_format_
.pixel_format
= PIXEL_FORMAT_YUY2
;
74 // This format is added after http:/crbug.com/508413.
75 if (sub_type
== MEDIASUBTYPE_UYVY
&&
76 pvi
->bmiHeader
.biCompression
== MAKEFOURCC('U', 'Y', 'V', 'Y')) {
77 resulting_format_
.pixel_format
= PIXEL_FORMAT_UYVY
;
80 if (sub_type
== MEDIASUBTYPE_MJPG
&&
81 pvi
->bmiHeader
.biCompression
== MAKEFOURCC('M', 'J', 'P', 'G')) {
82 resulting_format_
.pixel_format
= PIXEL_FORMAT_MJPEG
;
85 if (sub_type
== MEDIASUBTYPE_RGB24
&&
86 pvi
->bmiHeader
.biCompression
== BI_RGB
) {
87 resulting_format_
.pixel_format
= PIXEL_FORMAT_RGB24
;
90 if (sub_type
== MEDIASUBTYPE_RGB32
&&
91 pvi
->bmiHeader
.biCompression
== BI_RGB
) {
92 resulting_format_
.pixel_format
= PIXEL_FORMAT_RGB32
;
98 StringFromGUID2(sub_type
, guid_str
, arraysize(guid_str
));
99 DVLOG(2) << __FUNCTION__
<< " unsupported media type: " << guid_str
;
104 bool SinkInputPin::GetValidMediaType(int index
, AM_MEDIA_TYPE
* media_type
) {
105 if (media_type
->cbFormat
< sizeof(VIDEOINFOHEADER
))
108 VIDEOINFOHEADER
* const pvi
=
109 reinterpret_cast<VIDEOINFOHEADER
*>(media_type
->pbFormat
);
111 ZeroMemory(pvi
, sizeof(VIDEOINFOHEADER
));
112 pvi
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
113 pvi
->bmiHeader
.biPlanes
= 1;
114 pvi
->bmiHeader
.biClrImportant
= 0;
115 pvi
->bmiHeader
.biClrUsed
= 0;
116 if (requested_frame_rate_
> 0)
117 pvi
->AvgTimePerFrame
= kSecondsToReferenceTime
/ requested_frame_rate_
;
119 media_type
->majortype
= MEDIATYPE_Video
;
120 media_type
->formattype
= FORMAT_VideoInfo
;
121 media_type
->bTemporalCompression
= FALSE
;
123 if (requested_pixel_format_
== PIXEL_FORMAT_MJPEG
) {
124 // If the requested pixel format is MJPEG, accept only MJPEG.
125 // This is ok since the capabilities of the capturer have been
126 // enumerated and we know that it is supported.
130 pvi
->bmiHeader
= requested_info_header_
;
136 pvi
->bmiHeader
.biCompression
= MAKEFOURCC('I', '4', '2', '0');
137 pvi
->bmiHeader
.biBitCount
= 12; // bit per pixel
138 pvi
->bmiHeader
.biWidth
= requested_info_header_
.biWidth
;
139 pvi
->bmiHeader
.biHeight
= requested_info_header_
.biHeight
;
140 pvi
->bmiHeader
.biSizeImage
= GetArea(requested_info_header_
) * 3 / 2;
141 media_type
->subtype
= kMediaSubTypeI420
;
145 pvi
->bmiHeader
.biCompression
= MAKEFOURCC('Y', 'U', 'Y', '2');
146 pvi
->bmiHeader
.biBitCount
= 16;
147 pvi
->bmiHeader
.biWidth
= requested_info_header_
.biWidth
;
148 pvi
->bmiHeader
.biHeight
= requested_info_header_
.biHeight
;
149 pvi
->bmiHeader
.biSizeImage
= GetArea(requested_info_header_
) * 2;
150 media_type
->subtype
= MEDIASUBTYPE_YUY2
;
154 pvi
->bmiHeader
.biCompression
= MAKEFOURCC('U', 'Y', 'V', 'Y');
155 pvi
->bmiHeader
.biBitCount
= 16;
156 pvi
->bmiHeader
.biWidth
= requested_info_header_
.biWidth
;
157 pvi
->bmiHeader
.biHeight
= requested_info_header_
.biHeight
;
158 pvi
->bmiHeader
.biSizeImage
= GetArea(requested_info_header_
) * 2;
159 media_type
->subtype
= MEDIASUBTYPE_UYVY
;
163 pvi
->bmiHeader
.biCompression
= BI_RGB
;
164 pvi
->bmiHeader
.biBitCount
= 24;
165 pvi
->bmiHeader
.biWidth
= requested_info_header_
.biWidth
;
166 pvi
->bmiHeader
.biHeight
= requested_info_header_
.biHeight
;
167 pvi
->bmiHeader
.biSizeImage
= GetArea(requested_info_header_
) * 3;
168 media_type
->subtype
= MEDIASUBTYPE_RGB24
;
172 pvi
->bmiHeader
.biCompression
= BI_RGB
;
173 pvi
->bmiHeader
.biBitCount
= 32;
174 pvi
->bmiHeader
.biWidth
= requested_info_header_
.biWidth
;
175 pvi
->bmiHeader
.biHeight
= requested_info_header_
.biHeight
;
176 pvi
->bmiHeader
.biSizeImage
= GetArea(requested_info_header_
) * 4;
177 media_type
->subtype
= MEDIASUBTYPE_RGB32
;
184 media_type
->bFixedSizeSamples
= TRUE
;
185 media_type
->lSampleSize
= pvi
->bmiHeader
.biSizeImage
;
189 HRESULT
SinkInputPin::Receive(IMediaSample
* sample
) {
190 const int length
= sample
->GetActualDataLength();
191 uint8
* buffer
= NULL
;
194 DLOG(WARNING
) << "Media sample length is 0 or less.";
198 if (FAILED(sample
->GetPointer(&buffer
)))
201 REFERENCE_TIME start_time
, end_time
;
202 base::TimeTicks timestamp
;
203 if (SUCCEEDED(sample
->GetTime(&start_time
, &end_time
))) {
204 DCHECK(start_time
<= end_time
);
205 timestamp
+= base::TimeDelta::FromMicroseconds(start_time
/ 10);
207 timestamp
= base::TimeTicks::Now();
211 observer_
->FrameReceived(buffer
, length
, timestamp
);
215 SinkInputPin::~SinkInputPin() {