Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / media / capture / video / win / sink_input_pin_win.cc
blob91baf2a83b5213e254340c9b350ba72336ed7480
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"
7 #include <cstring>
9 // Avoid including strsafe.h via dshow as it will cause build warnings.
10 #define NO_DSHOW_STRSAFE
11 #include <dshow.h>
13 #include "base/logging.h"
15 namespace media {
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,
29 float frame_rate,
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)
42 return false;
44 const GUID format_type = media_type->formattype;
45 if (format_type != FORMAT_VideoInfo)
46 return false;
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);
52 if (pvi == NULL)
53 return false;
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);
61 } else {
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;
67 return true;
69 if (sub_type == MEDIASUBTYPE_YUY2 &&
70 pvi->bmiHeader.biCompression == MAKEFOURCC('Y', 'U', 'Y', '2')) {
71 resulting_format_.pixel_format = PIXEL_FORMAT_YUY2;
72 return true;
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;
78 return true;
80 if (sub_type == MEDIASUBTYPE_MJPG &&
81 pvi->bmiHeader.biCompression == MAKEFOURCC('M', 'J', 'P', 'G')) {
82 resulting_format_.pixel_format = PIXEL_FORMAT_MJPEG;
83 return true;
85 if (sub_type == MEDIASUBTYPE_RGB24 &&
86 pvi->bmiHeader.biCompression == BI_RGB) {
87 resulting_format_.pixel_format = PIXEL_FORMAT_RGB24;
88 return true;
90 if (sub_type == MEDIASUBTYPE_RGB32 &&
91 pvi->bmiHeader.biCompression == BI_RGB) {
92 resulting_format_.pixel_format = PIXEL_FORMAT_RGB32;
93 return true;
96 #ifndef NDEBUG
97 WCHAR guid_str[128];
98 StringFromGUID2(sub_type, guid_str, arraysize(guid_str));
99 DVLOG(2) << __FUNCTION__ << " unsupported media type: " << guid_str;
100 #endif
101 return false;
104 bool SinkInputPin::GetValidMediaType(int index, AM_MEDIA_TYPE* media_type) {
105 if (media_type->cbFormat < sizeof(VIDEOINFOHEADER))
106 return false;
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.
127 if (index != 0)
128 return false;
130 pvi->bmiHeader = requested_info_header_;
131 return true;
134 switch (index) {
135 case 0: {
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;
142 break;
144 case 1: {
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;
151 break;
153 case 2: {
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;
160 break;
162 case 3: {
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;
169 break;
171 case 4: {
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;
178 break;
180 default:
181 return false;
184 media_type->bFixedSizeSamples = TRUE;
185 media_type->lSampleSize = pvi->bmiHeader.biSizeImage;
186 return true;
189 HRESULT SinkInputPin::Receive(IMediaSample* sample) {
190 const int length = sample->GetActualDataLength();
191 uint8* buffer = NULL;
193 if (length <= 0) {
194 DLOG(WARNING) << "Media sample length is 0 or less.";
195 return S_FALSE;
198 if (FAILED(sample->GetPointer(&buffer)))
199 return S_FALSE;
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);
206 } else {
207 timestamp = base::TimeTicks::Now();
211 observer_->FrameReceived(buffer, length, timestamp);
212 return S_OK;
215 SinkInputPin::~SinkInputPin() {
218 } // namespace media