| 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 |