OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/video/capture/win/video_capture_device_mf_win.h" | 5 #include "media/video/capture/win/video_capture_device_mf_win.h" |
6 | 6 |
7 #include <mfapi.h> | 7 #include <mfapi.h> |
8 #include <mferror.h> | 8 #include <mferror.h> |
9 | 9 |
10 #include "base/memory/ref_counted.h" | 10 #include "base/memory/ref_counted.h" |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
64 capability->frame_rate_numerator / capability->frame_rate_denominator; | 64 capability->frame_rate_numerator / capability->frame_rate_denominator; |
65 | 65 |
66 return true; | 66 return true; |
67 } | 67 } |
68 | 68 |
69 HRESULT FillCapabilities(IMFSourceReader* source, | 69 HRESULT FillCapabilities(IMFSourceReader* source, |
70 CapabilityList* capabilities) { | 70 CapabilityList* capabilities) { |
71 DWORD stream_index = 0; | 71 DWORD stream_index = 0; |
72 ScopedComPtr<IMFMediaType> type; | 72 ScopedComPtr<IMFMediaType> type; |
73 HRESULT hr; | 73 HRESULT hr; |
74 while (SUCCEEDED(hr = source->GetNativeMediaType( | 74 for (hr = source->GetNativeMediaType(kFirstVideoStream, stream_index, |
75 MF_SOURCE_READER_FIRST_VIDEO_STREAM, stream_index, type.Receive()))) { | 75 type.Receive()); |
| 76 SUCCEEDED(hr); |
| 77 hr = source->GetNativeMediaType(kFirstVideoStream, stream_index, |
| 78 type.Receive())) { |
76 VideoCaptureCapabilityWin capability(stream_index++); | 79 VideoCaptureCapabilityWin capability(stream_index++); |
77 if (FillCapabilitiesFromType(type, &capability)) | 80 if (FillCapabilitiesFromType(type, &capability)) |
78 capabilities->Add(capability); | 81 capabilities->Add(capability); |
79 type.Release(); | 82 type.Release(); |
80 } | 83 } |
81 | 84 |
82 if (capabilities->empty() && (SUCCEEDED(hr) || hr == MF_E_NO_MORE_TYPES)) | 85 if (capabilities->empty() && (SUCCEEDED(hr) || hr == MF_E_NO_MORE_TYPES)) |
83 hr = HRESULT_FROM_WIN32(ERROR_EMPTY); | 86 hr = HRESULT_FROM_WIN32(ERROR_EMPTY); |
84 | 87 |
85 return (hr == MF_E_NO_MORE_TYPES) ? S_OK : hr; | 88 return (hr == MF_E_NO_MORE_TYPES) ? S_OK : hr; |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
187 | 190 |
188 return false; | 191 return false; |
189 } | 192 } |
190 | 193 |
191 const std::string VideoCaptureDevice::Name::GetModel() const { | 194 const std::string VideoCaptureDevice::Name::GetModel() const { |
192 const size_t vid_prefix_size = sizeof(kVidPrefix) - 1; | 195 const size_t vid_prefix_size = sizeof(kVidPrefix) - 1; |
193 const size_t pid_prefix_size = sizeof(kPidPrefix) - 1; | 196 const size_t pid_prefix_size = sizeof(kPidPrefix) - 1; |
194 const size_t vid_location = unique_id_.find(kVidPrefix); | 197 const size_t vid_location = unique_id_.find(kVidPrefix); |
195 if (vid_location == std::string::npos || | 198 if (vid_location == std::string::npos || |
196 vid_location + vid_prefix_size + kVidPidSize > unique_id_.size()) { | 199 vid_location + vid_prefix_size + kVidPidSize > unique_id_.size()) { |
197 return ""; | 200 return std::string(); |
198 } | 201 } |
199 const size_t pid_location = unique_id_.find(kPidPrefix); | 202 const size_t pid_location = unique_id_.find(kPidPrefix); |
200 if (pid_location == std::string::npos || | 203 if (pid_location == std::string::npos || |
201 pid_location + pid_prefix_size + kVidPidSize > unique_id_.size()) { | 204 pid_location + pid_prefix_size + kVidPidSize > unique_id_.size()) { |
202 return ""; | 205 return std::string(); |
203 } | 206 } |
204 std::string id_vendor = | 207 std::string id_vendor = |
205 unique_id_.substr(vid_location + vid_prefix_size, kVidPidSize); | 208 unique_id_.substr(vid_location + vid_prefix_size, kVidPidSize); |
206 std::string id_product = | 209 std::string id_product = |
207 unique_id_.substr(pid_location + pid_prefix_size, kVidPidSize); | 210 unique_id_.substr(pid_location + pid_prefix_size, kVidPidSize); |
208 return id_vendor + ":" + id_product; | 211 return id_vendor + ":" + id_product; |
209 } | 212 } |
210 | 213 |
211 VideoCaptureDeviceMFWin::VideoCaptureDeviceMFWin(const Name& device_name) | 214 VideoCaptureDeviceMFWin::VideoCaptureDeviceMFWin(const Name& device_name) |
212 : name_(device_name), capture_(0) { | 215 : name_(device_name), capture_(0) { |
(...skipping 25 matching lines...) Expand all Loading... |
238 scoped_ptr<VideoCaptureDevice::Client> client) { | 241 scoped_ptr<VideoCaptureDevice::Client> client) { |
239 DCHECK(CalledOnValidThread()); | 242 DCHECK(CalledOnValidThread()); |
240 | 243 |
241 base::AutoLock lock(lock_); | 244 base::AutoLock lock(lock_); |
242 | 245 |
243 client_ = client.Pass(); | 246 client_ = client.Pass(); |
244 DCHECK_EQ(capture_, false); | 247 DCHECK_EQ(capture_, false); |
245 | 248 |
246 CapabilityList capabilities; | 249 CapabilityList capabilities; |
247 HRESULT hr = S_OK; | 250 HRESULT hr = S_OK; |
248 if (!reader_ || FAILED(hr = FillCapabilities(reader_, &capabilities))) { | 251 if (reader_) { |
249 OnError(hr); | 252 hr = FillCapabilities(reader_, &capabilities); |
250 return; | 253 if (SUCCEEDED(hr)) { |
| 254 VideoCaptureCapabilityWin found_capability = |
| 255 capabilities.GetBestMatchedFormat( |
| 256 params.requested_format.frame_size.width(), |
| 257 params.requested_format.frame_size.height(), |
| 258 params.requested_format.frame_rate); |
| 259 |
| 260 ScopedComPtr<IMFMediaType> type; |
| 261 hr = reader_->GetNativeMediaType( |
| 262 kFirstVideoStream, found_capability.stream_index, type.Receive()); |
| 263 if (SUCCEEDED(hr)) { |
| 264 hr = reader_->SetCurrentMediaType(kFirstVideoStream, NULL, type); |
| 265 if (SUCCEEDED(hr)) { |
| 266 hr = reader_->ReadSample(kFirstVideoStream, 0, NULL, NULL, NULL, |
| 267 NULL); |
| 268 if (SUCCEEDED(hr)) { |
| 269 capture_format_ = found_capability.supported_format; |
| 270 capture_ = true; |
| 271 return; |
| 272 } |
| 273 } |
| 274 } |
| 275 } |
251 } | 276 } |
252 | 277 |
253 VideoCaptureCapabilityWin found_capability = | 278 OnError(hr); |
254 capabilities.GetBestMatchedFormat( | |
255 params.requested_format.frame_size.width(), | |
256 params.requested_format.frame_size.height(), | |
257 params.requested_format.frame_rate); | |
258 | |
259 ScopedComPtr<IMFMediaType> type; | |
260 if (FAILED(hr = reader_->GetNativeMediaType( | |
261 MF_SOURCE_READER_FIRST_VIDEO_STREAM, found_capability.stream_index, | |
262 type.Receive())) || | |
263 FAILED(hr = reader_->SetCurrentMediaType( | |
264 MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, type))) { | |
265 OnError(hr); | |
266 return; | |
267 } | |
268 | |
269 if (FAILED(hr = reader_->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, | |
270 NULL, NULL, NULL, NULL))) { | |
271 OnError(hr); | |
272 return; | |
273 } | |
274 capture_format_ = found_capability.supported_format; | |
275 capture_ = true; | |
276 } | 279 } |
277 | 280 |
278 void VideoCaptureDeviceMFWin::StopAndDeAllocate() { | 281 void VideoCaptureDeviceMFWin::StopAndDeAllocate() { |
279 DCHECK(CalledOnValidThread()); | 282 DCHECK(CalledOnValidThread()); |
280 base::WaitableEvent flushed(false, false); | 283 base::WaitableEvent flushed(false, false); |
281 const int kFlushTimeOutInMs = 1000; | 284 const int kFlushTimeOutInMs = 1000; |
282 bool wait = false; | 285 bool wait = false; |
283 { | 286 { |
284 base::AutoLock lock(lock_); | 287 base::AutoLock lock(lock_); |
285 if (capture_) { | 288 if (capture_) { |
286 capture_ = false; | 289 capture_ = false; |
287 callback_->SetSignalOnFlush(&flushed); | 290 callback_->SetSignalOnFlush(&flushed); |
288 HRESULT hr = reader_->Flush(MF_SOURCE_READER_ALL_STREAMS); | 291 wait = SUCCEEDED(reader_->Flush( |
289 wait = SUCCEEDED(hr); | 292 static_cast<DWORD>(MF_SOURCE_READER_ALL_STREAMS))); |
290 if (!wait) { | 293 if (!wait) { |
291 callback_->SetSignalOnFlush(NULL); | 294 callback_->SetSignalOnFlush(NULL); |
292 } | 295 } |
293 } | 296 } |
294 client_.reset(); | 297 client_.reset(); |
295 } | 298 } |
296 | 299 |
297 // If the device has been unplugged, the Flush() won't trigger the event | 300 // If the device has been unplugged, the Flush() won't trigger the event |
298 // and a timeout will happen. | 301 // and a timeout will happen. |
299 // TODO(tommi): Hook up the IMFMediaEventGenerator notifications API and | 302 // TODO(tommi): Hook up the IMFMediaEventGenerator notifications API and |
300 // do not wait at all after getting MEVideoCaptureDeviceRemoved event. | 303 // do not wait at all after getting MEVideoCaptureDeviceRemoved event. |
301 // See issue/226396. | 304 // See issue/226396. |
302 if (wait) | 305 if (wait) |
303 flushed.TimedWait(base::TimeDelta::FromMilliseconds(kFlushTimeOutInMs)); | 306 flushed.TimedWait(base::TimeDelta::FromMilliseconds(kFlushTimeOutInMs)); |
304 } | 307 } |
305 | 308 |
306 void VideoCaptureDeviceMFWin::OnIncomingCapturedData( | 309 void VideoCaptureDeviceMFWin::OnIncomingCapturedData( |
307 const uint8* data, | 310 const uint8* data, |
308 int length, | 311 int length, |
309 int rotation, | 312 int rotation, |
310 const base::TimeTicks& time_stamp) { | 313 const base::TimeTicks& time_stamp) { |
311 base::AutoLock lock(lock_); | 314 base::AutoLock lock(lock_); |
312 if (data && client_.get()) { | 315 if (data && client_.get()) { |
313 client_->OnIncomingCapturedData( | 316 client_->OnIncomingCapturedData( |
314 data, length, capture_format_, rotation, time_stamp); | 317 data, length, capture_format_, rotation, time_stamp); |
315 } | 318 } |
316 | 319 |
317 if (capture_) { | 320 if (capture_) { |
318 HRESULT hr = reader_->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, | 321 HRESULT hr = |
319 NULL, NULL, NULL, NULL); | 322 reader_->ReadSample(kFirstVideoStream, 0, NULL, NULL, NULL, NULL); |
320 if (FAILED(hr)) { | 323 if (FAILED(hr)) { |
321 // If running the *VideoCap* unit tests on repeat, this can sometimes | 324 // If running the *VideoCap* unit tests on repeat, this can sometimes |
322 // fail with HRESULT_FROM_WINHRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION). | 325 // fail with HRESULT_FROM_WINHRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION). |
323 // It's not clear to me why this is, but it is possible that it has | 326 // It's not clear to me why this is, but it is possible that it has |
324 // something to do with this bug: | 327 // something to do with this bug: |
325 // http://support.microsoft.com/kb/979567 | 328 // http://support.microsoft.com/kb/979567 |
326 OnError(hr); | 329 OnError(hr); |
327 } | 330 } |
328 } | 331 } |
329 } | 332 } |
330 | 333 |
331 void VideoCaptureDeviceMFWin::OnError(HRESULT hr) { | 334 void VideoCaptureDeviceMFWin::OnError(HRESULT hr) { |
332 std::string log_msg = base::StringPrintf("VideoCaptureDeviceMFWin: %x", hr); | 335 std::string log_msg = base::StringPrintf("VideoCaptureDeviceMFWin: %x", hr); |
333 DLOG(ERROR) << log_msg; | 336 DLOG(ERROR) << log_msg; |
334 if (client_.get()) | 337 if (client_.get()) |
335 client_->OnError(log_msg); | 338 client_->OnError(log_msg); |
336 } | 339 } |
337 | 340 |
338 } // namespace media | 341 } // namespace media |
OLD | NEW |